diff --git a/lib/Transforms/InstCombine/InstCombine.h b/lib/Transforms/InstCombine/InstCombine.h index 199df519ce0..41b2456e728 100644 --- a/lib/Transforms/InstCombine/InstCombine.h +++ b/lib/Transforms/InstCombine/InstCombine.h @@ -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 diff --git a/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 6a39fc33d48..8420a6a96e4 100644 --- a/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -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(GEP)->isInBounds(); + bool isInBounds = cast(GEP)->isInBounds() && !NoNUW; // Build a mask for high order bits. unsigned IntPtrWidth = TD.getPointerSizeInBits(); diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 82487a020f1..ea3f95ed230 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -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(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(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 Ops(GEP->idx_begin(), GEP->idx_end()); - if (!GEP->getPointerOperandType()->isPointerTy()) + if ((GEP = dyn_cast(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 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); + if (!OffsetValue) + OffsetValue = ConstantInt::get(ReturnTy, Offset); + if (ConstAlloc) + SizeValue = ConstantInt::get(ReturnTy, 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; + 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 diff --git a/test/Transforms/InstCombine/objsize.ll b/test/Transforms/InstCombine/objsize.ll index 524a28f614b..1e62a935487 100644 --- a/test/Transforms/InstCombine/objsize.ll +++ b/test/Transforms/InstCombine/objsize.ll @@ -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 +}