OSDN Git Service

Add capability to scheduler to commute nodes for profit.
authorEvan Cheng <evan.cheng@apple.com>
Fri, 12 May 2006 01:58:24 +0000 (01:58 +0000)
committerEvan Cheng <evan.cheng@apple.com>
Fri, 12 May 2006 01:58:24 +0000 (01:58 +0000)
If a two-address code whose first operand has uses below, it should be commuted
when possible.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@28230 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/ScheduleDAG.h
include/llvm/Target/TargetInstrInfo.h
lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp

index 5f9236d..6263dfb 100644 (file)
@@ -91,7 +91,7 @@ namespace llvm {
     short NumChainPredsLeft;            // # of chain preds not scheduled.
     short NumChainSuccsLeft;            // # of chain succs not scheduled.
     bool isTwoAddress     : 1;          // Is a two-address instruction.
-    bool isDefNUseOperand : 1;          // Is a def&use operand.
+    bool isCommutable     : 1;          // Is a commutable instruction.
     bool isPending        : 1;          // True once pending.
     bool isAvailable      : 1;          // True once available.
     bool isScheduled      : 1;          // True once scheduled.
@@ -105,7 +105,7 @@ namespace llvm {
     SUnit(SDNode *node, unsigned nodenum)
       : Node(node), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0),
         NumChainPredsLeft(0), NumChainSuccsLeft(0),
-        isTwoAddress(false), isDefNUseOperand(false),
+        isTwoAddress(false), isCommutable(false),
         isPending(false), isAvailable(false), isScheduled(false),
         Latency(0), CycleBound(0), Cycle(0), Depth(0), Height(0),
         NodeNum(nodenum) {}
@@ -162,10 +162,11 @@ namespace llvm {
     const MRegisterInfo *MRI;             // Target processor register info
     SSARegMap *RegMap;                    // Virtual/real register map
     MachineConstantPool *ConstPool;       // Target constant pool
-    std::vector<SUnit*> Sequence;         // The schedule.  Null SUnit*'s represent
-                                          // noop instructions.
+    std::vector<SUnit*> Sequence;         // The schedule. Null SUnit*'s
+                                          // represent noop instructions.
     std::map<SDNode*, SUnit*> SUnitMap;   // SDNode to SUnit mapping (n -> 1).
     std::vector<SUnit> SUnits;            // The scheduling units.
+    std::set<SDNode*> CommuteSet;         // Nodes the should be commuted.
 
     ScheduleDAG(SelectionDAG &dag, MachineBasicBlock *bb,
                 const TargetMachine &tm)
index c9a958e..625f5c2 100644 (file)
@@ -165,6 +165,9 @@ public:
   bool isTwoAddrInstr(MachineOpCode Opcode) const {
     return get(Opcode).Flags & M_2_ADDR_FLAG;
   }
+  bool isCommutableInstr(MachineOpCode Opcode) const {
+    return get(Opcode).Flags & M_COMMUTABLE;
+  }
   bool isTerminatorInstr(unsigned Opcode) const {
     return get(Opcode).Flags & M_TERMINATOR_FLAG;
   }
index 4a9b9c7..e05d9d7 100644 (file)
@@ -120,13 +120,10 @@ void ScheduleDAG::BuildSchedUnits() {
     
     if (MainNode->isTargetOpcode()) {
       unsigned Opc = MainNode->getTargetOpcode();
-      if (TII->isTwoAddrInstr(Opc)) {
+      if (TII->isTwoAddrInstr(Opc))
         SU->isTwoAddress = true;
-        SDNode *OpN = MainNode->getOperand(0).Val;
-        SUnit *OpSU = SUnitMap[OpN];
-        if (OpSU)
-          OpSU->isDefNUseOperand = true;
-      }
+      if (TII->isCommutableInstr(Opc))
+        SU->isCommutable = true;
     }
     
     // Find all predecessors and successors of the group.
@@ -391,7 +388,18 @@ void ScheduleDAG::EmitNode(SDNode *Node,
     // instruction as appropriate.
     for (unsigned i = 0; i != NodeOperands; ++i)
       AddOperand(MI, Node->getOperand(i), i+NumResults, &II, VRBaseMap);
-    
+
+    // Commute node if it has been determined to be profitable.
+    if (CommuteSet.count(Node)) {
+      MachineInstr *NewMI = TII->commuteInstruction(MI);
+      if (NewMI == 0)
+        DEBUG(std::cerr << "Sched: COMMUTING FAILED!\n");
+      else {
+        DEBUG(std::cerr << "Sched: COMMUTED TO: " << *NewMI);
+        MI = NewMI;
+      }
+    }
+
     // Now that we have emitted all operands, emit this instruction itself.
     if ((II.Flags & M_USES_CUSTOM_DAG_SCHED_INSERTION) == 0) {
       BB->insert(BB->end(), MI);
index acd6904..9b359aa 100644 (file)
@@ -30,7 +30,7 @@
 using namespace llvm;
 
 namespace {
-  cl::opt<bool> SchedLowerDefNUse("sched-lower-defnuse", cl::Hidden);
+  cl::opt<bool> SchedCommuteNodes("sched-commute-nodes", cl::Hidden);
 }
 
 namespace {
@@ -70,6 +70,7 @@ private:
   void ScheduleNodeTopDown(SUnit *SU, unsigned& CurCycle);
   void ListScheduleTopDown();
   void ListScheduleBottomUp();
+  void CommuteNodesToReducePressure();
 };
 }  // end anonymous namespace
 
@@ -95,6 +96,9 @@ void ScheduleDAGRRList::Schedule() {
     ListScheduleTopDown();
   
   AvailableQueue->releaseState();
+
+  if (SchedCommuteNodes)
+    CommuteNodesToReducePressure();
   
   DEBUG(std::cerr << "*** Final schedule ***\n");
   DEBUG(dumpSchedule());
@@ -104,6 +108,41 @@ void ScheduleDAGRRList::Schedule() {
   EmitSchedule();
 }
 
+/// CommuteNodesToReducePressure - Is a node is two-address and commutable, and
+/// it is not the last use of its first operand, add it to the CommuteSet if
+/// possible. It will be commuted when it is translated to a MI.
+void ScheduleDAGRRList::CommuteNodesToReducePressure() {
+  std::set<SUnit *> OperandSeen;
+  for (unsigned i = Sequence.size()-1; i != 0; --i) {  // Ignore first node.
+    SUnit *SU = Sequence[i];
+    if (!SU) continue;
+    if (SU->isTwoAddress && SU->isCommutable) {
+      SDNode *OpN = SU->Node->getOperand(0).Val;
+      SUnit *OpSU = SUnitMap[OpN];
+      if (OpSU && OperandSeen.count(OpSU) == 1) {
+        // Ok, so SU is not the last use of OpSU, but SU is two-address so
+        // it will clobber OpSU. Try to commute it if possible.
+        bool DoCommute = true;
+        for (unsigned j = 1, e = SU->Node->getNumOperands(); j != e; ++j) {
+          OpN = SU->Node->getOperand(j).Val;
+          OpSU = SUnitMap[OpN];
+          if (OpSU && OperandSeen.count(OpSU) == 1) {
+            DoCommute = false;
+            break;
+          }
+        }
+        if (DoCommute)
+          CommuteSet.insert(SU->Node);
+      }
+    }
+
+    for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Preds.begin(),
+           E = SU->Preds.end(); I != E; ++I) {
+      if (!I->second)
+        OperandSeen.insert(I->first);
+    }
+  }
+}
 
 //===----------------------------------------------------------------------===//
 //  Bottom-Up Scheduling
@@ -436,8 +475,7 @@ namespace {
     void initNodes(const std::vector<SUnit> &sunits) {
       SUnits = &sunits;
       // Add pseudo dependency edges for two-address nodes.
-      if (SchedLowerDefNUse)
-        AddPseudoTwoAddrDeps();
+      AddPseudoTwoAddrDeps();
       // Calculate node priorities.
       CalculatePriorities();
     }
@@ -513,23 +551,6 @@ bool bu_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
   if (RIsFloater)
     RBonus += 2;
 
-  if (!SchedLowerDefNUse) {
-    // Special tie breaker: if two nodes share a operand, the one that use it
-    // as a def&use operand is preferred.
-    if (LIsTarget && RIsTarget) {
-      if (left->isTwoAddress && !right->isTwoAddress) {
-        SDNode *DUNode = left->Node->getOperand(0).Val;
-        if (DUNode->isOperand(right->Node))
-          LBonus += 2;
-      }
-      if (!left->isTwoAddress && right->isTwoAddress) {
-        SDNode *DUNode = right->Node->getOperand(0).Val;
-        if (DUNode->isOperand(left->Node))
-          RBonus += 2;
-      }
-    }
-  }
-
   if (LPriority+LBonus < RPriority+RBonus)
     return true;
   else if (LPriority+LBonus == RPriority+RBonus)
@@ -602,16 +623,17 @@ void BURegReductionPriorityQueue<SF>::AddPseudoTwoAddrDeps() {
       continue;
 
     if (SU->isTwoAddress) {
-      unsigned Depth = SU->Node->getNodeDepth();
       SUnit *DUSU = getDefUsePredecessor(SU);
       if (!DUSU) continue;
 
       for (std::set<std::pair<SUnit*, bool> >::iterator I = DUSU->Succs.begin(),
              E = DUSU->Succs.end(); I != E; ++I) {
+        if (I->second) continue;
         SUnit *SuccSU = I->first;
-        if (SuccSU != SU && !canClobber(SuccSU, DUSU)) {
-          if (SuccSU->Node->getNodeDepth() <= Depth+2 &&
-              !isReachable(SuccSU, SU)) {
+        if (SuccSU != SU &&
+            (!canClobber(SuccSU, DUSU) ||
+             (SchedCommuteNodes && !SU->isCommutable && SuccSU->isCommutable))){
+          if (SuccSU->Depth <= SU->Depth+2 && !isReachable(SuccSU, SU)) {
             DEBUG(std::cerr << "Adding an edge from SU # " << SU->NodeNum
                   << " to SU #" << SuccSU->NodeNum << "\n");
             if (SU->Preds.insert(std::make_pair(SuccSU, true)).second)