READ_LATENCY patch for review.

Sample of use:
class RegConstraint<string C> {
string Constraints = C;
}

// AI_orr - Defines a (op r, r) pattern.
class AI_orr<string opc, SDNode opnode>
: AI<(ops GPR:$dst, GPR:$a, GPR:$b),
     !strconcat(opc, " $dst, $a, $b"),
     [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>,
      RegConstraint<"$a lat 2">;


Lauro

2007/1/26, Evan Cheng <[EMAIL PROTECTED]>:

On Jan 26, 2007, at 1:07 PM, Lauro Ramos Venancio wrote:

>> The facility does that have to be that general. There are 4 cycles
>> between every two instructions.  See LiveIntervalAnalysis:
>>
>>      struct InstrSlots {
>>        enum {
>>          LOAD  = 0,
>>          USE   = 1,
>>          DEF   = 2,
>>          STORE = 3,
>>          NUM   = 4
>>        };
>>      };
>>
>> We can restrict the constraint range to 1 - 3. This ensures the last
>> use is always the kill while retaining its flexibility.
>>
>> Evan
>
> I will try to implement this. Do you have any suggestion for
> constraint name and syntax?

I don't have any great ideas. Perhaps READ_LATENCY for constraint and
something like

$src +lat 2

for syntax?

Feel free to choose something else if you have better ideas.

Thanks,

Evan

>
> Lauro


Index: include/llvm/Target/TargetInstrInfo.h
===================================================================
RCS file: /var/cvs/llvm/llvm/include/llvm/Target/TargetInstrInfo.h,v
retrieving revision 1.111
diff -u -r1.111 TargetInstrInfo.h
--- include/llvm/Target/TargetInstrInfo.h	26 Jan 2007 14:34:51 -0000	1.111
+++ include/llvm/Target/TargetInstrInfo.h	5 Feb 2007 21:05:56 -0000
@@ -94,9 +94,10 @@
 const unsigned M_PREDICATE_OPERAND = 1 << 1;
 
 namespace TOI {
-  // Operand constraints: only "tied_to" for now.
+  // Operand constraints: only "tied_to" and read_latency for now.
   enum OperandConstraint {
-    TIED_TO = 0  // Must be allocated the same register as.
+    TIED_TO = 0,  // Must be allocated the same register as.
+    READ_LATENCY  // Number of cycles needed for read operand.
   };
 }
 
Index: lib/CodeGen/LiveIntervalAnalysis.cpp
===================================================================
RCS file: /var/cvs/llvm/llvm/lib/CodeGen/LiveIntervalAnalysis.cpp,v
retrieving revision 1.204
diff -u -r1.204 LiveIntervalAnalysis.cpp
--- lib/CodeGen/LiveIntervalAnalysis.cpp	19 Dec 2006 22:41:21 -0000	1.204
+++ lib/CodeGen/LiveIntervalAnalysis.cpp	5 Feb 2007 21:05:57 -0000
@@ -441,6 +441,24 @@
   DOUT << "\t\tregister: "; DEBUG(printRegName(interval.reg));
   LiveVariables::VarInfo& vi = lv_->getVarInfo(interval.reg);
 
+  // For each kill, get the greatest read latency of the virtual register.
+  std::vector<char> ReadLatency(vi.Kills.size());
+  for (unsigned i = 0, e = vi.Kills.size(); i != e; ++i){
+    const TargetInstrDescriptor *instrDescriptor =
+      vi.Kills[i]->getInstrDescriptor();
+    ReadLatency[i] = InstrSlots::USE; //default read latency
+    //find the operands that use the virtual register
+    for (unsigned j = 0, f = vi.Kills[i]->getNumOperands(); j != f; ++j){
+      MachineOperand op = vi.Kills[i]->getOperand(j);
+      if (op.isRegister() && op.isUse() && (op.getReg() == interval.reg)) {
+        int read_latency =
+          instrDescriptor->getOperandConstraint(j, TOI::READ_LATENCY);
+        if (read_latency != -1 && read_latency > ReadLatency[i])
+          ReadLatency[i] = (char) read_latency;
+      }
+    }
+  }
+
   // Virtual registers may be defined multiple times (due to phi
   // elimination and 2-addr elimination).  Much of what we do only has to be
   // done once for the vreg.  We use an empty interval to detect the first
@@ -467,7 +485,7 @@
       // FIXME: what about dead vars?
       unsigned killIdx;
       if (vi.Kills[0] != mi)
-        killIdx = getUseIndex(getInstructionIndex(vi.Kills[0]))+1;
+        killIdx = getInstructionIndex(vi.Kills[0]) + ReadLatency[0] + 1;
       else
         killIdx = defIndex+1;
 
@@ -514,7 +532,7 @@
     for (unsigned i = 0, e = vi.Kills.size(); i != e; ++i) {
       MachineInstr *Kill = vi.Kills[i];
       LiveRange LR(getMBBStartIdx(Kill->getParent()),
-                   getUseIndex(getInstructionIndex(Kill))+1,
+                   getInstructionIndex(Kill)+ ReadLatency[i] + 1,
                    ValNum);
       interval.addRange(LR);
       DOUT << " +" << LR;
@@ -574,7 +592,7 @@
         // Remove the old range that we now know has an incorrect number.
         MachineInstr *Killer = vi.Kills[0];
         unsigned Start = getMBBStartIdx(Killer->getParent());
-        unsigned End = getUseIndex(getInstructionIndex(Killer))+1;
+        unsigned End = getInstructionIndex(Killer) + ReadLatency[0] + 1;
         DOUT << "Removing [" << Start << "," << End << "] from: ";
         interval.print(DOUT, mri_); DOUT << "\n";
         interval.removeRange(Start, End);
Index: lib/CodeGen/RegAllocLocal.cpp
===================================================================
RCS file: /var/cvs/llvm/llvm/lib/CodeGen/RegAllocLocal.cpp,v
retrieving revision 1.100
diff -u -r1.100 RegAllocLocal.cpp
--- lib/CodeGen/RegAllocLocal.cpp	1 Feb 2007 05:31:50 -0000	1.100
+++ lib/CodeGen/RegAllocLocal.cpp	5 Feb 2007 21:05:57 -0000
@@ -567,10 +567,20 @@
     }
 
     SmallVector<unsigned, 8> Kills;
+    SmallVector<char, 8> ReadLatency;
     for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
       MachineOperand& MO = MI->getOperand(i);
-      if (MO.isRegister() && MO.isKill())
+      if (MO.isRegister() && MO.isKill()){
         Kills.push_back(MO.getReg());
+        int read_latency = 1;
+        //we can't call getOperandConstraint on a implicit MO
+        if (!MO.isImplicit()) {
+          read_latency = TID.getOperandConstraint(i,TOI::READ_LATENCY);
+          if (read_latency == -1)
+            read_latency = 1;
+        }
+        ReadLatency.push_back((char)read_latency);
+      }
     }
 
     // Get the used operands into registers.  This has the potential to spill
@@ -591,6 +601,7 @@
     // value, freeing the register being used, so it doesn't need to be
     // spilled to memory.
     //
+    SmallVector<unsigned, 8> PostponedRegRemove;
     for (unsigned i = 0, e = Kills.size(); i != e; ++i) {
       unsigned VirtReg = Kills[i];
       unsigned PhysReg = VirtReg;
@@ -606,16 +617,21 @@
       }
 
       if (PhysReg) {
-        DOUT << "  Last use of " << RegInfo->getName(PhysReg)
-             << "[%reg" << VirtReg <<"], removing it from live set\n";
-        removePhysReg(PhysReg);
-        for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg);
-             *AliasSet; ++AliasSet) {
-          if (PhysRegsUsed[*AliasSet] != -2) {
-            DOUT  << "  Last use of "
-                  << RegInfo->getName(*AliasSet)
-                  << "[%reg" << VirtReg <<"], removing it from live set\n";
-            removePhysReg(*AliasSet);
+        if (ReadLatency[i] > 1) {
+          //postpone the reg remove from live set.
+          PostponedRegRemove.push_back(PhysReg);
+        } else {
+          DOUT << "  Last use of " << RegInfo->getName(PhysReg)
+               << "[%reg" << VirtReg <<"], removing it from live set\n"; 
+          removePhysReg(PhysReg);
+          for (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg);
+               *AliasSet; ++AliasSet) {
+            if (PhysRegsUsed[*AliasSet] != -2) {
+              DOUT  << "  Last use of "
+                    << RegInfo->getName(*AliasSet)
+                    << "[%reg" << VirtReg <<"], removing it from live set\n";
+              removePhysReg(*AliasSet);
+            }
           }
         }
       }
@@ -731,7 +747,24 @@
         }
       }
     }
-    
+
+    //Do postponed reg removes from live set
+    for (unsigned i = 0, e = PostponedRegRemove.size(); i != e; ++i) {
+      DOUT << "  Last use of " << RegInfo->getName(PostponedRegRemove[i])
+           <<", removing it from live set (postponed)\n";
+      removePhysReg(PostponedRegRemove[i]);
+      for (const unsigned *AliasSet =
+             RegInfo->getAliasSet(PostponedRegRemove[i]);
+           *AliasSet; ++AliasSet) {
+        if (PhysRegsUsed[*AliasSet] != -2) {
+          DOUT  << "  Last use of "
+                << RegInfo->getName(*AliasSet)
+                <<", removing it from live set (postponed)\n";
+          removePhysReg(*AliasSet);
+        }
+      }
+    }
+
     // Finally, if this is a noop copy instruction, zap it.
     unsigned SrcReg, DstReg;
     if (TII.isMoveInstr(*MI, SrcReg, DstReg) && SrcReg == DstReg) {
Index: utils/TableGen/CodeGenTarget.cpp
===================================================================
RCS file: /var/cvs/llvm/llvm/utils/TableGen/CodeGenTarget.cpp,v
retrieving revision 1.82
diff -u -r1.82 CodeGenTarget.cpp
--- utils/TableGen/CodeGenTarget.cpp	26 Jan 2007 17:29:20 -0000	1.82
+++ utils/TableGen/CodeGenTarget.cpp	5 Feb 2007 21:06:00 -0000
@@ -20,6 +20,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Streams.h"
+#include "llvm/Target/TargetInstrInfo.h"
 #include <set>
 #include <algorithm>
 using namespace llvm;
@@ -284,38 +285,61 @@
 
 
 static void ParseConstraint(const std::string &CStr, CodeGenInstruction *I) {
-  // FIXME: Only supports TIED_TO for now.
-  std::string::size_type pos = CStr.find_first_of('=');
-  assert(pos != std::string::npos && "Unrecognized constraint");
-  std::string Name = CStr.substr(0, pos);
-
-  // TIED_TO: $src1 = $dst
-  std::string::size_type wpos = Name.find_first_of(" \t");
-  if (wpos == std::string::npos)
-    throw "Illegal format for tied-to constraint: '" + CStr + "'";
-  std::string DestOpName = Name.substr(0, wpos);
-  std::pair<unsigned,unsigned> DestOp = I->ParseOperandName(DestOpName, false);
-
-  Name = CStr.substr(pos+1);
-  wpos = Name.find_first_not_of(" \t");
-  if (wpos == std::string::npos)
-    throw "Illegal format for tied-to constraint: '" + CStr + "'";
-    
-  std::pair<unsigned,unsigned> SrcOp =
-    I->ParseOperandName(Name.substr(wpos), false);
-  if (SrcOp > DestOp)
-    throw "Illegal tied-to operand constraint '" + CStr + "'";
-  
-  
-  unsigned FlatOpNo = I->getFlattenedOperandNumber(SrcOp);
+  std::pair<unsigned,unsigned> Operand;
+  unsigned ConstraintValue;
+  TOI::OperandConstraint Constraint;
+  std::string::size_type pos;
+
+  if ((pos = CStr.find_first_of('=')) != std::string::npos) {
+    //TIED_TO Constraint
+    Constraint = TOI::TIED_TO;
+    std::string Name = CStr.substr(0, pos);
+    // TIED_TO: $src1 = $dst
+    std::string::size_type wpos = Name.find_first_of(" \t");
+    if (wpos == std::string::npos)
+      throw "Illegal format for tied-to constraint: '" + CStr + "'";
+    std::string DestOpName = Name.substr(0, wpos);
+    Operand = I->ParseOperandName(DestOpName, false);
+
+    Name = CStr.substr(pos+1);
+    wpos = Name.find_first_not_of(" \t");
+    if (wpos == std::string::npos)
+      throw "Illegal format for tied-to constraint: '" + CStr + "'";
+
+    std::pair<unsigned,unsigned> SrcOp =
+      I->ParseOperandName(Name.substr(wpos), false);
+    if (SrcOp > Operand)
+      throw "Illegal tied-to operand constraint '" + CStr + "'";
+    ConstraintValue = I->getFlattenedOperandNumber(SrcOp);
+
+  } else if ((pos = CStr.find("lat")) != std::string::npos) {
+    //READ_LATENCY Constraint
+    Constraint = TOI::READ_LATENCY;
+
+    //get read latency operand
+    std::string Name = CStr.substr(0, pos);
+    std::string::size_type wpos = Name.find_first_of(" \t");
+    if (wpos == std::string::npos)
+      throw "Illegal format for read-latency constraint: '" + CStr + "'";
+    std::string OpName = Name.substr(0, wpos);
+    Operand = I->ParseOperandName(OpName, false);
+
+    //get read latancy value
+    Name = CStr.substr(pos+3);
+    sscanf(Name.c_str(),"%u",&ConstraintValue);
+    if (ConstraintValue <= 0 || ConstraintValue > 3)
+      throw "Invalid read latency value: '" + CStr + "'";
+  } else {
+    throw "Unrecognized constraint";
+  }
+
   // Build the string for the operand.
-  std::string OpConstraint =
-    "((" + utostr(FlatOpNo) + " << 16) | (1 << TOI::TIED_TO))";
+  std::string OpConstraint ="((" + utostr(ConstraintValue) + " << " +
+    utostr(16 + Constraint * 4) + ") | (1 << " + utostr(Constraint) +"))";
 
-  
-  if (!I->OperandList[DestOp.first].Constraints[DestOp.second].empty())
-    throw "Operand '" + DestOpName + "' cannot have multiple constraints!";
-  I->OperandList[DestOp.first].Constraints[DestOp.second] = OpConstraint;
+  if (!I->OperandList[Operand.first].Constraints[Operand.second].empty())
+    throw "Operands cannot have multiple constraints.";
+  I->OperandList[Operand.first].Constraints[Operand.second] = OpConstraint;
 }
 
 static void ParseConstraints(const std::string &CStr, CodeGenInstruction *I) {
_______________________________________________
llvm-commits mailing list
llvm-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits

Reply via email to