[llvm-commits] CVS: llvm/lib/Target/X86/X86ISelDAGToDAG.cpp

Chris Lattner lattner at cs.uiuc.edu
Fri Nov 18 18:11:19 PST 2005



Changes in directory llvm/lib/Target/X86:

X86ISelDAGToDAG.cpp updated: 1.2 -> 1.3
---
Log message:

Add load and other support to the dag-dag isel.  Patch contributed by Evan
Cheng!


---
Diffs of the changes:  (+225 -2)

 X86ISelDAGToDAG.cpp |  227 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 225 insertions(+), 2 deletions(-)


Index: llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
diff -u llvm/lib/Target/X86/X86ISelDAGToDAG.cpp:1.2 llvm/lib/Target/X86/X86ISelDAGToDAG.cpp:1.3
--- llvm/lib/Target/X86/X86ISelDAGToDAG.cpp:1.2	Wed Nov 16 16:59:19 2005
+++ llvm/lib/Target/X86/X86ISelDAGToDAG.cpp	Fri Nov 18 20:11:08 2005
@@ -15,6 +15,8 @@
 #include "X86.h"
 #include "X86Subtarget.h"
 #include "X86ISelLowering.h"
+#include "llvm/GlobalValue.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/SelectionDAGISel.h"
 #include "llvm/Target/TargetMachine.h"
@@ -27,6 +29,32 @@
 //===----------------------------------------------------------------------===//
 
 namespace {
+  /// X86ISelAddressMode - This corresponds to X86AddressMode, but uses
+  /// SDOperand's instead of register numbers for the leaves of the matched
+  /// tree.
+  struct X86ISelAddressMode {
+    enum {
+      RegBase,
+      FrameIndexBase,
+    } BaseType;
+
+    struct {            // This is really a union, discriminated by BaseType!
+      SDOperand Reg;
+      int FrameIndex;
+    } Base;
+
+    unsigned Scale;
+    SDOperand IndexReg; 
+    unsigned Disp;
+    GlobalValue *GV;
+
+    X86ISelAddressMode()
+      : BaseType(RegBase), Scale(1), IndexReg(), Disp(), GV(0) {
+    }
+  };
+}
+
+namespace {
   Statistic<>
   NumFPKill("x86-codegen", "Number of FP_REG_KILL instructions added");
 
@@ -66,6 +94,15 @@
   private:
     SDOperand Select(SDOperand N);
 
+    void SelectAddress(SDOperand N, X86ISelAddressMode &AM);
+    bool MatchAddress(SDOperand N, X86ISelAddressMode &AM);
+
+    /// getI8Imm - Return a target constant with the specified value, of type
+    /// i8.
+    inline SDOperand getI8Imm(unsigned Imm) {
+      return CurDAG->getTargetConstant(Imm, MVT::i8);
+    }
+
     /// getI16Imm - Return a target constant with the specified value, of type
     /// i16.
     inline SDOperand getI16Imm(unsigned Imm) {
@@ -93,6 +130,141 @@
   ScheduleAndEmitDAG(DAG);
 }
 
+/// SelectAddress - Pattern match the maximal addressing mode for this node.
+void X86DAGToDAGISel::SelectAddress(SDOperand N, X86ISelAddressMode &AM) {
+  MatchAddress(N, AM);
+
+  if (AM.BaseType == X86ISelAddressMode::RegBase && !AM.Base.Reg.Val) {
+    AM.Base.Reg = CurDAG->getRegister(0, MVT::i32);
+  } else {
+    AM.Base.Reg = Select(AM.Base.Reg);
+  }
+  if (!AM.IndexReg.Val) {
+    AM.IndexReg = CurDAG->getRegister(0, MVT::i32);
+  } else {
+    AM.IndexReg = Select(AM.IndexReg);
+  }
+}
+
+/// FIXME: copied from X86ISelPattern.cpp
+/// MatchAddress - Add the specified node to the specified addressing mode,
+/// returning true if it cannot be done.  This just pattern matches for the
+/// addressing mode
+bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM) {
+  switch (N.getOpcode()) {
+  default: break;
+  case ISD::FrameIndex:
+    if (AM.BaseType == X86ISelAddressMode::RegBase && AM.Base.Reg.Val == 0) {
+      AM.BaseType = X86ISelAddressMode::FrameIndexBase;
+      AM.Base.FrameIndex = cast<FrameIndexSDNode>(N)->getIndex();
+      return false;
+    }
+    break;
+  case ISD::GlobalAddress:
+    if (AM.GV == 0) {
+      GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal();
+      // For Darwin, external and weak symbols are indirect, so we want to load
+      // the value at address GV, not the value of GV itself.  This means that
+      // the GlobalAddress must be in the base or index register of the address,
+      // not the GV offset field.
+      if (Subtarget->getIndirectExternAndWeakGlobals() &&
+          (GV->hasWeakLinkage() || GV->isExternal())) {
+        break;
+      } else {
+        AM.GV = GV;
+        return false;
+      }
+    }
+    break;
+  case ISD::Constant:
+    AM.Disp += cast<ConstantSDNode>(N)->getValue();
+    return false;
+  case ISD::SHL:
+    if (AM.IndexReg.Val == 0 && AM.Scale == 1)
+      if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1))) {
+        unsigned Val = CN->getValue();
+        if (Val == 1 || Val == 2 || Val == 3) {
+          AM.Scale = 1 << Val;
+          SDOperand ShVal = N.Val->getOperand(0);
+
+          // Okay, we know that we have a scale by now.  However, if the scaled
+          // value is an add of something and a constant, we can fold the
+          // constant into the disp field here.
+          if (ShVal.Val->getOpcode() == ISD::ADD && ShVal.hasOneUse() &&
+              isa<ConstantSDNode>(ShVal.Val->getOperand(1))) {
+            AM.IndexReg = ShVal.Val->getOperand(0);
+            ConstantSDNode *AddVal =
+              cast<ConstantSDNode>(ShVal.Val->getOperand(1));
+            AM.Disp += AddVal->getValue() << Val;
+          } else {
+            AM.IndexReg = ShVal;
+          }
+          return false;
+        }
+      }
+    break;
+  case ISD::MUL:
+    // X*[3,5,9] -> X+X*[2,4,8]
+    if (AM.IndexReg.Val == 0 && AM.BaseType == X86ISelAddressMode::RegBase &&
+        AM.Base.Reg.Val == 0)
+      if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.Val->getOperand(1)))
+        if (CN->getValue() == 3 || CN->getValue() == 5 || CN->getValue() == 9) {
+          AM.Scale = unsigned(CN->getValue())-1;
+
+          SDOperand MulVal = N.Val->getOperand(0);
+          SDOperand Reg;
+
+          // Okay, we know that we have a scale by now.  However, if the scaled
+          // value is an add of something and a constant, we can fold the
+          // constant into the disp field here.
+          if (MulVal.Val->getOpcode() == ISD::ADD && MulVal.hasOneUse() &&
+              isa<ConstantSDNode>(MulVal.Val->getOperand(1))) {
+            Reg = MulVal.Val->getOperand(0);
+            ConstantSDNode *AddVal =
+              cast<ConstantSDNode>(MulVal.Val->getOperand(1));
+            AM.Disp += AddVal->getValue() * CN->getValue();
+          } else {
+            Reg = N.Val->getOperand(0);
+          }
+
+          AM.IndexReg = AM.Base.Reg = Reg;
+          return false;
+        }
+    break;
+
+  case ISD::ADD: {
+    X86ISelAddressMode Backup = AM;
+    if (!MatchAddress(N.Val->getOperand(0), AM) &&
+        !MatchAddress(N.Val->getOperand(1), AM))
+      return false;
+    AM = Backup;
+    if (!MatchAddress(N.Val->getOperand(1), AM) &&
+        !MatchAddress(N.Val->getOperand(0), AM))
+      return false;
+    AM = Backup;
+    break;
+  }
+  }
+
+  // Is the base register already occupied?
+  if (AM.BaseType != X86ISelAddressMode::RegBase || AM.Base.Reg.Val) {
+    // If so, check to see if the scale index register is set.
+    if (AM.IndexReg.Val == 0) {
+      AM.IndexReg = N;
+      AM.Scale = 1;
+      return false;
+    }
+
+    // Otherwise, we cannot select it.
+    return true;
+  }
+
+  // Default, generate it as a register.
+  AM.BaseType = X86ISelAddressMode::RegBase;
+  AM.Base.Reg = N;
+  return false;
+}
+
 SDOperand X86DAGToDAGISel::Select(SDOperand Op) {
   SDNode *N = Op.Val;
   MVT::ValueType OpVT = Op.getValueType();
@@ -103,6 +275,21 @@
   
   switch (N->getOpcode()) {
     default: break;
+    case ISD::SHL:
+      if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
+        if (CN->getValue() == 1) {   // X = SHL Y, 1  -> X = ADD Y, Y
+          switch (OpVT) {
+            default: assert(0 && "Cannot shift this type!");
+            case MVT::i8:  Opc = X86::ADD8rr; break;
+            case MVT::i16: Opc = X86::ADD16rr; break;
+            case MVT::i32: Opc = X86::ADD32rr; break;
+          }
+          SDOperand Tmp0 = Select(N->getOperand(0));
+          CurDAG->SelectNodeTo(N, Opc, MVT::i32, Tmp0, Tmp0);
+          return SDOperand(N, 0);
+        }
+      }
+
     case ISD::RET: {
       SDOperand Chain = Select(N->getOperand(0));     // Token chain.
       switch (N->getNumOperands()) {
@@ -131,11 +318,47 @@
       if (X86Lowering.getBytesToPopOnReturn() == 0)
         CurDAG->SelectNodeTo(N, X86::RET, MVT::Other, Chain);
       else
-        CurDAG->SelectNodeTo(N, X86::RET, MVT::Other, Chain,
-                             getI16Imm(X86Lowering.getBytesToPopOnReturn()));
+        CurDAG->SelectNodeTo(N, X86::RET, MVT::Other,
+                             getI16Imm(X86Lowering.getBytesToPopOnReturn()),
+                             Chain);
 
       return SDOperand(N, 0);
     }
+
+    case ISD::LOAD: {
+      switch (N->getValueType(0)) {
+        default: assert(0 && "Cannot load this type!");
+        case MVT::i1:
+        case MVT::i8:  Opc = X86::MOV8rm; break;
+        case MVT::i16: Opc = X86::MOV16rm; break;
+        case MVT::i32: Opc = X86::MOV32rm; break;
+        case MVT::f32: Opc = X86::MOVSSrm; break;
+        case MVT::f64: Opc = X86::FLD64m; ContainsFPCode = true; break;
+      }
+
+      if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(N->getOperand(1))){
+        unsigned CPIdx = BB->getParent()->getConstantPool()->
+          getConstantPoolIndex(CP->get());
+        // ???
+        assert(0 && "Can't handle load from constant pool!");
+      } else {
+        SDOperand Chain = Select(N->getOperand(0));     // Token chain.
+        X86ISelAddressMode AM;
+        SelectAddress(N->getOperand(1), AM);
+        SDOperand Scale = getI8Imm (AM.Scale);
+        SDOperand Disp  = AM.GV ? CurDAG->getTargetGlobalAddress(AM.GV, MVT::i32)
+          : getI32Imm(AM.Disp);
+        if (AM.BaseType == X86ISelAddressMode::RegBase) {
+          CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other,
+                               AM.Base.Reg, Scale, AM.IndexReg, Disp, Chain);
+        } else {
+          SDOperand Base = CurDAG->getFrameIndex(AM.Base.FrameIndex, MVT::i32);
+          CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other,
+                               Base, Scale, AM.IndexReg, Disp, Chain);
+        }
+      }
+      return SDOperand(N, Op.ResNo);
+    }
   }
 
   return SelectCode(Op);






More information about the llvm-commits mailing list