//
// The LLVM Compiler Infrastructure
//
-// This file was developed by Evan Cheng and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ScheduleDAG class, which is used as the common
-// base class for SelectionDAG-based instruction scheduler.
+// base class for instruction schedulers.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_SCHEDULEDAG_H
#define LLVM_CODEGEN_SCHEDULEDAG_H
-#include "llvm/CodeGen/SelectionDAG.h"
-
-#include <set>
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/SmallVector.h"
namespace llvm {
- struct InstrStage;
+ struct SUnit;
class MachineConstantPool;
- class MachineDebugInfo;
+ class MachineFunction;
+ class MachineModuleInfo;
+ class MachineRegisterInfo;
class MachineInstr;
- class MRegisterInfo;
+ class TargetRegisterInfo;
+ class ScheduleDAG;
class SelectionDAG;
- class SSARegMap;
+ class SDNode;
class TargetInstrInfo;
- class TargetInstrDescriptor;
+ class TargetInstrDesc;
+ class TargetLowering;
class TargetMachine;
+ class TargetRegisterClass;
+ template<class Graph> class GraphWriter;
- /// HazardRecognizer - This determines whether or not an instruction can be
- /// issued this cycle, and whether or not a noop needs to be inserted to handle
- /// the hazard.
- class HazardRecognizer {
- public:
- virtual ~HazardRecognizer();
-
- enum HazardType {
- NoHazard, // This instruction can be emitted at this cycle.
- Hazard, // This instruction can't be emitted at this cycle.
- NoopHazard, // This instruction can't be emitted, and needs noops.
- };
-
- /// getHazardType - Return the hazard type of emitting this node. There are
- /// three possible results. Either:
- /// * NoHazard: it is legal to issue this instruction on this cycle.
- /// * Hazard: issuing this instruction would stall the machine. If some
- /// other instruction is available, issue it first.
- /// * NoopHazard: issuing this instruction would break the program. If
- /// some other instruction can be issued, do so, otherwise issue a noop.
- virtual HazardType getHazardType(SDNode *Node) {
- return NoHazard;
- }
-
- /// EmitInstruction - This callback is invoked when an instruction is
- /// emitted, to advance the hazard state.
- virtual void EmitInstruction(SDNode *Node) {
- }
-
- /// AdvanceCycle - This callback is invoked when no instructions can be
- /// issued on this cycle without a hazard. This should increment the
- /// internal state of the hazard recognizer so that previously "Hazard"
- /// instructions will now not be hazards.
- virtual void AdvanceCycle() {
- }
-
- /// EmitNoop - This callback is invoked when a noop was added to the
- /// instruction stream.
- virtual void EmitNoop() {
- }
+ /// SDep - Scheduling dependency. It keeps track of dependent nodes,
+ /// cost of the depdenency, etc.
+ struct SDep {
+ SUnit *Dep; // Dependent - either a predecessor or a successor.
+ unsigned Reg; // If non-zero, this dep is a physreg dependency.
+ int Cost; // Cost of the dependency.
+ bool isCtrl : 1; // True iff it's a control dependency.
+ bool isArtificial : 1; // True iff it's an artificial ctrl dep added
+ // during sched that may be safely deleted if
+ // necessary.
+ bool isAntiDep : 1; // True iff it's an anti-dependency (on a physical
+ // register.
+ SDep(SUnit *d, unsigned r, int t, bool c, bool a, bool anti)
+ : Dep(d), Reg(r), Cost(t), isCtrl(c), isArtificial(a), isAntiDep(anti) {}
};
-
- /// SUnit - Scheduling unit. It's an wrapper around either a single SDNode or
- /// a group of nodes flagged together.
+
+ /// SUnit - Scheduling unit. This is a node in the scheduling DAG.
struct SUnit {
+ private:
SDNode *Node; // Representative node.
- std::vector<SDNode*> FlaggedNodes; // All nodes flagged to Node.
+ MachineInstr *Instr; // Alternatively, a MachineInstr.
+ public:
+ SUnit *OrigNode; // If not this, the node from which
+ // this node was cloned.
// Preds/Succs - The SUnits before/after us in the graph. The boolean value
// is true if the edge is a token chain edge, false if it is a value edge.
- std::set<std::pair<SUnit*,bool> > Preds; // All sunit predecessors.
- std::set<std::pair<SUnit*,bool> > Succs; // All sunit successors.
+ SmallVector<SDep, 4> Preds; // All sunit predecessors.
+ SmallVector<SDep, 4> Succs; // All sunit successors.
- short NumPreds; // # of preds.
- short NumSuccs; // # of sucss.
+ typedef SmallVector<SDep, 4>::iterator pred_iterator;
+ typedef SmallVector<SDep, 4>::iterator succ_iterator;
+ typedef SmallVector<SDep, 4>::const_iterator const_pred_iterator;
+ typedef SmallVector<SDep, 4>::const_iterator const_succ_iterator;
+
+ unsigned NodeNum; // Entry # of node in the node vector.
+ unsigned NodeQueueId; // Queue id of node.
+ unsigned short Latency; // Node latency.
+ short NumPreds; // # of non-control preds.
+ short NumSuccs; // # of non-control sucss.
short NumPredsLeft; // # of preds not scheduled.
short NumSuccsLeft; // # of succs not scheduled.
- short NumChainPredsLeft; // # of chain preds not scheduled.
- short NumChainSuccsLeft; // # of chain succs not scheduled.
bool isTwoAddress : 1; // Is a two-address instruction.
bool isCommutable : 1; // Is a commutable instruction.
+ bool hasPhysRegDefs : 1; // Has physreg defs that are being used.
bool isPending : 1; // True once pending.
bool isAvailable : 1; // True once available.
bool isScheduled : 1; // True once scheduled.
- unsigned short Latency; // Node latency.
unsigned CycleBound; // Upper/lower cycle to be scheduled at.
unsigned Cycle; // Once scheduled, the cycle of the op.
unsigned Depth; // Node depth;
unsigned Height; // Node height;
- unsigned NodeNum; // Entry # of node in the node vector.
+ const TargetRegisterClass *CopyDstRC; // Is a special copy node if not null.
+ const TargetRegisterClass *CopySrcRC;
+ /// SUnit - Construct an SUnit for pre-regalloc scheduling to represent
+ /// an SDNode and any nodes flagged to it.
SUnit(SDNode *node, unsigned nodenum)
- : Node(node), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0),
- NumChainPredsLeft(0), NumChainSuccsLeft(0),
- isTwoAddress(false), isCommutable(false),
+ : Node(node), Instr(0), OrigNode(0), NodeNum(nodenum), NodeQueueId(0),
+ Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0),
+ isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false),
isPending(false), isAvailable(false), isScheduled(false),
- Latency(0), CycleBound(0), Cycle(0), Depth(0), Height(0),
- NodeNum(nodenum) {}
+ CycleBound(0), Cycle(~0u), Depth(0), Height(0),
+ CopyDstRC(NULL), CopySrcRC(NULL) {}
+
+ /// SUnit - Construct an SUnit for post-regalloc scheduling to represent
+ /// a MachineInstr.
+ SUnit(MachineInstr *instr, unsigned nodenum)
+ : Node(0), Instr(instr), OrigNode(0), NodeNum(nodenum), NodeQueueId(0),
+ Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0),
+ isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false),
+ isPending(false), isAvailable(false), isScheduled(false),
+ CycleBound(0), Cycle(~0u), Depth(0), Height(0),
+ CopyDstRC(NULL), CopySrcRC(NULL) {}
+
+ /// setNode - Assign the representative SDNode for this SUnit.
+ /// This may be used during pre-regalloc scheduling.
+ void setNode(SDNode *N) {
+ assert(!Instr && "Setting SDNode of SUnit with MachineInstr!");
+ Node = N;
+ }
+
+ /// getNode - Return the representative SDNode for this SUnit.
+ /// This may be used during pre-regalloc scheduling.
+ SDNode *getNode() const {
+ assert(!Instr && "Reading SDNode of SUnit with MachineInstr!");
+ return Node;
+ }
+
+ /// setInstr - Assign the instruction for the SUnit.
+ /// This may be used during post-regalloc scheduling.
+ void setInstr(MachineInstr *MI) {
+ assert(!Node && "Setting MachineInstr of SUnit with SDNode!");
+ Instr = MI;
+ }
+
+ /// getInstr - Return the representative MachineInstr for this SUnit.
+ /// This may be used during post-regalloc scheduling.
+ MachineInstr *getInstr() const {
+ assert(!Node && "Reading MachineInstr of SUnit with SDNode!");
+ return Instr;
+ }
+
+ /// addPred - This adds the specified node as a pred of the current node if
+ /// not already. It also adds the current node as a successor of the
+ /// specified node. This returns true if this is a new pred.
+ bool addPred(SUnit *N, bool isCtrl, bool isArtificial,
+ unsigned PhyReg = 0, int Cost = 1, bool isAntiDep = false) {
+ for (unsigned i = 0, e = (unsigned)Preds.size(); i != e; ++i)
+ if (Preds[i].Dep == N &&
+ Preds[i].isCtrl == isCtrl && Preds[i].isArtificial == isArtificial)
+ return false;
+ Preds.push_back(SDep(N, PhyReg, Cost, isCtrl, isArtificial, isAntiDep));
+ N->Succs.push_back(SDep(this, PhyReg, Cost, isCtrl,
+ isArtificial, isAntiDep));
+ if (!isCtrl) {
+ ++NumPreds;
+ ++N->NumSuccs;
+ }
+ if (!N->isScheduled)
+ ++NumPredsLeft;
+ if (!isScheduled)
+ ++N->NumSuccsLeft;
+ return true;
+ }
+
+ bool removePred(SUnit *N, bool isCtrl, bool isArtificial) {
+ for (SmallVector<SDep, 4>::iterator I = Preds.begin(), E = Preds.end();
+ I != E; ++I)
+ if (I->Dep == N && I->isCtrl == isCtrl && I->isArtificial == isArtificial) {
+ bool FoundSucc = false;
+ for (SmallVector<SDep, 4>::iterator II = N->Succs.begin(),
+ EE = N->Succs.end(); II != EE; ++II)
+ if (II->Dep == this &&
+ II->isCtrl == isCtrl && II->isArtificial == isArtificial) {
+ FoundSucc = true;
+ N->Succs.erase(II);
+ break;
+ }
+ assert(FoundSucc && "Mismatching preds / succs lists!");
+ Preds.erase(I);
+ if (!isCtrl) {
+ --NumPreds;
+ --N->NumSuccs;
+ }
+ if (!N->isScheduled)
+ --NumPredsLeft;
+ if (!isScheduled)
+ --N->NumSuccsLeft;
+ return true;
+ }
+ return false;
+ }
+
+ bool isPred(SUnit *N) {
+ for (unsigned i = 0, e = (unsigned)Preds.size(); i != e; ++i)
+ if (Preds[i].Dep == N)
+ return true;
+ return false;
+ }
+
+ bool isSucc(SUnit *N) {
+ for (unsigned i = 0, e = (unsigned)Succs.size(); i != e; ++i)
+ if (Succs[i].Dep == N)
+ return true;
+ return false;
+ }
- void dump(const SelectionDAG *G) const;
- void dumpAll(const SelectionDAG *G) const;
+ void dump(const ScheduleDAG *G) const;
+ void dumpAll(const ScheduleDAG *G) const;
+ void print(raw_ostream &O, const ScheduleDAG *G) const;
};
//===--------------------------------------------------------------------===//
public:
virtual ~SchedulingPriorityQueue() {}
- virtual void initNodes(const std::vector<SUnit> &SUnits) = 0;
+ virtual void initNodes(std::vector<SUnit> &SUnits) = 0;
+ virtual void addNode(const SUnit *SU) = 0;
+ virtual void updateNode(const SUnit *SU) = 0;
virtual void releaseState() = 0;
-
+
+ virtual unsigned size() const = 0;
virtual bool empty() const = 0;
virtual void push(SUnit *U) = 0;
virtual void push_all(const std::vector<SUnit *> &Nodes) = 0;
virtual SUnit *pop() = 0;
+ virtual void remove(SUnit *SU) = 0;
+
/// ScheduledNode - As each node is scheduled, this method is invoked. This
- /// allows the priority function to adjust the priority of node that have
- /// already been emitted.
- virtual void ScheduledNode(SUnit *Node) {}
+ /// allows the priority function to adjust the priority of related
+ /// unscheduled nodes, for example.
+ ///
+ virtual void ScheduledNode(SUnit *) {}
+
+ virtual void UnscheduledNode(SUnit *) {}
};
class ScheduleDAG {
public:
-
- // Scheduling heuristics
- enum SchedHeuristics {
- defaultScheduling, // Let the target specify its preference.
- noScheduling, // No scheduling, emit breadth first sequence.
- simpleScheduling, // Two pass, min. critical path, max. utilization.
- simpleNoItinScheduling, // Same as above exact using generic latency.
- listSchedulingBURR, // Bottom-up reg reduction list scheduling.
- listSchedulingTDRR, // Top-down reg reduction list scheduling.
- listSchedulingTD // Top-down list scheduler.
- };
-
- SelectionDAG &DAG; // DAG of the current basic block
+ SelectionDAG *DAG; // DAG of the current basic block
MachineBasicBlock *BB; // Current basic block
const TargetMachine &TM; // Target processor
const TargetInstrInfo *TII; // Target instruction information
- const MRegisterInfo *MRI; // Target processor register info
- SSARegMap *RegMap; // Virtual/real register map
+ const TargetRegisterInfo *TRI; // Target processor register info
+ TargetLowering *TLI; // Target lowering info
+ MachineFunction *MF; // Machine function
+ MachineRegisterInfo &MRI; // Virtual/real register map
MachineConstantPool *ConstPool; // Target constant pool
std::vector<SUnit*> Sequence; // The schedule. Null SUnit*'s
// represent noop instructions.
- std::map<SDNode*, SUnit*> SUnitMap; // SDNode to SUnit mapping (n -> 1).
std::vector<SUnit> SUnits; // The scheduling units.
- std::set<SDNode*> CommuteSet; // Nodes the should be commuted.
- ScheduleDAG(SelectionDAG &dag, MachineBasicBlock *bb,
- const TargetMachine &tm)
- : DAG(dag), BB(bb), TM(tm) {}
+ ScheduleDAG(SelectionDAG *dag, MachineBasicBlock *bb,
+ const TargetMachine &tm);
- virtual ~ScheduleDAG() {}
+ virtual ~ScheduleDAG();
+ /// viewGraph - Pop up a GraphViz/gv window with the ScheduleDAG rendered
+ /// using 'dot'.
+ ///
+ void viewGraph();
+
/// Run - perform scheduling.
///
- MachineBasicBlock *Run();
+ void Run();
- /// isPassiveNode - Return true if the node is a non-scheduled leaf.
+ /// BuildSchedUnits - Build SUnits and set up their Preds and Succs
+ /// to form the scheduling dependency graph.
///
- static bool isPassiveNode(SDNode *Node) {
- if (isa<ConstantSDNode>(Node)) return true;
- if (isa<RegisterSDNode>(Node)) return true;
- if (isa<GlobalAddressSDNode>(Node)) return true;
- if (isa<BasicBlockSDNode>(Node)) return true;
- if (isa<FrameIndexSDNode>(Node)) return true;
- if (isa<ConstantPoolSDNode>(Node)) return true;
- if (isa<JumpTableSDNode>(Node)) return true;
- if (isa<ExternalSymbolSDNode>(Node)) return true;
- return false;
- }
+ virtual void BuildSchedUnits() = 0;
- /// NewSUnit - Creates a new SUnit and return a ptr to it.
+ /// ComputeLatency - Compute node latency.
///
- SUnit *NewSUnit(SDNode *N) {
- SUnits.push_back(SUnit(N, SUnits.size()));
- return &SUnits.back();
- }
-
- /// BuildSchedUnits - Build SUnits from the selection dag that we are input.
- /// This SUnit graph is similar to the SelectionDAG, but represents flagged
- /// together nodes with a single SUnit.
- void BuildSchedUnits();
+ virtual void ComputeLatency(SUnit *SU) { SU->Latency = 1; }
/// CalculateDepths, CalculateHeights - Calculate node depth / height.
///
void CalculateDepths();
void CalculateHeights();
- /// EmitNode - Generate machine code for an node and needed dependencies.
- /// VRBaseMap contains, for each already emitted node, the first virtual
- /// register number for the results of the node.
- ///
- void EmitNode(SDNode *Node, std::map<SDNode*, unsigned> &VRBaseMap);
-
+ protected:
/// EmitNoop - Emit a noop instruction.
///
void EmitNoop();
-
- void EmitSchedule();
+
+ public:
+ virtual MachineBasicBlock *EmitSchedule() = 0;
void dumpSchedule() const;
- /// Schedule - Order nodes according to selected style.
+ /// Schedule - Order nodes according to selected style, filling
+ /// in the Sequence member.
///
- virtual void Schedule() {}
+ virtual void Schedule() = 0;
+
+ virtual void dumpNode(const SUnit *SU) const = 0;
+
+ /// getGraphNodeLabel - Return a label for an SUnit node in a visualization
+ /// of the ScheduleDAG.
+ virtual std::string getGraphNodeLabel(const SUnit *SU) const = 0;
+
+ /// addCustomGraphFeatures - Add custom features for a visualization of
+ /// the ScheduleDAG.
+ virtual void addCustomGraphFeatures(GraphWriter<ScheduleDAG*> &GW) const {}
+
+#ifndef NDEBUG
+ /// VerifySchedule - Verify that all SUnits were scheduled and that
+ /// their state is consistent.
+ void VerifySchedule(bool isBottomUp);
+#endif
+
+ protected:
+ void AddMemOperand(MachineInstr *MI, const MachineMemOperand &MO);
+
+ void EmitCrossRCCopy(SUnit *SU, DenseMap<SUnit*, unsigned> &VRBaseMap);
private:
- void AddOperand(MachineInstr *MI, SDOperand Op, unsigned IIOpNum,
- const TargetInstrDescriptor *II,
- std::map<SDNode*, unsigned> &VRBaseMap);
+ /// EmitLiveInCopy - Emit a copy for a live in physical register. If the
+ /// physical register has only a single copy use, then coalesced the copy
+ /// if possible.
+ void EmitLiveInCopy(MachineBasicBlock *MBB,
+ MachineBasicBlock::iterator &InsertPos,
+ unsigned VirtReg, unsigned PhysReg,
+ const TargetRegisterClass *RC,
+ DenseMap<MachineInstr*, unsigned> &CopyRegMap);
+
+ /// EmitLiveInCopies - If this is the first basic block in the function,
+ /// and if it has live ins that need to be copied into vregs, emit the
+ /// copies into the top of the block.
+ void EmitLiveInCopies(MachineBasicBlock *MBB);
};
- ScheduleDAG *createBFS_DAGScheduler(SelectionDAG &DAG, MachineBasicBlock *BB);
-
- /// createSimpleDAGScheduler - This creates a simple two pass instruction
- /// scheduler.
- ScheduleDAG* createSimpleDAGScheduler(bool NoItins, SelectionDAG &DAG,
- MachineBasicBlock *BB);
-
- /// createBURRListDAGScheduler - This creates a bottom up register usage
- /// reduction list scheduler.
- ScheduleDAG* createBURRListDAGScheduler(SelectionDAG &DAG,
- MachineBasicBlock *BB);
-
- /// createTDRRListDAGScheduler - This creates a top down register usage
- /// reduction list scheduler.
- ScheduleDAG* createTDRRListDAGScheduler(SelectionDAG &DAG,
- MachineBasicBlock *BB);
-
- /// createTDListDAGScheduler - This creates a top-down list scheduler with
- /// the specified hazard recognizer. This takes ownership of the hazard
- /// recognizer and deletes it when done.
- ScheduleDAG* createTDListDAGScheduler(SelectionDAG &DAG,
- MachineBasicBlock *BB,
- HazardRecognizer *HR);
+ class SUnitIterator : public forward_iterator<SUnit, ptrdiff_t> {
+ SUnit *Node;
+ unsigned Operand;
+
+ SUnitIterator(SUnit *N, unsigned Op) : Node(N), Operand(Op) {}
+ public:
+ bool operator==(const SUnitIterator& x) const {
+ return Operand == x.Operand;
+ }
+ bool operator!=(const SUnitIterator& x) const { return !operator==(x); }
+
+ const SUnitIterator &operator=(const SUnitIterator &I) {
+ assert(I.Node == Node && "Cannot assign iterators to two different nodes!");
+ Operand = I.Operand;
+ return *this;
+ }
+
+ pointer operator*() const {
+ return Node->Preds[Operand].Dep;
+ }
+ pointer operator->() const { return operator*(); }
+
+ SUnitIterator& operator++() { // Preincrement
+ ++Operand;
+ return *this;
+ }
+ SUnitIterator operator++(int) { // Postincrement
+ SUnitIterator tmp = *this; ++*this; return tmp;
+ }
+
+ static SUnitIterator begin(SUnit *N) { return SUnitIterator(N, 0); }
+ static SUnitIterator end (SUnit *N) {
+ return SUnitIterator(N, (unsigned)N->Preds.size());
+ }
+
+ unsigned getOperand() const { return Operand; }
+ const SUnit *getNode() const { return Node; }
+ bool isCtrlDep() const { return Node->Preds[Operand].isCtrl; }
+ bool isArtificialDep() const { return Node->Preds[Operand].isArtificial; }
+ };
+
+ template <> struct GraphTraits<SUnit*> {
+ typedef SUnit NodeType;
+ typedef SUnitIterator ChildIteratorType;
+ static inline NodeType *getEntryNode(SUnit *N) { return N; }
+ static inline ChildIteratorType child_begin(NodeType *N) {
+ return SUnitIterator::begin(N);
+ }
+ static inline ChildIteratorType child_end(NodeType *N) {
+ return SUnitIterator::end(N);
+ }
+ };
+
+ template <> struct GraphTraits<ScheduleDAG*> : public GraphTraits<SUnit*> {
+ typedef std::vector<SUnit>::iterator nodes_iterator;
+ static nodes_iterator nodes_begin(ScheduleDAG *G) {
+ return G->SUnits.begin();
+ }
+ static nodes_iterator nodes_end(ScheduleDAG *G) {
+ return G->SUnits.end();
+ }
+ };
}
#endif