objectsize: add support for GEPs with non-constant indexes
authorNuno Lopes <nunoplopes@sapo.pt>
Thu, 10 May 2012 23:17:35 +0000 (23:17 +0000)
committerNuno Lopes <nunoplopes@sapo.pt>
Thu, 10 May 2012 23:17:35 +0000 (23:17 +0000)
add an additional parameter to InstCombiner::EmitGEPOffset() to force it to *not* emit operations with NUW flag

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

lib/Transforms/InstCombine/InstCombine.h
lib/Transforms/InstCombine/InstCombineAddSub.cpp
lib/Transforms/InstCombine/InstCombineCalls.cpp
test/Transforms/InstCombine/objsize.ll

index 199df519ce07827f260934fe53c6459984f89744..41b2456e728ff56239312f4977ce576ab77de048 100644 (file)
@@ -226,7 +226,7 @@ private:
                                  bool DoXform = true);
   Instruction *transformSExtICmp(ICmpInst *ICI, Instruction &CI);
   bool WillNotOverflowSignedAdd(Value *LHS, Value *RHS);
-  Value *EmitGEPOffset(User *GEP);
+  Value *EmitGEPOffset(User *GEP, bool NoNUW = false);
 
 public:
   // InsertNewInstBefore - insert an instruction New before instruction Old
index 6a39fc33d488be4113d0c9261c682d547473193c..8420a6a96e47d92a345b2d34a2b345c79a426b6d 100644 (file)
@@ -423,7 +423,8 @@ Instruction *InstCombiner::visitFAdd(BinaryOperator &I) {
 /// EmitGEPOffset - Given a getelementptr instruction/constantexpr, emit the
 /// code necessary to compute the offset from the base pointer (without adding
 /// in the base pointer).  Return the result as a signed integer of intptr size.
-Value *InstCombiner::EmitGEPOffset(User *GEP) {
+/// If NoNUW is true, then the NUW flag is not used.
+Value *InstCombiner::EmitGEPOffset(User *GEP, bool NoNUW) {
   TargetData &TD = *getTargetData();
   gep_type_iterator GTI = gep_type_begin(GEP);
   Type *IntPtrTy = TD.getIntPtrType(GEP->getContext());
@@ -431,7 +432,7 @@ Value *InstCombiner::EmitGEPOffset(User *GEP) {
 
   // If the GEP is inbounds, we know that none of the addressing operations will
   // overflow in an unsigned sense.
-  bool isInBounds = cast<GEPOperator>(GEP)->isInBounds();
+  bool isInBounds = cast<GEPOperator>(GEP)->isInBounds() && !NoNUW;
   
   // Build a mask for high order bits.
   unsigned IntPtrWidth = TD.getPointerSizeInBits();
index 82487a020f11fd5767c18aae79f777fa4f9bb01e..ea3f95ed2303eecdb6e292143b6339da0f561680 100644 (file)
@@ -173,7 +173,7 @@ static int computeAllocSize(Value *Alloc, uint64_t &Size, Value* &SizeValue,
                             uint64_t Penalty, TargetData *TD,
                             InstCombiner::BuilderTy *Builder) {
   if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Alloc)) {
-    if (GV->hasUniqueInitializer()) {
+    if (GV->hasDefinitiveInitializer()) {
       Constant *C = GV->getInitializer();
       Size = TD->getTypeAllocSize(C->getType());
       return 1;
@@ -198,7 +198,8 @@ static int computeAllocSize(Value *Alloc, uint64_t &Size, Value* &SizeValue,
     if (Penalty < 2)
       return 2;
 
-    SizeValue = Builder->CreateMul(Builder->getInt64(Size), ArraySize);
+    SizeValue = ConstantInt::get(ArraySize->getType(), Size);
+    SizeValue = Builder->CreateMul(SizeValue, ArraySize);
     return 0;
 
   } else if (CallInst *MI = extractMallocCall(Alloc)) {
@@ -320,22 +321,12 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
 
     // Get to the real allocated thing and offset as fast as possible.
     Value *Op1 = II->getArgOperand(0)->stripPointerCasts();
+    GEPOperator *GEP;
 
-    uint64_t Offset = 0;
-    Value *OffsetValue;
-    bool ConstOffset = true;
-
-    // Try to look through constant GEPs.
-    if (GEPOperator *GEP = dyn_cast<GEPOperator>(Op1)) {
-      if (!GEP->hasAllConstantIndices()) return 0;
-
-      // Get the current byte offset into the thing. Use the original
-      // operand in case we're looking through a bitcast.
-      SmallVector<Value*, 8> Ops(GEP->idx_begin(), GEP->idx_end());
-      if (!GEP->getPointerOperandType()->isPointerTy())
+    if ((GEP = dyn_cast<GEPOperator>(Op1))) {
+      // check if we will be able to get the offset
+      if (!GEP->hasAllConstantIndices() && Penalty < 2)
         return 0;
-      Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
-
       Op1 = GEP->getPointerOperand()->stripPointerCasts();
     }
 
@@ -349,28 +340,36 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
     if (ConstAlloc == 2)
       return 0;
 
-    if (ConstOffset && ConstAlloc) {
+    uint64_t Offset = 0;
+    Value *OffsetValue = 0;
+
+    if (GEP) {
+      if (GEP->hasAllConstantIndices()) {
+        SmallVector<Value*, 8> Ops(GEP->idx_begin(), GEP->idx_end());
+        assert(GEP->getPointerOperandType()->isPointerTy());
+        Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
+      } else
+        OffsetValue = EmitGEPOffset(GEP, true /*NoNUW*/);
+    }
+
+    if (!OffsetValue && ConstAlloc) {
       if (Size < Offset) {
         // Out of bounds
         return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, 0));
       }
       return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, Size-Offset));
+    }
 
-    } else if (Penalty >= 2) {
-      if (ConstOffset)
-        OffsetValue = Builder->getInt64(Offset);
-      if (ConstAlloc)
-        SizeValue = Builder->getInt64(Size);
-
-      Value *Val = Builder->CreateSub(SizeValue, OffsetValue);
-      Val = Builder->CreateTrunc(Val, ReturnTy);
-      // return 0 if there's an overflow
-      Value *Cmp = Builder->CreateICmpULT(SizeValue, OffsetValue);
-      Val = Builder->CreateSelect(Cmp, ConstantInt::get(ReturnTy, 0), Val);
-      return ReplaceInstUsesWith(CI, Val);
+    if (!OffsetValue)
+      OffsetValue = ConstantInt::get(ReturnTy, Offset);
+    if (ConstAlloc)
+      SizeValue = ConstantInt::get(ReturnTy, Size);
 
-    } else
-      return 0;
+    Value *Val = Builder->CreateSub(SizeValue, OffsetValue);
+    // return 0 if there's an overflow
+    Value *Cmp = Builder->CreateICmpULT(SizeValue, OffsetValue);
+    Val = Builder->CreateSelect(Cmp, ConstantInt::get(ReturnTy, 0), Val);
+    return ReplaceInstUsesWith(CI, Val);
   }
   case Intrinsic::bswap:
     // bswap(bswap(x)) -> x
index 524a28f614b0da538ade914c462b43d93df3a12f..1e62a9354878b1d3ea09b469a1772199afcdb184 100644 (file)
@@ -168,3 +168,28 @@ define i32 @test8() {
 ; CHECK-NEXT: ret i32 30
   ret i32 %objsize
 }
+
+; CHECK: @test9
+define i32 @test9(i32 %x, i32 %y) nounwind {
+  %a = alloca [3 x [4 x double]], align 8
+  %1 = getelementptr inbounds [3 x [4 x double]]* %a, i32 0, i32 %x
+  %2 = getelementptr inbounds [4 x double]* %1, i32 0, i32 %y
+  %3 = bitcast double* %2 to i8*
+  %objsize = call i32 @llvm.objectsize.i32(i8* %3, i1 false, i32 2)
+  ret i32 %objsize
+; CHECK-NEXT: shl i32 %x, 5
+; CHECK-NEXT: shl i32 %y, 3
+; CHECK-NEXT: add i32
+; CHECK-NEXT: sub i32 96,
+; CHECK-NEXT: icmp ugt i32 {{.*}}, 96
+; CHECK-NEXT: select i1 {{.*}}, i32 0, 
+}
+
+; CHECK: @overflow
+define i32 @overflow() {
+  %alloc = call noalias i8* @malloc(i32 21) nounwind
+  %gep = getelementptr inbounds i8* %alloc, i32 50
+  %objsize = call i32 @llvm.objectsize.i32(i8* %gep, i1 false, i32 0) nounwind readonly
+; CHECK-NEXT: ret i32 0
+  ret i32 %objsize
+}