Factor out the code for sign-extending/truncating gep indices
authorDan Gohman <gohman@apple.com>
Mon, 8 Dec 2008 07:57:47 +0000 (07:57 +0000)
committerDan Gohman <gohman@apple.com>
Mon, 8 Dec 2008 07:57:47 +0000 (07:57 +0000)
and use it in x86 address mode folding. Also, make
getRegForValue return 0 for illegal types even if it has a
ValueMap for them, because Argument values are put in the
ValueMap. This fixes PR3181.

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

include/llvm/CodeGen/FastISel.h
lib/CodeGen/SelectionDAG/FastISel.cpp
lib/Target/X86/X86FastISel.cpp
test/CodeGen/X86/fast-isel-gep-sext.ll [new file with mode: 0644]

index 71db9b580239433bbe720e944e7c27b05e39bc52..1cc83106052e3168e59e1255df081f5e08c1dc7b 100644 (file)
@@ -106,6 +106,11 @@ public:
   /// defined locally.
   unsigned lookUpRegForValue(Value *V);
 
+  /// getRegForGEPIndex - This is a wrapper around getRegForValue that also
+  /// takes care of truncating or sign-extending the given getelementptr
+  /// index value.
+  unsigned getRegForGEPIndex(Value *V);
+
   virtual ~FastISel();
 
 protected:
index 037a46d382cfba59100edadbce4c810859510c1f..3d0348d5d118e118472c186a3cb0e8be2f7dc7b4 100644 (file)
 using namespace llvm;
 
 unsigned FastISel::getRegForValue(Value *V) {
-  // Look up the value to see if we already have a register for it. We
-  // cache values defined by Instructions across blocks, and other values
-  // only locally. This is because Instructions already have the SSA
-  // def-dominatess-use requirement enforced.
-  if (ValueMap.count(V))
-    return ValueMap[V];
-  unsigned Reg = LocalValueMap[V];
-  if (Reg != 0)
-    return Reg;
-
   MVT::SimpleValueType VT = TLI.getValueType(V->getType()).getSimpleVT();
 
-  // Ignore illegal types.
+  // Ignore illegal types. We must do this before looking up the value
+  // in ValueMap because Arguments are given virtual registers regardless
+  // of whether FastISel can handle them.
   if (!TLI.isTypeLegal(VT)) {
     // Promote MVT::i1 to a legal type though, because it's common and easy.
     if (VT == MVT::i1)
@@ -76,6 +68,16 @@ unsigned FastISel::getRegForValue(Value *V) {
       return 0;
   }
 
+  // Look up the value to see if we already have a register for it. We
+  // cache values defined by Instructions across blocks, and other values
+  // only locally. This is because Instructions already have the SSA
+  // def-dominatess-use requirement enforced.
+  if (ValueMap.count(V))
+    return ValueMap[V];
+  unsigned Reg = LocalValueMap[V];
+  if (Reg != 0)
+    return Reg;
+
   if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
     if (CI->getValue().getActiveBits() <= 64)
       Reg = FastEmit_i(VT, VT, ISD::Constant, CI->getZExtValue());
@@ -153,6 +155,24 @@ void FastISel::UpdateValueMap(Value* I, unsigned Reg) {
                      Reg, MRI.getRegClass(Reg), MRI.getRegClass(Reg));
 }
 
+unsigned FastISel::getRegForGEPIndex(Value *Idx) {
+  unsigned IdxN = getRegForValue(Idx);
+  if (IdxN == 0)
+    // Unhandled operand. Halt "fast" selection and bail.
+    return 0;
+
+  // If the index is smaller or larger than intptr_t, truncate or extend it.
+  MVT PtrVT = TLI.getPointerTy();
+  MVT IdxVT = MVT::getMVT(Idx->getType(), /*HandleUnknown=*/false);
+  if (IdxVT.bitsLT(PtrVT))
+    IdxN = FastEmit_r(IdxVT.getSimpleVT(), PtrVT.getSimpleVT(),
+                      ISD::SIGN_EXTEND, IdxN);
+  else if (IdxVT.bitsGT(PtrVT))
+    IdxN = FastEmit_r(IdxVT.getSimpleVT(), PtrVT.getSimpleVT(),
+                      ISD::TRUNCATE, IdxN);
+  return IdxN;
+}
+
 /// SelectBinaryOp - Select and emit code for a binary operator instruction,
 /// which has an opcode which directly corresponds to the given ISD opcode.
 ///
@@ -263,18 +283,7 @@ bool FastISel::SelectGetElementPtr(User *I) {
       
       // N = N + Idx * ElementSize;
       uint64_t ElementSize = TD.getABITypeSize(Ty);
-      unsigned IdxN = getRegForValue(Idx);
-      if (IdxN == 0)
-        // Unhandled operand. Halt "fast" selection and bail.
-        return false;
-
-      // If the index is smaller or larger than intptr_t, truncate or extend
-      // it.
-      MVT IdxVT = MVT::getMVT(Idx->getType(), /*HandleUnknown=*/false);
-      if (IdxVT.bitsLT(VT))
-        IdxN = FastEmit_r(IdxVT.getSimpleVT(), VT, ISD::SIGN_EXTEND, IdxN);
-      else if (IdxVT.bitsGT(VT))
-        IdxN = FastEmit_r(IdxVT.getSimpleVT(), VT, ISD::TRUNCATE, IdxN);
+      unsigned IdxN = getRegForGEPIndex(Idx);
       if (IdxN == 0)
         // Unhandled operand. Halt "fast" selection and bail.
         return false;
index b280d65290140fdd4b42d79bc1a02fc43f74feb9..04a26303dcf7bd0f0cf962781a55b732fa7ae695 100644 (file)
@@ -372,8 +372,8 @@ bool X86FastISel::X86SelectAddress(Value *V, X86AddressMode &AM, bool isCall) {
     unsigned IndexReg = AM.IndexReg;
     unsigned Scale = AM.Scale;
     gep_type_iterator GTI = gep_type_begin(U);
-    // Look at all but the last index. Constants can be folded,
-    // and one dynamic index can be handled, if the scale is supported.
+    // Iterate through the indices, folding what we can. Constants can be
+    // folded, and one dynamic index can be handled, if the scale is supported.
     for (User::op_iterator i = U->op_begin() + 1, e = U->op_end();
          i != e; ++i, ++GTI) {
       Value *Op = *i;
@@ -392,7 +392,7 @@ bool X86FastISel::X86SelectAddress(Value *V, X86AddressMode &AM, bool isCall) {
                    (S == 1 || S == 2 || S == 4 || S == 8)) {
           // Scaled-index addressing.
           Scale = S;
-          IndexReg = getRegForValue(Op);
+          IndexReg = getRegForGEPIndex(Op);
           if (IndexReg == 0)
             return false;
         } else
diff --git a/test/CodeGen/X86/fast-isel-gep-sext.ll b/test/CodeGen/X86/fast-isel-gep-sext.ll
new file mode 100644 (file)
index 0000000..ec420ff
--- /dev/null
@@ -0,0 +1,17 @@
+; RUN: llvm-as < %s | llc -march=x86-64 -fast | grep movslq
+; RUN: llvm-as < %s | llc -march=x86 -fast
+; PR3181
+
+; GEP indices are interpreted as signed integers, so they
+; should be sign-extended to 64 bits on 64-bit targets.
+
+define i32 @foo(i32 %t3, i32* %t1) nounwind {
+       %t9 = getelementptr i32* %t1, i32 %t3           ; <i32*> [#uses=1]
+       %t15 = load i32* %t9            ; <i32> [#uses=1]
+       ret i32 %t15
+}
+define i32 @bar(i64 %t3, i32* %t1) nounwind {
+       %t9 = getelementptr i32* %t1, i64 %t3           ; <i32*> [#uses=1]
+       %t15 = load i32* %t9            ; <i32> [#uses=1]
+       ret i32 %t15
+}