aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Transforms/InstCombine/InstCombineCalls.cpp31
-rw-r--r--test/Transforms/InstCombine/objsize.ll20
2 files changed, 42 insertions, 9 deletions
diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 88d8abdeb7..a241f169f2 100644
--- a/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -304,29 +304,39 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
switch (II->getIntrinsicID()) {
default: break;
case Intrinsic::objectsize: {
- const Type *ReturnTy = CI.getType();
- Value *Op1 = II->getOperand(1);
- bool Min = (cast<ConstantInt>(II->getOperand(2))->getZExtValue() == 1);
-
// We need target data for just about everything so depend on it.
if (!TD) break;
+ const Type *ReturnTy = CI.getType();
+ bool Min = (cast<ConstantInt>(II->getOperand(2))->getZExtValue() == 1);
+
// Get to the real allocated thing and offset as fast as possible.
- Op1 = Op1->stripPointerCasts();
+ Value *Op1 = II->getOperand(1)->stripPointerCasts();
// 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();
- uint64_t globalSize = TD->getTypeAllocSize(C->getType());
- return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, globalSize));
+ uint64_t GlobalSize = TD->getTypeAllocSize(C->getType());
+ return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, GlobalSize));
} else {
+ // Can't determine size of the GV.
Constant *RetVal = ConstantInt::get(ReturnTy, Min ? 0 : -1ULL);
return ReplaceInstUsesWith(CI, RetVal);
}
- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Op1)) {
-
+ } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Op1)) {
+ // Get alloca size.
+ if (AI->getAllocatedType()->isSized()) {
+ uint64_t AllocaSize = TD->getTypeAllocSize(AI->getAllocatedType());
+ if (AI->isArrayAllocation()) {
+ const ConstantInt *C = dyn_cast<ConstantInt>(AI->getArraySize());
+ if (!C) break;
+ AllocaSize *= C->getZExtValue();
+ }
+ return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, AllocaSize));
+ }
+ } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Op1)) {
// Only handle constant GEPs here.
if (CE->getOpcode() != Instruction::GetElementPtr) break;
GEPOperator *GEP = cast<GEPOperator>(CE);
@@ -361,6 +371,9 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
return ReplaceInstUsesWith(CI, RetVal);
}
+
+ // Do not return "I don't know" here. Later optimization passes could
+ // make it possible to evaluate objectsize to a constant.
break;
}
case Intrinsic::bswap:
diff --git a/test/Transforms/InstCombine/objsize.ll b/test/Transforms/InstCombine/objsize.ll
index 9df122499e..bf1a37f975 100644
--- a/test/Transforms/InstCombine/objsize.ll
+++ b/test/Transforms/InstCombine/objsize.ll
@@ -102,4 +102,24 @@ bb12:
unreachable
}
+; rdar://7718857
+
+%struct.data = type { [100 x i32], [100 x i32], [1024 x i8] }
+
+define i32 @test4() nounwind ssp {
+; CHECK: @test4
+entry:
+ %0 = alloca %struct.data, align 8
+ %1 = bitcast %struct.data* %0 to i8*
+ %2 = call i64 @llvm.objectsize.i64(i8* %1, i1 false) nounwind
+; CHECK-NOT: @llvm.objectsize
+; CHECK: @__memset_chk(i8* %1, i32 0, i64 1824, i64 1824)
+ %3 = call i8* @__memset_chk(i8* %1, i32 0, i64 1824, i64 %2) nounwind
+ ret i32 0
+}
+
+declare i8* @__memset_chk(i8*, i32, i64, i64) nounwind
+
declare i32 @llvm.objectsize.i32(i8*, i1) nounwind readonly
+
+declare i64 @llvm.objectsize.i64(i8*, i1) nounwind readonly