Implement PR1795, an instcombine hack for forming GEPs with integer pointer arithmetic.
authorChris Lattner <sabre@nondot.org>
Tue, 8 Jan 2008 07:23:51 +0000 (07:23 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 8 Jan 2008 07:23:51 +0000 (07:23 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@45745 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/InstructionCombining.cpp
test/Transforms/InstCombine/add2.ll

index 19f86f9b9c45972c8b4de1a63fe7d79fa8ed44f8..93fad0a1fae069c784d521ea2cf8635806621af5 100644 (file)
@@ -210,7 +210,7 @@ namespace {
     Instruction *visitUIToFP(CastInst &CI);
     Instruction *visitSIToFP(CastInst &CI);
     Instruction *visitPtrToInt(CastInst &CI);
-    Instruction *visitIntToPtr(CastInst &CI);
+    Instruction *visitIntToPtr(IntToPtrInst &CI);
     Instruction *visitBitCast(BitCastInst &CI);
     Instruction *FoldSelectOpOp(SelectInst &SI, Instruction *TI,
                                 Instruction *FI);
@@ -7148,8 +7148,58 @@ Instruction *InstCombiner::visitPtrToInt(CastInst &CI) {
   return commonPointerCastTransforms(CI);
 }
 
-Instruction *InstCombiner::visitIntToPtr(CastInst &CI) {
-  return commonCastTransforms(CI);
+Instruction *InstCombiner::visitIntToPtr(IntToPtrInst &CI) {
+  if (Instruction *I = commonCastTransforms(CI))
+    return I;
+  
+  const Type *DestPointee = cast<PointerType>(CI.getType())->getElementType();
+  if (!DestPointee->isSized()) return 0;
+
+  // If this is inttoptr(add (ptrtoint x), cst), try to turn this into a GEP.
+  ConstantInt *Cst;
+  Value *X;
+  if (match(CI.getOperand(0), m_Add(m_Cast<PtrToIntInst>(m_Value(X)),
+                                    m_ConstantInt(Cst)))) {
+    // If the source and destination operands have the same type, see if this
+    // is a single-index GEP.
+    if (X->getType() == CI.getType()) {
+      // Get the size of the pointee type.
+      uint64_t Size = TD->getABITypeSizeInBits(DestPointee);
+
+      // Convert the constant to intptr type.
+      APInt Offset = Cst->getValue();
+      Offset.sextOrTrunc(TD->getPointerSizeInBits());
+
+      // If Offset is evenly divisible by Size, we can do this xform.
+      if (Size && !APIntOps::srem(Offset, APInt(Offset.getBitWidth(), Size))){
+        Offset = APIntOps::sdiv(Offset, APInt(Offset.getBitWidth(), Size));
+        return new GetElementPtrInst(X, ConstantInt::get(Offset));
+      }
+    }
+    // TODO: Could handle other cases, e.g. where add is indexing into field of
+    // struct etc.
+  } else if (CI.getOperand(0)->hasOneUse() &&
+             match(CI.getOperand(0), m_Add(m_Value(X), m_ConstantInt(Cst)))) {
+    // Otherwise, if this is inttoptr(add x, cst), try to turn this into an
+    // "inttoptr+GEP" instead of "add+intptr".
+    
+    // Get the size of the pointee type.
+    uint64_t Size = TD->getABITypeSize(DestPointee);
+    
+    // Convert the constant to intptr type.
+    APInt Offset = Cst->getValue();
+    Offset.sextOrTrunc(TD->getPointerSizeInBits());
+    
+    // If Offset is evenly divisible by Size, we can do this xform.
+    if (Size && !APIntOps::srem(Offset, APInt(Offset.getBitWidth(), Size))){
+      Offset = APIntOps::sdiv(Offset, APInt(Offset.getBitWidth(), Size));
+      
+      Instruction *P = InsertNewInstBefore(new IntToPtrInst(X, CI.getType(),
+                                                            "tmp"), CI);
+      return new GetElementPtrInst(P, ConstantInt::get(Offset), "tmp");
+    }
+  }
+  return 0;
 }
 
 Instruction *InstCombiner::visitBitCast(BitCastInst &CI) {
index ff899461dd106779a7122fcf5408af54dd9c270a..de1bbf41b0981dbed13aa7b63fd8345309797c27 100644 (file)
@@ -1,6 +1,10 @@
 ; RUN: llvm-as < %s | opt -instcombine | llvm-dis | \
 ; RUN:    grep -v OK | not grep add
 
+;; Target triple for gep raising case below.
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
+target triple = "i686-apple-darwin8"
+
 define i64 @test1(i64 %A, i32 %B) {
         %tmp12 = zext i32 %B to i64
         %tmp3 = shl i64 %tmp12, 32
@@ -9,3 +13,19 @@ define i64 @test1(i64 %A, i32 %B) {
         ret i64 %tmp6
 }
 
+; PR1795
+define void @test2(i32 %.val24) {
+EntryBlock:
+        add i32 %.val24, -12
+        inttoptr i32 %0 to i32*
+        store i32 1, i32* %1
+        add i32 %.val24, -16
+        inttoptr i32 %2 to i32*
+        getelementptr i32* %3, i32 1
+        load i32* %4
+        tail call i32 @callee( i32 %5 )
+        ret void
+}
+
+declare i32 @callee(i32)
+