Canonicalize indices in a constantexpr GEP. If Indices exceed the

static extents of the static array type, it causes GlobalOpt and
other passes to be more conservative. This canonicalization also
allows the constant folder to add "inbounds" to GEPs.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79440 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dan Gohman 2009-08-19 18:18:36 +00:00
parent 6a402dc952
commit de0e587e63
2 changed files with 98 additions and 4 deletions

View File

@ -131,6 +131,7 @@ static Constant *SymbolicallyEvaluateGEP(Constant* const* Ops, unsigned NumOps,
return 0;
uint64_t BasePtr = 0;
bool BaseIsInt = true;
if (!Ptr->isNullValue()) {
// If this is a inttoptr from a constant int, we can fold this as the base,
// otherwise we can't.
@ -140,19 +141,62 @@ static Constant *SymbolicallyEvaluateGEP(Constant* const* Ops, unsigned NumOps,
BasePtr = Base->getZExtValue();
if (BasePtr == 0)
return 0;
BaseIsInt = false;
}
// If this is a constant expr gep that is effectively computing an
// "offsetof", fold it into 'cast int Size to T*' instead of 'gep 0, 0, 12'
for (unsigned i = 1; i != NumOps; ++i)
if (!isa<ConstantInt>(Ops[i]))
return false;
return 0;
uint64_t Offset = TD->getIndexedOffset(Ptr->getType(),
(Value**)Ops+1, NumOps-1);
Constant *C = ConstantInt::get(TD->getIntPtrType(Context), Offset+BasePtr);
return ConstantExpr::getIntToPtr(C, ResultTy);
// If the base value for this address is a literal integer value, fold the
// getelementptr to the resulting integer value casted to the pointer type.
if (BaseIsInt) {
Constant *C = ConstantInt::get(TD->getIntPtrType(Context), Offset+BasePtr);
return ConstantExpr::getIntToPtr(C, ResultTy);
}
// Otherwise form a regular getelementptr. Recompute the indices so that
// we eliminate over-indexing of the notional static type array bounds.
// This makes it easy to determine if the getelementptr is "inbounds".
// Also, this helps GlobalOpt do SROA on GlobalVariables.
const Type *Ty = Ptr->getType();
SmallVector<Constant*, 32> NewIdxs;
for (unsigned Index = 1; Index != NumOps; ++Index) {
if (const SequentialType *ATy = dyn_cast<SequentialType>(Ty)) {
// Determine which element of the array the offset points into.
uint64_t ElemSize = TD->getTypeAllocSize(ATy->getElementType());
if (ElemSize == 0)
return 0;
uint64_t NewIdx = Offset / ElemSize;
Offset -= NewIdx * ElemSize;
NewIdxs.push_back(ConstantInt::get(TD->getIntPtrType(Context), NewIdx));
Ty = ATy->getElementType();
} else if (const StructType *STy = dyn_cast<StructType>(Ty)) {
// Determine which field of the struct the offset points into.
const StructLayout &SL = *TD->getStructLayout(STy);
unsigned ElIdx = SL.getElementContainingOffset(Offset);
NewIdxs.push_back(ConstantInt::get(Type::getInt32Ty(Context), ElIdx));
Offset -= SL.getElementOffset(ElIdx);
Ty = STy->getTypeAtIndex(ElIdx);
} else {
return 0;
}
}
// If the base is the start of a GlobalVariable and all the array indices
// remain in their static bounds, the GEP is inbounds. We can check that
// all indices are in bounds by just checking the first index only
// because we've just normalized all the indices.
if (isa<GlobalVariable>(Ptr) && NewIdxs[0]->isNullValue())
return ConstantExpr::getInBoundsGetElementPtr(Ptr,
&NewIdxs[0], NewIdxs.size());
// Otherwise it may not be inbounds.
return ConstantExpr::getGetElementPtr(Ptr, &NewIdxs[0], NewIdxs.size());
}
/// FoldBitCast - Constant fold bitcast, symbolically evaluating it with

View File

@ -0,0 +1,50 @@
; RUN: llvm-as < %s | opt -instcombine | llvm-dis | FileCheck %s
; Constant folding should fix notionally out-of-bounds indices
; and add inbounds keywords.
%struct.X = type { [3 x i32], [3 x i32] }
@Y = internal global [3 x %struct.X] zeroinitializer
define void @frob() {
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 0), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 0), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 1), align 4
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 1), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 2), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 2), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 0), align 4
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 3), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 1), align 4
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 4), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 2), align 4
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 5), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 0), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 6), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 1), align 4
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 7), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 2), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 8), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 0), align 4
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 9), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 1), align 4
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 10), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 2), align 4
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 11), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 0), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 12), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 1), align 4
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 13), align 4
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 2), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 14), align 8
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 0), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 15), align 8
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 1), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 16), align 8
; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 2), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 17), align 8
; CHECK: store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 1, i64 0, i32 0, i64 0), align 8
store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 18), align 8
ret void
}