diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -277,27 +277,30 @@ unsigned PtrSize = IntPtrTy->getIntegerBitWidth(); if (Idx->getType()->getPrimitiveSizeInBits().getFixedSize() > PtrSize) Idx = Builder.CreateTrunc(Idx, IntPtrTy); + } - unsigned ElementSize = - DL.getTypeAllocSize(Init->getType()->getArrayElementType()); - - // If inbounds keyword is not present, Idx * ElementSize can overflow. - // Let's assume that ElementSize is 2 and the wanted value is at offset 0. - // Then, there are two possible values for Idx to match offset 0: - // 0x00..00, 0x80..00. - // Emitting 'icmp eq Idx, 0' isn't correct in this case because the - // comparison is false if Idx was 0x80..00. - // We need to erase the highest countTrailingZeros(ElementSize) bits of Idx. - if (countTrailingZeros(ElementSize) != 0) { - Value *Mask = ConstantInt::getSigned(Idx->getType(), -1); + // If inbounds keyword is not present, Idx * ElementSize can overflow. + // Let's assume that ElementSize is 2 and the wanted value is at offset 0. + // Then, there are two possible values for Idx to match offset 0: + // 0x00..00, 0x80..00. + // Emitting 'icmp eq Idx, 0' isn't correct in this case because the + // comparison is false if Idx was 0x80..00. + // We need to erase the highest countTrailingZeros(ElementSize) bits of Idx. + unsigned ElementSize = + DL.getTypeAllocSize(Init->getType()->getArrayElementType()); + auto MaskIdx = [&](Value* Idx){ + if (!GEP->isInBounds() && countTrailingZeros(ElementSize) != 0) { + Value *Mask = ConstantInt::get(Idx->getType(), -1); Mask = Builder.CreateLShr(Mask, countTrailingZeros(ElementSize)); Idx = Builder.CreateAnd(Idx, Mask); } - } + return Idx; + }; // If the comparison is only true for one or two elements, emit direct // comparisons. if (SecondTrueElement != Overdefined) { + Idx = MaskIdx(Idx); // None true -> false. if (FirstTrueElement == Undefined) return replaceInstUsesWith(ICI, Builder.getFalse()); @@ -318,6 +321,7 @@ // If the comparison is only false for one or two elements, emit direct // comparisons. if (SecondFalseElement != Overdefined) { + Idx = MaskIdx(Idx); // None false -> true. if (FirstFalseElement == Undefined) return replaceInstUsesWith(ICI, Builder.getTrue()); @@ -339,6 +343,7 @@ // where it is true, emit the range check. if (TrueRangeEnd != Overdefined) { assert(TrueRangeEnd != FirstTrueElement && "Should emit single compare"); + Idx = MaskIdx(Idx); // Generate (i-FirstTrue) u (FalseRangeEnd-FirstFalse). if (FirstFalseElement) { Value *Offs = ConstantInt::get(Idx->getType(), -FirstFalseElement); @@ -380,6 +386,7 @@ Ty = DL.getSmallestLegalIntType(Init->getContext(), ArrayElementCount); if (Ty) { + Idx = MaskIdx(Idx); Value *V = Builder.CreateIntCast(Idx, Ty, false); V = Builder.CreateLShr(ConstantInt::get(Ty, MagicBitvector), V); V = Builder.CreateAnd(ConstantInt::get(Ty, 1), V); diff --git a/llvm/test/Transforms/InstCombine/load-cmp.ll b/llvm/test/Transforms/InstCombine/load-cmp.ll --- a/llvm/test/Transforms/InstCombine/load-cmp.ll +++ b/llvm/test/Transforms/InstCombine/load-cmp.ll @@ -299,7 +299,6 @@ } define i1 @test10_struct_arr_noinbounds_i16(i16 %x) { -; CHECK-LABEL: @test10_struct_arr_noinbounds_i16( ; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[X:%.*]] to i32 ; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 268435455 ; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[TMP2]], 1