//===---- ScheduleDAG.cpp - Implement the ScheduleDAG class ---------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This implements the ScheduleDAG class, which is a base class used by // scheduling implementation classes. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sched-instrs" #include "llvm/CodeGen/ScheduleDAGInstrs.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; ScheduleDAGInstrs::ScheduleDAGInstrs(MachineBasicBlock *bb, const TargetMachine &tm) : ScheduleDAG(0, bb, tm) {} void ScheduleDAGInstrs::BuildSchedUnits() { SUnits.clear(); SUnits.reserve(BB->size()); std::vector PendingLoads; SUnit *Terminator = 0; SUnit *Chain = 0; SUnit *Defs[TargetRegisterInfo::FirstVirtualRegister] = {}; std::vector Uses[TargetRegisterInfo::FirstVirtualRegister] = {}; int Cost = 1; // FIXME for (MachineBasicBlock::iterator MII = BB->end(), MIE = BB->begin(); MII != MIE; --MII) { MachineInstr *MI = prior(MII); SUnit *SU = NewSUnit(MI); for (unsigned j = 0, n = MI->getNumOperands(); j != n; ++j) { const MachineOperand &MO = MI->getOperand(j); if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); if (Reg == 0) continue; assert(TRI->isPhysicalRegister(Reg) && "Virtual register encountered!"); std::vector &UseList = Uses[Reg]; SUnit *&Def = Defs[Reg]; // Optionally add output and anti dependencies. if (Def && Def != SU) Def->addPred(SU, /*isCtrl=*/true, /*isArtificial=*/false, /*PhyReg=*/Reg, Cost, /*isAntiDep=*/MO.isUse()); for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { SUnit *&Def = Defs[*Alias]; if (Def && Def != SU) Def->addPred(SU, /*isCtrl=*/true, /*isArtificial=*/false, /*PhyReg=*/*Alias, Cost, /*isAntiDep=*/MO.isUse()); } if (MO.isDef()) { // Add any data dependencies. for (unsigned i = 0, e = UseList.size(); i != e; ++i) if (UseList[i] != SU) UseList[i]->addPred(SU, /*isCtrl=*/false, /*isArtificial=*/false, /*PhysReg=*/Reg, Cost); for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { std::vector &UseList = Uses[*Alias]; for (unsigned i = 0, e = UseList.size(); i != e; ++i) if (UseList[i] != SU) UseList[i]->addPred(SU, /*isCtrl=*/false, /*isArtificial=*/false, /*PhysReg=*/*Alias, Cost); } UseList.clear(); Def = SU; } else { UseList.push_back(SU); } } bool False = false; bool True = true; if (!MI->isSafeToMove(TII, False)) { if (Chain) Chain->addPred(SU, /*isCtrl=*/true, /*isArtificial=*/false); for (unsigned k = 0, m = PendingLoads.size(); k != m; ++k) PendingLoads[k]->addPred(SU, /*isCtrl=*/true, /*isArtificial=*/false); PendingLoads.clear(); Chain = SU; } else if (!MI->isSafeToMove(TII, True)) { if (Chain) Chain->addPred(SU, /*isCtrl=*/true, /*isArtificial=*/false); PendingLoads.push_back(SU); } if (Terminator && SU->Succs.empty()) Terminator->addPred(SU, /*isCtrl=*/true, /*isArtificial=*/false); if (MI->getDesc().isTerminator() || MI->isLabel()) Terminator = SU; // Assign the Latency field of SU using target-provided information. ComputeLatency(SU); } } 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. SU->Latency = InstrItins.getLatency(SU->getInstr()->getDesc().getSchedClass()); } void ScheduleDAGInstrs::dumpNode(const SUnit *SU) const { SU->getInstr()->dump(); } std::string ScheduleDAGInstrs::getGraphNodeLabel(const SUnit *SU) const { std::string s; raw_string_ostream oss(s); SU->getInstr()->print(oss); return oss.str(); } // EmitSchedule - Emit the machine code in scheduled order. MachineBasicBlock *ScheduleDAGInstrs::EmitSchedule() { // For MachineInstr-based scheduling, we're rescheduling the instructions in // the block, so start by removing them from the block. while (!BB->empty()) BB->remove(BB->begin()); for (unsigned i = 0, e = Sequence.size(); i != e; i++) { SUnit *SU = Sequence[i]; if (!SU) { // Null SUnit* is a noop. EmitNoop(); continue; } BB->push_back(SU->getInstr()); } return BB; }