From: Evan Cheng Date: Sat, 21 Jan 2006 02:32:06 +0000 (+0000) Subject: Do some code refactoring on Jim's scheduler in preparation of the new list X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=a9c2091cd38e401c846391c9951ff416e709b65e;p=oota-llvm.git Do some code refactoring on Jim's scheduler in preparation of the new list scheduler. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@25493 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/ScheduleDAG.h b/include/llvm/CodeGen/ScheduleDAG.h new file mode 100644 index 00000000000..c3e973113e5 --- /dev/null +++ b/include/llvm/CodeGen/ScheduleDAG.h @@ -0,0 +1,288 @@ +//===------- llvm/CodeGen/ScheduleDAG.h - Common Base Class------*- C++ -*-===// +// +// 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 implements the ScheduleDAG class, which is used as the common +// base class for SelectionDAG-based instruction scheduler. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_SCHEDULEDAG_H +#define LLVM_CODEGEN_SCHEDULEDAG_H + +#include "llvm/CodeGen/SelectionDAG.h" + +namespace llvm { + class InstrStage; + class MachineConstantPool; + class MachineDebugInfo; + class MachineInstr; + class MRegisterInfo; + class SelectionDAG; + class SSARegMap; + class TargetInstrInfo; + class TargetInstrDescriptor; + class TargetMachine; + + class NodeInfo; + typedef NodeInfo *NodeInfoPtr; + typedef std::vector NIVector; + typedef std::vector::iterator NIIterator; + + + //===--------------------------------------------------------------------===// + /// + /// Node group - This struct is used to manage flagged node groups. + /// + class NodeGroup { + private: + NIVector Members; // Group member nodes + NodeInfo *Dominator; // Node with highest latency + unsigned Latency; // Total latency of the group + int Pending; // Number of visits pending before + // adding to order + + public: + // Ctor. + NodeGroup() : Dominator(NULL), Pending(0) {} + + // Accessors + inline void setDominator(NodeInfo *D) { Dominator = D; } + inline NodeInfo *getDominator() { return Dominator; } + inline void setLatency(unsigned L) { Latency = L; } + inline unsigned getLatency() { return Latency; } + inline int getPending() const { return Pending; } + inline void setPending(int P) { Pending = P; } + inline int addPending(int I) { return Pending += I; } + + // Pass thru + inline bool group_empty() { return Members.empty(); } + inline NIIterator group_begin() { return Members.begin(); } + inline NIIterator group_end() { return Members.end(); } + inline void group_push_back(const NodeInfoPtr &NI) { + Members.push_back(NI); + } + inline NIIterator group_insert(NIIterator Pos, const NodeInfoPtr &NI) { + return Members.insert(Pos, NI); + } + inline void group_insert(NIIterator Pos, NIIterator First, + NIIterator Last) { + Members.insert(Pos, First, Last); + } + + static void Add(NodeInfo *D, NodeInfo *U); + static unsigned CountInternalUses(NodeInfo *D, NodeInfo *U); + }; + + //===--------------------------------------------------------------------===// + /// + /// NodeInfo - This struct tracks information used to schedule the a node. + /// + class NodeInfo { + private: + int Pending; // Number of visits pending before + // adding to order + public: + SDNode *Node; // DAG node + InstrStage *StageBegin; // First stage in itinerary + InstrStage *StageEnd; // Last+1 stage in itinerary + unsigned Latency; // Total cycles to complete instr + bool IsCall : 1; // Is function call + bool IsLoad : 1; // Is memory load + bool IsStore : 1; // Is memory store + unsigned Slot; // Node's time slot + NodeGroup *Group; // Grouping information + unsigned VRBase; // Virtual register base +#ifndef NDEBUG + unsigned Preorder; // Index before scheduling +#endif + + // Ctor. + NodeInfo(SDNode *N = NULL) + : Pending(0) + , Node(N) + , StageBegin(NULL) + , StageEnd(NULL) + , Latency(0) + , IsCall(false) + , Slot(0) + , Group(NULL) + , VRBase(0) +#ifndef NDEBUG + , Preorder(0) +#endif + {} + + // Accessors + inline bool isInGroup() const { + assert(!Group || !Group->group_empty() && "Group with no members"); + return Group != NULL; + } + inline bool isGroupDominator() const { + return isInGroup() && Group->getDominator() == this; + } + inline int getPending() const { + return Group ? Group->getPending() : Pending; + } + inline void setPending(int P) { + if (Group) Group->setPending(P); + else Pending = P; + } + inline int addPending(int I) { + if (Group) return Group->addPending(I); + else return Pending += I; + } + }; + + //===--------------------------------------------------------------------===// + /// + /// NodeGroupIterator - Iterates over all the nodes indicated by the node + /// info. If the node is in a group then iterate over the members of the + /// group, otherwise just the node info. + /// + class NodeGroupIterator { + private: + NodeInfo *NI; // Node info + NIIterator NGI; // Node group iterator + NIIterator NGE; // Node group iterator end + + public: + // Ctor. + NodeGroupIterator(NodeInfo *N) : NI(N) { + // If the node is in a group then set up the group iterator. Otherwise + // the group iterators will trip first time out. + if (N->isInGroup()) { + // get Group + NodeGroup *Group = NI->Group; + NGI = Group->group_begin(); + NGE = Group->group_end(); + // Prevent this node from being used (will be in members list + NI = NULL; + } + } + + /// next - Return the next node info, otherwise NULL. + /// + NodeInfo *next() { + // If members list + if (NGI != NGE) return *NGI++; + // Use node as the result (may be NULL) + NodeInfo *Result = NI; + // Only use once + NI = NULL; + // Return node or NULL + return Result; + } + }; + //===--------------------------------------------------------------------===// + + + //===--------------------------------------------------------------------===// + /// + /// NodeGroupOpIterator - Iterates over all the operands of a node. If the + /// node is a member of a group, this iterates over all the operands of all + /// the members of the group. + /// + class NodeGroupOpIterator { + private: + NodeInfo *NI; // Node containing operands + NodeGroupIterator GI; // Node group iterator + SDNode::op_iterator OI; // Operand iterator + SDNode::op_iterator OE; // Operand iterator end + + /// CheckNode - Test if node has more operands. If not get the next node + /// skipping over nodes that have no operands. + void CheckNode() { + // Only if operands are exhausted first + while (OI == OE) { + // Get next node info + NodeInfo *NI = GI.next(); + // Exit if nodes are exhausted + if (!NI) return; + // Get node itself + SDNode *Node = NI->Node; + // Set up the operand iterators + OI = Node->op_begin(); + OE = Node->op_end(); + } + } + + public: + // Ctor. + NodeGroupOpIterator(NodeInfo *N) + : NI(N), GI(N), OI(SDNode::op_iterator()), OE(SDNode::op_iterator()) {} + + /// isEnd - Returns true when not more operands are available. + /// + inline bool isEnd() { CheckNode(); return OI == OE; } + + /// next - Returns the next available operand. + /// + inline SDOperand next() { + assert(OI != OE && + "Not checking for end of NodeGroupOpIterator correctly"); + return *OI++; + } + }; + + class ScheduleDAG { + public: + 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 + MachineConstantPool *ConstPool; // Target constant pool + std::map Map; // Map nodes to info + + ScheduleDAG(SelectionDAG &dag, MachineBasicBlock *bb, + const TargetMachine &tm) + : DAG(dag), BB(bb), TM(tm) {} + + virtual ~ScheduleDAG() {}; + + /// Run - perform scheduling. + /// + MachineBasicBlock *Run(); + + /// getNI - Returns the node info for the specified node. + /// + NodeInfo *getNI(SDNode *Node) { return Map[Node]; } + + /// getVR - Returns the virtual register number of the node. + /// + unsigned getVR(SDOperand Op) { + NodeInfo *NI = getNI(Op.Val); + assert(NI->VRBase != 0 && "Node emitted out of order - late"); + return NI->VRBase + Op.ResNo; + } + + void EmitNode(NodeInfo *NI); + + virtual void Schedule() {}; + + virtual void print(std::ostream &O) const {}; + + void dump(const char *tag) const; + + void dump() const; + + private: + unsigned CreateVirtualRegisters(MachineInstr *MI, + unsigned NumResults, + const TargetInstrDescriptor &II); + }; + + /// createSimpleDAGScheduler - This creates a simple two pass instruction + /// scheduler. + ScheduleDAG* createSimpleDAGScheduler(SelectionDAG &DAG, + MachineBasicBlock *BB); +} + +#endif diff --git a/include/llvm/CodeGen/SelectionDAGISel.h b/include/llvm/CodeGen/SelectionDAGISel.h index 301ac0e7b8b..5a58297cb25 100644 --- a/include/llvm/CodeGen/SelectionDAGISel.h +++ b/include/llvm/CodeGen/SelectionDAGISel.h @@ -52,7 +52,7 @@ public: protected: /// Pick a safe ordering and emit instructions for each target node in the /// graph. - void ScheduleAndEmitDAG(SelectionDAG &SD); + void ScheduleAndEmitDAG(SelectionDAG &DAG); private: SDOperand CopyValueToVirtualRegister(SelectionDAGLowering &SDL, diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp index 3ad59d77ee4..9c1f1a8d636 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp @@ -1,4 +1,4 @@ -//===-- ScheduleDAG.cpp - Implement a trivial DAG scheduler ---------------===// +//===---- ScheduleDAG.cpp - Implement the ScheduleDAG class ---------------===// // // The LLVM Compiler Infrastructure // @@ -16,1002 +16,21 @@ #define DEBUG_TYPE "sched" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/SelectionDAGISel.h" -#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/ScheduleDAG.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetInstrItineraries.h" #include "llvm/Target/TargetLowering.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include -#include -#include using namespace llvm; -namespace { - // Style of scheduling to use. - enum ScheduleChoices { - noScheduling, - simpleScheduling, - simpleNoItinScheduling - }; -} // namespace - -cl::opt ScheduleStyle("sched", - cl::desc("Choose scheduling style"), - cl::init(noScheduling), - cl::values( - clEnumValN(noScheduling, "none", - "Trivial emission with no analysis"), - clEnumValN(simpleScheduling, "simple", - "Minimize critical path and maximize processor utilization"), - clEnumValN(simpleNoItinScheduling, "simple-noitin", - "Same as simple except using generic latency"), - clEnumValEnd)); - - -#ifndef NDEBUG -static cl::opt -ViewDAGs("view-sched-dags", cl::Hidden, - cl::desc("Pop up a window to show sched dags as they are processed")); -#else -static const bool ViewDAGs = 0; -#endif - -namespace { -//===----------------------------------------------------------------------===// -/// -/// BitsIterator - Provides iteration through individual bits in a bit vector. -/// -template -class BitsIterator { -private: - T Bits; // Bits left to iterate through - -public: - /// Ctor. - BitsIterator(T Initial) : Bits(Initial) {} - - /// Next - Returns the next bit set or zero if exhausted. - inline T Next() { - // Get the rightmost bit set - T Result = Bits & -Bits; - // Remove from rest - Bits &= ~Result; - // Return single bit or zero - return Result; - } -}; - -//===----------------------------------------------------------------------===// - - -//===----------------------------------------------------------------------===// -/// -/// ResourceTally - Manages the use of resources over time intervals. Each -/// item (slot) in the tally vector represents the resources used at a given -/// moment. A bit set to 1 indicates that a resource is in use, otherwise -/// available. An assumption is made that the tally is large enough to schedule -/// all current instructions (asserts otherwise.) -/// -template -class ResourceTally { -private: - std::vector Tally; // Resources used per slot - typedef typename std::vector::iterator Iter; - // Tally iterator - - /// SlotsAvailable - Returns true if all units are available. - /// - bool SlotsAvailable(Iter Begin, unsigned N, unsigned ResourceSet, - unsigned &Resource) { - assert(N && "Must check availability with N != 0"); - // Determine end of interval - Iter End = Begin + N; - assert(End <= Tally.end() && "Tally is not large enough for schedule"); - - // Iterate thru each resource - BitsIterator Resources(ResourceSet & ~*Begin); - while (unsigned Res = Resources.Next()) { - // Check if resource is available for next N slots - Iter Interval = End; - do { - Interval--; - if (*Interval & Res) break; - } while (Interval != Begin); - - // If available for N - if (Interval == Begin) { - // Success - Resource = Res; - return true; - } - } - - // No luck - Resource = 0; - return false; - } - - /// RetrySlot - Finds a good candidate slot to retry search. - Iter RetrySlot(Iter Begin, unsigned N, unsigned ResourceSet) { - assert(N && "Must check availability with N != 0"); - // Determine end of interval - Iter End = Begin + N; - assert(End <= Tally.end() && "Tally is not large enough for schedule"); - - while (Begin != End--) { - // Clear units in use - ResourceSet &= ~*End; - // If no units left then we should go no further - if (!ResourceSet) return End + 1; - } - // Made it all the way through - return Begin; - } - - /// FindAndReserveStages - Return true if the stages can be completed. If - /// so mark as busy. - bool FindAndReserveStages(Iter Begin, - InstrStage *Stage, InstrStage *StageEnd) { - // If at last stage then we're done - if (Stage == StageEnd) return true; - // Get number of cycles for current stage - unsigned N = Stage->Cycles; - // Check to see if N slots are available, if not fail - unsigned Resource; - if (!SlotsAvailable(Begin, N, Stage->Units, Resource)) return false; - // Check to see if remaining stages are available, if not fail - if (!FindAndReserveStages(Begin + N, Stage + 1, StageEnd)) return false; - // Reserve resource - Reserve(Begin, N, Resource); - // Success - return true; - } - - /// Reserve - Mark busy (set) the specified N slots. - void Reserve(Iter Begin, unsigned N, unsigned Resource) { - // Determine end of interval - Iter End = Begin + N; - assert(End <= Tally.end() && "Tally is not large enough for schedule"); - - // Set resource bit in each slot - for (; Begin < End; Begin++) - *Begin |= Resource; - } - - /// FindSlots - Starting from Begin, locate consecutive slots where all stages - /// can be completed. Returns the address of first slot. - Iter FindSlots(Iter Begin, InstrStage *StageBegin, InstrStage *StageEnd) { - // Track position - Iter Cursor = Begin; - - // Try all possible slots forward - while (true) { - // Try at cursor, if successful return position. - if (FindAndReserveStages(Cursor, StageBegin, StageEnd)) return Cursor; - // Locate a better position - Cursor = RetrySlot(Cursor + 1, StageBegin->Cycles, StageBegin->Units); - } - } - -public: - /// Initialize - Resize and zero the tally to the specified number of time - /// slots. - inline void Initialize(unsigned N) { - Tally.assign(N, 0); // Initialize tally to all zeros. - } - - // FindAndReserve - Locate an ideal slot for the specified stages and mark - // as busy. - unsigned FindAndReserve(unsigned Slot, InstrStage *StageBegin, - InstrStage *StageEnd) { - // Where to begin - Iter Begin = Tally.begin() + Slot; - // Find a free slot - Iter Where = FindSlots(Begin, StageBegin, StageEnd); - // Distance is slot number - unsigned Final = Where - Tally.begin(); - return Final; - } - -}; -//===----------------------------------------------------------------------===// - -// Forward -class NodeInfo; -typedef NodeInfo *NodeInfoPtr; -typedef std::vector NIVector; -typedef std::vector::iterator NIIterator; - -//===----------------------------------------------------------------------===// -/// -/// Node group - This struct is used to manage flagged node groups. -/// -class NodeGroup { -private: - NIVector Members; // Group member nodes - NodeInfo *Dominator; // Node with highest latency - unsigned Latency; // Total latency of the group - int Pending; // Number of visits pending before - // adding to order - -public: - // Ctor. - NodeGroup() : Dominator(NULL), Pending(0) {} - - // Accessors - inline void setDominator(NodeInfo *D) { Dominator = D; } - inline NodeInfo *getDominator() { return Dominator; } - inline void setLatency(unsigned L) { Latency = L; } - inline unsigned getLatency() { return Latency; } - inline int getPending() const { return Pending; } - inline void setPending(int P) { Pending = P; } - inline int addPending(int I) { return Pending += I; } - - // Pass thru - inline bool group_empty() { return Members.empty(); } - inline NIIterator group_begin() { return Members.begin(); } - inline NIIterator group_end() { return Members.end(); } - inline void group_push_back(const NodeInfoPtr &NI) { Members.push_back(NI); } - inline NIIterator group_insert(NIIterator Pos, const NodeInfoPtr &NI) { - return Members.insert(Pos, NI); - } - inline void group_insert(NIIterator Pos, NIIterator First, NIIterator Last) { - Members.insert(Pos, First, Last); - } - - static void Add(NodeInfo *D, NodeInfo *U); - static unsigned CountInternalUses(NodeInfo *D, NodeInfo *U); -}; -//===----------------------------------------------------------------------===// - - -//===----------------------------------------------------------------------===// -/// -/// NodeInfo - This struct tracks information used to schedule the a node. -/// -class NodeInfo { -private: - int Pending; // Number of visits pending before - // adding to order -public: - SDNode *Node; // DAG node - InstrStage *StageBegin; // First stage in itinerary - InstrStage *StageEnd; // Last+1 stage in itinerary - unsigned Latency; // Total cycles to complete instruction - bool IsCall : 1; // Is function call - bool IsLoad : 1; // Is memory load - bool IsStore : 1; // Is memory store - unsigned Slot; // Node's time slot - NodeGroup *Group; // Grouping information - unsigned VRBase; // Virtual register base -#ifndef NDEBUG - unsigned Preorder; // Index before scheduling -#endif - - // Ctor. - NodeInfo(SDNode *N = NULL) - : Pending(0) - , Node(N) - , StageBegin(NULL) - , StageEnd(NULL) - , Latency(0) - , IsCall(false) - , Slot(0) - , Group(NULL) - , VRBase(0) -#ifndef NDEBUG - , Preorder(0) -#endif - {} - - // Accessors - inline bool isInGroup() const { - assert(!Group || !Group->group_empty() && "Group with no members"); - return Group != NULL; - } - inline bool isGroupDominator() const { - return isInGroup() && Group->getDominator() == this; - } - inline int getPending() const { - return Group ? Group->getPending() : Pending; - } - inline void setPending(int P) { - if (Group) Group->setPending(P); - else Pending = P; - } - inline int addPending(int I) { - if (Group) return Group->addPending(I); - else return Pending += I; - } -}; -//===----------------------------------------------------------------------===// - - -//===----------------------------------------------------------------------===// -/// -/// NodeGroupIterator - Iterates over all the nodes indicated by the node info. -/// If the node is in a group then iterate over the members of the group, -/// otherwise just the node info. -/// -class NodeGroupIterator { -private: - NodeInfo *NI; // Node info - NIIterator NGI; // Node group iterator - NIIterator NGE; // Node group iterator end - -public: - // Ctor. - NodeGroupIterator(NodeInfo *N) : NI(N) { - // If the node is in a group then set up the group iterator. Otherwise - // the group iterators will trip first time out. - if (N->isInGroup()) { - // get Group - NodeGroup *Group = NI->Group; - NGI = Group->group_begin(); - NGE = Group->group_end(); - // Prevent this node from being used (will be in members list - NI = NULL; - } - } - - /// next - Return the next node info, otherwise NULL. - /// - NodeInfo *next() { - // If members list - if (NGI != NGE) return *NGI++; - // Use node as the result (may be NULL) - NodeInfo *Result = NI; - // Only use once - NI = NULL; - // Return node or NULL - return Result; - } -}; -//===----------------------------------------------------------------------===// - - -//===----------------------------------------------------------------------===// -/// -/// NodeGroupOpIterator - Iterates over all the operands of a node. If the node -/// is a member of a group, this iterates over all the operands of all the -/// members of the group. -/// -class NodeGroupOpIterator { -private: - NodeInfo *NI; // Node containing operands - NodeGroupIterator GI; // Node group iterator - SDNode::op_iterator OI; // Operand iterator - SDNode::op_iterator OE; // Operand iterator end - - /// CheckNode - Test if node has more operands. If not get the next node - /// skipping over nodes that have no operands. - void CheckNode() { - // Only if operands are exhausted first - while (OI == OE) { - // Get next node info - NodeInfo *NI = GI.next(); - // Exit if nodes are exhausted - if (!NI) return; - // Get node itself - SDNode *Node = NI->Node; - // Set up the operand iterators - OI = Node->op_begin(); - OE = Node->op_end(); - } - } - -public: - // Ctor. - NodeGroupOpIterator(NodeInfo *N) - : NI(N), GI(N), OI(SDNode::op_iterator()), OE(SDNode::op_iterator()) {} - - /// isEnd - Returns true when not more operands are available. - /// - inline bool isEnd() { CheckNode(); return OI == OE; } - - /// next - Returns the next available operand. - /// - inline SDOperand next() { - assert(OI != OE && "Not checking for end of NodeGroupOpIterator correctly"); - return *OI++; - } -}; -//===----------------------------------------------------------------------===// - - -//===----------------------------------------------------------------------===// -/// -/// SimpleSched - Simple two pass scheduler. -/// -class SimpleSched { -private: - MachineBasicBlock *BB; // Current basic block - SelectionDAG &DAG; // DAG of the current basic block - const TargetMachine &TM; // Target processor - const TargetInstrInfo &TII; // Target instruction information - const MRegisterInfo &MRI; // Target processor register information - SSARegMap *RegMap; // Virtual/real register map - MachineConstantPool *ConstPool; // Target constant pool - unsigned NodeCount; // Number of nodes in DAG - bool HasGroups; // True if there are any groups - NodeInfo *Info; // Info for nodes being scheduled - std::map Map; // Map nodes to info - NIVector Ordering; // Emit ordering of nodes - ResourceTally Tally; // Resource usage tally - unsigned NSlots; // Total latency - static const unsigned NotFound = ~0U; // Search marker - -public: - - // Ctor. - SimpleSched(SelectionDAG &D, MachineBasicBlock *bb) - : BB(bb), DAG(D), TM(D.getTarget()), TII(*TM.getInstrInfo()), - MRI(*TM.getRegisterInfo()), RegMap(BB->getParent()->getSSARegMap()), - ConstPool(BB->getParent()->getConstantPool()), - NodeCount(0), HasGroups(false), Info(NULL), Map(), Tally(), NSlots(0) { - assert(&TII && "Target doesn't provide instr info?"); - assert(&MRI && "Target doesn't provide register info?"); - } - - // Run - perform scheduling. - MachineBasicBlock *Run() { - Schedule(); - return BB; - } - -private: - /// getNI - Returns the node info for the specified node. - /// - inline NodeInfo *getNI(SDNode *Node) { return Map[Node]; } - - /// getVR - Returns the virtual register number of the node. - /// - inline unsigned getVR(SDOperand Op) { - NodeInfo *NI = getNI(Op.Val); - assert(NI->VRBase != 0 && "Node emitted out of order - late"); - return NI->VRBase + Op.ResNo; - } - - static bool isFlagDefiner(SDNode *A); - static bool isFlagUser(SDNode *A); - static bool isDefiner(NodeInfo *A, NodeInfo *B); - static bool isPassiveNode(SDNode *Node); - void IncludeNode(NodeInfo *NI); - void VisitAll(); - void Schedule(); - void IdentifyGroups(); - void GatherSchedulingInfo(); - void FakeGroupDominators(); - void PrepareNodeInfo(); - bool isStrongDependency(NodeInfo *A, NodeInfo *B); - bool isWeakDependency(NodeInfo *A, NodeInfo *B); - void ScheduleBackward(); - void ScheduleForward(); - void EmitAll(); - void EmitNode(NodeInfo *NI); - static unsigned CountResults(SDNode *Node); - static unsigned CountOperands(SDNode *Node); - unsigned CreateVirtualRegisters(MachineInstr *MI, - unsigned NumResults, - const TargetInstrDescriptor &II); - - void printChanges(unsigned Index); - void printSI(std::ostream &O, NodeInfo *NI) const; - void print(std::ostream &O) const; - inline void dump(const char *tag) const { std::cerr << tag; dump(); } - void dump() const; -}; - - -//===----------------------------------------------------------------------===// -/// Special case itineraries. -/// -enum { - CallLatency = 40, // To push calls back in time - - RSInteger = 0xC0000000, // Two integer units - RSFloat = 0x30000000, // Two float units - RSLoadStore = 0x0C000000, // Two load store units - RSBranch = 0x02000000 // One branch unit -}; -static InstrStage CallStage = { CallLatency, RSBranch }; -static InstrStage LoadStage = { 5, RSLoadStore }; -static InstrStage StoreStage = { 2, RSLoadStore }; -static InstrStage IntStage = { 2, RSInteger }; -static InstrStage FloatStage = { 3, RSFloat }; -//===----------------------------------------------------------------------===// - - -//===----------------------------------------------------------------------===// - -} // namespace - -//===----------------------------------------------------------------------===// - - -//===----------------------------------------------------------------------===// -/// Add - Adds a definer and user pair to a node group. -/// -void NodeGroup::Add(NodeInfo *D, NodeInfo *U) { - // Get current groups - NodeGroup *DGroup = D->Group; - NodeGroup *UGroup = U->Group; - // If both are members of groups - if (DGroup && UGroup) { - // There may have been another edge connecting - if (DGroup == UGroup) return; - // Add the pending users count - DGroup->addPending(UGroup->getPending()); - // For each member of the users group - NodeGroupIterator UNGI(U); - while (NodeInfo *UNI = UNGI.next() ) { - // Change the group - UNI->Group = DGroup; - // For each member of the definers group - NodeGroupIterator DNGI(D); - while (NodeInfo *DNI = DNGI.next() ) { - // Remove internal edges - DGroup->addPending(-CountInternalUses(DNI, UNI)); - } - } - // Merge the two lists - DGroup->group_insert(DGroup->group_end(), - UGroup->group_begin(), UGroup->group_end()); - } else if (DGroup) { - // Make user member of definers group - U->Group = DGroup; - // Add users uses to definers group pending - DGroup->addPending(U->Node->use_size()); - // For each member of the definers group - NodeGroupIterator DNGI(D); - while (NodeInfo *DNI = DNGI.next() ) { - // Remove internal edges - DGroup->addPending(-CountInternalUses(DNI, U)); - } - DGroup->group_push_back(U); - } else if (UGroup) { - // Make definer member of users group - D->Group = UGroup; - // Add definers uses to users group pending - UGroup->addPending(D->Node->use_size()); - // For each member of the users group - NodeGroupIterator UNGI(U); - while (NodeInfo *UNI = UNGI.next() ) { - // Remove internal edges - UGroup->addPending(-CountInternalUses(D, UNI)); - } - UGroup->group_insert(UGroup->group_begin(), D); - } else { - D->Group = U->Group = DGroup = new NodeGroup(); - DGroup->addPending(D->Node->use_size() + U->Node->use_size() - - CountInternalUses(D, U)); - DGroup->group_push_back(D); - DGroup->group_push_back(U); - } -} - -/// CountInternalUses - Returns the number of edges between the two nodes. -/// -unsigned NodeGroup::CountInternalUses(NodeInfo *D, NodeInfo *U) { - unsigned N = 0; - for (unsigned M = U->Node->getNumOperands(); 0 < M--;) { - SDOperand Op = U->Node->getOperand(M); - if (Op.Val == D->Node) N++; - } - - return N; -} -//===----------------------------------------------------------------------===// - - -//===----------------------------------------------------------------------===// -/// isFlagDefiner - Returns true if the node defines a flag result. -bool SimpleSched::isFlagDefiner(SDNode *A) { - unsigned N = A->getNumValues(); - return N && A->getValueType(N - 1) == MVT::Flag; -} - -/// isFlagUser - Returns true if the node uses a flag result. -/// -bool SimpleSched::isFlagUser(SDNode *A) { - unsigned N = A->getNumOperands(); - return N && A->getOperand(N - 1).getValueType() == MVT::Flag; -} - -/// isDefiner - Return true if node A is a definer for B. -/// -bool SimpleSched::isDefiner(NodeInfo *A, NodeInfo *B) { - // While there are A nodes - NodeGroupIterator NII(A); - while (NodeInfo *NI = NII.next()) { - // Extract node - SDNode *Node = NI->Node; - // While there operands in nodes of B - NodeGroupOpIterator NGOI(B); - while (!NGOI.isEnd()) { - SDOperand Op = NGOI.next(); - // If node from A defines a node in B - if (Node == Op.Val) return true; - } - } - return false; -} - -/// isPassiveNode - Return true if the node is a non-scheduled leaf. -/// -bool SimpleSched::isPassiveNode(SDNode *Node) { - if (isa(Node)) return true; - if (isa(Node)) return true; - if (isa(Node)) return true; - if (isa(Node)) return true; - if (isa(Node)) return true; - if (isa(Node)) return true; - if (isa(Node)) return true; - return false; -} - -/// IncludeNode - Add node to NodeInfo vector. -/// -void SimpleSched::IncludeNode(NodeInfo *NI) { - // Get node - SDNode *Node = NI->Node; - // Ignore entry node - if (Node->getOpcode() == ISD::EntryToken) return; - // Check current count for node - int Count = NI->getPending(); - // If the node is already in list - if (Count < 0) return; - // Decrement count to indicate a visit - Count--; - // If count has gone to zero then add node to list - if (!Count) { - // Add node - if (NI->isInGroup()) { - Ordering.push_back(NI->Group->getDominator()); - } else { - Ordering.push_back(NI); - } - // indicate node has been added - Count--; - } - // Mark as visited with new count - NI->setPending(Count); -} - -/// VisitAll - Visit each node breadth-wise to produce an initial ordering. -/// Note that the ordering in the Nodes vector is reversed. -void SimpleSched::VisitAll() { - // Add first element to list - NodeInfo *NI = getNI(DAG.getRoot().Val); - if (NI->isInGroup()) { - Ordering.push_back(NI->Group->getDominator()); - } else { - Ordering.push_back(NI); - } - - // Iterate through all nodes that have been added - for (unsigned i = 0; i < Ordering.size(); i++) { // note: size() varies - // Visit all operands - NodeGroupOpIterator NGI(Ordering[i]); - while (!NGI.isEnd()) { - // Get next operand - SDOperand Op = NGI.next(); - // Get node - SDNode *Node = Op.Val; - // Ignore passive nodes - if (isPassiveNode(Node)) continue; - // Check out node - IncludeNode(getNI(Node)); - } - } - - // Add entry node last (IncludeNode filters entry nodes) - if (DAG.getEntryNode().Val != DAG.getRoot().Val) - Ordering.push_back(getNI(DAG.getEntryNode().Val)); - - // Reverse the order - std::reverse(Ordering.begin(), Ordering.end()); -} - -/// IdentifyGroups - Put flagged nodes into groups. -/// -void SimpleSched::IdentifyGroups() { - for (unsigned i = 0, N = NodeCount; i < N; i++) { - NodeInfo* NI = &Info[i]; - SDNode *Node = NI->Node; - - // For each operand (in reverse to only look at flags) - for (unsigned N = Node->getNumOperands(); 0 < N--;) { - // Get operand - SDOperand Op = Node->getOperand(N); - // No more flags to walk - if (Op.getValueType() != MVT::Flag) break; - // Add to node group - NodeGroup::Add(getNI(Op.Val), NI); - // Let evryone else know - HasGroups = true; - } - } -} - -/// GatherSchedulingInfo - Get latency and resource information about each node. -/// -void SimpleSched::GatherSchedulingInfo() { - // Get instruction itineraries for the target - const InstrItineraryData InstrItins = TM.getInstrItineraryData(); - - // For each node - for (unsigned i = 0, N = NodeCount; i < N; i++) { - // Get node info - NodeInfo* NI = &Info[i]; - SDNode *Node = NI->Node; - - // If there are itineraries and it is a machine instruction - if (InstrItins.isEmpty() || ScheduleStyle == simpleNoItinScheduling) { - // If machine opcode - if (Node->isTargetOpcode()) { - // Get return type to guess which processing unit - MVT::ValueType VT = Node->getValueType(0); - // Get machine opcode - MachineOpCode TOpc = Node->getTargetOpcode(); - NI->IsCall = TII.isCall(TOpc); - NI->IsLoad = TII.isLoad(TOpc); - NI->IsStore = TII.isStore(TOpc); - - if (TII.isLoad(TOpc)) NI->StageBegin = &LoadStage; - else if (TII.isStore(TOpc)) NI->StageBegin = &StoreStage; - else if (MVT::isInteger(VT)) NI->StageBegin = &IntStage; - else if (MVT::isFloatingPoint(VT)) NI->StageBegin = &FloatStage; - if (NI->StageBegin) NI->StageEnd = NI->StageBegin + 1; - } - } else if (Node->isTargetOpcode()) { - // get machine opcode - MachineOpCode TOpc = Node->getTargetOpcode(); - // Check to see if it is a call - NI->IsCall = TII.isCall(TOpc); - // Get itinerary stages for instruction - unsigned II = TII.getSchedClass(TOpc); - NI->StageBegin = InstrItins.begin(II); - NI->StageEnd = InstrItins.end(II); - } - - // One slot for the instruction itself - NI->Latency = 1; - - // Add long latency for a call to push it back in time - if (NI->IsCall) NI->Latency += CallLatency; - - // Sum up all the latencies - for (InstrStage *Stage = NI->StageBegin, *E = NI->StageEnd; - Stage != E; Stage++) { - NI->Latency += Stage->Cycles; - } - - // Sum up all the latencies for max tally size - NSlots += NI->Latency; - } - - // Unify metrics if in a group - if (HasGroups) { - for (unsigned i = 0, N = NodeCount; i < N; i++) { - NodeInfo* NI = &Info[i]; - - if (NI->isInGroup()) { - NodeGroup *Group = NI->Group; - - if (!Group->getDominator()) { - NIIterator NGI = Group->group_begin(), NGE = Group->group_end(); - NodeInfo *Dominator = *NGI; - unsigned Latency = 0; - - for (NGI++; NGI != NGE; NGI++) { - NodeInfo* NGNI = *NGI; - Latency += NGNI->Latency; - if (Dominator->Latency < NGNI->Latency) Dominator = NGNI; - } - - Dominator->Latency = Latency; - Group->setDominator(Dominator); - } - } - } - } -} - -/// FakeGroupDominators - Set dominators for non-scheduling. -/// -void SimpleSched::FakeGroupDominators() { - for (unsigned i = 0, N = NodeCount; i < N; i++) { - NodeInfo* NI = &Info[i]; - - if (NI->isInGroup()) { - NodeGroup *Group = NI->Group; - - if (!Group->getDominator()) { - Group->setDominator(NI); - } - } - } -} - -/// PrepareNodeInfo - Set up the basic minimum node info for scheduling. -/// -void SimpleSched::PrepareNodeInfo() { - // Allocate node information - Info = new NodeInfo[NodeCount]; - - unsigned i = 0; - for (SelectionDAG::allnodes_iterator I = DAG.allnodes_begin(), - E = DAG.allnodes_end(); I != E; ++I, ++i) { - // Fast reference to node schedule info - NodeInfo* NI = &Info[i]; - // Set up map - Map[I] = NI; - // Set node - NI->Node = I; - // Set pending visit count - NI->setPending(I->use_size()); - } -} - -/// isStrongDependency - Return true if node A has results used by node B. -/// I.E., B must wait for latency of A. -bool SimpleSched::isStrongDependency(NodeInfo *A, NodeInfo *B) { - // If A defines for B then it's a strong dependency or - // if a load follows a store (may be dependent but why take a chance.) - return isDefiner(A, B) || (A->IsStore && B->IsLoad); -} - -/// isWeakDependency Return true if node A produces a result that will -/// conflict with operands of B. It is assumed that we have called -/// isStrongDependency prior. -bool SimpleSched::isWeakDependency(NodeInfo *A, NodeInfo *B) { - // TODO check for conflicting real registers and aliases -#if 0 // FIXME - Since we are in SSA form and not checking register aliasing - return A->Node->getOpcode() == ISD::EntryToken || isStrongDependency(B, A); -#else - return A->Node->getOpcode() == ISD::EntryToken; -#endif -} - -/// ScheduleBackward - Schedule instructions so that any long latency -/// instructions and the critical path get pushed back in time. Time is run in -/// reverse to allow code reuse of the Tally and eliminate the overhead of -/// biasing every slot indices against NSlots. -void SimpleSched::ScheduleBackward() { - // Size and clear the resource tally - Tally.Initialize(NSlots); - // Get number of nodes to schedule - unsigned N = Ordering.size(); - - // For each node being scheduled - for (unsigned i = N; 0 < i--;) { - NodeInfo *NI = Ordering[i]; - // Track insertion - unsigned Slot = NotFound; - - // Compare against those previously scheduled nodes - unsigned j = i + 1; - for (; j < N; j++) { - // Get following instruction - NodeInfo *Other = Ordering[j]; - - // Check dependency against previously inserted nodes - if (isStrongDependency(NI, Other)) { - Slot = Other->Slot + Other->Latency; - break; - } else if (isWeakDependency(NI, Other)) { - Slot = Other->Slot; - break; - } - } - - // If independent of others (or first entry) - if (Slot == NotFound) Slot = 0; - -#if 0 // FIXME - measure later - // Find a slot where the needed resources are available - if (NI->StageBegin != NI->StageEnd) - Slot = Tally.FindAndReserve(Slot, NI->StageBegin, NI->StageEnd); -#endif - - // Set node slot - NI->Slot = Slot; - - // Insert sort based on slot - j = i + 1; - for (; j < N; j++) { - // Get following instruction - NodeInfo *Other = Ordering[j]; - // Should we look further (remember slots are in reverse time) - if (Slot >= Other->Slot) break; - // Shuffle other into ordering - Ordering[j - 1] = Other; - } - // Insert node in proper slot - if (j != i + 1) Ordering[j - 1] = NI; - } -} - -/// ScheduleForward - Schedule instructions to maximize packing. -/// -void SimpleSched::ScheduleForward() { - // Size and clear the resource tally - Tally.Initialize(NSlots); - // Get number of nodes to schedule - unsigned N = Ordering.size(); - - // For each node being scheduled - for (unsigned i = 0; i < N; i++) { - NodeInfo *NI = Ordering[i]; - // Track insertion - unsigned Slot = NotFound; - - // Compare against those previously scheduled nodes - unsigned j = i; - for (; 0 < j--;) { - // Get following instruction - NodeInfo *Other = Ordering[j]; - - // Check dependency against previously inserted nodes - if (isStrongDependency(Other, NI)) { - Slot = Other->Slot + Other->Latency; - break; - } else if (Other->IsCall || isWeakDependency(Other, NI)) { - Slot = Other->Slot; - break; - } - } - - // If independent of others (or first entry) - if (Slot == NotFound) Slot = 0; - - // Find a slot where the needed resources are available - if (NI->StageBegin != NI->StageEnd) - Slot = Tally.FindAndReserve(Slot, NI->StageBegin, NI->StageEnd); - - // Set node slot - NI->Slot = Slot; - - // Insert sort based on slot - j = i; - for (; 0 < j--;) { - // Get prior instruction - NodeInfo *Other = Ordering[j]; - // Should we look further - if (Slot >= Other->Slot) break; - // Shuffle other into ordering - Ordering[j + 1] = Other; - } - // Insert node in proper slot - if (j != i) Ordering[j + 1] = NI; - } -} - -/// EmitAll - Emit all nodes in schedule sorted order. -/// -void SimpleSched::EmitAll() { - // For each node in the ordering - for (unsigned i = 0, N = Ordering.size(); i < N; i++) { - // Get the scheduling info - NodeInfo *NI = Ordering[i]; - if (NI->isInGroup()) { - NodeGroupIterator NGI(Ordering[i]); - while (NodeInfo *NI = NGI.next()) EmitNode(NI); - } else { - EmitNode(NI); - } - } -} /// 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.) -unsigned SimpleSched::CountResults(SDNode *Node) { +static unsigned CountResults(SDNode *Node) { unsigned N = Node->getNumValues(); while (N && Node->getValueType(N - 1) == MVT::Flag) --N; @@ -1023,7 +42,7 @@ unsigned SimpleSched::CountResults(SDNode *Node) { /// CountOperands The inputs to target nodes have any actual inputs first, /// followed by an optional chain operand, then flag operands. Compute the /// number of actual operands that will go into the machine instr. -unsigned SimpleSched::CountOperands(SDNode *Node) { +static unsigned CountOperands(SDNode *Node) { unsigned N = Node->getNumOperands(); while (N && Node->getOperand(N - 1).getValueType() == MVT::Flag) --N; @@ -1034,7 +53,7 @@ unsigned SimpleSched::CountOperands(SDNode *Node) { /// CreateVirtualRegisters - Add result register values for things that are /// defined by this instruction. -unsigned SimpleSched::CreateVirtualRegisters(MachineInstr *MI, +unsigned ScheduleDAG::CreateVirtualRegisters(MachineInstr *MI, unsigned NumResults, const TargetInstrDescriptor &II) { // Create the result registers for this node and add the result regs to @@ -1052,14 +71,14 @@ unsigned SimpleSched::CreateVirtualRegisters(MachineInstr *MI, /// EmitNode - Generate machine code for an node and needed dependencies. /// -void SimpleSched::EmitNode(NodeInfo *NI) { +void ScheduleDAG::EmitNode(NodeInfo *NI) { unsigned VRBase = 0; // First virtual register for node SDNode *Node = NI->Node; // If machine instruction if (Node->isTargetOpcode()) { unsigned Opc = Node->getTargetOpcode(); - const TargetInstrDescriptor &II = TII.get(Opc); + const TargetInstrDescriptor &II = TII->get(Opc); unsigned NumResults = CountResults(Node); unsigned NodeOperands = CountOperands(Node); @@ -1176,8 +195,8 @@ void SimpleSched::EmitNode(NodeInfo *NI) { unsigned InReg = getVR(Node->getOperand(2)); unsigned DestReg = cast(Node->getOperand(1))->getReg(); if (InReg != DestReg) // Coallesced away the copy? - MRI.copyRegToReg(*BB, BB->end(), DestReg, InReg, - RegMap->getRegClass(InReg)); + MRI->copyRegToReg(*BB, BB->end(), DestReg, InReg, + RegMap->getRegClass(InReg)); break; } case ISD::CopyFromReg: { @@ -1209,8 +228,8 @@ void SimpleSched::EmitNode(NodeInfo *NI) { } else { // Pick the register class of the right type that contains this physreg. - for (MRegisterInfo::regclass_iterator I = MRI.regclass_begin(), - E = MRI.regclass_end(); I != E; ++I) + for (MRegisterInfo::regclass_iterator I = MRI->regclass_begin(), + E = MRI->regclass_end(); I != E; ++I) if ((*I)->hasType(Node->getValueType(0)) && (*I)->contains(SrcReg)) { TRC = *I; @@ -1221,7 +240,7 @@ void SimpleSched::EmitNode(NodeInfo *NI) { // Create the reg, emit the copy. VRBase = RegMap->createVirtualRegister(TRC); } - MRI.copyRegToReg(*BB, BB->end(), VRBase, SrcReg, TRC); + MRI->copyRegToReg(*BB, BB->end(), VRBase, SrcReg, TRC); break; } } @@ -1231,143 +250,21 @@ void SimpleSched::EmitNode(NodeInfo *NI) { NI->VRBase = VRBase; } -/// Schedule - Order nodes according to selected style. -/// -void SimpleSched::Schedule() { - // Number the nodes - NodeCount = std::distance(DAG.allnodes_begin(), DAG.allnodes_end()); - // Test to see if scheduling should occur - bool ShouldSchedule = NodeCount > 3 && ScheduleStyle != noScheduling; - // Set up minimum info for scheduling - PrepareNodeInfo(); - // Construct node groups for flagged nodes - IdentifyGroups(); - - // Don't waste time if is only entry and return - if (ShouldSchedule) { - // Get latency and resource requirements - GatherSchedulingInfo(); - } else if (HasGroups) { - // Make sure all the groups have dominators - FakeGroupDominators(); - } - - // Breadth first walk of DAG - VisitAll(); - -#ifndef NDEBUG - static unsigned Count = 0; - Count++; - for (unsigned i = 0, N = Ordering.size(); i < N; i++) { - NodeInfo *NI = Ordering[i]; - NI->Preorder = i; - } -#endif - - // Don't waste time if is only entry and return - if (ShouldSchedule) { - // Push back long instructions and critical path - ScheduleBackward(); - - // Pack instructions to maximize resource utilization - ScheduleForward(); - } - - DEBUG(printChanges(Count)); - - // Emit in scheduled order - EmitAll(); -} - -/// printChanges - Hilight changes in order caused by scheduling. -/// -void SimpleSched::printChanges(unsigned Index) { -#ifndef NDEBUG - // Get the ordered node count - unsigned N = Ordering.size(); - // Determine if any changes - unsigned i = 0; - for (; i < N; i++) { - NodeInfo *NI = Ordering[i]; - if (NI->Preorder != i) break; - } - - if (i < N) { - std::cerr << Index << ". New Ordering\n"; - - for (i = 0; i < N; i++) { - NodeInfo *NI = Ordering[i]; - std::cerr << " " << NI->Preorder << ". "; - printSI(std::cerr, NI); - std::cerr << "\n"; - if (NI->isGroupDominator()) { - NodeGroup *Group = NI->Group; - for (NIIterator NII = Group->group_begin(), E = Group->group_end(); - NII != E; NII++) { - std::cerr << " "; - printSI(std::cerr, *NII); - std::cerr << "\n"; - } - } - } - } else { - std::cerr << Index << ". No Changes\n"; - } -#endif -} - -/// printSI - Print schedule info. -/// -void SimpleSched::printSI(std::ostream &O, NodeInfo *NI) const { -#ifndef NDEBUG - SDNode *Node = NI->Node; - O << " " - << std::hex << Node << std::dec - << ", Lat=" << NI->Latency - << ", Slot=" << NI->Slot - << ", ARITY=(" << Node->getNumOperands() << "," - << Node->getNumValues() << ")" - << " " << Node->getOperationName(&DAG); - if (isFlagDefiner(Node)) O << "<#"; - if (isFlagUser(Node)) O << ">#"; -#endif -} - -/// print - Print ordering to specified output stream. -/// -void SimpleSched::print(std::ostream &O) const { -#ifndef NDEBUG - using namespace std; - O << "Ordering\n"; - for (unsigned i = 0, N = Ordering.size(); i < N; i++) { - NodeInfo *NI = Ordering[i]; - printSI(O, NI); - O << "\n"; - if (NI->isGroupDominator()) { - NodeGroup *Group = NI->Group; - for (NIIterator NII = Group->group_begin(), E = Group->group_end(); - NII != E; NII++) { - O << " "; - printSI(O, *NII); - O << "\n"; - } - } - } -#endif +void ScheduleDAG::dump(const char *tag) const { + std::cerr << tag; dump(); } -/// dump - Print ordering to std::cerr. -/// -void SimpleSched::dump() const { +void ScheduleDAG::dump() const { print(std::cerr); } -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -/// ScheduleAndEmitDAG - Pick a safe ordering and emit instructions for each -/// target node in the graph. -void SelectionDAGISel::ScheduleAndEmitDAG(SelectionDAG &SD) { - if (ViewDAGs) SD.viewGraph(); - BB = SimpleSched(SD, BB).Run(); +/// Run - perform scheduling. +/// +MachineBasicBlock *ScheduleDAG::Run() { + TII = TM.getInstrInfo(); + MRI = TM.getRegisterInfo(); + RegMap = BB->getParent()->getSSARegMap(); + ConstPool = BB->getParent()->getConstantPool(); + Schedule(); + return BB; } diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGSimple.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGSimple.cpp new file mode 100644 index 00000000000..b22eae499a9 --- /dev/null +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGSimple.cpp @@ -0,0 +1,891 @@ +//===-- ScheduleDAGSimple.cpp - Implement a trivial DAG scheduler ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by James M. Laskey and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements a simple two pass scheduler. The first pass attempts to push +// backward any lengthy instructions and critical paths. The second pass packs +// instructions into semi-optimal time slots. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sched" +#include "llvm/CodeGen/ScheduleDAG.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include +#include +#include +using namespace llvm; + +namespace { + // Style of scheduling to use. + enum ScheduleChoices { + noScheduling, + simpleScheduling, + simpleNoItinScheduling + }; +} // namespace + +cl::opt ScheduleStyle("sched", + cl::desc("Choose scheduling style"), + cl::init(noScheduling), + cl::values( + clEnumValN(noScheduling, "none", + "Trivial emission with no analysis"), + clEnumValN(simpleScheduling, "simple", + "Minimize critical path and maximize processor utilization"), + clEnumValN(simpleNoItinScheduling, "simple-noitin", + "Same as simple except using generic latency"), + clEnumValEnd)); + + +namespace { +//===----------------------------------------------------------------------===// +/// +/// BitsIterator - Provides iteration through individual bits in a bit vector. +/// +template +class BitsIterator { +private: + T Bits; // Bits left to iterate through + +public: + /// Ctor. + BitsIterator(T Initial) : Bits(Initial) {} + + /// Next - Returns the next bit set or zero if exhausted. + inline T Next() { + // Get the rightmost bit set + T Result = Bits & -Bits; + // Remove from rest + Bits &= ~Result; + // Return single bit or zero + return Result; + } +}; + +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +/// +/// ResourceTally - Manages the use of resources over time intervals. Each +/// item (slot) in the tally vector represents the resources used at a given +/// moment. A bit set to 1 indicates that a resource is in use, otherwise +/// available. An assumption is made that the tally is large enough to schedule +/// all current instructions (asserts otherwise.) +/// +template +class ResourceTally { +private: + std::vector Tally; // Resources used per slot + typedef typename std::vector::iterator Iter; + // Tally iterator + + /// SlotsAvailable - Returns true if all units are available. + /// + bool SlotsAvailable(Iter Begin, unsigned N, unsigned ResourceSet, + unsigned &Resource) { + assert(N && "Must check availability with N != 0"); + // Determine end of interval + Iter End = Begin + N; + assert(End <= Tally.end() && "Tally is not large enough for schedule"); + + // Iterate thru each resource + BitsIterator Resources(ResourceSet & ~*Begin); + while (unsigned Res = Resources.Next()) { + // Check if resource is available for next N slots + Iter Interval = End; + do { + Interval--; + if (*Interval & Res) break; + } while (Interval != Begin); + + // If available for N + if (Interval == Begin) { + // Success + Resource = Res; + return true; + } + } + + // No luck + Resource = 0; + return false; + } + + /// RetrySlot - Finds a good candidate slot to retry search. + Iter RetrySlot(Iter Begin, unsigned N, unsigned ResourceSet) { + assert(N && "Must check availability with N != 0"); + // Determine end of interval + Iter End = Begin + N; + assert(End <= Tally.end() && "Tally is not large enough for schedule"); + + while (Begin != End--) { + // Clear units in use + ResourceSet &= ~*End; + // If no units left then we should go no further + if (!ResourceSet) return End + 1; + } + // Made it all the way through + return Begin; + } + + /// FindAndReserveStages - Return true if the stages can be completed. If + /// so mark as busy. + bool FindAndReserveStages(Iter Begin, + InstrStage *Stage, InstrStage *StageEnd) { + // If at last stage then we're done + if (Stage == StageEnd) return true; + // Get number of cycles for current stage + unsigned N = Stage->Cycles; + // Check to see if N slots are available, if not fail + unsigned Resource; + if (!SlotsAvailable(Begin, N, Stage->Units, Resource)) return false; + // Check to see if remaining stages are available, if not fail + if (!FindAndReserveStages(Begin + N, Stage + 1, StageEnd)) return false; + // Reserve resource + Reserve(Begin, N, Resource); + // Success + return true; + } + + /// Reserve - Mark busy (set) the specified N slots. + void Reserve(Iter Begin, unsigned N, unsigned Resource) { + // Determine end of interval + Iter End = Begin + N; + assert(End <= Tally.end() && "Tally is not large enough for schedule"); + + // Set resource bit in each slot + for (; Begin < End; Begin++) + *Begin |= Resource; + } + + /// FindSlots - Starting from Begin, locate consecutive slots where all stages + /// can be completed. Returns the address of first slot. + Iter FindSlots(Iter Begin, InstrStage *StageBegin, InstrStage *StageEnd) { + // Track position + Iter Cursor = Begin; + + // Try all possible slots forward + while (true) { + // Try at cursor, if successful return position. + if (FindAndReserveStages(Cursor, StageBegin, StageEnd)) return Cursor; + // Locate a better position + Cursor = RetrySlot(Cursor + 1, StageBegin->Cycles, StageBegin->Units); + } + } + +public: + /// Initialize - Resize and zero the tally to the specified number of time + /// slots. + inline void Initialize(unsigned N) { + Tally.assign(N, 0); // Initialize tally to all zeros. + } + + // FindAndReserve - Locate an ideal slot for the specified stages and mark + // as busy. + unsigned FindAndReserve(unsigned Slot, InstrStage *StageBegin, + InstrStage *StageEnd) { + // Where to begin + Iter Begin = Tally.begin() + Slot; + // Find a free slot + Iter Where = FindSlots(Begin, StageBegin, StageEnd); + // Distance is slot number + unsigned Final = Where - Tally.begin(); + return Final; + } + +}; + +//===----------------------------------------------------------------------===// +/// +/// ScheduleDAGSimple - Simple two pass scheduler. +/// +class ScheduleDAGSimple : public ScheduleDAG { +private: + unsigned NodeCount; // Number of nodes in DAG + bool HasGroups; // True if there are any groups + NodeInfo *Info; // Info for nodes being scheduled + NIVector Ordering; // Emit ordering of nodes + ResourceTally Tally; // Resource usage tally + unsigned NSlots; // Total latency + static const unsigned NotFound = ~0U; // Search marker + +public: + + // Ctor. + ScheduleDAGSimple(SelectionDAG &dag, MachineBasicBlock *bb, + const TargetMachine &tm) + : ScheduleDAG(dag, bb, tm), + NodeCount(0), HasGroups(false), Info(NULL), Tally(), NSlots(0) { + assert(&TII && "Target doesn't provide instr info?"); + assert(&MRI && "Target doesn't provide register info?"); + } + + virtual ~ScheduleDAGSimple() {}; + +private: + static bool isFlagDefiner(SDNode *A); + static bool isFlagUser(SDNode *A); + static bool isDefiner(NodeInfo *A, NodeInfo *B); + static bool isPassiveNode(SDNode *Node); + void IncludeNode(NodeInfo *NI); + void VisitAll(); + void Schedule(); + void IdentifyGroups(); + void GatherSchedulingInfo(); + void FakeGroupDominators(); + void PrepareNodeInfo(); + bool isStrongDependency(NodeInfo *A, NodeInfo *B); + bool isWeakDependency(NodeInfo *A, NodeInfo *B); + void ScheduleBackward(); + void ScheduleForward(); + void EmitAll(); + + void printChanges(unsigned Index); + void printSI(std::ostream &O, NodeInfo *NI) const; + void print(std::ostream &O) const; +}; + + +//===----------------------------------------------------------------------===// +/// Special case itineraries. +/// +enum { + CallLatency = 40, // To push calls back in time + + RSInteger = 0xC0000000, // Two integer units + RSFloat = 0x30000000, // Two float units + RSLoadStore = 0x0C000000, // Two load store units + RSBranch = 0x02000000 // One branch unit +}; +static InstrStage CallStage = { CallLatency, RSBranch }; +static InstrStage LoadStage = { 5, RSLoadStore }; +static InstrStage StoreStage = { 2, RSLoadStore }; +static InstrStage IntStage = { 2, RSInteger }; +static InstrStage FloatStage = { 3, RSFloat }; +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// + +} // namespace + +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +/// Add - Adds a definer and user pair to a node group. +/// +void NodeGroup::Add(NodeInfo *D, NodeInfo *U) { + // Get current groups + NodeGroup *DGroup = D->Group; + NodeGroup *UGroup = U->Group; + // If both are members of groups + if (DGroup && UGroup) { + // There may have been another edge connecting + if (DGroup == UGroup) return; + // Add the pending users count + DGroup->addPending(UGroup->getPending()); + // For each member of the users group + NodeGroupIterator UNGI(U); + while (NodeInfo *UNI = UNGI.next() ) { + // Change the group + UNI->Group = DGroup; + // For each member of the definers group + NodeGroupIterator DNGI(D); + while (NodeInfo *DNI = DNGI.next() ) { + // Remove internal edges + DGroup->addPending(-CountInternalUses(DNI, UNI)); + } + } + // Merge the two lists + DGroup->group_insert(DGroup->group_end(), + UGroup->group_begin(), UGroup->group_end()); + } else if (DGroup) { + // Make user member of definers group + U->Group = DGroup; + // Add users uses to definers group pending + DGroup->addPending(U->Node->use_size()); + // For each member of the definers group + NodeGroupIterator DNGI(D); + while (NodeInfo *DNI = DNGI.next() ) { + // Remove internal edges + DGroup->addPending(-CountInternalUses(DNI, U)); + } + DGroup->group_push_back(U); + } else if (UGroup) { + // Make definer member of users group + D->Group = UGroup; + // Add definers uses to users group pending + UGroup->addPending(D->Node->use_size()); + // For each member of the users group + NodeGroupIterator UNGI(U); + while (NodeInfo *UNI = UNGI.next() ) { + // Remove internal edges + UGroup->addPending(-CountInternalUses(D, UNI)); + } + UGroup->group_insert(UGroup->group_begin(), D); + } else { + D->Group = U->Group = DGroup = new NodeGroup(); + DGroup->addPending(D->Node->use_size() + U->Node->use_size() - + CountInternalUses(D, U)); + DGroup->group_push_back(D); + DGroup->group_push_back(U); + } +} + +/// CountInternalUses - Returns the number of edges between the two nodes. +/// +unsigned NodeGroup::CountInternalUses(NodeInfo *D, NodeInfo *U) { + unsigned N = 0; + for (unsigned M = U->Node->getNumOperands(); 0 < M--;) { + SDOperand Op = U->Node->getOperand(M); + if (Op.Val == D->Node) N++; + } + + return N; +} +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +/// isFlagDefiner - Returns true if the node defines a flag result. +bool ScheduleDAGSimple::isFlagDefiner(SDNode *A) { + unsigned N = A->getNumValues(); + return N && A->getValueType(N - 1) == MVT::Flag; +} + +/// isFlagUser - Returns true if the node uses a flag result. +/// +bool ScheduleDAGSimple::isFlagUser(SDNode *A) { + unsigned N = A->getNumOperands(); + return N && A->getOperand(N - 1).getValueType() == MVT::Flag; +} + +/// isDefiner - Return true if node A is a definer for B. +/// +bool ScheduleDAGSimple::isDefiner(NodeInfo *A, NodeInfo *B) { + // While there are A nodes + NodeGroupIterator NII(A); + while (NodeInfo *NI = NII.next()) { + // Extract node + SDNode *Node = NI->Node; + // While there operands in nodes of B + NodeGroupOpIterator NGOI(B); + while (!NGOI.isEnd()) { + SDOperand Op = NGOI.next(); + // If node from A defines a node in B + if (Node == Op.Val) return true; + } + } + return false; +} + +/// isPassiveNode - Return true if the node is a non-scheduled leaf. +/// +bool ScheduleDAGSimple::isPassiveNode(SDNode *Node) { + if (isa(Node)) return true; + if (isa(Node)) return true; + if (isa(Node)) return true; + if (isa(Node)) return true; + if (isa(Node)) return true; + if (isa(Node)) return true; + if (isa(Node)) return true; + return false; +} + +/// IncludeNode - Add node to NodeInfo vector. +/// +void ScheduleDAGSimple::IncludeNode(NodeInfo *NI) { + // Get node + SDNode *Node = NI->Node; + // Ignore entry node + if (Node->getOpcode() == ISD::EntryToken) return; + // Check current count for node + int Count = NI->getPending(); + // If the node is already in list + if (Count < 0) return; + // Decrement count to indicate a visit + Count--; + // If count has gone to zero then add node to list + if (!Count) { + // Add node + if (NI->isInGroup()) { + Ordering.push_back(NI->Group->getDominator()); + } else { + Ordering.push_back(NI); + } + // indicate node has been added + Count--; + } + // Mark as visited with new count + NI->setPending(Count); +} + +/// VisitAll - Visit each node breadth-wise to produce an initial ordering. +/// Note that the ordering in the Nodes vector is reversed. +void ScheduleDAGSimple::VisitAll() { + // Add first element to list + NodeInfo *NI = getNI(DAG.getRoot().Val); + if (NI->isInGroup()) { + Ordering.push_back(NI->Group->getDominator()); + } else { + Ordering.push_back(NI); + } + + // Iterate through all nodes that have been added + for (unsigned i = 0; i < Ordering.size(); i++) { // note: size() varies + // Visit all operands + NodeGroupOpIterator NGI(Ordering[i]); + while (!NGI.isEnd()) { + // Get next operand + SDOperand Op = NGI.next(); + // Get node + SDNode *Node = Op.Val; + // Ignore passive nodes + if (isPassiveNode(Node)) continue; + // Check out node + IncludeNode(getNI(Node)); + } + } + + // Add entry node last (IncludeNode filters entry nodes) + if (DAG.getEntryNode().Val != DAG.getRoot().Val) + Ordering.push_back(getNI(DAG.getEntryNode().Val)); + + // Reverse the order + std::reverse(Ordering.begin(), Ordering.end()); +} + +/// IdentifyGroups - Put flagged nodes into groups. +/// +void ScheduleDAGSimple::IdentifyGroups() { + for (unsigned i = 0, N = NodeCount; i < N; i++) { + NodeInfo* NI = &Info[i]; + SDNode *Node = NI->Node; + + // For each operand (in reverse to only look at flags) + for (unsigned N = Node->getNumOperands(); 0 < N--;) { + // Get operand + SDOperand Op = Node->getOperand(N); + // No more flags to walk + if (Op.getValueType() != MVT::Flag) break; + // Add to node group + NodeGroup::Add(getNI(Op.Val), NI); + // Let evryone else know + HasGroups = true; + } + } +} + +/// GatherSchedulingInfo - Get latency and resource information about each node. +/// +void ScheduleDAGSimple::GatherSchedulingInfo() { + // Get instruction itineraries for the target + const InstrItineraryData InstrItins = TM.getInstrItineraryData(); + + // For each node + for (unsigned i = 0, N = NodeCount; i < N; i++) { + // Get node info + NodeInfo* NI = &Info[i]; + SDNode *Node = NI->Node; + + // If there are itineraries and it is a machine instruction + if (InstrItins.isEmpty() || ScheduleStyle == simpleNoItinScheduling) { + // If machine opcode + if (Node->isTargetOpcode()) { + // Get return type to guess which processing unit + MVT::ValueType VT = Node->getValueType(0); + // Get machine opcode + MachineOpCode TOpc = Node->getTargetOpcode(); + NI->IsCall = TII->isCall(TOpc); + NI->IsLoad = TII->isLoad(TOpc); + NI->IsStore = TII->isStore(TOpc); + + if (TII->isLoad(TOpc)) NI->StageBegin = &LoadStage; + else if (TII->isStore(TOpc)) NI->StageBegin = &StoreStage; + else if (MVT::isInteger(VT)) NI->StageBegin = &IntStage; + else if (MVT::isFloatingPoint(VT)) NI->StageBegin = &FloatStage; + if (NI->StageBegin) NI->StageEnd = NI->StageBegin + 1; + } + } else if (Node->isTargetOpcode()) { + // get machine opcode + MachineOpCode TOpc = Node->getTargetOpcode(); + // Check to see if it is a call + NI->IsCall = TII->isCall(TOpc); + // Get itinerary stages for instruction + unsigned II = TII->getSchedClass(TOpc); + NI->StageBegin = InstrItins.begin(II); + NI->StageEnd = InstrItins.end(II); + } + + // One slot for the instruction itself + NI->Latency = 1; + + // Add long latency for a call to push it back in time + if (NI->IsCall) NI->Latency += CallLatency; + + // Sum up all the latencies + for (InstrStage *Stage = NI->StageBegin, *E = NI->StageEnd; + Stage != E; Stage++) { + NI->Latency += Stage->Cycles; + } + + // Sum up all the latencies for max tally size + NSlots += NI->Latency; + } + + // Unify metrics if in a group + if (HasGroups) { + for (unsigned i = 0, N = NodeCount; i < N; i++) { + NodeInfo* NI = &Info[i]; + + if (NI->isInGroup()) { + NodeGroup *Group = NI->Group; + + if (!Group->getDominator()) { + NIIterator NGI = Group->group_begin(), NGE = Group->group_end(); + NodeInfo *Dominator = *NGI; + unsigned Latency = 0; + + for (NGI++; NGI != NGE; NGI++) { + NodeInfo* NGNI = *NGI; + Latency += NGNI->Latency; + if (Dominator->Latency < NGNI->Latency) Dominator = NGNI; + } + + Dominator->Latency = Latency; + Group->setDominator(Dominator); + } + } + } + } +} + +/// FakeGroupDominators - Set dominators for non-scheduling. +/// +void ScheduleDAGSimple::FakeGroupDominators() { + for (unsigned i = 0, N = NodeCount; i < N; i++) { + NodeInfo* NI = &Info[i]; + + if (NI->isInGroup()) { + NodeGroup *Group = NI->Group; + + if (!Group->getDominator()) { + Group->setDominator(NI); + } + } + } +} + +/// PrepareNodeInfo - Set up the basic minimum node info for scheduling. +/// +void ScheduleDAGSimple::PrepareNodeInfo() { + // Allocate node information + Info = new NodeInfo[NodeCount]; + + unsigned i = 0; + for (SelectionDAG::allnodes_iterator I = DAG.allnodes_begin(), + E = DAG.allnodes_end(); I != E; ++I, ++i) { + // Fast reference to node schedule info + NodeInfo* NI = &Info[i]; + // Set up map + Map[I] = NI; + // Set node + NI->Node = I; + // Set pending visit count + NI->setPending(I->use_size()); + } +} + +/// isStrongDependency - Return true if node A has results used by node B. +/// I.E., B must wait for latency of A. +bool ScheduleDAGSimple::isStrongDependency(NodeInfo *A, NodeInfo *B) { + // If A defines for B then it's a strong dependency or + // if a load follows a store (may be dependent but why take a chance.) + return isDefiner(A, B) || (A->IsStore && B->IsLoad); +} + +/// isWeakDependency Return true if node A produces a result that will +/// conflict with operands of B. It is assumed that we have called +/// isStrongDependency prior. +bool ScheduleDAGSimple::isWeakDependency(NodeInfo *A, NodeInfo *B) { + // TODO check for conflicting real registers and aliases +#if 0 // FIXME - Since we are in SSA form and not checking register aliasing + return A->Node->getOpcode() == ISD::EntryToken || isStrongDependency(B, A); +#else + return A->Node->getOpcode() == ISD::EntryToken; +#endif +} + +/// ScheduleBackward - Schedule instructions so that any long latency +/// instructions and the critical path get pushed back in time. Time is run in +/// reverse to allow code reuse of the Tally and eliminate the overhead of +/// biasing every slot indices against NSlots. +void ScheduleDAGSimple::ScheduleBackward() { + // Size and clear the resource tally + Tally.Initialize(NSlots); + // Get number of nodes to schedule + unsigned N = Ordering.size(); + + // For each node being scheduled + for (unsigned i = N; 0 < i--;) { + NodeInfo *NI = Ordering[i]; + // Track insertion + unsigned Slot = NotFound; + + // Compare against those previously scheduled nodes + unsigned j = i + 1; + for (; j < N; j++) { + // Get following instruction + NodeInfo *Other = Ordering[j]; + + // Check dependency against previously inserted nodes + if (isStrongDependency(NI, Other)) { + Slot = Other->Slot + Other->Latency; + break; + } else if (isWeakDependency(NI, Other)) { + Slot = Other->Slot; + break; + } + } + + // If independent of others (or first entry) + if (Slot == NotFound) Slot = 0; + +#if 0 // FIXME - measure later + // Find a slot where the needed resources are available + if (NI->StageBegin != NI->StageEnd) + Slot = Tally.FindAndReserve(Slot, NI->StageBegin, NI->StageEnd); +#endif + + // Set node slot + NI->Slot = Slot; + + // Insert sort based on slot + j = i + 1; + for (; j < N; j++) { + // Get following instruction + NodeInfo *Other = Ordering[j]; + // Should we look further (remember slots are in reverse time) + if (Slot >= Other->Slot) break; + // Shuffle other into ordering + Ordering[j - 1] = Other; + } + // Insert node in proper slot + if (j != i + 1) Ordering[j - 1] = NI; + } +} + +/// ScheduleForward - Schedule instructions to maximize packing. +/// +void ScheduleDAGSimple::ScheduleForward() { + // Size and clear the resource tally + Tally.Initialize(NSlots); + // Get number of nodes to schedule + unsigned N = Ordering.size(); + + // For each node being scheduled + for (unsigned i = 0; i < N; i++) { + NodeInfo *NI = Ordering[i]; + // Track insertion + unsigned Slot = NotFound; + + // Compare against those previously scheduled nodes + unsigned j = i; + for (; 0 < j--;) { + // Get following instruction + NodeInfo *Other = Ordering[j]; + + // Check dependency against previously inserted nodes + if (isStrongDependency(Other, NI)) { + Slot = Other->Slot + Other->Latency; + break; + } else if (Other->IsCall || isWeakDependency(Other, NI)) { + Slot = Other->Slot; + break; + } + } + + // If independent of others (or first entry) + if (Slot == NotFound) Slot = 0; + + // Find a slot where the needed resources are available + if (NI->StageBegin != NI->StageEnd) + Slot = Tally.FindAndReserve(Slot, NI->StageBegin, NI->StageEnd); + + // Set node slot + NI->Slot = Slot; + + // Insert sort based on slot + j = i; + for (; 0 < j--;) { + // Get prior instruction + NodeInfo *Other = Ordering[j]; + // Should we look further + if (Slot >= Other->Slot) break; + // Shuffle other into ordering + Ordering[j + 1] = Other; + } + // Insert node in proper slot + if (j != i) Ordering[j + 1] = NI; + } +} + +/// EmitAll - Emit all nodes in schedule sorted order. +/// +void ScheduleDAGSimple::EmitAll() { + // For each node in the ordering + for (unsigned i = 0, N = Ordering.size(); i < N; i++) { + // Get the scheduling info + NodeInfo *NI = Ordering[i]; + if (NI->isInGroup()) { + NodeGroupIterator NGI(Ordering[i]); + while (NodeInfo *NI = NGI.next()) EmitNode(NI); + } else { + EmitNode(NI); + } + } +} + +/// Schedule - Order nodes according to selected style. +/// +void ScheduleDAGSimple::Schedule() { + // Number the nodes + NodeCount = std::distance(DAG.allnodes_begin(), DAG.allnodes_end()); + // Test to see if scheduling should occur + bool ShouldSchedule = NodeCount > 3 && ScheduleStyle != noScheduling; + // Set up minimum info for scheduling + PrepareNodeInfo(); + // Construct node groups for flagged nodes + IdentifyGroups(); + + // Don't waste time if is only entry and return + if (ShouldSchedule) { + // Get latency and resource requirements + GatherSchedulingInfo(); + } else if (HasGroups) { + // Make sure all the groups have dominators + FakeGroupDominators(); + } + + // Breadth first walk of DAG + VisitAll(); + +#ifndef NDEBUG + static unsigned Count = 0; + Count++; + for (unsigned i = 0, N = Ordering.size(); i < N; i++) { + NodeInfo *NI = Ordering[i]; + NI->Preorder = i; + } +#endif + + // Don't waste time if is only entry and return + if (ShouldSchedule) { + // Push back long instructions and critical path + ScheduleBackward(); + + // Pack instructions to maximize resource utilization + ScheduleForward(); + } + + DEBUG(printChanges(Count)); + + // Emit in scheduled order + EmitAll(); +} + +/// printChanges - Hilight changes in order caused by scheduling. +/// +void ScheduleDAGSimple::printChanges(unsigned Index) { +#ifndef NDEBUG + // Get the ordered node count + unsigned N = Ordering.size(); + // Determine if any changes + unsigned i = 0; + for (; i < N; i++) { + NodeInfo *NI = Ordering[i]; + if (NI->Preorder != i) break; + } + + if (i < N) { + std::cerr << Index << ". New Ordering\n"; + + for (i = 0; i < N; i++) { + NodeInfo *NI = Ordering[i]; + std::cerr << " " << NI->Preorder << ". "; + printSI(std::cerr, NI); + std::cerr << "\n"; + if (NI->isGroupDominator()) { + NodeGroup *Group = NI->Group; + for (NIIterator NII = Group->group_begin(), E = Group->group_end(); + NII != E; NII++) { + std::cerr << " "; + printSI(std::cerr, *NII); + std::cerr << "\n"; + } + } + } + } else { + std::cerr << Index << ". No Changes\n"; + } +#endif +} + +/// printSI - Print schedule info. +/// +void ScheduleDAGSimple::printSI(std::ostream &O, NodeInfo *NI) const { +#ifndef NDEBUG + SDNode *Node = NI->Node; + O << " " + << std::hex << Node << std::dec + << ", Lat=" << NI->Latency + << ", Slot=" << NI->Slot + << ", ARITY=(" << Node->getNumOperands() << "," + << Node->getNumValues() << ")" + << " " << Node->getOperationName(&DAG); + if (isFlagDefiner(Node)) O << "<#"; + if (isFlagUser(Node)) O << ">#"; +#endif +} + +/// print - Print ordering to specified output stream. +/// +void ScheduleDAGSimple::print(std::ostream &O) const { +#ifndef NDEBUG + using namespace std; + O << "Ordering\n"; + for (unsigned i = 0, N = Ordering.size(); i < N; i++) { + NodeInfo *NI = Ordering[i]; + printSI(O, NI); + O << "\n"; + if (NI->isGroupDominator()) { + NodeGroup *Group = NI->Group; + for (NIIterator NII = Group->group_begin(), E = Group->group_end(); + NII != E; NII++) { + O << " "; + printSI(O, *NII); + O << "\n"; + } + } + } +#endif +} + +/// createSimpleDAGScheduler - This creates a simple two pass instruction +/// scheduler. +llvm::ScheduleDAG* llvm::createSimpleDAGScheduler(SelectionDAG &DAG, + MachineBasicBlock *BB) { + return new ScheduleDAGSimple(DAG, BB, DAG.getTarget()); +} diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 02ae7108aee..d70ffd94961 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "isel" #include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/ScheduleDAG.h" #include "llvm/CallingConv.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" @@ -43,10 +44,14 @@ using namespace llvm; #ifndef NDEBUG static cl::opt -ViewDAGs("view-isel-dags", cl::Hidden, - cl::desc("Pop up a window to show isel dags as they are selected")); +ViewISelDAGs("view-isel-dags", cl::Hidden, + cl::desc("Pop up a window to show isel dags as they are selected")); +static cl::opt +ViewSchedDAGs("view-sched-dags", cl::Hidden, + cl::desc("Pop up a window to show sched dags as they are processed")); #else -static const bool ViewDAGs = 0; +static const bool ViewISelDAGs = 0; +static const bool ViewSchedDAGs = 0; #endif namespace llvm { @@ -1708,7 +1713,7 @@ void SelectionDAGISel::SelectBasicBlock(BasicBlock *LLVMBB, MachineFunction &MF, // Run the DAG combiner in post-legalize mode. DAG.Combine(true); - if (ViewDAGs) DAG.viewGraph(); + if (ViewISelDAGs) DAG.viewGraph(); // Third, instruction select all of the operations to machine code, adding the // code to the MachineBasicBlock. @@ -1735,3 +1740,12 @@ void SelectionDAGISel::SelectBasicBlock(BasicBlock *LLVMBB, MachineFunction &MF, BB->addSuccessor(Succ0MBB); } } + +//===----------------------------------------------------------------------===// +/// ScheduleAndEmitDAG - Pick a safe ordering and emit instructions for each +/// target node in the graph. +void SelectionDAGISel::ScheduleAndEmitDAG(SelectionDAG &DAG) { + if (ViewSchedDAGs) DAG.viewGraph(); + ScheduleDAG *SL = createSimpleDAGScheduler(DAG, BB); + SL->Run(); +}