[llvm-commits] [llvm] r156515 - in /llvm/trunk: lib/Transforms/InstCombine/InstCombineCalls.cpp test/Transforms/InstCombine/objsize.ll

Nuno Lopes nunoplopes at sapo.pt
Wed May 9 14:30:57 PDT 2012


Author: nlopes
Date: Wed May  9 16:30:57 2012
New Revision: 156515

URL: http://llvm.org/viewvc/llvm-project?rev=156515&view=rev
Log:
objectsize:
refactor code a bit to enable future changes to support run-time information
add support to compute allocation sizes at run-time if penalty > 1 (e.g., malloc(x), calloc(x, y), and VLAs)

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
    llvm/trunk/test/Transforms/InstCombine/objsize.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp?rev=156515&r1=156514&r2=156515&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp Wed May  9 16:30:57 2012
@@ -165,6 +165,72 @@
   return 0;
 }
 
+/// computeAllocSize - compute the object size allocated by an allocation
+/// site. Returns 0 if the size is not constant (in SizeValue), 1 if the size
+/// is constant (in Size), and 2 if the size could not be determined within the
+/// given maximum Penalty that the computation would incurr at run-time.
+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()) {
+      Constant *C = GV->getInitializer();
+      Size = TD->getTypeAllocSize(C->getType());
+      return 1;
+    }
+    // Can't determine size of the GV.
+    return 2;
+
+  } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Alloc)) {
+    if (!AI->getAllocatedType()->isSized())
+      return 2;
+
+    Size = TD->getTypeAllocSize(AI->getAllocatedType());
+    if (!AI->isArrayAllocation())
+      return 1; // we are done
+
+    Value *ArraySize = AI->getArraySize();
+    if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
+      Size *= C->getZExtValue();
+      return 1;
+    }
+
+    if (Penalty < 2)
+      return 2;
+
+    SizeValue = Builder->CreateMul(Builder->getInt64(Size), ArraySize);
+    return 0;
+
+  } else if (CallInst *MI = extractMallocCall(Alloc)) {
+    SizeValue = MI->getArgOperand(0);
+    if (ConstantInt *CI = dyn_cast<ConstantInt>(SizeValue)) {
+      Size = CI->getZExtValue();
+      return 1;
+    }
+    return 0;
+
+  } else if (CallInst *MI = extractCallocCall(Alloc)) {
+    Value *Arg1 = MI->getArgOperand(0);
+    Value *Arg2 = MI->getArgOperand(1);
+    if (ConstantInt *CI1 = dyn_cast<ConstantInt>(Arg1)) {
+      if (ConstantInt *CI2 = dyn_cast<ConstantInt>(Arg2)) {
+        Size = (CI1->getValue() * CI2->getValue()).getZExtValue();
+        return 1;
+      }
+    }
+
+    if (Penalty < 2)
+      return 2;
+
+    SizeValue = Builder->CreateMul(Arg1, Arg2);
+    return 0;
+  }
+
+  DEBUG(errs() << "computeAllocSize failed:\n");
+  DEBUG(Alloc->dump());
+  return 2;
+}
+
 /// visitCallInst - CallInst simplification.  This mostly only handles folding
 /// of intrinsic instructions.  For normal calls, it allows visitCallSite to do
 /// the heavy lifting.
@@ -250,13 +316,14 @@
     if (!TD) return 0;
 
     Type *ReturnTy = CI.getType();
-    uint64_t DontKnow = II->getArgOperand(1) == Builder->getTrue() ? 0 : -1ULL;
+    uint64_t Penalty = cast<ConstantInt>(II->getArgOperand(2))->getZExtValue();
 
     // Get to the real allocated thing and offset as fast as possible.
     Value *Op1 = II->getArgOperand(0)->stripPointerCasts();
 
     uint64_t Offset = 0;
-    uint64_t Size = -1ULL;
+    Value *OffsetValue;
+    bool ConstOffset = true;
 
     // Try to look through constant GEPs.
     if (GEPOperator *GEP = dyn_cast<GEPOperator>(Op1)) {
@@ -270,66 +337,40 @@
       Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
 
       Op1 = GEP->getPointerOperand()->stripPointerCasts();
-
-      // Make sure we're not a constant offset from an external
-      // global.
-      if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Op1))
-        if (!GV->hasDefinitiveInitializer()) return 0;
     }
 
-    // If we've stripped down to a single global variable that we
-    // can know the size of then just return that.
-    if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Op1)) {
-      if (GV->hasDefinitiveInitializer()) {
-        Constant *C = GV->getInitializer();
-        Size = TD->getTypeAllocSize(C->getType());
-      } else {
-        // Can't determine size of the GV.
-        Constant *RetVal = ConstantInt::get(ReturnTy, DontKnow);
-        return ReplaceInstUsesWith(CI, RetVal);
-      }
-    } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Op1)) {
-      // Get alloca size.
-      if (AI->getAllocatedType()->isSized()) {
-        Size = TD->getTypeAllocSize(AI->getAllocatedType());
-        if (AI->isArrayAllocation()) {
-          const ConstantInt *C = dyn_cast<ConstantInt>(AI->getArraySize());
-          if (!C) return 0;
-          Size *= C->getZExtValue();
-        }
-      }
-    } else if (CallInst *MI = extractMallocCall(Op1)) {
-      // Get allocation size.
-      Value *Arg = MI->getArgOperand(0);
-      if (ConstantInt *CI = dyn_cast<ConstantInt>(Arg))
-          Size = CI->getZExtValue();
-
-    } else if (CallInst *MI = extractCallocCall(Op1)) {
-      // Get allocation size.
-      Value *Arg1 = MI->getArgOperand(0);
-      Value *Arg2 = MI->getArgOperand(1);
-      if (ConstantInt *CI1 = dyn_cast<ConstantInt>(Arg1))
-        if (ConstantInt *CI2 = dyn_cast<ConstantInt>(Arg2)) {
-          bool overflow;
-          APInt SizeAP = CI1->getValue().umul_ov(CI2->getValue(), overflow);
-          if (!overflow)
-            Size = SizeAP.getZExtValue();
-          else
-            return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, DontKnow));
-        }
-    }
+    uint64_t Size;
+    Value *SizeValue;
+    int ConstAlloc = computeAllocSize(Op1, Size, SizeValue, Penalty, TD,
+                                      Builder);
 
     // Do not return "I don't know" here. Later optimization passes could
     // make it possible to evaluate objectsize to a constant.
-    if (Size == -1ULL)
+    if (ConstAlloc == 2)
       return 0;
 
-    if (Size < Offset) {
-      // Out of bound reference? Negative index normalized to large
-      // index? Just return "I don't know".
-      return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, DontKnow));
-    }
-    return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, Size-Offset));
+    if (ConstOffset && 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);
+
+    } else
+      return 0;
   }
   case Intrinsic::bswap:
     // bswap(bswap(x)) -> x

Modified: llvm/trunk/test/Transforms/InstCombine/objsize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/objsize.ll?rev=156515&r1=156514&r2=156515&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/objsize.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/objsize.ll Wed May  9 16:30:57 2012
@@ -42,7 +42,7 @@
 
 define i1 @baz() nounwind {
 ; CHECK: @baz
-; CHECK-NEXT: ret i1 true
+; CHECK-NEXT: objectsize
   %1 = tail call i32 @llvm.objectsize.i32(i8* getelementptr inbounds ([0 x i8]* @window, i32 0, i32 0), i1 false, i32 0)
   %2 = icmp eq i32 %1, -1
   ret i1 %2
@@ -168,13 +168,3 @@
 ; CHECK-NEXT: ret i32 30
   ret i32 %objsize
 }
-
-; test for overflow in calloc
-define i32 @test9() {
-; CHECK: @test9
-  %alloc = call noalias i8* @calloc(i32 100000000, i32 100000000) nounwind
-  %gep = getelementptr inbounds i8* %alloc, i32 2
-  %objsize = call i32 @llvm.objectsize.i32(i8* %gep, i1 true, i32 0) nounwind readonly
-; CHECK-NEXT: ret i32 0
-  ret i32 %objsize
-}





More information about the llvm-commits mailing list