mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-22 13:29:44 +00:00
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:
parent
deaa3f3e52
commit
9d236f909c
@ -226,7 +226,7 @@ private:
|
|||||||
bool DoXform = true);
|
bool DoXform = true);
|
||||||
Instruction *transformSExtICmp(ICmpInst *ICI, Instruction &CI);
|
Instruction *transformSExtICmp(ICmpInst *ICI, Instruction &CI);
|
||||||
bool WillNotOverflowSignedAdd(Value *LHS, Value *RHS);
|
bool WillNotOverflowSignedAdd(Value *LHS, Value *RHS);
|
||||||
Value *EmitGEPOffset(User *GEP);
|
Value *EmitGEPOffset(User *GEP, bool NoNUW = false);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// InsertNewInstBefore - insert an instruction New before instruction Old
|
// InsertNewInstBefore - insert an instruction New before instruction Old
|
||||||
|
@ -423,7 +423,8 @@ Instruction *InstCombiner::visitFAdd(BinaryOperator &I) {
|
|||||||
/// EmitGEPOffset - Given a getelementptr instruction/constantexpr, emit the
|
/// EmitGEPOffset - Given a getelementptr instruction/constantexpr, emit the
|
||||||
/// code necessary to compute the offset from the base pointer (without adding
|
/// 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.
|
/// 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();
|
TargetData &TD = *getTargetData();
|
||||||
gep_type_iterator GTI = gep_type_begin(GEP);
|
gep_type_iterator GTI = gep_type_begin(GEP);
|
||||||
Type *IntPtrTy = TD.getIntPtrType(GEP->getContext());
|
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
|
// If the GEP is inbounds, we know that none of the addressing operations will
|
||||||
// overflow in an unsigned sense.
|
// 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.
|
// Build a mask for high order bits.
|
||||||
unsigned IntPtrWidth = TD.getPointerSizeInBits();
|
unsigned IntPtrWidth = TD.getPointerSizeInBits();
|
||||||
|
@ -173,7 +173,7 @@ static int computeAllocSize(Value *Alloc, uint64_t &Size, Value* &SizeValue,
|
|||||||
uint64_t Penalty, TargetData *TD,
|
uint64_t Penalty, TargetData *TD,
|
||||||
InstCombiner::BuilderTy *Builder) {
|
InstCombiner::BuilderTy *Builder) {
|
||||||
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Alloc)) {
|
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Alloc)) {
|
||||||
if (GV->hasUniqueInitializer()) {
|
if (GV->hasDefinitiveInitializer()) {
|
||||||
Constant *C = GV->getInitializer();
|
Constant *C = GV->getInitializer();
|
||||||
Size = TD->getTypeAllocSize(C->getType());
|
Size = TD->getTypeAllocSize(C->getType());
|
||||||
return 1;
|
return 1;
|
||||||
@ -198,7 +198,8 @@ static int computeAllocSize(Value *Alloc, uint64_t &Size, Value* &SizeValue,
|
|||||||
if (Penalty < 2)
|
if (Penalty < 2)
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
SizeValue = Builder->CreateMul(Builder->getInt64(Size), ArraySize);
|
SizeValue = ConstantInt::get(ArraySize->getType(), Size);
|
||||||
|
SizeValue = Builder->CreateMul(SizeValue, ArraySize);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} else if (CallInst *MI = extractMallocCall(Alloc)) {
|
} 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.
|
// Get to the real allocated thing and offset as fast as possible.
|
||||||
Value *Op1 = II->getArgOperand(0)->stripPointerCasts();
|
Value *Op1 = II->getArgOperand(0)->stripPointerCasts();
|
||||||
|
GEPOperator *GEP;
|
||||||
|
|
||||||
uint64_t Offset = 0;
|
if ((GEP = dyn_cast<GEPOperator>(Op1))) {
|
||||||
Value *OffsetValue;
|
// check if we will be able to get the offset
|
||||||
bool ConstOffset = true;
|
if (!GEP->hasAllConstantIndices() && Penalty < 2)
|
||||||
|
|
||||||
// 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())
|
|
||||||
return 0;
|
return 0;
|
||||||
Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
|
|
||||||
|
|
||||||
Op1 = GEP->getPointerOperand()->stripPointerCasts();
|
Op1 = GEP->getPointerOperand()->stripPointerCasts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,28 +340,36 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
|||||||
if (ConstAlloc == 2)
|
if (ConstAlloc == 2)
|
||||||
return 0;
|
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) {
|
if (Size < Offset) {
|
||||||
// Out of bounds
|
// Out of bounds
|
||||||
return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, 0));
|
return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, 0));
|
||||||
}
|
}
|
||||||
return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, Size-Offset));
|
return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, Size-Offset));
|
||||||
|
}
|
||||||
|
|
||||||
} else if (Penalty >= 2) {
|
if (!OffsetValue)
|
||||||
if (ConstOffset)
|
OffsetValue = ConstantInt::get(ReturnTy, Offset);
|
||||||
OffsetValue = Builder->getInt64(Offset);
|
if (ConstAlloc)
|
||||||
if (ConstAlloc)
|
SizeValue = ConstantInt::get(ReturnTy, Size);
|
||||||
SizeValue = Builder->getInt64(Size);
|
|
||||||
|
|
||||||
Value *Val = Builder->CreateSub(SizeValue, OffsetValue);
|
Value *Val = Builder->CreateSub(SizeValue, OffsetValue);
|
||||||
Val = Builder->CreateTrunc(Val, ReturnTy);
|
// return 0 if there's an overflow
|
||||||
// return 0 if there's an overflow
|
Value *Cmp = Builder->CreateICmpULT(SizeValue, OffsetValue);
|
||||||
Value *Cmp = Builder->CreateICmpULT(SizeValue, OffsetValue);
|
Val = Builder->CreateSelect(Cmp, ConstantInt::get(ReturnTy, 0), Val);
|
||||||
Val = Builder->CreateSelect(Cmp, ConstantInt::get(ReturnTy, 0), Val);
|
return ReplaceInstUsesWith(CI, Val);
|
||||||
return ReplaceInstUsesWith(CI, Val);
|
|
||||||
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
case Intrinsic::bswap:
|
case Intrinsic::bswap:
|
||||||
// bswap(bswap(x)) -> x
|
// bswap(bswap(x)) -> x
|
||||||
|
@ -168,3 +168,28 @@ define i32 @test8() {
|
|||||||
; CHECK-NEXT: ret i32 30
|
; CHECK-NEXT: ret i32 30
|
||||||
ret i32 %objsize
|
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
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user