forked from OSchip/llvm-project
[Analysis] Centralize objectsize lowering logic.
We're currently doing nearly the same thing for @llvm.objectsize in three different places: two of them are missing checks for overflow, and one of them could subtly break if InstCombine gets much smarter about removing alloc sites. Seems like a good idea to not do that. llvm-svn: 290214
This commit is contained in:
parent
e52614b5c7
commit
3f08914e7e
|
@ -141,6 +141,16 @@ bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
|
||||||
const TargetLibraryInfo *TLI, bool RoundToAlign = false,
|
const TargetLibraryInfo *TLI, bool RoundToAlign = false,
|
||||||
ObjSizeMode Mode = ObjSizeMode::Exact);
|
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;
|
typedef std::pair<APInt, APInt> SizeOffsetType;
|
||||||
|
|
||||||
/// \brief Evaluate the size and offset of an object pointed to by a Value*
|
/// \brief Evaluate the size and offset of an object pointed to by a Value*
|
||||||
|
|
|
@ -388,6 +388,36 @@ bool llvm::getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
|
||||||
return true;
|
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,
|
STATISTIC(ObjectVisitorArgument,
|
||||||
"Number of arguments with unsolved size and offset");
|
"Number of arguments with unsolved size and offset");
|
||||||
STATISTIC(ObjectVisitorLoad,
|
STATISTIC(ObjectVisitorLoad,
|
||||||
|
|
|
@ -1948,18 +1948,8 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, bool& ModifiedDT) {
|
||||||
default: break;
|
default: break;
|
||||||
case Intrinsic::objectsize: {
|
case Intrinsic::objectsize: {
|
||||||
// Lower all uses of llvm.objectsize.*
|
// Lower all uses of llvm.objectsize.*
|
||||||
uint64_t Size;
|
ConstantInt *RetVal =
|
||||||
Type *ReturnTy = CI->getType();
|
lowerObjectSizeCall(II, *DL, TLInfo, /*MustSucceed=*/true);
|
||||||
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);
|
|
||||||
}
|
|
||||||
// Substituting this can cause recursive simplifications, which can
|
// Substituting this can cause recursive simplifications, which can
|
||||||
// invalidate our iterator. Use a WeakVH to hold onto it in case this
|
// invalidate our iterator. Use a WeakVH to hold onto it in case this
|
||||||
// happens.
|
// happens.
|
||||||
|
|
|
@ -1440,17 +1440,12 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
||||||
|
|
||||||
switch (II->getIntrinsicID()) {
|
switch (II->getIntrinsicID()) {
|
||||||
default: break;
|
default: break;
|
||||||
case Intrinsic::objectsize: {
|
case Intrinsic::objectsize:
|
||||||
uint64_t Size;
|
if (ConstantInt *N =
|
||||||
if (getObjectSize(II->getArgOperand(0), Size, DL, &TLI)) {
|
lowerObjectSizeCall(II, DL, &TLI, /*MustSucceed=*/false))
|
||||||
APInt APSize(II->getType()->getIntegerBitWidth(), Size);
|
return replaceInstUsesWith(CI, N);
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
case Intrinsic::bswap: {
|
case Intrinsic::bswap: {
|
||||||
Value *IIOperand = II->getArgOperand(0);
|
Value *IIOperand = II->getArgOperand(0);
|
||||||
Value *X = nullptr;
|
Value *X = nullptr;
|
||||||
|
|
|
@ -2027,12 +2027,9 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
|
||||||
|
|
||||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
|
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
|
||||||
if (II->getIntrinsicID() == Intrinsic::objectsize) {
|
if (II->getIntrinsicID() == Intrinsic::objectsize) {
|
||||||
uint64_t Size;
|
ConstantInt *Result = lowerObjectSizeCall(II, DL, &TLI,
|
||||||
if (!getObjectSize(II->getArgOperand(0), Size, DL, &TLI)) {
|
/*MustSucceed=*/true);
|
||||||
ConstantInt *CI = cast<ConstantInt>(II->getArgOperand(1));
|
replaceInstUsesWith(*I, Result);
|
||||||
Size = CI->isZero() ? -1ULL : 0;
|
|
||||||
}
|
|
||||||
replaceInstUsesWith(*I, ConstantInt::get(I->getType(), Size));
|
|
||||||
eraseInstFromFunction(*I);
|
eraseInstFromFunction(*I);
|
||||||
Users[i] = nullptr; // Skip examining in the next loop.
|
Users[i] = nullptr; // Skip examining in the next loop.
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,38 @@
|
||||||
; RUN: opt -codegenprepare -S < %s | FileCheck %s
|
; 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>
|
; #include<stdlib.h>
|
||||||
; #define STATIC_BUF_SIZE 10
|
; #define STATIC_BUF_SIZE 10
|
||||||
; #define LARGER_BUF_SIZE 30
|
; #define LARGER_BUF_SIZE 30
|
||||||
|
@ -87,4 +120,4 @@ entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @printf(i8* nocapture readonly, ...)
|
declare i32 @printf(i8* nocapture readonly, ...)
|
||||||
|
|
Loading…
Reference in New Issue