objectsize: add support for GEPs with non-constant indexes

add an additional parameter to InstCombiner::EmitGEPOffset() to force it to *not* emit operations with NUW flag

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@156585 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Nuno Lopes
2012-05-10 23:17:35 +00:00
parent deaa3f3e52
commit 9d236f909c
4 changed files with 59 additions and 34 deletions

View File

@@ -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

View File

@@ -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<GEPOperator>(GEP)->isInBounds();
bool isInBounds = cast<GEPOperator>(GEP)->isInBounds() && !NoNUW;
// Build a mask for high order bits.
unsigned IntPtrWidth = TD.getPointerSizeInBits();

View File

@@ -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<GlobalVariable>(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<GEPOperator>(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<Value*, 8> Ops(GEP->idx_begin(), GEP->idx_end());
if (!GEP->getPointerOperandType()->isPointerTy())
if ((GEP = dyn_cast<GEPOperator>(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<Value*, 8> 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