diff options
-rw-r--r-- | llvm/include/llvm/Analysis/MemoryBuiltins.h | 10 | ||||
-rw-r--r-- | llvm/lib/Analysis/MemoryBuiltins.cpp | 30 | ||||
-rw-r--r-- | llvm/lib/CodeGen/CodeGenPrepare.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 15 | ||||
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstructionCombining.cpp | 9 | ||||
-rw-r--r-- | llvm/test/Transforms/CodeGenPrepare/builtin-condition.ll | 35 |
6 files changed, 84 insertions, 29 deletions
diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h index 140b731c59d..b58f07e6947 100644 --- a/llvm/include/llvm/Analysis/MemoryBuiltins.h +++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h @@ -141,6 +141,16 @@ bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, const TargetLibraryInfo *TLI, bool RoundToAlign = false, ObjSizeMode Mode = ObjSizeMode::Exact); +/// Try to turn a call to @llvm.objectsize into an integer value of the given +/// Type. Returns null on failure. +/// If MustSucceed is true, this function will not return null, and may return +/// conservative values governed by the second argument of the call to +/// objectsize. +ConstantInt *lowerObjectSizeCall(IntrinsicInst *ObjectSize, + const DataLayout &DL, + const TargetLibraryInfo *TLI, + bool MustSucceed); + typedef std::pair<APInt, APInt> SizeOffsetType; /// \brief Evaluate the size and offset of an object pointed to by a Value* diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index 0f4bfb8e2fb..eaac506dec4 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -388,6 +388,36 @@ bool llvm::getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, return true; } +ConstantInt *llvm::lowerObjectSizeCall(IntrinsicInst *ObjectSize, + const DataLayout &DL, + const TargetLibraryInfo *TLI, + bool MustSucceed) { + assert(ObjectSize->getIntrinsicID() == Intrinsic::objectsize && + "ObjectSize must be a call to llvm.objectsize!"); + + bool MaxVal = cast<ConstantInt>(ObjectSize->getArgOperand(1))->isZero(); + ObjSizeMode Mode; + // Unless we have to fold this to something, try to be as accurate as + // possible. + if (MustSucceed) + Mode = MaxVal ? ObjSizeMode::Max : ObjSizeMode::Min; + else + Mode = ObjSizeMode::Exact; + + // FIXME: Does it make sense to just return a failure value if the size won't + // fit in the output and `!MustSucceed`? + uint64_t Size; + auto *ResultType = cast<IntegerType>(ObjectSize->getType()); + if (getObjectSize(ObjectSize->getArgOperand(0), Size, DL, TLI, false, Mode) && + isUIntN(ResultType->getBitWidth(), Size)) + return ConstantInt::get(ResultType, Size); + + if (!MustSucceed) + return nullptr; + + return ConstantInt::get(ResultType, MaxVal ? -1ULL : 0); +} + STATISTIC(ObjectVisitorArgument, "Number of arguments with unsolved size and offset"); STATISTIC(ObjectVisitorLoad, diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index 1e5d682a331..3dea9eb6b1f 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -1948,18 +1948,8 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, bool& ModifiedDT) { default: break; case Intrinsic::objectsize: { // Lower all uses of llvm.objectsize.* - uint64_t Size; - Type *ReturnTy = CI->getType(); - Constant *RetVal = nullptr; - ConstantInt *Op1 = cast<ConstantInt>(II->getArgOperand(1)); - ObjSizeMode Mode = Op1->isZero() ? ObjSizeMode::Max : ObjSizeMode::Min; - if (getObjectSize(II->getArgOperand(0), - Size, *DL, TLInfo, false, Mode)) { - RetVal = ConstantInt::get(ReturnTy, Size); - } else { - RetVal = ConstantInt::get(ReturnTy, - Mode == ObjSizeMode::Min ? 0 : -1ULL); - } + ConstantInt *RetVal = + lowerObjectSizeCall(II, *DL, TLInfo, /*MustSucceed=*/true); // Substituting this can cause recursive simplifications, which can // invalidate our iterator. Use a WeakVH to hold onto it in case this // happens. diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 4d432d56aa3..eb5c63433e7 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1440,17 +1440,12 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { switch (II->getIntrinsicID()) { default: break; - case Intrinsic::objectsize: { - uint64_t Size; - if (getObjectSize(II->getArgOperand(0), Size, DL, &TLI)) { - APInt APSize(II->getType()->getIntegerBitWidth(), Size); - // Equality check to be sure that `Size` can fit in a value of type - // `II->getType()` - if (APSize == Size) - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), APSize)); - } + case Intrinsic::objectsize: + if (ConstantInt *N = + lowerObjectSizeCall(II, DL, &TLI, /*MustSucceed=*/false)) + return replaceInstUsesWith(CI, N); return nullptr; - } + case Intrinsic::bswap: { Value *IIOperand = II->getArgOperand(0); Value *X = nullptr; diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 0d29c1dceea..9a52874c4c2 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2027,12 +2027,9 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) { if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) { if (II->getIntrinsicID() == Intrinsic::objectsize) { - uint64_t Size; - if (!getObjectSize(II->getArgOperand(0), Size, DL, &TLI)) { - ConstantInt *CI = cast<ConstantInt>(II->getArgOperand(1)); - Size = CI->isZero() ? -1ULL : 0; - } - replaceInstUsesWith(*I, ConstantInt::get(I->getType(), Size)); + ConstantInt *Result = lowerObjectSizeCall(II, DL, &TLI, + /*MustSucceed=*/true); + replaceInstUsesWith(*I, Result); eraseInstFromFunction(*I); Users[i] = nullptr; // Skip examining in the next loop. } diff --git a/llvm/test/Transforms/CodeGenPrepare/builtin-condition.ll b/llvm/test/Transforms/CodeGenPrepare/builtin-condition.ll index e18d1b0fc0e..0d41e9e1edd 100644 --- a/llvm/test/Transforms/CodeGenPrepare/builtin-condition.ll +++ b/llvm/test/Transforms/CodeGenPrepare/builtin-condition.ll @@ -1,5 +1,38 @@ ; RUN: opt -codegenprepare -S < %s | FileCheck %s +; Ensure we act sanely on overflow. +; CHECK-LABEL: define i32 @bar +define i32 @bar() { +entry: + ; CHECK: ret i32 -1 + %az = alloca [2147483649 x i32], align 16 + %a = alloca i8*, align 8 + %arraydecay = getelementptr inbounds [2147483649 x i32], [2147483649 x i32]* %az, i32 0, i32 0 + %0 = bitcast i32* %arraydecay to i8* + store i8* %0, i8** %a, align 8 + %1 = load i8*, i8** %a, align 8 + %2 = call i32 @llvm.objectsize.i32.p0i8(i8* %1, i1 false) + ret i32 %2 +} + +; CHECK-LABEL: define i32 @baz +define i32 @baz(i32 %n) { +entry: + ; CHECK: ret i32 -1 + %az = alloca [1 x i32], align 16 + %bz = alloca [4294967297 x i32], align 16 + %tobool = icmp ne i32 %n, 0 + %arraydecay = getelementptr inbounds [1 x i32], [1 x i32]* %az, i64 0, i64 0 + %arraydecay1 = getelementptr inbounds [4294967297 x i32], [4294967297 x i32]* %bz, i64 0, i64 0 + %cond = select i1 %tobool, i32* %arraydecay, i32* %arraydecay1 + %0 = bitcast i32* %cond to i8* + %1 = call i32 @llvm.objectsize.i32.p0i8(i8* %0, i1 false) + ret i32 %1 +} + +declare i32 @llvm.objectsize.i32.p0i8(i8*, i1) + +; The following tests were generated by: ; #include<stdlib.h> ; #define STATIC_BUF_SIZE 10 ; #define LARGER_BUF_SIZE 30 @@ -87,4 +120,4 @@ entry: ret void } -declare i32 @printf(i8* nocapture readonly, ...)
\ No newline at end of file +declare i32 @printf(i8* nocapture readonly, ...) |