| //===---- 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<SUnit *> PendingLoads; |
| SUnit *Terminator = 0; |
| SUnit *Chain = 0; |
| SUnit *Defs[TargetRegisterInfo::FirstVirtualRegister] = {}; |
| std::vector<SUnit *> 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<SUnit *> &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<SUnit *> &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; |
| } |