From: David Majnemer Date: Wed, 13 Jul 2016 03:24:41 +0000 (+0000) Subject: [ConstantFold] Don't incorrectly infer inbounds on array GEP X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4f80506591dfb5f32ee2ab0e2f99d5dc7061aac4;p=llvm [ConstantFold] Don't incorrectly infer inbounds on array GEP The many levels of nesting inside the responsible code made it easy for bugs to sneak in. Flattening the logic makes it easier to see what's going on. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275244 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/IR/ConstantFold.cpp b/lib/IR/ConstantFold.cpp index 575a88894dd..c06a99c0536 100644 --- a/lib/IR/ConstantFold.cpp +++ b/lib/IR/ConstantFold.cpp @@ -2192,51 +2192,68 @@ static Constant *ConstantFoldGetElementPtrImpl(Type *PointeeTy, Constant *C, bool Unknown = !isa(Idxs[0]); for (unsigned i = 1, e = Idxs.size(); i != e; Prev = Ty, Ty = cast(Ty)->getTypeAtIndex(Idxs[i]), ++i) { - if (ConstantInt *CI = dyn_cast(Idxs[i])) { - if (isa(Ty) && CI->getSExtValue() > 0 && - !isIndexInRangeOfSequentialType(cast(Ty), CI)) { - if (isa(Prev)) { - // It's out of range, but we can factor it into the prior - // dimension. - NewIdxs.resize(Idxs.size()); - uint64_t NumElements = 0; - if (auto *ATy = dyn_cast(Ty)) - NumElements = ATy->getNumElements(); - else - NumElements = cast(Ty)->getNumElements(); - - ConstantInt *Factor = ConstantInt::get(CI->getType(), NumElements); - NewIdxs[i] = ConstantExpr::getSRem(CI, Factor); - - Constant *PrevIdx = cast(Idxs[i - 1]); - Constant *Div = ConstantExpr::getSDiv(CI, Factor); - - unsigned CommonExtendedWidth = - std::max(PrevIdx->getType()->getIntegerBitWidth(), - Div->getType()->getIntegerBitWidth()); - CommonExtendedWidth = std::max(CommonExtendedWidth, 64U); - - // Before adding, extend both operands to i64 to avoid - // overflow trouble. - if (!PrevIdx->getType()->isIntegerTy(CommonExtendedWidth)) - PrevIdx = ConstantExpr::getSExt( - PrevIdx, - Type::getIntNTy(Div->getContext(), CommonExtendedWidth)); - if (!Div->getType()->isIntegerTy(CommonExtendedWidth)) - Div = ConstantExpr::getSExt( - Div, Type::getIntNTy(Div->getContext(), CommonExtendedWidth)); - - NewIdxs[i - 1] = ConstantExpr::getAdd(PrevIdx, Div); - } else { - // It's out of range, but the prior dimension is a struct - // so we can't do anything about it. - Unknown = true; - } - } - } else { + auto *CI = dyn_cast(Idxs[i]); + if (!CI) { // We don't know if it's in range or not. Unknown = true; + continue; + } + if (isa(Ty)) { + // The verify makes sure that GEPs into a struct are in range. + continue; + } + auto *STy = cast(Ty); + if (isa(STy)) { + // We don't know if it's in range or not. + Unknown = true; + continue; + } + if (isa(STy)) { + // There can be awkward padding in after a non-power of two vector. + Unknown = true; + continue; + } + if (isIndexInRangeOfSequentialType(STy, CI)) + // It's in range, skip to the next index. + continue; + if (!isa(Prev)) { + // It's out of range, but the prior dimension is a struct + // so we can't do anything about it. + Unknown = true; + continue; + } + if (CI->getSExtValue() < 0) { + // It's out of range and negative, don't try to factor it. + Unknown = true; + continue; } + // It's out of range, but we can factor it into the prior + // dimension. + NewIdxs.resize(Idxs.size()); + // Determine the number of elements in our sequential type. + uint64_t NumElements = STy->getArrayNumElements(); + + ConstantInt *Factor = ConstantInt::get(CI->getType(), NumElements); + NewIdxs[i] = ConstantExpr::getSRem(CI, Factor); + + Constant *PrevIdx = cast(Idxs[i - 1]); + Constant *Div = ConstantExpr::getSDiv(CI, Factor); + + unsigned CommonExtendedWidth = + std::max(PrevIdx->getType()->getIntegerBitWidth(), + Div->getType()->getIntegerBitWidth()); + CommonExtendedWidth = std::max(CommonExtendedWidth, 64U); + + // Before adding, extend both operands to i64 to avoid + // overflow trouble. + if (!PrevIdx->getType()->isIntegerTy(CommonExtendedWidth)) + PrevIdx = ConstantExpr::getSExt( + PrevIdx, Type::getIntNTy(Div->getContext(), CommonExtendedWidth)); + if (!Div->getType()->isIntegerTy(CommonExtendedWidth)) + Div = ConstantExpr::getSExt( + Div, Type::getIntNTy(Div->getContext(), CommonExtendedWidth)); + + NewIdxs[i - 1] = ConstantExpr::getAdd(PrevIdx, Div); } // If we did any factoring, start over with the adjusted indices. diff --git a/test/Assembler/getelementptr.ll b/test/Assembler/getelementptr.ll index 0a0fddfc4dd..824848d77b5 100644 --- a/test/Assembler/getelementptr.ll +++ b/test/Assembler/getelementptr.ll @@ -46,3 +46,13 @@ define <2 x i8*> @test8(<2 x [2 x i8]*> %a) { %w = getelementptr [2 x i8], <2 x [2 x i8]*> %a, <2 x i32> , <2 x i8> ret <2 x i8*> %w } + +@array = internal global [16 x i32] [i32 -200, i32 -199, i32 -198, i32 -197, i32 -196, i32 -195, i32 -194, i32 -193, i32 -192, i32 -191, i32 -190, i32 -189, i32 -188, i32 -187, i32 -186, i32 -185], align 16 + +; Verify that array GEP doesn't incorrectly infer inbounds. +define i32* @test9() { +entry: + ret i32* getelementptr ([16 x i32], [16 x i32]* @array, i64 0, i64 -13) +; CHECK-LABEL: define i32* @test9( +; CHECK: ret i32* getelementptr ([16 x i32], [16 x i32]* @array, i64 0, i64 -13) +}