From: Nikita Popov Date: Tue, 19 Mar 2019 17:53:56 +0000 (+0000) Subject: [ValueTracking] Use computeConstantRange() for unsigned add/sub overflow X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cd6f62dcd4b4cf8d7637dfe94e36984202f871d2;p=llvm [ValueTracking] Use computeConstantRange() for unsigned add/sub overflow Improve computeOverflowForUnsignedAdd/Sub in ValueTracking by intersecting the computeConstantRange() result into the ConstantRange created from computeKnownBits(). This allows us to detect some additional never/always overflows conditions that can't be determined from known bits. This revision also adds basic handling for constants to computeConstantRange(). Non-splat vectors will be handled in a followup. The signed case will also be handled in a followup, as it needs some more groundwork. Differential Revision: https://reviews.llvm.org/D59386 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@356489 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index b566a70ceaa..99d6010acee 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -4077,18 +4077,27 @@ static OverflowResult mapOverflowResult(ConstantRange::OverflowResult OR) { llvm_unreachable("Unknown OverflowResult"); } +/// Combine constant ranges from computeConstantRange() and computeKnownBits(). +static ConstantRange computeConstantRangeIncludingKnownBits( + const Value *V, bool ForSigned, const DataLayout &DL, unsigned Depth, + AssumptionCache *AC, const Instruction *CxtI, const DominatorTree *DT, + OptimizationRemarkEmitter *ORE = nullptr, bool UseInstrInfo = true) { + KnownBits Known = computeKnownBits( + V, DL, Depth, AC, CxtI, DT, ORE, UseInstrInfo); + ConstantRange CR = computeConstantRange(V, UseInstrInfo); + return ConstantRange::fromKnownBits(Known, ForSigned).intersectWith(CR); +} + OverflowResult llvm::computeOverflowForUnsignedAdd( const Value *LHS, const Value *RHS, const DataLayout &DL, AssumptionCache *AC, const Instruction *CxtI, const DominatorTree *DT, bool UseInstrInfo) { - KnownBits LHSKnown = computeKnownBits(LHS, DL, /*Depth=*/0, AC, CxtI, DT, - nullptr, UseInstrInfo); - KnownBits RHSKnown = computeKnownBits(RHS, DL, /*Depth=*/0, AC, CxtI, DT, - nullptr, UseInstrInfo); - ConstantRange LHSRange = - ConstantRange::fromKnownBits(LHSKnown, /*signed*/ false); - ConstantRange RHSRange = - ConstantRange::fromKnownBits(RHSKnown, /*signed*/ false); + ConstantRange LHSRange = computeConstantRangeIncludingKnownBits( + LHS, /*ForSigned=*/false, DL, /*Depth=*/0, AC, CxtI, DT, + nullptr, UseInstrInfo); + ConstantRange RHSRange = computeConstantRangeIncludingKnownBits( + RHS, /*ForSigned=*/false, DL, /*Depth=*/0, AC, CxtI, DT, + nullptr, UseInstrInfo); return mapOverflowResult(LHSRange.unsignedAddMayOverflow(RHSRange)); } @@ -4161,12 +4170,10 @@ OverflowResult llvm::computeOverflowForUnsignedSub(const Value *LHS, AssumptionCache *AC, const Instruction *CxtI, const DominatorTree *DT) { - KnownBits LHSKnown = computeKnownBits(LHS, DL, /*Depth=*/0, AC, CxtI, DT); - KnownBits RHSKnown = computeKnownBits(RHS, DL, /*Depth=*/0, AC, CxtI, DT); - ConstantRange LHSRange = - ConstantRange::fromKnownBits(LHSKnown, /*signed*/ false); - ConstantRange RHSRange = - ConstantRange::fromKnownBits(RHSKnown, /*signed*/ false); + ConstantRange LHSRange = computeConstantRangeIncludingKnownBits( + LHS, /*ForSigned=*/false, DL, /*Depth=*/0, AC, CxtI, DT); + ConstantRange RHSRange = computeConstantRangeIncludingKnownBits( + RHS, /*ForSigned=*/false, DL, /*Depth=*/0, AC, CxtI, DT); return mapOverflowResult(LHSRange.unsignedSubMayOverflow(RHSRange)); } @@ -5690,6 +5697,10 @@ static void setLimitsForSelectPattern(const SelectInst &SI, APInt &Lower, ConstantRange llvm::computeConstantRange(const Value *V, bool UseInstrInfo) { assert(V->getType()->isIntOrIntVectorTy() && "Expected integer instruction"); + const APInt *C; + if (match(V, m_APInt(C))) + return ConstantRange(*C); + InstrInfoQuery IIQ(UseInstrInfo); unsigned BitWidth = V->getType()->getScalarSizeInBits(); APInt Lower = APInt(BitWidth, 0); diff --git a/test/Transforms/InstCombine/and2.ll b/test/Transforms/InstCombine/and2.ll index ec23f61cb67..3cae1cfb2c9 100644 --- a/test/Transforms/InstCombine/and2.ll +++ b/test/Transforms/InstCombine/and2.ll @@ -154,7 +154,7 @@ define i8 @and1_lshr1_is_cmp_eq_0_multiuse(i8 %x) { ; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0_multiuse( ; CHECK-NEXT: [[SH:%.*]] = lshr i8 1, %x ; CHECK-NEXT: [[AND:%.*]] = and i8 [[SH]], 1 -; CHECK-NEXT: [[ADD:%.*]] = add i8 [[SH]], [[AND]] +; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 [[SH]], [[AND]] ; CHECK-NEXT: ret i8 [[ADD]] ; %sh = lshr i8 1, %x diff --git a/test/Transforms/InstCombine/saturating-add-sub.ll b/test/Transforms/InstCombine/saturating-add-sub.ll index aebfd479ca7..19b1e5943ef 100644 --- a/test/Transforms/InstCombine/saturating-add-sub.ll +++ b/test/Transforms/InstCombine/saturating-add-sub.ll @@ -355,7 +355,7 @@ define i8 @test_scalar_uadd_sub_nuw_lost_no_ov(i8 %a) { define i8 @test_scalar_uadd_urem_no_ov(i8 %a) { ; CHECK-LABEL: @test_scalar_uadd_urem_no_ov( ; CHECK-NEXT: [[B:%.*]] = urem i8 [[A:%.*]], 100 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[B]], i8 -100) +; CHECK-NEXT: [[R:%.*]] = add nuw nsw i8 [[B]], -100 ; CHECK-NEXT: ret i8 [[R]] ; %b = urem i8 %a, 100 @@ -379,7 +379,7 @@ define i8 @test_scalar_uadd_urem_known_bits(i8 %a, i8 %b) { ; CHECK-LABEL: @test_scalar_uadd_urem_known_bits( ; CHECK-NEXT: [[AA:%.*]] = udiv i8 -66, [[A:%.*]] ; CHECK-NEXT: [[BB:%.*]] = and i8 [[B:%.*]], 63 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[AA]], i8 [[BB]]) +; CHECK-NEXT: [[R:%.*]] = add nuw i8 [[AA]], [[BB]] ; CHECK-NEXT: ret i8 [[R]] ; %aa = udiv i8 190, %a @@ -768,8 +768,7 @@ define <2 x i8> @test_vector_ssub_neg_nneg(<2 x i8> %a) { define i8 @test_scalar_usub_add_nuw_no_ov(i8 %a) { ; CHECK-LABEL: @test_scalar_usub_add_nuw_no_ov( -; CHECK-NEXT: [[B:%.*]] = add nuw i8 [[A:%.*]], 10 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[B]], i8 9) +; CHECK-NEXT: [[R:%.*]] = add i8 [[A:%.*]], 1 ; CHECK-NEXT: ret i8 [[R]] ; %b = add nuw i8 %a, 10 @@ -779,9 +778,7 @@ define i8 @test_scalar_usub_add_nuw_no_ov(i8 %a) { define i8 @test_scalar_usub_add_nuw_eq(i8 %a) { ; CHECK-LABEL: @test_scalar_usub_add_nuw_eq( -; CHECK-NEXT: [[B:%.*]] = add nuw i8 [[A:%.*]], 10 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[B]], i8 10) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 [[A:%.*]] ; %b = add nuw i8 %a, 10 %r = call i8 @llvm.usub.sat.i8(i8 %b, i8 10) @@ -801,9 +798,7 @@ define i8 @test_scalar_usub_add_nuw_may_ov(i8 %a) { define i8 @test_scalar_usub_urem_must_ov(i8 %a) { ; CHECK-LABEL: @test_scalar_usub_urem_must_ov( -; CHECK-NEXT: [[B:%.*]] = urem i8 [[A:%.*]], 10 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[B]], i8 10) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 0 ; %b = urem i8 %a, 10 %r = call i8 @llvm.usub.sat.i8(i8 %b, i8 10) @@ -828,7 +823,7 @@ define i8 @test_scalar_usub_add_nuw_known_bits(i8 %a, i8 %b) { ; CHECK-LABEL: @test_scalar_usub_add_nuw_known_bits( ; CHECK-NEXT: [[AA:%.*]] = add nuw i8 [[A:%.*]], 10 ; CHECK-NEXT: [[BB:%.*]] = and i8 [[B:%.*]], 7 -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[AA]], i8 [[BB]]) +; CHECK-NEXT: [[R:%.*]] = sub nuw i8 [[AA]], [[BB]] ; CHECK-NEXT: ret i8 [[R]] ; %aa = add nuw i8 %a, 10 @@ -840,7 +835,7 @@ define i8 @test_scalar_usub_add_nuw_known_bits(i8 %a, i8 %b) { define i8 @test_scalar_usub_add_nuw_inferred(i8 %a) { ; CHECK-LABEL: @test_scalar_usub_add_nuw_inferred( ; CHECK-NEXT: [[B:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 10) -; CHECK-NEXT: [[R:%.*]] = add i8 [[B]], 9 +; CHECK-NEXT: [[R:%.*]] = add nuw i8 [[B]], 9 ; CHECK-NEXT: ret i8 [[R]] ; %b = call i8 @llvm.usub.sat.i8(i8 %a, i8 10) @@ -850,8 +845,7 @@ define i8 @test_scalar_usub_add_nuw_inferred(i8 %a) { define <2 x i8> @test_vector_usub_add_nuw_no_ov(<2 x i8> %a) { ; CHECK-LABEL: @test_vector_usub_add_nuw_no_ov( -; CHECK-NEXT: [[B:%.*]] = add nuw <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[R:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[B]], <2 x i8> ) +; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[A:%.*]], ; CHECK-NEXT: ret <2 x i8> [[R]] ; %b = add nuw <2 x i8> %a, diff --git a/test/Transforms/InstCombine/uadd-with-overflow.ll b/test/Transforms/InstCombine/uadd-with-overflow.ll index a7122e163f6..c9776f43528 100644 --- a/test/Transforms/InstCombine/uadd-with-overflow.ll +++ b/test/Transforms/InstCombine/uadd-with-overflow.ll @@ -33,9 +33,8 @@ define { i8, i1 } @fold_on_constant_add_no_overflow(i8 %x) { define { i8, i1 } @no_fold_on_constant_add_overflow(i8 %x) { ; CHECK-LABEL: @no_fold_on_constant_add_overflow( -; CHECK-NEXT: [[A:%.*]] = add nuw i8 [[X:%.*]], -56 -; CHECK-NEXT: [[B:%.*]] = tail call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[A]], i8 56) -; CHECK-NEXT: ret { i8, i1 } [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i8, i1 } { i8 undef, i1 true }, i8 [[X:%.*]], 0 +; CHECK-NEXT: ret { i8, i1 } [[TMP1]] ; %a = add nuw i8 %x, 200 %b = tail call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %a, i8 56) diff --git a/test/Transforms/LoopVectorize/X86/small-size.ll b/test/Transforms/LoopVectorize/X86/small-size.ll index 2027963f071..cbc76b14953 100644 --- a/test/Transforms/LoopVectorize/X86/small-size.ll +++ b/test/Transforms/LoopVectorize/X86/small-size.ll @@ -81,7 +81,7 @@ define void @example2(i32 %n, i32 %x) optsize { ; CHECK-NEXT: [[N_RND_UP:%.*]] = add nuw nsw i64 [[TMP3]], 4 ; CHECK-NEXT: [[TMP4:%.*]] = and i32 [[TMP2]], 3 ; CHECK-NEXT: [[N_MOD_VF:%.*]] = zext i32 [[TMP4]] to i64 -; CHECK-NEXT: [[N_VEC:%.*]] = sub nsw i64 [[N_RND_UP]], [[N_MOD_VF]] +; CHECK-NEXT: [[N_VEC:%.*]] = sub nuw nsw i64 [[N_RND_UP]], [[N_MOD_VF]] ; CHECK-NEXT: [[BROADCAST_SPLATINSERT1:%.*]] = insertelement <4 x i64> undef, i64 [[TMP3]], i32 0 ; CHECK-NEXT: [[BROADCAST_SPLAT2:%.*]] = shufflevector <4 x i64> [[BROADCAST_SPLATINSERT1]], <4 x i64> undef, <4 x i32> zeroinitializer ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]