[llvm-commits] CVS: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

Chris Lattner lattner at cs.uiuc.edu
Wed Feb 22 14:37:25 PST 2006



Changes in directory llvm/lib/CodeGen/SelectionDAG:

SelectionDAGISel.cpp updated: 1.166 -> 1.167
---
Log message:

Change a whole bunch of code to be built around RegsForValue instead of
a single register number.  This fully implements promotion for inline asms,
expand is close but not quite right yet.



---
Diffs of the changes:  (+248 -124)

 SelectionDAGISel.cpp |  372 ++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 248 insertions(+), 124 deletions(-)


Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
diff -u llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.166 llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.167
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.166	Tue Feb 21 18:56:12 2006
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp	Wed Feb 22 16:37:12 2006
@@ -78,6 +78,43 @@
       clEnumValEnd));
 } // namespace
 
+namespace {
+  /// RegsForValue - This struct represents the physical registers that a
+  /// particular value is assigned and the type information about the value.
+  /// This is needed because values can be promoted into larger registers and
+  /// expanded into multiple smaller registers than the value.
+  struct RegsForValue {
+    /// Regs - This list hold the register (for legal and promoted values)
+    /// or register set (for expanded values) that the value should be assigned
+    /// to.
+    std::vector<unsigned> Regs;
+    
+    /// RegVT - The value type of each register.
+    ///
+    MVT::ValueType RegVT;
+    
+    /// ValueVT - The value type of the LLVM value, which may be promoted from
+    /// RegVT or made from merging the two expanded parts.
+    MVT::ValueType ValueVT;
+    
+    RegsForValue() : RegVT(MVT::Other), ValueVT(MVT::Other) {}
+    
+    RegsForValue(unsigned Reg, MVT::ValueType regvt, MVT::ValueType valuevt)
+      : RegVT(regvt), ValueVT(valuevt) {
+        Regs.push_back(Reg);
+    }
+    RegsForValue(const std::vector<unsigned> &regs, 
+                 MVT::ValueType regvt, MVT::ValueType valuevt)
+      : Regs(regs), RegVT(regvt), ValueVT(valuevt) {
+    }
+    
+    /// getCopyFromRegs - Emit a series of CopyFromReg nodes that copies from
+    /// this value and returns the result as a ValueVT value.  This uses 
+    /// Chain/Flag as the input and updates them for the output Chain/Flag.
+    SDOperand getCopyFromRegs(SelectionDAG &DAG,
+                              SDOperand &Chain, SDOperand &Flag);
+  };
+}
 
 namespace llvm {
   //===--------------------------------------------------------------------===//
@@ -120,7 +157,7 @@
       }
 
       // If this value is represented with multiple target registers, make sure
-      // to create enough consequtive registers of the right (smaller) type.
+      // to create enough consecutive registers of the right (smaller) type.
       unsigned NT = VT-1;  // Find the type to use.
       while (TLI.getNumElements((MVT::ValueType)NT) != 1)
         --NT;
@@ -412,11 +449,12 @@
     return N = NewN;
   }
   
-  unsigned GetAvailableRegister(bool OutReg, bool InReg,
-                                const std::vector<unsigned> &RegChoices,
-                                std::set<unsigned> &OutputRegs, 
-                                std::set<unsigned> &InputRegs);
-
+  RegsForValue GetRegistersForValue(const std::string &ConstrCode,
+                                    MVT::ValueType VT,
+                                    bool OutReg, bool InReg,
+                                    std::set<unsigned> &OutputRegs, 
+                                    std::set<unsigned> &InputRegs);
+                                                
   // Terminator instructions.
   void visitRet(ReturnInst &I);
   void visitBr(BranchInst &I);
@@ -1130,49 +1168,145 @@
   DAG.setRoot(Result.second);
 }
 
-/// GetAvailableRegister - Pick a register from RegChoices that is available
-/// for input and/or output as specified by isOutReg/isInReg.  If an allocatable
-/// register is found, it is returned and added to the specified set of used
-/// registers.  If not, zero is returned.
-unsigned SelectionDAGLowering::
-GetAvailableRegister(bool isOutReg, bool isInReg,
-                     const std::vector<unsigned> &RegChoices,
-                     std::set<unsigned> &OutputRegs,
+SDOperand RegsForValue::getCopyFromRegs(SelectionDAG &DAG,
+                                        SDOperand &Chain, SDOperand &Flag) {
+  SDOperand Val = DAG.getCopyFromReg(Chain, Regs[0], RegVT, Flag);
+  Chain = Val.getValue(1);
+  Flag  = Val.getValue(2);
+  
+  // If the result was expanded, copy from the top part.
+  if (Regs.size() > 1) {
+    assert(Regs.size() == 2 &&
+           "Cannot expand to more than 2 elts yet!");
+    SDOperand Hi = DAG.getCopyFromReg(Chain, Regs[1], RegVT, Flag);
+    Chain = Val.getValue(1);
+    Flag  = Val.getValue(2);
+    return DAG.getNode(ISD::MERGE_VALUES, ValueVT, Val, Hi);
+  }
+
+  // Otherwise, if the return value was promoted, truncate it to the
+  // appropriate type.
+  if (RegVT == ValueVT)
+    return Val;
+  
+  if (MVT::isInteger(RegVT))
+    return DAG.getNode(ISD::TRUNCATE, ValueVT, Val);
+  else
+    return DAG.getNode(ISD::FP_ROUND, ValueVT, Val);
+}
+
+
+
+/// isAllocatableRegister - If the specified register is safe to allocate, 
+/// i.e. it isn't a stack pointer or some other special register, return the
+/// register class for the register.  Otherwise, return null.
+static const TargetRegisterClass *
+isAllocatableRegister(unsigned Reg, MachineFunction &MF, 
+                      const MRegisterInfo *MRI) {
+  for (MRegisterInfo::regclass_iterator RC = MRI->regclass_begin(),
+       E = MRI->regclass_end(); RC != E; ++RC) {
+    // NOTE: This isn't ideal.  In particular, this might allocate the
+    // frame pointer in functions that need it (due to them not being taken
+    // out of allocation, because a variable sized allocation hasn't been seen
+    // yet).  This is a slight code pessimization, but should still work.
+    for (TargetRegisterClass::iterator I = (*RC)->allocation_order_begin(MF),
+         E = (*RC)->allocation_order_end(MF); I != E; ++I)
+      if (*I == Reg)
+        return *RC;
+  }
+  return 0;
+}    
+
+RegsForValue SelectionDAGLowering::
+GetRegistersForValue(const std::string &ConstrCode,
+                     MVT::ValueType VT, bool isOutReg, bool isInReg,
+                     std::set<unsigned> &OutputRegs, 
                      std::set<unsigned> &InputRegs) {
+  std::pair<unsigned, const TargetRegisterClass*> PhysReg = 
+    TLI.getRegForInlineAsmConstraint(ConstrCode, VT);
+  std::vector<unsigned> Regs;
+
+  unsigned NumRegs = VT != MVT::Other ? TLI.getNumElements(VT) : 1;
+  MVT::ValueType RegVT;
+  MVT::ValueType ValueVT = VT;
+  
+  if (PhysReg.first) {
+    if (VT == MVT::Other)
+      ValueVT = *PhysReg.second->vt_begin();
+    RegVT = VT;
+    
+    // This is a explicit reference to a physical register.
+    Regs.push_back(PhysReg.first);
+
+    // If this is an expanded reference, add the rest of the regs to Regs.
+    if (NumRegs != 1) {
+      RegVT = *PhysReg.second->vt_begin();
+      TargetRegisterClass::iterator I = PhysReg.second->begin();
+      TargetRegisterClass::iterator E = PhysReg.second->end();
+      for (; *I != PhysReg.first; ++I)
+        assert(I != E && "Didn't find reg!"); 
+      
+      // Already added the first reg.
+      --NumRegs; ++I;
+      for (; NumRegs; --NumRegs, ++I) {
+        assert(I != E && "Ran out of registers to allocate!");
+        Regs.push_back(*I);
+      }
+    }
+    return RegsForValue(Regs, RegVT, ValueVT);
+  }
+  
+  // This is a reference to a register class.  Allocate NumRegs consecutive,
+  // available, registers from the class.
+  std::vector<unsigned> RegClassRegs =
+    TLI.getRegClassForInlineAsmConstraint(ConstrCode, VT);
+
   const MRegisterInfo *MRI = DAG.getTarget().getRegisterInfo();
   MachineFunction &MF = *CurMBB->getParent();
-  for (unsigned i = 0, e = RegChoices.size(); i != e; ++i) {
-    unsigned Reg = RegChoices[i];
+  unsigned NumAllocated = 0;
+  for (unsigned i = 0, e = RegClassRegs.size(); i != e; ++i) {
+    unsigned Reg = RegClassRegs[i];
     // See if this register is available.
-    if (isOutReg && OutputRegs.count(Reg)) continue;  // Already used.
-    if (isInReg  && InputRegs.count(Reg)) continue;  // Already used.
-
+    if ((isOutReg && OutputRegs.count(Reg)) ||   // Already used.
+        (isInReg  && InputRegs.count(Reg))) {    // Already used.
+      // Make sure we find consecutive registers.
+      NumAllocated = 0;
+      continue;
+    }
+    
     // Check to see if this register is allocatable (i.e. don't give out the
     // stack pointer).
-    bool Found = false;
-    for (MRegisterInfo::regclass_iterator RC = MRI->regclass_begin(),
-         E = MRI->regclass_end(); !Found && RC != E; ++RC) {
-      // NOTE: This isn't ideal.  In particular, this might allocate the
-      // frame pointer in functions that need it (due to them not being taken
-      // out of allocation, because a variable sized allocation hasn't been seen
-      // yet).  This is a slight code pessimization, but should still work.
-      for (TargetRegisterClass::iterator I = (*RC)->allocation_order_begin(MF),
-           E = (*RC)->allocation_order_end(MF); I != E; ++I)
-        if (*I == Reg) {
-          Found = true;
-          break;
-        }
+    const TargetRegisterClass *RC = isAllocatableRegister(Reg, MF, MRI);
+    if (!RC) {
+      // Make sure we find consecutive registers.
+      NumAllocated = 0;
+      continue;
     }
-    if (!Found) continue;
     
-    // Okay, this register is good, return it.
-    if (isOutReg) OutputRegs.insert(Reg);  // Mark used.
-    if (isInReg)  InputRegs.insert(Reg);   // Mark used.
-    return Reg;
+    // Okay, this register is good, we can use it.
+    ++NumAllocated;
+
+    // If we allocated enough consecutive   
+    if (NumAllocated == NumRegs) {
+      unsigned RegStart = (i-NumAllocated)+1;
+      unsigned RegEnd   = i+1;
+      // Mark all of the allocated registers used.
+      for (unsigned i = RegStart; i != RegEnd; ++i) {
+        unsigned Reg = RegClassRegs[i];
+        Regs.push_back(Reg);
+        if (isOutReg) OutputRegs.insert(Reg);    // Mark reg used.
+        if (isInReg)  InputRegs.insert(Reg);     // Mark reg used.
+      }
+      
+      return RegsForValue(Regs, *RC->vt_begin(), VT);
+    }
   }
-  return 0;
+  
+  // Otherwise, we couldn't allocate enough registers for this.
+  return RegsForValue();
 }
 
+
 /// visitInlineAsm - Handle a call to an InlineAsm object.
 ///
 void SelectionDAGLowering::visitInlineAsm(CallInst &I) {
@@ -1235,39 +1369,40 @@
     
     ConstraintVTs.push_back(OpVT);
 
-    std::pair<unsigned, const TargetRegisterClass*> Reg = 
-       TLI.getRegForInlineAsmConstraint(ConstraintCode, OpVT);
-    if (Reg.first == 0) continue;  // Not assigned a fixed reg.
-    unsigned TheReg = Reg.first;
+    if (TLI.getRegForInlineAsmConstraint(ConstraintCode, OpVT).first == 0)
+      continue;  // Not assigned a fixed reg.
     
-    // FIXME: Handle expanded physreg refs!
+    // Build a list of regs that this operand uses.  This always has a single
+    // element for promoted/expanded operands.
+    RegsForValue Regs = GetRegistersForValue(ConstraintCode, OpVT,
+                                             false, false,
+                                             OutputRegs, InputRegs);
     
     switch (Constraints[i].Type) {
     case InlineAsm::isOutput:
       // We can't assign any other output to this register.
-      OutputRegs.insert(TheReg);
+      OutputRegs.insert(Regs.Regs.begin(), Regs.Regs.end());
       // If this is an early-clobber output, it cannot be assigned to the same
       // value as the input reg.
       if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput)
-        InputRegs.insert(TheReg);
+        InputRegs.insert(Regs.Regs.begin(), Regs.Regs.end());
       break;
     case InlineAsm::isInput:
       // We can't assign any other input to this register.
-      InputRegs.insert(TheReg);
+      InputRegs.insert(Regs.Regs.begin(), Regs.Regs.end());
       break;
     case InlineAsm::isClobber:
       // Clobbered regs cannot be used as inputs or outputs.
-      InputRegs.insert(TheReg);
-      OutputRegs.insert(TheReg);
+      InputRegs.insert(Regs.Regs.begin(), Regs.Regs.end());
+      OutputRegs.insert(Regs.Regs.begin(), Regs.Regs.end());
       break;
     }
   }      
   
   // Loop over all of the inputs, copying the operand values into the
   // appropriate registers and processing the output regs.
-  unsigned RetValReg = 0;
-  std::vector<std::pair<unsigned, Value*> > IndirectStoresToEmit;
-  bool FoundOutputConstraint = false;
+  RegsForValue RetValRegs;
+  std::vector<std::pair<RegsForValue, Value*> > IndirectStoresToEmit;
   OpNum = 1;
   
   for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
@@ -1276,58 +1411,47 @@
 
     switch (Constraints[i].Type) {
     case InlineAsm::isOutput: {
-      // Copy the output from the appropriate register.  Find a regsister that
-      // we can use.
-      
-      // Check to see if this is a physreg reference.
-      std::pair<unsigned, const TargetRegisterClass*> PhysReg = 
-         TLI.getRegForInlineAsmConstraint(ConstraintCode, ConstraintVTs[i]);
-      unsigned DestReg;
-      if (PhysReg.first)
-        DestReg = PhysReg.first;
-      else {
-        std::vector<unsigned> Regs =
-          TLI.getRegClassForInlineAsmConstraint(ConstraintCode, 
-                                                ConstraintVTs[i]);
-
-        // If this is an early-clobber output, or if there is an input
-        // constraint that matches this, we need to reserve the input register
-        // so no other inputs allocate to it.
-        bool UsesInputRegister = false;
-        if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput)
-          UsesInputRegister = true;
-        DestReg = GetAvailableRegister(true, UsesInputRegister, 
-                                       Regs, OutputRegs, InputRegs);
-      }
+      // If this is an early-clobber output, or if there is an input
+      // constraint that matches this, we need to reserve the input register
+      // so no other inputs allocate to it.
+      bool UsesInputRegister = false;
+      if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput)
+        UsesInputRegister = true;
       
-      assert(DestReg && "Couldn't allocate output reg!");
+      // Copy the output from the appropriate register.  Find a register that
+      // we can use.
+      RegsForValue Regs =
+        GetRegistersForValue(ConstraintCode, ConstraintVTs[i],
+                             true, UsesInputRegister, 
+                             OutputRegs, InputRegs);
+      assert(!Regs.Regs.empty() && "Couldn't allocate output reg!");
 
-      const Type *OpTy;
       if (!Constraints[i].isIndirectOutput) {
-        assert(!FoundOutputConstraint &&
+        assert(RetValRegs.Regs.empty() &&
                "Cannot have multiple output constraints yet!");
-        FoundOutputConstraint = true;
         assert(I.getType() != Type::VoidTy && "Bad inline asm!");
-        
-        RetValReg = DestReg;
+        RetValRegs = Regs;
       } else {
         Value *CallOperand = I.getOperand(OpNum);
-        IndirectStoresToEmit.push_back(std::make_pair(DestReg, CallOperand));
+        IndirectStoresToEmit.push_back(std::make_pair(Regs, CallOperand));
         OpNum++;  // Consumes a call operand.
       }
       
       // Add information to the INLINEASM node to know that this register is
       // set.
-      AsmNodeOperands.push_back(DAG.getRegister(DestReg, ConstraintVTs[i]));
-      AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF
       
+      // FIXME:
+      // FIXME: Handle multiple regs here.
+      // FIXME:
+      unsigned DestReg = Regs.Regs[0];
+      AsmNodeOperands.push_back(DAG.getRegister(DestReg, Regs.RegVT));
+      AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF
       break;
     }
     case InlineAsm::isInput: {
       Value *CallOperand = I.getOperand(OpNum);
       OpNum++;  // Consumes a call operand.
 
-      unsigned SrcReg;
       SDOperand ResOp;
       unsigned ResOpType;
       SDOperand InOperandVal = getValue(CallOperand);
@@ -1336,6 +1460,7 @@
         // If this is required to match an output register we have already set,
         // just use its register.
         unsigned OperandNo = atoi(ConstraintCode.c_str());
+        unsigned SrcReg;
         SrcReg = cast<RegisterSDNode>(AsmNodeOperands[OperandNo*2+2])->getReg();
         ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]);
         ResOpType = 1;
@@ -1343,39 +1468,46 @@
         Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag);
         Flag = Chain.getValue(1);
       } else {
-        TargetLowering::ConstraintType CTy = TargetLowering::C_Register;
+        TargetLowering::ConstraintType CTy = TargetLowering::C_RegisterClass;
         if (ConstraintCode.size() == 1)   // not a physreg name.
           CTy = TLI.getConstraintType(ConstraintCode[0]);
         
         switch (CTy) {
         default: assert(0 && "Unknown constraint type! FAIL!");
-        case TargetLowering::C_Register: {
-          std::pair<unsigned, const TargetRegisterClass*> PhysReg = 
-            TLI.getRegForInlineAsmConstraint(ConstraintCode, ConstraintVTs[i]);
-          // FIXME: should be match fail.
-          assert(PhysReg.first && "Unknown physical register name!");
-          SrcReg = PhysReg.first;
-
-          Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag);
-          Flag = Chain.getValue(1);
-          
-          ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]);
-          ResOpType = 1;
-          break;
-        }
         case TargetLowering::C_RegisterClass: {
-          // Copy the input into the appropriate register.
-          std::vector<unsigned> Regs =
-            TLI.getRegClassForInlineAsmConstraint(ConstraintCode, 
-                                                  ConstraintVTs[i]);
-          SrcReg = GetAvailableRegister(false, true, Regs, 
-                                        OutputRegs, InputRegs);
+          // Copy the input into the appropriate registers.
+          RegsForValue InRegs =
+            GetRegistersForValue(ConstraintCode, ConstraintVTs[i],
+                                 false, true, OutputRegs, InputRegs);
           // FIXME: should be match fail.
-          assert(SrcReg && "Wasn't able to allocate register!");
-          Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag);
-          Flag = Chain.getValue(1);
+          assert(!InRegs.Regs.empty() && "Couldn't allocate input reg!");
+
+          if (InRegs.Regs.size() == 1) {
+            // If there is a single register and the types differ, this must be
+            // a promotion.
+            if (InRegs.RegVT != InRegs.ValueVT) {
+              if (MVT::isInteger(InRegs.RegVT))
+                InOperandVal = DAG.getNode(ISD::ANY_EXTEND, InRegs.RegVT,
+                                           InOperandVal);
+              else
+                InOperandVal = DAG.getNode(ISD::FP_EXTEND, InRegs.RegVT,
+                                           InOperandVal);
+            }
+            Chain = DAG.getCopyToReg(Chain, InRegs.Regs[0], InOperandVal, Flag);
+            Flag = Chain.getValue(1);
+            
+            ResOp = DAG.getRegister(InRegs.Regs[0], InRegs.RegVT);
+          } else {
+            for (unsigned i = 0, e = InRegs.Regs.size(); i != e; ++i) {
+              SDOperand Part = DAG.getNode(ISD::EXTRACT_ELEMENT, InRegs.RegVT,
+                                           InOperandVal, 
+                                           DAG.getConstant(i, MVT::i32));
+              Chain = DAG.getCopyToReg(Chain, InRegs.Regs[i], Part, Flag);
+              Flag = Chain.getValue(1);
+            }
+            ResOp = DAG.getRegister(InRegs.Regs[0], InRegs.RegVT);
+          }
           
-          ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]);
           ResOpType = 1;
           break;
         }
@@ -1411,26 +1543,18 @@
 
   // If this asm returns a register value, copy the result from that register
   // and set it as the value of the call.
-  if (RetValReg) {
-    SDOperand Val = DAG.getCopyFromReg(Chain, RetValReg,
-                                       TLI.getValueType(I.getType()), Flag);
-    Chain = Val.getValue(1);
-    Flag  = Val.getValue(2);
-    setValue(&I, Val);
-  }
+  if (!RetValRegs.Regs.empty())
+    setValue(&I, RetValRegs.getCopyFromRegs(DAG, Chain, Flag));
   
   std::vector<std::pair<SDOperand, Value*> > StoresToEmit;
   
   // Process indirect outputs, first output all of the flagged copies out of
   // physregs.
   for (unsigned i = 0, e = IndirectStoresToEmit.size(); i != e; ++i) {
+    RegsForValue &OutRegs = IndirectStoresToEmit[i].first;
     Value *Ptr = IndirectStoresToEmit[i].second;
-    const Type *Ty = cast<PointerType>(Ptr->getType())->getElementType();
-    SDOperand Val = DAG.getCopyFromReg(Chain, IndirectStoresToEmit[i].first, 
-                                       TLI.getValueType(Ty), Flag);
-    Chain = Val.getValue(1);
-    Flag  = Val.getValue(2);
-    StoresToEmit.push_back(std::make_pair(Val, Ptr));
+    SDOperand OutVal = OutRegs.getCopyFromRegs(DAG, Chain, Flag);
+    StoresToEmit.push_back(std::make_pair(OutVal, Ptr));
   }
   
   // Emit the non-flagged stores from the physregs.
@@ -1689,8 +1813,8 @@
           SDOperand Value = getMemsetValue(Op2, VT, DAG);
           SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, getRoot(),
                                         Value,
-                                        getMemBasePlusOffset(Op1, Offset, DAG, TLI),
-                                        DAG.getSrcValue(I.getOperand(1), Offset));
+                                    getMemBasePlusOffset(Op1, Offset, DAG, TLI),
+                                      DAG.getSrcValue(I.getOperand(1), Offset));
           OutChains.push_back(Store);
           Offset += VTSize;
         }






More information about the llvm-commits mailing list