[Mesa-dev] [PATCH 6/6] R600: initial scheduler code
Tom Stellard
tom at stellard.net
Tue Feb 19 07:34:54 PST 2013
Hi Vincent,
>From now on, please cc llvm-commits at cs.uiuc.edu when you submit a patch.
I'm cc'ing that list now.
This looks OK to me at first glance, but I would like to test it with
compute shaders before you merge it.
On Mon, Feb 18, 2013 at 05:27:30PM +0100, Vincent Lejeune wrote:
> From: Vadim Girlin <vadimgirlin at gmail.com>
>
> This is a skeleton for a pre-RA MachineInstr scheduler strategy. Currently
> it only tries to expose more parallelism for ALU instructions (this also
> makes the distribution of GPR channels more uniform and increases the
> chances of ALU instructions to be packed together in a single VLIW group).
> Also it tries to reduce clause switching by grouping instruction of the
> same kind (ALU/FETCH/CF) together.
>
> Vincent Lejeune:
> - Support for VLIW4 Slot assignement
> - Recomputation of ScheduleDAG to get more parallelism opportunities
>
> Tom Stellard:
> - Fix assertion failure when trying to determine an instruction's slot
> based on its destination register's class
> - Fix some compiler warnings
>
> Vincent Lejeune: [v2]
> - Remove recomputation of ScheduleDAG (will be provided in a later patch)
> - Improve estimation of an ALU clause size so that heuristic does not emit cf
> instructions at the wrong position.
> - Make schedule heuristic smarter using SUnit Depth
> - Take constant read limitations into account
> ---
> lib/Target/R600/AMDGPUTargetMachine.cpp | 17 +-
> lib/Target/R600/R600MachineScheduler.cpp | 483 +++++++++++++++++++++++++++++++
> lib/Target/R600/R600MachineScheduler.h | 121 ++++++++
> test/CodeGen/R600/fdiv.v4f32.ll | 6 +-
> 4 files changed, 623 insertions(+), 4 deletions(-)
> create mode 100644 lib/Target/R600/R600MachineScheduler.cpp
> create mode 100644 lib/Target/R600/R600MachineScheduler.h
>
> diff --git a/lib/Target/R600/AMDGPUTargetMachine.cpp b/lib/Target/R600/AMDGPUTargetMachine.cpp
> index 70b34b0..eb58853 100644
> --- a/lib/Target/R600/AMDGPUTargetMachine.cpp
> +++ b/lib/Target/R600/AMDGPUTargetMachine.cpp
> @@ -17,6 +17,7 @@
> #include "AMDGPU.h"
> #include "R600ISelLowering.h"
> #include "R600InstrInfo.h"
> +#include "R600MachineScheduler.h"
> #include "SIISelLowering.h"
> #include "SIInstrInfo.h"
> #include "llvm/Analysis/Passes.h"
> @@ -39,6 +40,14 @@ extern "C" void LLVMInitializeR600Target() {
> RegisterTargetMachine<AMDGPUTargetMachine> X(TheAMDGPUTarget);
> }
>
> +static ScheduleDAGInstrs *createR600MachineScheduler(MachineSchedContext *C) {
> + return new ScheduleDAGMI(C, new R600SchedStrategy());
> +}
> +
> +static MachineSchedRegistry
> +SchedCustomRegistry("r600", "Run R600's custom scheduler",
> + createR600MachineScheduler);
> +
> AMDGPUTargetMachine::AMDGPUTargetMachine(const Target &T, StringRef TT,
> StringRef CPU, StringRef FS,
> TargetOptions Options,
> @@ -70,7 +79,13 @@ namespace {
> class AMDGPUPassConfig : public TargetPassConfig {
> public:
> AMDGPUPassConfig(AMDGPUTargetMachine *TM, PassManagerBase &PM)
> - : TargetPassConfig(TM, PM) {}
> + : TargetPassConfig(TM, PM) {
> + const AMDGPUSubtarget &ST = TM->getSubtarget<AMDGPUSubtarget>();
> + if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD6XXX) {
> + enablePass(&MachineSchedulerID);
> + MachineSchedRegistry::setDefault(createR600MachineScheduler);
> + }
> + }
>
> AMDGPUTargetMachine &getAMDGPUTargetMachine() const {
> return getTM<AMDGPUTargetMachine>();
> diff --git a/lib/Target/R600/R600MachineScheduler.cpp b/lib/Target/R600/R600MachineScheduler.cpp
> new file mode 100644
> index 0000000..efd9490
> --- /dev/null
> +++ b/lib/Target/R600/R600MachineScheduler.cpp
> @@ -0,0 +1,483 @@
> +//===-- R600MachineScheduler.cpp - R600 Scheduler Interface -*- C++ -*-----===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +/// \file
> +/// \brief R600 Machine Scheduler interface
> +// TODO: Scheduling is optimised for VLIW4 arch, modify it to support TRANS slot
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#define DEBUG_TYPE "misched"
> +
> +#include "R600MachineScheduler.h"
> +#include "llvm/CodeGen/MachineRegisterInfo.h"
> +#include "llvm/CodeGen/LiveIntervalAnalysis.h"
> +#include "llvm/Pass.h"
> +#include "llvm/PassManager.h"
> +#include <set>
> +#include <iostream>
> +using namespace llvm;
> +
> +void R600SchedStrategy::initialize(ScheduleDAGMI *dag) {
> +
> + DAG = dag;
> + TII = static_cast<const R600InstrInfo*>(DAG->TII);
> + TRI = static_cast<const R600RegisterInfo*>(DAG->TRI);
> + MRI = &DAG->MRI;
> + Available[IDAlu]->clear();
> + Available[IDFetch]->clear();
> + Available[IDOther]->clear();
> + CurInstKind = IDOther;
> + CurEmitted = 0;
> + memset(InstructionsGroupCandidate, 0, sizeof(InstructionsGroupCandidate));
> + InstKindLimit[IDAlu] = 120; // 120 minus 8 for security
> +
> +
> + const AMDGPUSubtarget &ST = DAG->TM.getSubtarget<AMDGPUSubtarget>();
> + if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD5XXX) {
> + InstKindLimit[IDFetch] = 7; // 8 minus 1 for security
> + } else {
> + InstKindLimit[IDFetch] = 15; // 16 minus 1 for security
> + }
> +}
> +
> +void R600SchedStrategy::MoveUnits(ReadyQueue *QSrc, ReadyQueue *QDst)
> +{
> + if (QSrc->empty())
> + return;
> + for (ReadyQueue::iterator I = QSrc->begin(),
> + E = QSrc->end(); I != E; ++I) {
> + (*I)->NodeQueueId &= ~QSrc->getID();
> + QDst->push(*I);
> + }
> + QSrc->clear();
> +}
> +
> +SUnit* R600SchedStrategy::pickNode(bool &IsTopNode) {
> + SUnit *SU = 0;
> + IsTopNode = true;
> + NextInstKind = IDOther;
> +
> + // check if we might want to switch current clause type
> + bool AllowSwitchToAlu = (CurInstKind == IDOther) ||
> + (CurEmitted > InstKindLimit[CurInstKind]) ||
> + (Available[CurInstKind]->empty());
> + bool AllowSwitchFromAlu = (CurEmitted > InstKindLimit[CurInstKind]) &&
> + (!Available[IDFetch]->empty() || !Available[IDOther]->empty());
> +
> + if ((AllowSwitchToAlu && CurInstKind != IDAlu) ||
> + (!AllowSwitchFromAlu && CurInstKind == IDAlu)) {
> + // try to pick ALU
> + SU = pickAlu();
> + if (SU)
> + if (CurEmitted > InstKindLimit[IDAlu])
> + CurEmitted = 0;
> + NextInstKind = IDAlu;
> + }
> +
> + if (!SU) {
> + // try to pick FETCH
> + SU = pickOther(IDFetch);
> + if (SU)
> + NextInstKind = IDFetch;
> + }
> +
> + // try to pick other
> + if (!SU) {
> + SU = pickOther(IDOther);
> + if (SU)
> + NextInstKind = IDOther;
> + }
> +
> + DEBUG(
> + if (SU) {
> + dbgs() << "picked node: ";
> + SU->dump(DAG);
> + } else {
> + dbgs() << "NO NODE ";
> + for (int i = 0; i < IDLast; ++i) {
> + Available[i]->dump();
> + Pending[i]->dump();
> + }
> + for (unsigned i = 0; i < DAG->SUnits.size(); i++) {
> + const SUnit &S = DAG->SUnits[i];
> + if (!S.isScheduled)
> + S.dump(DAG);
> + }
> + }
> + );
> +
> + return SU;
> +}
> +
> +void R600SchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
> +
> + DEBUG(dbgs() << "scheduled: ");
> + DEBUG(SU->dump(DAG));
> +
> + if (NextInstKind != CurInstKind) {
> + DEBUG(dbgs() << "Instruction Type Switch\n");
> + if (NextInstKind != IDAlu)
> + OccupedSlotsMask = 0;
> + CurEmitted = 0;
> + CurInstKind = NextInstKind;
> + }
> +
> + if (CurInstKind == IDAlu) {
> + switch (getAluKind(SU)) {
> + case AluT_XYZW:
> + CurEmitted += 4;
> + break;
> + case AluDiscarded:
> + break;
> + default: {
> + ++CurEmitted;
> + for (MachineInstr::mop_iterator It = SU->getInstr()->operands_begin(),
> + E = SU->getInstr()->operands_end(); It != E; ++It) {
> + MachineOperand &MO = *It;
> + if (MO.isReg() && MO.getReg() == AMDGPU::ALU_LITERAL_X)
> + ++CurEmitted;
> + }
> + }
> + }
> + } else {
> + ++CurEmitted;
> + }
> +
> +
> + DEBUG(dbgs() << CurEmitted << " Instructions Emitted in this clause\n");
> +
> + if (CurInstKind != IDFetch) {
> + MoveUnits(Pending[IDFetch], Available[IDFetch]);
> + }
> + MoveUnits(Pending[IDOther], Available[IDOther]);
> +}
> +
> +void R600SchedStrategy::releaseTopNode(SUnit *SU) {
> + int IK = getInstKind(SU);
> +
> + DEBUG(dbgs() << IK << " <= ");
> + DEBUG(SU->dump(DAG));
> +
> + Pending[IK]->push(SU);
> +}
> +
> +void R600SchedStrategy::releaseBottomNode(SUnit *SU) {
> +}
> +
> +bool R600SchedStrategy::regBelongsToClass(unsigned Reg,
> + const TargetRegisterClass *RC) const {
> + if (!TargetRegisterInfo::isVirtualRegister(Reg)) {
> + return RC->contains(Reg);
> + } else {
> + return MRI->getRegClass(Reg) == RC;
> + }
> +}
> +
> +R600SchedStrategy::AluKind R600SchedStrategy::getAluKind(SUnit *SU) const {
> + MachineInstr *MI = SU->getInstr();
> +
> + switch (MI->getOpcode()) {
> + case AMDGPU::INTERP_PAIR_XY:
> + case AMDGPU::INTERP_PAIR_ZW:
> + case AMDGPU::INTERP_VEC_LOAD:
> + return AluT_XYZW;
> + case AMDGPU::COPY:
> + if (TargetRegisterInfo::isPhysicalRegister(MI->getOperand(1).getReg())) {
> + // %vregX = COPY Tn_X is likely to be discarded in favor of an
> + // assignement of Tn_X to %vregX, don't considers it in scheduling
> + return AluDiscarded;
> + }
> + else if (MI->getOperand(1).isUndef()) {
> + // MI will become a KILL, don't considers it in scheduling
> + return AluDiscarded;
> + }
> + default:
> + break;
> + }
> +
> + // Does the instruction take a whole IG ?
> + if(TII->isVector(*MI) ||
> + TII->isCubeOp(MI->getOpcode()) ||
> + TII->isReductionOp(MI->getOpcode()))
> + return AluT_XYZW;
> +
> + // Is the result already assigned to a channel ?
> + unsigned DestSubReg = MI->getOperand(0).getSubReg();
> + switch (DestSubReg) {
> + case AMDGPU::sub0:
> + return AluT_X;
> + case AMDGPU::sub1:
> + return AluT_Y;
> + case AMDGPU::sub2:
> + return AluT_Z;
> + case AMDGPU::sub3:
> + return AluT_W;
> + default:
> + break;
> + }
> +
> + // Is the result already member of a X/Y/Z/W class ?
> + unsigned DestReg = MI->getOperand(0).getReg();
> + if (regBelongsToClass(DestReg, &AMDGPU::R600_TReg32_XRegClass) ||
> + regBelongsToClass(DestReg, &AMDGPU::R600_AddrRegClass))
> + return AluT_X;
> + if (regBelongsToClass(DestReg, &AMDGPU::R600_TReg32_YRegClass))
> + return AluT_Y;
> + if (regBelongsToClass(DestReg, &AMDGPU::R600_TReg32_ZRegClass))
> + return AluT_Z;
> + if (regBelongsToClass(DestReg, &AMDGPU::R600_TReg32_WRegClass))
> + return AluT_W;
> + if (regBelongsToClass(DestReg, &AMDGPU::R600_Reg128RegClass))
> + return AluT_XYZW;
> +
> + return AluAny;
> +
> +}
> +
> +int R600SchedStrategy::getInstKind(SUnit* SU) {
> + int Opcode = SU->getInstr()->getOpcode();
> +
> + if (TII->isALUInstr(Opcode)) {
> + return IDAlu;
> + }
> +
> + switch (Opcode) {
> + case AMDGPU::COPY:
> + case AMDGPU::CONST_COPY:
> + case AMDGPU::INTERP_PAIR_XY:
> + case AMDGPU::INTERP_PAIR_ZW:
> + case AMDGPU::INTERP_VEC_LOAD:
> + case AMDGPU::DOT4_eg_pseudo:
> + case AMDGPU::DOT4_r600_pseudo:
> + return IDAlu;
> + case AMDGPU::TEX_VTX_CONSTBUF:
> + case AMDGPU::TEX_VTX_TEXBUF:
> + case AMDGPU::TEX_LD:
> + case AMDGPU::TEX_GET_TEXTURE_RESINFO:
> + case AMDGPU::TEX_GET_GRADIENTS_H:
> + case AMDGPU::TEX_GET_GRADIENTS_V:
> + case AMDGPU::TEX_SET_GRADIENTS_H:
> + case AMDGPU::TEX_SET_GRADIENTS_V:
> + case AMDGPU::TEX_SAMPLE:
> + case AMDGPU::TEX_SAMPLE_C:
> + case AMDGPU::TEX_SAMPLE_L:
> + case AMDGPU::TEX_SAMPLE_C_L:
> + case AMDGPU::TEX_SAMPLE_LB:
> + case AMDGPU::TEX_SAMPLE_C_LB:
> + case AMDGPU::TEX_SAMPLE_G:
> + case AMDGPU::TEX_SAMPLE_C_G:
> + case AMDGPU::TXD:
> + case AMDGPU::TXD_SHADOW:
> + return IDFetch;
> + default:
> + DEBUG(
> + dbgs() << "other inst: ";
> + SU->dump(DAG);
> + );
> + return IDOther;
> + }
> +}
> +
> +class ConstPairs {
> +private:
> + unsigned XYPair;
> + unsigned ZWPair;
> +public:
> + ConstPairs(unsigned ReadConst[3]) {
> + for (unsigned i = 0; i < 3; i++) {
> + unsigned ReadConstChan = ReadConst[i] & 3;
> + unsigned ReadConstIndex = ReadConst[i] & (~3);
> + if (ReadConstChan < 2) {
> + if (!XYPair) {
> + XYPair = ReadConstIndex;
> + }
> + } else {
> + if (!ZWPair) {
> + ZWPair = ReadConstIndex;
> + }
> + }
> + }
> + }
> +
> + bool isCompatibleWith(const ConstPairs& CP) const {
> + return (!XYPair || !CP.XYPair || CP.XYPair == XYPair) &&
> + (!ZWPair || !CP.ZWPair || CP.ZWPair == ZWPair);
> + }
> +};
> +
> +static
> +const ConstPairs getPairs(const R600InstrInfo *TII, const MachineInstr& MI) {
> + unsigned ReadConsts[3] = {0, 0, 0};
> + R600Operands::Ops OpTable[3][2] = {
> + {R600Operands::SRC0, R600Operands::SRC0_SEL},
> + {R600Operands::SRC1, R600Operands::SRC1_SEL},
> + {R600Operands::SRC2, R600Operands::SRC2_SEL},
> + };
> +
> + if (!TII->isALUInstr(MI.getOpcode()))
> + return ConstPairs(ReadConsts);
> +
> + for (unsigned i = 0; i < 3; i++) {
> + int SrcIdx = TII->getOperandIdx(MI.getOpcode(), OpTable[i][0]);
> + if (SrcIdx < 0)
> + break;
> + if (MI.getOperand(SrcIdx).getReg() == AMDGPU::ALU_CONST)
> + ReadConsts[i] =MI.getOperand(
> + TII->getOperandIdx(MI.getOpcode(), OpTable[i][1])).getImm();
> + }
> + return ConstPairs(ReadConsts);
> +}
> +
> +bool
> +R600SchedStrategy::isBundleable(const MachineInstr& MI) {
> + const ConstPairs &MIPair = getPairs(TII, MI);
> + for (unsigned i = 0; i < 4; i++) {
> + if (!InstructionsGroupCandidate[i])
> + continue;
> + const ConstPairs &IGPair = getPairs(TII,
> + *InstructionsGroupCandidate[i]->getInstr());
> + if (!IGPair.isCompatibleWith(MIPair))
> + return false;
> + }
> + return true;
> +}
> +
> +SUnit *R600SchedStrategy::PopInst(std::multiset<SUnit *, CompareSUnit> &Q) {
> + if (Q.empty())
> + return NULL;
> + for (std::set<SUnit *, CompareSUnit>::iterator It = Q.begin(), E = Q.end();
> + It != E; ++It) {
> + SUnit *SU = *It;
> + if (isBundleable(*SU->getInstr())) {
> + Q.erase(It);
> + return SU;
> + }
> + }
> + return NULL;
> +}
> +
> +void R600SchedStrategy::LoadAlu() {
> + ReadyQueue *QSrc = Pending[IDAlu];
> + for (ReadyQueue::iterator I = QSrc->begin(),
> + E = QSrc->end(); I != E; ++I) {
> + (*I)->NodeQueueId &= ~QSrc->getID();
> + AluKind AK = getAluKind(*I);
> + AvailableAlus[AK].insert(*I);
> + }
> + QSrc->clear();
> +}
> +
> +void R600SchedStrategy::PrepareNextSlot() {
> + DEBUG(dbgs() << "New Slot\n");
> + OccupedSlotsMask = 0;
> + memset(InstructionsGroupCandidate, 0, sizeof(InstructionsGroupCandidate));
> + LoadAlu();
> +}
> +
> +void R600SchedStrategy::AssignSlot(MachineInstr* MI, unsigned Slot) {
> + unsigned DestReg = MI->getOperand(0).getReg();
> + // PressureRegister crashes if an operand is def and used in the same inst
> + // and we try to constraint its regclass
> + for (MachineInstr::mop_iterator It = MI->operands_begin(),
> + E = MI->operands_end(); It != E; ++It) {
> + MachineOperand &MO = *It;
> + if (MO.isReg() && !MO.isDef() &&
> + MO.getReg() == MI->getOperand(0).getReg())
> + return;
> + }
> + // Constrains the regclass of DestReg to assign it to Slot
> + switch (Slot) {
> + case 0:
> + MRI->constrainRegClass(DestReg, &AMDGPU::R600_TReg32_XRegClass);
> + break;
> + case 1:
> + MRI->constrainRegClass(DestReg, &AMDGPU::R600_TReg32_YRegClass);
> + break;
> + case 2:
> + MRI->constrainRegClass(DestReg, &AMDGPU::R600_TReg32_ZRegClass);
> + break;
> + case 3:
> + MRI->constrainRegClass(DestReg, &AMDGPU::R600_TReg32_WRegClass);
> + break;
> + }
> +}
> +
> +SUnit *R600SchedStrategy::AttemptFillSlot(unsigned Slot) {
> + static const AluKind IndexToID[] = {AluT_X, AluT_Y, AluT_Z, AluT_W};
> + SUnit *SlotedSU = PopInst(AvailableAlus[IndexToID[Slot]]);
> + SUnit *UnslotedSU = PopInst(AvailableAlus[AluAny]);
> + if (!UnslotedSU) {
> + return SlotedSU;
> + } else if (!SlotedSU) {
> + AssignSlot(UnslotedSU->getInstr(), Slot);
> + return UnslotedSU;
> + } else {
> + //Determine which one to pick (the lesser one)
> + if (CompareSUnit()(SlotedSU, UnslotedSU)) {
> + AvailableAlus[AluAny].insert(UnslotedSU);
> + return SlotedSU;
> + } else {
> + AvailableAlus[IndexToID[Slot]].insert(SlotedSU);
> + AssignSlot(UnslotedSU->getInstr(), Slot);
> + return UnslotedSU;
> + }
> + }
> +}
> +
> +bool R600SchedStrategy::isAvailablesAluEmpty() const {
> + return Pending[IDAlu]->empty() && AvailableAlus[AluAny].empty() &&
> + AvailableAlus[AluT_XYZW].empty() && AvailableAlus[AluT_X].empty() &&
> + AvailableAlus[AluT_Y].empty() && AvailableAlus[AluT_Z].empty() &&
> + AvailableAlus[AluT_W].empty() && AvailableAlus[AluDiscarded].empty();
> +}
> +
> +SUnit* R600SchedStrategy::pickAlu() {
> + while (!isAvailablesAluEmpty()) {
> + if (!OccupedSlotsMask) {
> + // Flush physical reg copies (RA will discard them)
> + if (!AvailableAlus[AluDiscarded].empty()) {
> + return PopInst(AvailableAlus[AluDiscarded]);
> + }
> + // If there is a T_XYZW alu available, use it
> + if (!AvailableAlus[AluT_XYZW].empty()) {
> + OccupedSlotsMask = 15;
> + return PopInst(AvailableAlus[AluT_XYZW]);
> + }
> + }
> + for (unsigned Chan = 0; Chan < 4; ++Chan) {
> + bool isOccupied = OccupedSlotsMask & (1 << Chan);
> + if (!isOccupied) {
> + SUnit *SU = AttemptFillSlot(Chan);
> + if (SU) {
> + OccupedSlotsMask |= (1 << Chan);
> + InstructionsGroupCandidate[Chan] = SU;
> + return SU;
> + }
> + }
> + }
> + PrepareNextSlot();
> + }
> + return NULL;
> +}
> +
> +SUnit* R600SchedStrategy::pickOther(int QID) {
> + SUnit *SU = 0;
> + ReadyQueue *AQ = Available[QID];
> +
> + if (AQ->empty()) {
> + MoveUnits(Pending[QID], AQ);
> + }
> + if (!AQ->empty()) {
> + SU = *AQ->begin();
> + AQ->remove(AQ->begin());
> + }
> + return SU;
> +}
> +
> diff --git a/lib/Target/R600/R600MachineScheduler.h b/lib/Target/R600/R600MachineScheduler.h
> new file mode 100644
> index 0000000..d74ff1e
> --- /dev/null
> +++ b/lib/Target/R600/R600MachineScheduler.h
> @@ -0,0 +1,121 @@
> +//===-- R600MachineScheduler.h - R600 Scheduler Interface -*- C++ -*-------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +/// \file
> +/// \brief R600 Machine Scheduler interface
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef R600MACHINESCHEDULER_H_
> +#define R600MACHINESCHEDULER_H_
> +
> +#include "R600InstrInfo.h"
> +#include "llvm/CodeGen/MachineScheduler.h"
> +#include "llvm/Support/Debug.h"
> +#include "llvm/ADT/PriorityQueue.h"
> +
> +using namespace llvm;
> +
> +namespace llvm {
> +
> +class CompareSUnit {
> +public:
> + bool operator()(const SUnit *S1, const SUnit *S2) {
> + return S1->getDepth() > S2->getDepth();
> + }
> +};
> +
> +class R600SchedStrategy : public MachineSchedStrategy {
> +
> + const ScheduleDAGMI *DAG;
> + const R600InstrInfo *TII;
> + const R600RegisterInfo *TRI;
> + MachineRegisterInfo *MRI;
> +
> + enum InstQueue {
> + QAlu = 1,
> + QFetch = 2,
> + QOther = 4
> + };
> +
> + enum InstKind {
> + IDAlu,
> + IDFetch,
> + IDOther,
> + IDLast
> + };
> +
> + enum AluKind {
> + AluAny,
> + AluT_X,
> + AluT_Y,
> + AluT_Z,
> + AluT_W,
> + AluT_XYZW,
> + AluDiscarded, // LLVM Instructions that are going to be eliminated
> + AluLast
> + };
> +
> + ReadyQueue *Available[IDLast], *Pending[IDLast];
> + std::multiset<SUnit *, CompareSUnit> AvailableAlus[AluLast];
> +
> + InstKind CurInstKind;
> + int CurEmitted;
> + InstKind NextInstKind;
> +
> + int InstKindLimit[IDLast];
> +
> + int OccupedSlotsMask;
> +
> +public:
> + R600SchedStrategy() :
> + DAG(0), TII(0), TRI(0), MRI(0) {
> + Available[IDAlu] = new ReadyQueue(QAlu, "AAlu");
> + Available[IDFetch] = new ReadyQueue(QFetch, "AFetch");
> + Available[IDOther] = new ReadyQueue(QOther, "AOther");
> + Pending[IDAlu] = new ReadyQueue(QAlu<<4, "PAlu");
> + Pending[IDFetch] = new ReadyQueue(QFetch<<4, "PFetch");
> + Pending[IDOther] = new ReadyQueue(QOther<<4, "POther");
> + }
> +
> + virtual ~R600SchedStrategy() {
> + for (unsigned I = 0; I < IDLast; ++I) {
> + delete Available[I];
> + delete Pending[I];
> + }
> + }
> +
> + virtual void initialize(ScheduleDAGMI *dag);
> + virtual SUnit *pickNode(bool &IsTopNode);
> + virtual void schedNode(SUnit *SU, bool IsTopNode);
> + virtual void releaseTopNode(SUnit *SU);
> + virtual void releaseBottomNode(SUnit *SU);
> +
> +private:
> + SUnit *InstructionsGroupCandidate[4];
> +
> + int getInstKind(SUnit *SU);
> + bool regBelongsToClass(unsigned Reg, const TargetRegisterClass *RC) const;
> + AluKind getAluKind(SUnit *SU) const;
> + void LoadAlu();
> + bool isAvailablesAluEmpty() const;
> + SUnit *AttemptFillSlot (unsigned Slot);
> + void PrepareNextSlot();
> + SUnit *PopInst(std::multiset<SUnit *, CompareSUnit> &Q);
> +
> + void AssignSlot(MachineInstr *MI, unsigned Slot);
> + SUnit* pickAlu();
> + SUnit* pickOther(int QID);
> + bool isBundleable(const MachineInstr& MI);
> + void MoveUnits(ReadyQueue *QSrc, ReadyQueue *QDst);
> +};
> +
> +} // namespace llvm
> +
> +#endif /* R600MACHINESCHEDULER_H_ */
> diff --git a/test/CodeGen/R600/fdiv.v4f32.ll b/test/CodeGen/R600/fdiv.v4f32.ll
> index 459fd11..79e677f 100644
> --- a/test/CodeGen/R600/fdiv.v4f32.ll
> +++ b/test/CodeGen/R600/fdiv.v4f32.ll
> @@ -1,13 +1,13 @@
> ;RUN: llc < %s -march=r600 -mcpu=redwood | FileCheck %s
>
> ;CHECK: RECIP_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> -;CHECK: MUL_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> ;CHECK: RECIP_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> -;CHECK: MUL_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> ;CHECK: RECIP_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> -;CHECK: MUL_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> ;CHECK: RECIP_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> ;CHECK: MUL_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> +;CHECK: MUL_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> +;CHECK: MUL_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> +;CHECK: MUL_IEEE T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
>
> define void @test(<4 x float> addrspace(1)* %out, <4 x float> addrspace(1)* %in) {
> %b_ptr = getelementptr <4 x float> addrspace(1)* %in, i32 1
> --
> 1.8.1.2
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list