diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index 5fae1ea0a75..459a1883d87 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -165,8 +165,11 @@ static Constant *SymbolicallyEvaluateGEP(Constant* const* Ops, unsigned NumOps, // Also, this helps GlobalOpt do SROA on GlobalVariables. const Type *Ty = Ptr->getType(); SmallVector NewIdxs; - for (unsigned Index = 1; Index != NumOps; ++Index) { + do { if (const SequentialType *ATy = dyn_cast(Ty)) { + // The only pointer indexing we'll do is on the first index of the GEP. + if (isa(ATy) && ATy != Ptr->getType()) + break; // Determine which element of the array the offset points into. uint64_t ElemSize = TD->getTypeAllocSize(ATy->getElementType()); if (ElemSize == 0) @@ -183,20 +186,33 @@ static Constant *SymbolicallyEvaluateGEP(Constant* const* Ops, unsigned NumOps, Offset -= SL.getElementOffset(ElIdx); Ty = STy->getTypeAtIndex(ElIdx); } else { - return 0; + // We've reached some non-indexable type. + break; } - } + } while (Ty != cast(ResultTy)->getElementType()); + + // If we haven't used up the entire offset by descending the static + // type, then the offset is pointing into the middle of an indivisible + // member, so we can't simplify it. + if (Offset != 0) + 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(Ptr) && NewIdxs[0]->isNullValue()) - return ConstantExpr::getInBoundsGetElementPtr(Ptr, - &NewIdxs[0], NewIdxs.size()); + Constant *C = isa(Ptr) && NewIdxs[0]->isNullValue() ? + ConstantExpr::getInBoundsGetElementPtr(Ptr, &NewIdxs[0], NewIdxs.size()) : + ConstantExpr::getGetElementPtr(Ptr, &NewIdxs[0], NewIdxs.size()); + assert(cast(C->getType())->getElementType() == Ty && + "Computed GetElementPtr has unexpected type!"); - // Otherwise it may not be inbounds. - return ConstantExpr::getGetElementPtr(Ptr, &NewIdxs[0], NewIdxs.size()); + // If we ended up indexing a member with a type that doesn't match + // type type of what the original indices indexed, add a cast. + if (Ty != cast(ResultTy)->getElementType()) + C = ConstantExpr::getBitCast(C, ResultTy); + + return C; } /// FoldBitCast - Constant fold bitcast, symbolically evaluating it with diff --git a/test/Transforms/InstCombine/constant-fold-gep-overindex.ll b/test/Transforms/InstCombine/constant-fold-gep-overindex.ll new file mode 100644 index 00000000000..15bdab49eec --- /dev/null +++ b/test/Transforms/InstCombine/constant-fold-gep-overindex.ll @@ -0,0 +1,17 @@ +; RUN: llvm-as < %s | opt -instcombine +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" +target triple = "i386-apple-darwin10.0" + +%0 = type { i8*, [19 x i8] } +%1 = type { i8*, [0 x i8] } + +@s = external global %0 ; <%0*> [#uses=1] +@"\01LC8" = external constant [17 x i8] ; <[17 x i8]*> [#uses=1] + +define i32 @main() nounwind { +entry: + %0 = call i32 (i8*, ...)* @printf(i8* getelementptr ([17 x i8]* @"\01LC8", i32 0, i32 0), i8* undef, i8* getelementptr (%1* bitcast (%0* @s to %1*), i32 0, i32 1, i32 0)) nounwind ; [#uses=0] + ret i32 0 +} + +declare i32 @printf(i8*, ...) nounwind