X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FCodeGen%2FScheduleDAGInstrs.cpp;h=880782e28176bee610cbcaeada68e8f29efa28e9;hb=eef55dc3fdebf915128e5d3848f372c7db6c38e8;hp=9541de642423ca375328e8abf002a6697dad77d4;hpb=3311a1f8f0d8a2c6d940802bbb95eba0b801a615;p=oota-llvm.git diff --git a/lib/CodeGen/ScheduleDAGInstrs.cpp b/lib/CodeGen/ScheduleDAGInstrs.cpp index 9541de64242..880782e2817 100644 --- a/lib/CodeGen/ScheduleDAGInstrs.cpp +++ b/lib/CodeGen/ScheduleDAGInstrs.cpp @@ -13,118 +13,60 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sched-instrs" +#include "ScheduleDAGInstrs.h" +#include "llvm/Operator.h" #include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/ScheduleDAGInstrs.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtarget.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallSet.h" -#include using namespace llvm; -namespace { - class VISIBILITY_HIDDEN LoopDependencies { - const MachineLoopInfo &MLI; - const MachineDominatorTree &MDT; - - public: - typedef std::map > - LoopDeps; - LoopDeps Deps; - - LoopDependencies(const MachineLoopInfo &mli, - const MachineDominatorTree &mdt) : - MLI(mli), MDT(mdt) {} - - void VisitLoop(const MachineLoop *Loop) { - Deps.clear(); - MachineBasicBlock *Header = Loop->getHeader(); - SmallSet LoopLiveIns; - for (MachineBasicBlock::livein_iterator LI = Header->livein_begin(), - LE = Header->livein_end(); LI != LE; ++LI) - LoopLiveIns.insert(*LI); - - const MachineDomTreeNode *Node = MDT.getNode(Header); - const MachineBasicBlock *MBB = Node->getBlock(); - assert(Loop->contains(MBB) && - "Loop does not contain header!"); - VisitRegion(Node, MBB, Loop, LoopLiveIns); - } - - private: - void VisitRegion(const MachineDomTreeNode *Node, - const MachineBasicBlock *MBB, - const MachineLoop *Loop, - const SmallSet &LoopLiveIns) { - unsigned Count = 0; - for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end(); - I != E; ++I, ++Count) { - const MachineInstr *MI = I; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - const MachineOperand &MO = MI->getOperand(i); - if (!MO.isReg() || !MO.isUse()) - continue; - unsigned MOReg = MO.getReg(); - if (LoopLiveIns.count(MOReg)) - Deps.insert(std::make_pair(MOReg, std::make_pair(&MO, Count))); - } - } - - const std::vector &Children = Node->getChildren(); - for (std::vector::const_iterator I = - Children.begin(), E = Children.end(); I != E; ++I) { - const MachineDomTreeNode *ChildNode = *I; - MachineBasicBlock *ChildBlock = ChildNode->getBlock(); - if (Loop->contains(ChildBlock)) - VisitRegion(ChildNode, ChildBlock, Loop, LoopLiveIns); - } - } - }; -} - ScheduleDAGInstrs::ScheduleDAGInstrs(MachineFunction &mf, const MachineLoopInfo &mli, const MachineDominatorTree &mdt) - : ScheduleDAG(mf), MLI(mli), MDT(mdt) {} - -/// getOpcode - If this is an Instruction or a ConstantExpr, return the -/// opcode value. Otherwise return UserOp1. -static unsigned getOpcode(const Value *V) { - if (const Instruction *I = dyn_cast(V)) - return I->getOpcode(); - if (const ConstantExpr *CE = dyn_cast(V)) - return CE->getOpcode(); - // Use UserOp1 to mean there's no opcode. - return Instruction::UserOp1; + : ScheduleDAG(mf), MLI(mli), MDT(mdt), LoopRegs(MLI, MDT) { + MFI = mf.getFrameInfo(); +} + +/// Run - perform scheduling. +/// +void ScheduleDAGInstrs::Run(MachineBasicBlock *bb, + MachineBasicBlock::iterator begin, + MachineBasicBlock::iterator end, + unsigned endcount) { + BB = bb; + Begin = begin; + InsertPosIndex = endcount; + + ScheduleDAG::Run(bb, end); } /// getUnderlyingObjectFromInt - This is the function that does the work of /// looking through basic ptrtoint+arithmetic+inttoptr sequences. static const Value *getUnderlyingObjectFromInt(const Value *V) { do { - if (const User *U = dyn_cast(V)) { + if (const Operator *U = dyn_cast(V)) { // If we find a ptrtoint, we can transfer control back to the // regular getUnderlyingObjectFromInt. - if (getOpcode(U) == Instruction::PtrToInt) + if (U->getOpcode() == Instruction::PtrToInt) return U->getOperand(0); // If we find an add of a constant or a multiplied value, it's // likely that the other operand will lead us to the base // object. We don't have to worry about the case where the - // object address is somehow being computed bt the multiply, + // object address is somehow being computed by the multiply, // because our callers only care when the result is an // identifibale object. - if (getOpcode(U) != Instruction::Add || + if (U->getOpcode() != Instruction::Add || (!isa(U->getOperand(1)) && - getOpcode(U->getOperand(1)) != Instruction::Mul)) + Operator::getOpcode(U->getOperand(1)) != Instruction::Mul)) return V; V = U->getOperand(0); } else { @@ -141,7 +83,7 @@ static const Value *getUnderlyingObject(const Value *V) { do { V = V->getUnderlyingObject(); // If it found an inttoptr, use special code to continue climing. - if (getOpcode(V) != Instruction::IntToPtr) + if (Operator::getOpcode(V) != Instruction::IntToPtr) break; const Value *O = getUnderlyingObjectFromInt(cast(V)->getOperand(0)); // If that succeeded in finding a pointer, continue the search. @@ -155,24 +97,47 @@ static const Value *getUnderlyingObject(const Value *V) { /// getUnderlyingObjectForInstr - If this machine instr has memory reference /// information and it can be tracked to a normal reference to a known /// object, return the Value for that object. Otherwise return null. -static const Value *getUnderlyingObjectForInstr(const MachineInstr *MI) { +static const Value *getUnderlyingObjectForInstr(const MachineInstr *MI, + const MachineFrameInfo *MFI) { if (!MI->hasOneMemOperand() || - !MI->memoperands_begin()->getValue() || - MI->memoperands_begin()->isVolatile()) + !(*MI->memoperands_begin())->getValue() || + (*MI->memoperands_begin())->isVolatile()) return 0; - const Value *V = MI->memoperands_begin()->getValue(); + const Value *V = (*MI->memoperands_begin())->getValue(); if (!V) return 0; V = getUnderlyingObject(V); - if (!isa(V) && !isIdentifiedObject(V)) - return 0; + if (const PseudoSourceValue *PSV = dyn_cast(V)) { + // For now, ignore PseudoSourceValues which may alias LLVM IR values + // because the code that uses this function has no way to cope with + // such aliases. + if (PSV->isAliased(MFI)) + return 0; + return V; + } - return V; + if (isIdentifiedObject(V)) + return V; + + return 0; } -void ScheduleDAGInstrs::BuildSchedGraph() { +void ScheduleDAGInstrs::StartBlock(MachineBasicBlock *BB) { + if (MachineLoop *ML = MLI.getLoopFor(BB)) + if (BB == ML->getLoopLatch()) { + MachineBasicBlock *Header = ML->getHeader(); + for (MachineBasicBlock::livein_iterator I = Header->livein_begin(), + E = Header->livein_end(); I != E; ++I) + LoopLiveInRegs.insert(*I); + LoopRegs.VisitLoop(ML); + } +} + +void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { + // We'll be allocating one SUnit for each instruction, plus one for + // the region exit node. SUnits.reserve(BB->size()); // We build scheduling units by walking a block's instruction list from bottom @@ -189,41 +154,21 @@ void ScheduleDAGInstrs::BuildSchedGraph() { std::map MemDefs; std::map > MemUses; - // If we have an SUnit which is representing a terminator instruction, we - // can use it as a place-holder successor for inter-block dependencies. - SUnit *Terminator = 0; - - // Terminators can perform control transfers, we we need to make sure that - // all the work of the block is done before the terminator. Labels can - // mark points of interest for various types of meta-data (eg. EH data), - // and we need to make sure nothing is scheduled around them. - SUnit *SchedulingBarrier = 0; - - LoopDependencies LoopRegs(MLI, MDT); - - // Track which regs are live into a loop, to help guide back-edge-aware - // scheduling. - SmallSet LoopLiveInRegs; - if (MachineLoop *ML = MLI.getLoopFor(BB)) - if (BB == ML->getLoopLatch()) { - MachineBasicBlock *Header = ML->getHeader(); - for (MachineBasicBlock::livein_iterator I = Header->livein_begin(), - E = Header->livein_end(); I != E; ++I) - LoopLiveInRegs.insert(*I); - LoopRegs.VisitLoop(ML); - } - // Check to see if the scheduler cares about latencies. bool UnitLatencies = ForceUnitLatencies(); // Ask the target if address-backscheduling is desirable, and if so how much. - unsigned SpecialAddressLatency = - TM.getSubtarget().getSpecialAddressLatency(); + const TargetSubtarget &ST = TM.getSubtarget(); + unsigned SpecialAddressLatency = ST.getSpecialAddressLatency(); - for (MachineBasicBlock::iterator MII = End, MIE = Begin; + // Walk the list of instructions, from bottom moving up. + for (MachineBasicBlock::iterator MII = InsertPos, MIE = Begin; MII != MIE; --MII) { MachineInstr *MI = prior(MII); const TargetInstrDesc &TID = MI->getDesc(); + assert(!TID.isTerminator() && !MI->isLabel() && + "Cannot schedule terminators or labels!"); + // Create the SUnit for this MI. SUnit *SU = NewSUnit(MI); // Assign the Latency field of SU using target-provided information. @@ -242,16 +187,20 @@ void ScheduleDAGInstrs::BuildSchedGraph() { assert(TRI->isPhysicalRegister(Reg) && "Virtual register encountered!"); std::vector &UseList = Uses[Reg]; std::vector &DefList = Defs[Reg]; - // Optionally add output and anti dependencies. - // TODO: Using a latency of 1 here assumes there's no cost for - // reusing registers. + // Optionally add output and anti dependencies. For anti + // dependencies we use a latency of 0 because for a multi-issue + // target we want to allow the defining instruction to issue + // in the same cycle as the using instruction. + // TODO: Using a latency of 1 here for output dependencies assumes + // there's no cost for reusing registers. SDep::Kind Kind = MO.isUse() ? SDep::Anti : SDep::Output; + unsigned AOLatency = (Kind == SDep::Anti) ? 0 : 1; for (unsigned i = 0, e = DefList.size(); i != e; ++i) { SUnit *DefSU = DefList[i]; if (DefSU != SU && (Kind != SDep::Output || !MO.isDead() || !DefSU->getInstr()->registerDefIsDead(Reg))) - DefSU->addPred(SDep(SU, Kind, /*Latency=*/1, /*Reg=*/Reg)); + DefSU->addPred(SDep(SU, Kind, AOLatency, /*Reg=*/Reg)); } for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { std::vector &DefList = Defs[*Alias]; @@ -259,8 +208,8 @@ void ScheduleDAGInstrs::BuildSchedGraph() { SUnit *DefSU = DefList[i]; if (DefSU != SU && (Kind != SDep::Output || !MO.isDead() || - !DefSU->getInstr()->registerDefIsDead(Reg))) - DefSU->addPred(SDep(SU, Kind, /*Latency=*/1, /*Reg=*/ *Alias)); + !DefSU->getInstr()->registerDefIsDead(*Alias))) + DefSU->addPred(SDep(SU, Kind, AOLatency, /*Reg=*/ *Alias)); } } @@ -274,6 +223,10 @@ void ScheduleDAGInstrs::BuildSchedGraph() { // Optionally add in a special extra latency for nodes that // feed addresses. // TODO: Do this for register aliases too. + // TODO: Perhaps we should get rid of + // SpecialAddressLatency and just move this into + // adjustSchedDependency for the targets that care about + // it. if (SpecialAddressLatency != 0 && !UnitLatencies) { MachineInstr *UseMI = UseSU->getInstr(); const TargetInstrDesc &UseTID = UseMI->getDesc(); @@ -284,22 +237,35 @@ void ScheduleDAGInstrs::BuildSchedGraph() { UseTID.OpInfo[RegUseIndex].isLookupPtrRegClass()) LDataLatency += SpecialAddressLatency; } - UseSU->addPred(SDep(SU, SDep::Data, LDataLatency, Reg)); + // Adjust the dependence latency using operand def/use + // information (if any), and then allow the target to + // perform its own adjustments. + const SDep& dep = SDep(SU, SDep::Data, LDataLatency, Reg); + if (!UnitLatencies) { + ComputeOperandLatency(SU, UseSU, (SDep &)dep); + ST.adjustSchedDependency(SU, UseSU, (SDep &)dep); + } + UseSU->addPred(dep); } } for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { std::vector &UseList = Uses[*Alias]; for (unsigned i = 0, e = UseList.size(); i != e; ++i) { SUnit *UseSU = UseList[i]; - if (UseSU != SU) - UseSU->addPred(SDep(SU, SDep::Data, DataLatency, *Alias)); + if (UseSU != SU) { + const SDep& dep = SDep(SU, SDep::Data, DataLatency, *Alias); + if (!UnitLatencies) { + ComputeOperandLatency(SU, UseSU, (SDep &)dep); + ST.adjustSchedDependency(SU, UseSU, (SDep &)dep); + } + UseSU->addPred(dep); + } } } // If a def is going to wrap back around to the top of the loop, // backschedule it. - // TODO: Blocks in loops without terminators can benefit too. - if (!UnitLatencies && Terminator && DefList.empty()) { + if (!UnitLatencies && DefList.empty()) { LoopDependencies::LoopDeps::iterator I = LoopRegs.Deps.find(Reg); if (I != LoopRegs.Deps.end()) { const MachineOperand *UseMO = I->second.first; @@ -323,10 +289,10 @@ void ScheduleDAGInstrs::BuildSchedGraph() { // scheduling region. Latency -= std::min(Latency, Count); // Add the artifical edge. - Terminator->addPred(SDep(SU, SDep::Order, Latency, - /*Reg=*/0, /*isNormalMemory=*/false, - /*isMustAlias=*/false, - /*isArtificial=*/true)); + ExitSU.addPred(SDep(SU, SDep::Order, Latency, + /*Reg=*/0, /*isNormalMemory=*/false, + /*isMustAlias=*/false, + /*isArtificial=*/true)); } else if (SpecialAddressLatency > 0 && UseTID.OpInfo[UseMOIdx].isLookupPtrRegClass()) { // The entire loop body is within the current scheduling region @@ -355,7 +321,7 @@ void ScheduleDAGInstrs::BuildSchedGraph() { // after stack slots are lowered to actual addresses. // TODO: Use an AliasAnalysis and do real alias-analysis queries, and // produce more precise dependence information. - if (TID.isCall() || TID.isTerminator() || TID.hasUnmodeledSideEffects()) { + if (TID.isCall() || TID.hasUnmodeledSideEffects()) { new_chain: // This is the conservative case. Add dependencies on all memory // references. @@ -379,18 +345,18 @@ void ScheduleDAGInstrs::BuildSchedGraph() { // See if it is known to just have a single memory reference. MachineInstr *ChainMI = Chain->getInstr(); const TargetInstrDesc &ChainTID = ChainMI->getDesc(); - if (!ChainTID.isCall() && !ChainTID.isTerminator() && + if (!ChainTID.isCall() && !ChainTID.hasUnmodeledSideEffects() && ChainMI->hasOneMemOperand() && - !ChainMI->memoperands_begin()->isVolatile() && - ChainMI->memoperands_begin()->getValue()) + !(*ChainMI->memoperands_begin())->isVolatile() && + (*ChainMI->memoperands_begin())->getValue()) // We know that the Chain accesses one specific memory location. - ChainMMO = &*ChainMI->memoperands_begin(); + ChainMMO = *ChainMI->memoperands_begin(); else // Unknown memory accesses. Assume the worst. ChainMMO = 0; } else if (TID.mayStore()) { - if (const Value *V = getUnderlyingObjectForInstr(MI)) { + if (const Value *V = getUnderlyingObjectForInstr(MI, MFI)) { // A store to a specific PseudoSourceValue. Add precise dependencies. // Handle the def in MemDefs, if there is one. std::map::iterator I = MemDefs.find(V); @@ -421,9 +387,9 @@ void ScheduleDAGInstrs::BuildSchedGraph() { // Treat all other stores conservatively. goto new_chain; } else if (TID.mayLoad()) { - if (TII->isInvariantLoad(MI)) { + if (MI->isInvariantLoad(AA)) { // Invariant load, no chain dependencies needed! - } else if (const Value *V = getUnderlyingObjectForInstr(MI)) { + } else if (const Value *V = getUnderlyingObjectForInstr(MI, MFI)) { // A load from a specific PseudoSourceValue. Add precise dependencies. std::map::iterator I = MemDefs.find(V); if (I != MemDefs.end()) @@ -452,28 +418,6 @@ void ScheduleDAGInstrs::BuildSchedGraph() { PendingLoads.push_back(SU); } } - - // Add chain edges from terminators and labels to ensure that no - // instructions are scheduled past them. - if (SchedulingBarrier && SU->Succs.empty()) - SchedulingBarrier->addPred(SDep(SU, SDep::Order, SU->Latency)); - // If we encounter a mid-block label, we need to go back and add - // dependencies on SUnits we've already processed to prevent the - // label from moving downward. - if (MI->isLabel()) - for (SUnit *I = SU; I != &SUnits[0]; --I) { - SUnit *SuccSU = SU-1; - SuccSU->addPred(SDep(SU, SDep::Order, SU->Latency)); - MachineInstr *SuccMI = SuccSU->getInstr(); - if (SuccMI->getDesc().isTerminator() || SuccMI->isLabel()) - break; - } - // If this instruction obstructs all scheduling, remember it. - if (TID.isTerminator() || MI->isLabel()) - SchedulingBarrier = SU; - // If this instruction is a terminator, remember it. - if (TID.isTerminator()) - Terminator = SU; } for (int i = 0, e = TRI->getNumRegs(); i != e; ++i) { @@ -483,13 +427,16 @@ void ScheduleDAGInstrs::BuildSchedGraph() { PendingLoads.clear(); } +void ScheduleDAGInstrs::FinishBlock() { + // Nothing to do. +} + void ScheduleDAGInstrs::ComputeLatency(SUnit *SU) { const InstrItineraryData &InstrItins = TM.getInstrItineraryData(); - // Compute the latency for the node. We use the sum of the latencies for - // all nodes flagged together into this SUnit. + // Compute the latency for the node. SU->Latency = - InstrItins.getLatency(SU->getInstr()->getDesc().getSchedClass()); + InstrItins.getStageLatency(SU->getInstr()->getDesc().getSchedClass()); // Simplistic target-independent heuristic: assume that loads take // extra time. @@ -498,6 +445,50 @@ void ScheduleDAGInstrs::ComputeLatency(SUnit *SU) { SU->Latency += 2; } +void ScheduleDAGInstrs::ComputeOperandLatency(SUnit *Def, SUnit *Use, + SDep& dep) const { + const InstrItineraryData &InstrItins = TM.getInstrItineraryData(); + if (InstrItins.isEmpty()) + return; + + // For a data dependency with a known register... + if ((dep.getKind() != SDep::Data) || (dep.getReg() == 0)) + return; + + const unsigned Reg = dep.getReg(); + + // ... find the definition of the register in the defining + // instruction + MachineInstr *DefMI = Def->getInstr(); + int DefIdx = DefMI->findRegisterDefOperandIdx(Reg); + if (DefIdx != -1) { + int DefCycle = InstrItins.getOperandCycle(DefMI->getDesc().getSchedClass(), DefIdx); + if (DefCycle >= 0) { + MachineInstr *UseMI = Use->getInstr(); + const unsigned UseClass = UseMI->getDesc().getSchedClass(); + + // For all uses of the register, calculate the maxmimum latency + int Latency = -1; + for (unsigned i = 0, e = UseMI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = UseMI->getOperand(i); + if (!MO.isReg() || !MO.isUse()) + continue; + unsigned MOReg = MO.getReg(); + if (MOReg != Reg) + continue; + + int UseCycle = InstrItins.getOperandCycle(UseClass, i); + if (UseCycle >= 0) + Latency = std::max(Latency, DefCycle - UseCycle + 1); + } + + // If we found a latency, then replace the existing dependence latency. + if (Latency >= 0) + dep.setLatency(Latency); + } + } +} + void ScheduleDAGInstrs::dumpNode(const SUnit *SU) const { SU->getInstr()->dump(); } @@ -505,15 +496,21 @@ void ScheduleDAGInstrs::dumpNode(const SUnit *SU) const { std::string ScheduleDAGInstrs::getGraphNodeLabel(const SUnit *SU) const { std::string s; raw_string_ostream oss(s); - SU->getInstr()->print(oss); + if (SU == &EntrySU) + oss << ""; + else if (SU == &ExitSU) + oss << ""; + else + SU->getInstr()->print(oss); return oss.str(); } // EmitSchedule - Emit the machine code in scheduled order. -MachineBasicBlock *ScheduleDAGInstrs::EmitSchedule() { +MachineBasicBlock *ScheduleDAGInstrs:: +EmitSchedule(DenseMap *EM) { // For MachineInstr-based scheduling, we're rescheduling the instructions in // the block, so start by removing them from the block. - while (Begin != End) { + while (Begin != InsertPos) { MachineBasicBlock::iterator I = Begin; ++Begin; BB->remove(I); @@ -528,8 +525,13 @@ MachineBasicBlock *ScheduleDAGInstrs::EmitSchedule() { continue; } - BB->insert(End, SU->getInstr()); + BB->insert(InsertPos, SU->getInstr()); } + // Update the Begin iterator, as the first instruction in the block + // may have been scheduled later. + if (!Sequence.empty()) + Begin = Sequence[0]->getInstr(); + return BB; }