//===----------------------------------------------------------------------===//
//
// This file implements the ScheduleDAG class, which is used as the common
-// base class for SelectionDAG-based instruction scheduler.
+// base class for instruction schedulers.
//
//===----------------------------------------------------------------------===//
#define LLVM_CODEGEN_SCHEDULEDAG_H
#include "llvm/CodeGen/MachineBasicBlock.h"
-#include "llvm/CodeGen/SelectionDAG.h"
-#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/GraphTraits.h"
-#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
namespace llvm {
- struct InstrStage;
struct SUnit;
class MachineConstantPool;
class MachineFunction;
class MachineRegisterInfo;
class MachineInstr;
class TargetRegisterInfo;
+ class ScheduleDAG;
class SelectionDAG;
- class SelectionDAGISel;
+ class SDNode;
class TargetInstrInfo;
class TargetInstrDesc;
class TargetLowering;
class TargetMachine;
class TargetRegisterClass;
-
- /// 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() {
- }
- };
+ template<class Graph> class GraphWriter;
/// 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 phy register dependency.
+ 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 isSpecial : 1; // True iff it's a special ctrl dep added during sched.
- SDep(SUnit *d, unsigned r, int t, bool c, bool s)
- : Dep(d), Reg(r), Cost(t), isCtrl(c), isSpecial(s) {}
+ 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.
- SmallVector<SDNode*,4> FlaggedNodes;// All nodes flagged to Node.
- unsigned InstanceNo; // Instance#. One SDNode can be multiple
- // SUnit due to cloning.
+ 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.
unsigned NodeNum; // Entry # of node in the node vector.
unsigned NodeQueueId; // Queue id of node.
unsigned short Latency; // Node latency.
- short NumPreds; // # of preds.
- short NumSuccs; // # of sucss.
+ short NumPreds; // # of non-control preds.
+ short NumSuccs; // # of non-control sucss.
short NumPredsLeft; // # of preds not scheduled.
short NumSuccsLeft; // # of succs not scheduled.
bool isTwoAddress : 1; // Is a two-address instruction.
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), InstanceNo(0), NodeNum(nodenum), NodeQueueId(0), Latency(0),
- NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0),
+ : 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),
- CycleBound(0), Cycle(0), Depth(0), Height(0),
+ 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. This returns true if this is a new pred.
- bool addPred(SUnit *N, bool isCtrl, bool isSpecial,
- unsigned PhyReg = 0, int Cost = 1) {
+ /// 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].isSpecial == isSpecial)
+ Preds[i].isCtrl == isCtrl && Preds[i].isArtificial == isArtificial)
return false;
- Preds.push_back(SDep(N, PhyReg, Cost, isCtrl, isSpecial));
- N->Succs.push_back(SDep(this, PhyReg, Cost, isCtrl, isSpecial));
+ 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;
return true;
}
- bool removePred(SUnit *N, bool isCtrl, bool isSpecial) {
+ 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->isSpecial == isSpecial) {
+ 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->isSpecial == isSpecial) {
+ II->isCtrl == isCtrl && II->isArtificial == isArtificial) {
FoundSucc = true;
N->Succs.erase(II);
break;
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(DenseMap<SDNode*, std::vector<SUnit*> > &SUMap,
- 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 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 *Node) {}
+ virtual void UnscheduledNode(SUnit *) {}
};
class ScheduleDAG {
public:
- 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
MachineConstantPool *ConstPool; // Target constant pool
std::vector<SUnit*> Sequence; // The schedule. Null SUnit*'s
// represent noop instructions.
- DenseMap<SDNode*, std::vector<SUnit*> > SUnitMap;
- // SDNode to SUnit mapping (n -> n).
std::vector<SUnit> SUnits; // The scheduling units.
- SmallSet<SDNode*, 16> CommuteSet; // Nodes that should be commuted.
- ScheduleDAG(SelectionDAG &dag, MachineBasicBlock *bb,
+ 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'.
/// 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<ConstantFPSDNode>(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;
- if (isa<MemOperandSDNode>(Node)) return true;
- if (Node->getOpcode() == ISD::EntryToken) return true;
- return false;
- }
-
- /// NewSUnit - Creates a new SUnit and return a ptr to it.
- ///
- SUnit *NewSUnit(SDNode *N) {
- SUnits.push_back(SUnit(N, (unsigned)SUnits.size()));
- return &SUnits.back();
- }
-
- /// Clone - Creates a clone of the specified SUnit. It does not copy the
- /// predecessors / successors info nor the temporary scheduling states.
- SUnit *Clone(SUnit *N);
-
- /// 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 BuildSchedUnits() = 0;
/// ComputeLatency - Compute node latency.
///
- void ComputeLatency(SUnit *SU);
+ virtual void ComputeLatency(SUnit *SU) { SU->Latency = 1; }
/// CalculateDepths, CalculateHeights - Calculate node depth / height.
///
void CalculateDepths();
void CalculateHeights();
- /// CountResults - The results of target nodes have register or immediate
- /// operands first, then an optional chain, and optional flag operands
- /// (which do not go into the machine instrs.)
- static unsigned CountResults(SDNode *Node);
-
- /// CountOperands - The inputs to target nodes have any actual inputs first,
- /// followed by special operands that describe memory references, then an
- /// optional chain operand, then flag operands. Compute the number of
- /// actual operands that will go into the resulting MachineInstr.
- static unsigned CountOperands(SDNode *Node);
-
- /// ComputeMemOperandsEnd - Find the index one past the last
- /// MemOperandSDNode operand
- static unsigned ComputeMemOperandsEnd(SDNode *Node);
-
- /// 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, unsigned InstNo,
- DenseMap<SDOperand, 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;
- private:
- /// EmitSubregNode - Generate machine code for subreg nodes.
- ///
- void EmitSubregNode(SDNode *Node,
- DenseMap<SDOperand, unsigned> &VRBaseMap);
+ virtual void dumpNode(const SUnit *SU) const = 0;
- /// getVR - Return the virtual register corresponding to the specified result
- /// of the specified node.
- unsigned getVR(SDOperand Op, DenseMap<SDOperand, unsigned> &VRBaseMap);
-
- /// getDstOfCopyToRegUse - If the only use of the specified result number of
- /// node is a CopyToReg, return its destination register. Return 0 otherwise.
- unsigned getDstOfOnlyCopyToRegUse(SDNode *Node, unsigned ResNo) const;
+ /// 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 {}
- void AddOperand(MachineInstr *MI, SDOperand Op, unsigned IIOpNum,
- const TargetInstrDesc *II,
- DenseMap<SDOperand, unsigned> &VRBaseMap);
+#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);
- /// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an
- /// implicit physical register output.
- void EmitCopyFromReg(SDNode *Node, unsigned ResNo, unsigned InstNo,
- unsigned SrcReg,
- DenseMap<SDOperand, unsigned> &VRBaseMap);
-
- void CreateVirtualRegisters(SDNode *Node, MachineInstr *MI,
- const TargetInstrDesc &II,
- DenseMap<SDOperand, unsigned> &VRBaseMap);
-
+ private:
/// 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 EmitLiveInCopies(MachineBasicBlock *MBB);
};
- /// createBURRListDAGScheduler - This creates a bottom up register usage
- /// reduction list scheduler.
- ScheduleDAG* createBURRListDAGScheduler(SelectionDAGISel *IS,
- SelectionDAG *DAG,
- MachineBasicBlock *BB);
-
- /// createTDRRListDAGScheduler - This creates a top down register usage
- /// reduction list scheduler.
- ScheduleDAG* createTDRRListDAGScheduler(SelectionDAGISel *IS,
- SelectionDAG *DAG,
- MachineBasicBlock *BB);
-
- /// createTDListDAGScheduler - This creates a top-down list scheduler with
- /// a hazard recognizer.
- ScheduleDAG* createTDListDAGScheduler(SelectionDAGISel *IS,
- SelectionDAG *DAG,
- MachineBasicBlock *BB);
-
- /// createDefaultScheduler - This creates an instruction scheduler appropriate
- /// for the target.
- ScheduleDAG* createDefaultScheduler(SelectionDAGISel *IS,
- SelectionDAG *DAG,
- MachineBasicBlock *BB);
-
class SUnitIterator : public forward_iterator<SUnit, ptrdiff_t> {
SUnit *Node;
unsigned Operand;
unsigned getOperand() const { return Operand; }
const SUnit *getNode() const { return Node; }
bool isCtrlDep() const { return Node->Preds[Operand].isCtrl; }
- bool isSpecialDep() const { return Node->Preds[Operand].isSpecial; }
+ bool isArtificialDep() const { return Node->Preds[Operand].isArtificial; }
};
template <> struct GraphTraits<SUnit*> {