[llvm] Add extra handling to compute constant range (PR #190571)
Takashi Idobe via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 5 18:59:03 PDT 2026
https://github.com/Takashiidobe created https://github.com/llvm/llvm-project/pull/190571
Relates: https://github.com/llvm/llvm-project/pull/190565
This PR adds some extra handling to ValueTracking's computeConstantRange. This handles udiv, sdiv, urem, srem, mul, add, sub, trunc.
This allows for recursive handling for those cases. Most of the time (changed tests) nsw or nuw is tacked onto some tests that had defined ranges. This is a pretty minor win in most cases.
There are some interesting cases like:
InstCombine/add.ll:3274
add, zext, add -> zext because the add and decrement cancel each other out due to improved range analysis:
```llvm
%a = add nsw <2 x i8> %o, <i8 -1, i8 -1>
%b = zext <2 x i8> %a to <2 x i32>
%c = add nuw nsw <2 x i32> %b, <i32 1, i32 poison>
```
```llvm
%c = zext <2 x i8> %o to <2 x i32>
```
This one does turn into a concrete codegen change:
```asm
dec_zext_add_nonzero_vec_poison2: # @dec_zext_add_nonzero_vec_poison2
por xmm0, xmmword ptr [rip + .LCPI0_0]
pcmpeqd xmm1, xmm1
paddb xmm0, xmm1
pxor xmm1, xmm1
punpcklbw xmm0, xmm1
punpcklwd xmm0, xmm1
mov eax, 1
movd xmm1, eax
paddd xmm0, xmm1
ret
```
Turns into:
```asm
dec_zext_add_nonzero_vec_poison2: # @dec_zext_add_nonzero_vec_poison2
por xmm0, xmmword ptr [rip + .LCPI0_0]
pxor xmm1, xmm1
punpcklbw xmm0, xmm1
punpcklwd xmm0, xmm1
ret
```
InstCombine/icmp-add.ll:3163
%x is bounded so %x + 4 is always less than -6. You can delete all of this and return true.
```llvm
%add = add nsw i32 %x, 4
%cmp = icmp ult i32 %add, -6
ret i1 %cmp
```
```llvm
ret i1 true
```
InstCombine/icmp-mul.ll:950
mul range proves that %m cannot be > 3060 so it just deletes the code and replaces it with false:
```llvm
%x30 = and i32 %x, 12
%y8 = and i32 %y, 255
%m = mul nuw nsw i32 %y8, %x30
%r = icmp samesign ugt i32 %m, 3060
ret i1 %r
```
```llvm
ret i1 false
```
InstCombine/saturating-add-sub.ll:1112
Because there's no unsigned wrap, there's no need to call the intrinsic:
```llvm
%b = add nuw <2 x i8> %a, <i8 10, i8 9>
%r = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %b, <2 x i8> <i8 9, i8 9>)
ret <2 x i8> %r
```
```llvm
%r = add <2 x i8> %a, <i8 1, i8 0>
ret <2 x i8> %r
```
llvm/test/Transforms/InstCombine/pr80597.ll:4
```llvm
entry:
%add = select i1 %cond, i64 0, i64 -12884901888
%sext1 = add nsw i64 %add, 8836839514384105472
%cmp = icmp ult i64 %sext1, -34359738368
br i1 %cmp, label %if.then, label %if.else
if.else:
%sext2 = ashr exact i64 %add, 1
%ashr = or disjoint i64 %sext2, 4418419761487020032
ret i64 %ashr
if.then:
ret i64 0
```
Turns into this in instcombine:
```llvm
entry:
br i1 true, label %if.then, label %if.else
if.else:
ret i64 poison
if.then:
ret i64 0
```
>From 579c4a18a4448690bb8b1f15d7a5bea93c3ea8dd Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Sun, 5 Apr 2026 21:01:22 -0400
Subject: [PATCH 1/2] NFC: clean up some todos around computeConstantRange
---
llvm/lib/Analysis/ValueTracking.cpp | 38 ++++++++++++++---------------
1 file changed, 18 insertions(+), 20 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index a0fb28612c534..8530fcbcf680e 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9936,10 +9936,12 @@ std::optional<bool> llvm::isImpliedByDomCondition(CmpPredicate Pred,
return std::nullopt;
}
-static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
- APInt &Upper, const InstrInfoQuery &IIQ,
- bool PreferSignedRange) {
- unsigned Width = Lower.getBitWidth();
+static ConstantRange getRangeForBinOp(const BinaryOperator &BO,
+ const InstrInfoQuery &IIQ,
+ bool PreferSignedRange) {
+ unsigned Width = BO.getType()->getScalarSizeInBits();
+ APInt Lower(Width, 0);
+ APInt Upper(Width, 0);
const APInt *C;
switch (BO.getOpcode()) {
case Instruction::Sub:
@@ -10159,6 +10161,7 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
default:
break;
}
+ return ConstantRange::getNonEmpty(Lower, Upper);
}
static ConstantRange getRangeForIntrinsic(const IntrinsicInst &II,
@@ -10321,12 +10324,14 @@ static ConstantRange getRangeForSelectPattern(const SelectInst &SI,
}
}
-static void setLimitForFPToI(const Instruction *I, APInt &Lower, APInt &Upper) {
+static ConstantRange getRangeForFPToI(const Instruction *I) {
// The maximum representable value of a half is 65504. For floats the maximum
// value is 3.4e38 which requires roughly 129 bits.
unsigned BitWidth = I->getType()->getScalarSizeInBits();
if (!I->getOperand(0)->getType()->getScalarType()->isHalfTy())
- return;
+ return ConstantRange::getFull(BitWidth);
+ APInt Lower(BitWidth, 0);
+ APInt Upper(BitWidth, 0);
if (isa<FPToSIInst>(I) && BitWidth >= 17) {
Lower = APInt(BitWidth, -65504, true);
Upper = APInt(BitWidth, 65505);
@@ -10336,6 +10341,7 @@ static void setLimitForFPToI(const Instruction *I, APInt &Lower, APInt &Upper) {
// For a fptoui the lower limit is left as 0.
Upper = APInt(BitWidth, 65505);
}
+ return ConstantRange::getNonEmpty(Lower, Upper);
}
ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
@@ -10354,13 +10360,9 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
unsigned BitWidth = V->getType()->getScalarSizeInBits();
InstrInfoQuery IIQ(UseInstrInfo);
ConstantRange CR = ConstantRange::getFull(BitWidth);
- if (auto *BO = dyn_cast<BinaryOperator>(V)) {
- APInt Lower = APInt(BitWidth, 0);
- APInt Upper = APInt(BitWidth, 0);
- // TODO: Return ConstantRange.
- setLimitsForBinOp(*BO, Lower, Upper, IIQ, ForSigned);
- CR = ConstantRange::getNonEmpty(Lower, Upper);
- } else if (auto *II = dyn_cast<IntrinsicInst>(V))
+ if (auto *BO = dyn_cast<BinaryOperator>(V))
+ CR = getRangeForBinOp(*BO, IIQ, ForSigned);
+ else if (auto *II = dyn_cast<IntrinsicInst>(V))
CR = getRangeForIntrinsic(*II, UseInstrInfo);
else if (auto *SI = dyn_cast<SelectInst>(V)) {
ConstantRange CRTrue = computeConstantRange(
@@ -10369,13 +10371,9 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
SI->getFalseValue(), ForSigned, UseInstrInfo, AC, CtxI, DT, Depth + 1);
CR = CRTrue.unionWith(CRFalse);
CR = CR.intersectWith(getRangeForSelectPattern(*SI, IIQ));
- } else if (isa<FPToUIInst>(V) || isa<FPToSIInst>(V)) {
- APInt Lower = APInt(BitWidth, 0);
- APInt Upper = APInt(BitWidth, 0);
- // TODO: Return ConstantRange.
- setLimitForFPToI(cast<Instruction>(V), Lower, Upper);
- CR = ConstantRange::getNonEmpty(Lower, Upper);
- } else if (const auto *A = dyn_cast<Argument>(V))
+ } else if (isa<FPToUIInst>(V) || isa<FPToSIInst>(V))
+ CR = getRangeForFPToI(cast<Instruction>(V));
+ else if (const auto *A = dyn_cast<Argument>(V))
if (std::optional<ConstantRange> Range = A->getRange())
CR = *Range;
>From b5d135072e9fd9fadb2da9d5b480ac131e73d0c5 Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Sun, 5 Apr 2026 21:27:01 -0400
Subject: [PATCH 2/2] wip: try adding some extra constantRange cases
---
llvm/lib/Analysis/ValueTracking.cpp | 97 +++++++-
llvm/test/Transforms/InstCombine/add.ll | 4 +-
llvm/test/Transforms/InstCombine/div.ll | 2 +-
llvm/test/Transforms/InstCombine/fls.ll | 2 +-
llvm/test/Transforms/InstCombine/icmp-add.ll | 4 +-
llvm/test/Transforms/InstCombine/icmp-mul.ll | 6 +-
llvm/test/Transforms/InstCombine/icmp-srem.ll | 2 +-
.../InstCombine/mul-inseltpoison.ll | 2 +-
llvm/test/Transforms/InstCombine/mul.ll | 12 +-
.../Transforms/InstCombine/mul_full_32.ll | 16 +-
.../Transforms/InstCombine/mul_full_64.ll | 88 +++----
llvm/test/Transforms/InstCombine/pr80597.ll | 9 +-
.../InstCombine/saturating-add-sub.ll | 5 +-
llvm/unittests/Analysis/ValueTrackingTest.cpp | 231 ++++++++++++++++++
14 files changed, 393 insertions(+), 87 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 8530fcbcf680e..350deeb83ef48 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -10360,9 +10360,95 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
unsigned BitWidth = V->getType()->getScalarSizeInBits();
InstrInfoQuery IIQ(UseInstrInfo);
ConstantRange CR = ConstantRange::getFull(BitWidth);
- if (auto *BO = dyn_cast<BinaryOperator>(V))
+ if (auto *BO = dyn_cast<BinaryOperator>(V)) {
CR = getRangeForBinOp(*BO, IIQ, ForSigned);
- else if (auto *II = dyn_cast<IntrinsicInst>(V))
+ // For these opcodes, recurse into operands to get a tighter range than
+ // getRangeForBinOp can produce with constant-only operand matching.
+ switch (BO->getOpcode()) {
+ case Instruction::UDiv: {
+ ConstantRange LHS =
+ computeConstantRange(BO->getOperand(0), /*ForSigned=*/false,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ ConstantRange RHS =
+ computeConstantRange(BO->getOperand(1), /*ForSigned=*/false,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ CR = CR.intersectWith(LHS.udiv(RHS));
+ break;
+ }
+ case Instruction::SDiv: {
+ ConstantRange LHS =
+ computeConstantRange(BO->getOperand(0), /*ForSigned=*/true,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ ConstantRange RHS =
+ computeConstantRange(BO->getOperand(1), /*ForSigned=*/true,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ CR = CR.intersectWith(LHS.sdiv(RHS));
+ break;
+ }
+ case Instruction::URem: {
+ ConstantRange LHS =
+ computeConstantRange(BO->getOperand(0), /*ForSigned=*/false,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ ConstantRange RHS =
+ computeConstantRange(BO->getOperand(1), /*ForSigned=*/false,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ CR = CR.intersectWith(LHS.urem(RHS));
+ break;
+ }
+ case Instruction::SRem: {
+ ConstantRange LHS =
+ computeConstantRange(BO->getOperand(0), /*ForSigned=*/true,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ ConstantRange RHS =
+ computeConstantRange(BO->getOperand(1), /*ForSigned=*/true,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ CR = CR.intersectWith(LHS.srem(RHS));
+ break;
+ }
+ case Instruction::Mul: {
+ ConstantRange LHS =
+ computeConstantRange(BO->getOperand(0), /*ForSigned=*/false,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ ConstantRange RHS =
+ computeConstantRange(BO->getOperand(1), /*ForSigned=*/false,
+ UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ CR = CR.intersectWith(LHS.multiply(RHS));
+ break;
+ }
+ case Instruction::Add: {
+ ConstantRange LHS = computeConstantRange(
+ BO->getOperand(0), ForSigned, UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ ConstantRange RHS = computeConstantRange(
+ BO->getOperand(1), ForSigned, UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ unsigned NoWrapKind =
+ cast<OverflowingBinaryOperator>(BO)->getNoWrapKind();
+ ConstantRange::PreferredRangeType RangeType =
+ ForSigned ? ConstantRange::Signed : ConstantRange::Unsigned;
+ ConstantRange Res = NoWrapKind
+ ? LHS.addWithNoWrap(RHS, NoWrapKind, RangeType)
+ : LHS.add(RHS);
+ CR = CR.intersectWith(Res);
+ break;
+ }
+ case Instruction::Sub: {
+ ConstantRange LHS = computeConstantRange(
+ BO->getOperand(0), ForSigned, UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ ConstantRange RHS = computeConstantRange(
+ BO->getOperand(1), ForSigned, UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ unsigned NoWrapKind =
+ cast<OverflowingBinaryOperator>(BO)->getNoWrapKind();
+ ConstantRange::PreferredRangeType RangeType =
+ ForSigned ? ConstantRange::Signed : ConstantRange::Unsigned;
+ ConstantRange Res = NoWrapKind
+ ? LHS.subWithNoWrap(RHS, NoWrapKind, RangeType)
+ : LHS.sub(RHS);
+ CR = CR.intersectWith(Res);
+ break;
+ }
+ default:
+ break;
+ }
+ } else if (auto *II = dyn_cast<IntrinsicInst>(V))
CR = getRangeForIntrinsic(*II, UseInstrInfo);
else if (auto *SI = dyn_cast<SelectInst>(V)) {
ConstantRange CRTrue = computeConstantRange(
@@ -10371,6 +10457,10 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
SI->getFalseValue(), ForSigned, UseInstrInfo, AC, CtxI, DT, Depth + 1);
CR = CRTrue.unionWith(CRFalse);
CR = CR.intersectWith(getRangeForSelectPattern(*SI, IIQ));
+ } else if (auto *TI = dyn_cast<TruncInst>(V)) {
+ ConstantRange SrcCR = computeConstantRange(
+ TI->getOperand(0), ForSigned, UseInstrInfo, AC, CtxI, DT, Depth + 1);
+ CR = SrcCR.truncate(BitWidth, TI->getNoWrapKind());
} else if (isa<FPToUIInst>(V) || isa<FPToSIInst>(V))
CR = getRangeForFPToI(cast<Instruction>(V));
else if (const auto *A = dyn_cast<Argument>(V))
@@ -10404,9 +10494,8 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
// Currently we just use information from comparisons.
if (!Cmp || Cmp->getOperand(0) != V)
continue;
- // TODO: Set "ForSigned" parameter via Cmp->isSigned()?
ConstantRange RHS =
- computeConstantRange(Cmp->getOperand(1), /* ForSigned */ false,
+ computeConstantRange(Cmp->getOperand(1), Cmp->isSigned(),
UseInstrInfo, AC, I, DT, Depth + 1);
CR = CR.intersectWith(
ConstantRange::makeAllowedICmpRegion(Cmp->getPredicate(), RHS));
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index aa68dfb540064..9d19ff1d37c26 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -3274,9 +3274,7 @@ define <2 x i32> @dec_zext_add_nonzero_vec_poison1(<2 x i8> %x) {
define <2 x i32> @dec_zext_add_nonzero_vec_poison2(<2 x i8> %x) {
; CHECK-LABEL: @dec_zext_add_nonzero_vec_poison2(
; CHECK-NEXT: [[O:%.*]] = or <2 x i8> [[X:%.*]], splat (i8 8)
-; CHECK-NEXT: [[A:%.*]] = add nsw <2 x i8> [[O]], splat (i8 -1)
-; CHECK-NEXT: [[B:%.*]] = zext <2 x i8> [[A]] to <2 x i32>
-; CHECK-NEXT: [[C:%.*]] = add nuw nsw <2 x i32> [[B]], <i32 1, i32 poison>
+; CHECK-NEXT: [[C:%.*]] = zext <2 x i8> [[O]] to <2 x i32>
; CHECK-NEXT: ret <2 x i32> [[C]]
;
%o = or <2 x i8> %x, <i8 8, i8 8>
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index fa8e9c9723e4e..26668da0adde2 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -933,7 +933,7 @@ define <2 x i8> @negate_sdiv_vec_one_element(<2 x i8> %x) {
define <2 x i8> @negate_sdiv_vec_signed_min_elt(<2 x i8> %x) {
; CHECK-LABEL: @negate_sdiv_vec_signed_min_elt(
; CHECK-NEXT: [[DIV:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 -1, i8 -128>
-; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i8> zeroinitializer, [[DIV]]
+; CHECK-NEXT: [[NEG:%.*]] = sub nsw <2 x i8> zeroinitializer, [[DIV]]
; CHECK-NEXT: ret <2 x i8> [[NEG]]
;
%div = sdiv <2 x i8> %x, <i8 -1, i8 -128>
diff --git a/llvm/test/Transforms/InstCombine/fls.ll b/llvm/test/Transforms/InstCombine/fls.ll
index 68bc0a2fc8a1d..ea757268259f5 100644
--- a/llvm/test/Transforms/InstCombine/fls.ll
+++ b/llvm/test/Transforms/InstCombine/fls.ll
@@ -33,7 +33,7 @@ define i32 @flsnotconst(i64 %z) {
; CHECK-LABEL: @flsnotconst(
; CHECK-NEXT: [[CTLZ:%.*]] = call range(i64 0, 65) i64 @llvm.ctlz.i64(i64 [[Z:%.*]], i1 false)
; CHECK-NEXT: [[TMP1:%.*]] = trunc nuw nsw i64 [[CTLZ]] to i32
-; CHECK-NEXT: [[GOO:%.*]] = sub nsw i32 64, [[TMP1]]
+; CHECK-NEXT: [[GOO:%.*]] = sub nuw nsw i32 64, [[TMP1]]
; CHECK-NEXT: ret i32 [[GOO]]
;
%goo = call i32 @flsl(i64 %z)
diff --git a/llvm/test/Transforms/InstCombine/icmp-add.ll b/llvm/test/Transforms/InstCombine/icmp-add.ll
index 1b66a50c26e59..82a0ec27fadfe 100644
--- a/llvm/test/Transforms/InstCombine/icmp-add.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-add.ll
@@ -3162,9 +3162,7 @@ define i1 @icmp_add_constant_with_constant_ult_to_slt_neg2(i8 range(i8 -4, 120)
; Negative test: C2 is negative
define i1 @icmp_add_constant_with_constant_ult_to_slt_neg3(i32 range(i32 -4, 10) %x) {
; CHECK-LABEL: @icmp_add_constant_with_constant_ult_to_slt_neg3(
-; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[X:%.*]], 4
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ADD]], -6
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%add = add nsw i32 %x, 4
%cmp = icmp ult i32 %add, -6
diff --git a/llvm/test/Transforms/InstCombine/icmp-mul.ll b/llvm/test/Transforms/InstCombine/icmp-mul.ll
index 1e4876d5cd569..315245eee5e78 100644
--- a/llvm/test/Transforms/InstCombine/icmp-mul.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-mul.ll
@@ -949,11 +949,7 @@ define i1 @not_mul_of_pow2(i32 %x, i8 %y) {
define i1 @not_mul_of_pow2_commute(i32 %x, i32 %y) {
; CHECK-LABEL: @not_mul_of_pow2_commute(
-; CHECK-NEXT: [[X30:%.*]] = and i32 [[X:%.*]], 12
-; CHECK-NEXT: [[Y8:%.*]] = and i32 [[Y:%.*]], 255
-; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i32 [[Y8]], [[X30]]
-; CHECK-NEXT: [[R:%.*]] = icmp samesign ugt i32 [[M]], 3060
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 false
;
%x30 = and i32 %x, 12
%y8 = and i32 %y, 255
diff --git a/llvm/test/Transforms/InstCombine/icmp-srem.ll b/llvm/test/Transforms/InstCombine/icmp-srem.ll
index e4838131713e8..7fea6d397a02d 100644
--- a/llvm/test/Transforms/InstCombine/icmp-srem.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-srem.ll
@@ -122,7 +122,7 @@ define i1 @icmp_ugt_srem5_m5(i32 %x) {
define i64 @srem_zero_ult_poison(i1 %c) {
; CHECK-LABEL: define i64 @srem_zero_ult_poison(
; CHECK-SAME: i1 [[C:%.*]]) {
-; CHECK-NEXT: ret i64 poison
+; CHECK-NEXT: ret i64 1
;
%sel = select i1 %c, i64 3, i64 0
%trunc = trunc i64 %sel to i8
diff --git a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
index 8baf6a70fdd5d..b8fa7a5db505e 100644
--- a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
@@ -781,7 +781,7 @@ define <2 x i8> @negate_if_true_commute(<2 x i8> %px, i1 %cond) {
define <2 x i8> @negate_if_false_commute(<2 x i8> %px, <2 x i1> %cond) {
; CHECK-LABEL: @negate_if_false_commute(
; CHECK-NEXT: [[X:%.*]] = sdiv <2 x i8> <i8 42, i8 5>, [[PX:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i8> zeroinitializer, [[X]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub nsw <2 x i8> zeroinitializer, [[X]]
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i8> [[X]], <2 x i8> [[TMP1]]
; CHECK-NEXT: ret <2 x i8> [[R]]
;
diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll
index 696490190511d..c8451632e631d 100644
--- a/llvm/test/Transforms/InstCombine/mul.ll
+++ b/llvm/test/Transforms/InstCombine/mul.ll
@@ -323,7 +323,7 @@ define <2 x i8> @shl1_decrement_vec(<2 x i8> %x) {
define i32 @mul_bool(i32 %x, i1 %y) !prof !0 {
; CHECK-LABEL: @mul_bool(
-; CHECK-NEXT: [[M:%.*]] = select i1 [[Y:%.*]], i32 [[X:%.*]], i32 0
+; CHECK-NEXT: [[M:%.*]] = select i1 [[Y:%.*]], i32 [[X:%.*]], i32 0, !prof [[PROF1]]
; CHECK-NEXT: ret i32 [[M]]
;
%z = zext i1 %y to i32
@@ -357,7 +357,7 @@ define <2 x i32> @mul_bool_vec_commute(<2 x i32> %px, <2 x i1> %y) {
define i32 @mul_sext_bool(i1 %x) !prof !0 {
; CHECK-LABEL: @mul_sext_bool(
-; CHECK-NEXT: [[M:%.*]] = select i1 [[X:%.*]], i32 -42, i32 0
+; CHECK-NEXT: [[M:%.*]] = select i1 [[X:%.*]], i32 -42, i32 0, !prof [[PROF1]]
; CHECK-NEXT: ret i32 [[M]]
;
%s = sext i1 %x to i32
@@ -369,7 +369,7 @@ define i32 @mul_sext_bool_use(i1 %x) !prof !0 {
; CHECK-LABEL: @mul_sext_bool_use(
; CHECK-NEXT: [[S:%.*]] = sext i1 [[X:%.*]] to i32
; CHECK-NEXT: call void @use32(i32 [[S]])
-; CHECK-NEXT: [[M:%.*]] = select i1 [[X]], i32 -42, i32 0
+; CHECK-NEXT: [[M:%.*]] = select i1 [[X]], i32 -42, i32 0, !prof [[PROF1]]
; CHECK-NEXT: ret i32 [[M]]
;
%s = sext i1 %x to i32
@@ -436,7 +436,7 @@ define i32 @mul_bools_use3(i1 %x, i1 %y) !prof !0 {
; CHECK-NEXT: call void @use32(i32 [[ZX]])
; CHECK-NEXT: [[ZY:%.*]] = zext i1 [[Y:%.*]] to i32
; CHECK-NEXT: call void @use32(i32 [[ZY]])
-; CHECK-NEXT: [[R:%.*]] = select i1 [[X]], i32 [[ZY]], i32 0
+; CHECK-NEXT: [[R:%.*]] = select i1 [[X]], i32 [[ZY]], i32 0, !prof [[PROF1]]
; CHECK-NEXT: ret i32 [[R]]
;
%zx = zext i1 %x to i32
@@ -745,7 +745,7 @@ define i32 @not_lowbit_mul(i32 %a, i32 %b) {
define i32 @signsplat_mul(i32 %x) !prof !0 {
; CHECK-LABEL: @signsplat_mul(
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[X:%.*]], 0
-; CHECK-NEXT: [[MUL:%.*]] = select i1 [[ISNEG]], i32 -42, i32 0
+; CHECK-NEXT: [[MUL:%.*]] = select i1 [[ISNEG]], i32 -42, i32 0, !prof [[PROF1]]
; CHECK-NEXT: ret i32 [[MUL]]
;
%ash = ashr i32 %x, 31
@@ -1499,7 +1499,7 @@ define <2 x i8> @negate_if_true_commute(<2 x i8> %px, i1 %cond) {
define <2 x i8> @negate_if_false_commute(<2 x i8> %px, <2 x i1> %cond) {
; CHECK-LABEL: @negate_if_false_commute(
; CHECK-NEXT: [[X:%.*]] = sdiv <2 x i8> <i8 42, i8 5>, [[PX:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i8> zeroinitializer, [[X]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub nsw <2 x i8> zeroinitializer, [[X]]
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[COND:%.*]], <2 x i8> [[X]], <2 x i8> [[TMP1]]
; CHECK-NEXT: ret <2 x i8> [[R]]
;
diff --git a/llvm/test/Transforms/InstCombine/mul_full_32.ll b/llvm/test/Transforms/InstCombine/mul_full_32.ll
index 23d35115dbd1d..e85062bee3a25 100644
--- a/llvm/test/Transforms/InstCombine/mul_full_32.ll
+++ b/llvm/test/Transforms/InstCombine/mul_full_32.ll
@@ -16,15 +16,15 @@ define { i64, i64 } @mul_full_64(i64 %x, i64 %y) {
; CHECK-NEXT: [[T3:%.*]] = mul nuw i64 [[YH]], [[XH]]
; CHECK-NEXT: [[T0L:%.*]] = and i64 [[T0]], 4294967295
; CHECK-NEXT: [[T0H:%.*]] = lshr i64 [[T0]], 32
-; CHECK-NEXT: [[U0:%.*]] = add i64 [[T0H]], [[T1]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i64 [[T0H]], [[T1]]
; CHECK-NEXT: [[U0L:%.*]] = and i64 [[U0]], 4294967295
; CHECK-NEXT: [[U0H:%.*]] = lshr i64 [[U0]], 32
-; CHECK-NEXT: [[U1:%.*]] = add i64 [[U0L]], [[T2]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i64 [[U0L]], [[T2]]
; CHECK-NEXT: [[U1LS:%.*]] = shl i64 [[U1]], 32
; CHECK-NEXT: [[U1H:%.*]] = lshr i64 [[U1]], 32
-; CHECK-NEXT: [[U2:%.*]] = add i64 [[U0H]], [[T3]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i64 [[U0H]], [[T3]]
; CHECK-NEXT: [[LO:%.*]] = or disjoint i64 [[U1LS]], [[T0L]]
-; CHECK-NEXT: [[HI:%.*]] = add i64 [[U2]], [[U1H]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i64 [[U2]], [[U1H]]
; CHECK-NEXT: [[RES_LO:%.*]] = insertvalue { i64, i64 } undef, i64 [[LO]], 0
; CHECK-NEXT: [[RES:%.*]] = insertvalue { i64, i64 } [[RES_LO]], i64 [[HI]], 1
; CHECK-NEXT: ret { i64, i64 } [[RES]]
@@ -72,15 +72,15 @@ define { i32, i32 } @mul_full_32(i32 %x, i32 %y) {
; CHECK-NEXT: [[T3:%.*]] = mul nuw i32 [[YH]], [[XH]]
; CHECK-NEXT: [[T0L:%.*]] = and i32 [[T0]], 65535
; CHECK-NEXT: [[T0H:%.*]] = lshr i32 [[T0]], 16
-; CHECK-NEXT: [[U0:%.*]] = add i32 [[T0H]], [[T1]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i32 [[T0H]], [[T1]]
; CHECK-NEXT: [[U0L:%.*]] = and i32 [[U0]], 65535
; CHECK-NEXT: [[U0H:%.*]] = lshr i32 [[U0]], 16
-; CHECK-NEXT: [[U1:%.*]] = add i32 [[U0L]], [[T2]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i32 [[U0L]], [[T2]]
; CHECK-NEXT: [[U1LS:%.*]] = shl i32 [[U1]], 16
; CHECK-NEXT: [[U1H:%.*]] = lshr i32 [[U1]], 16
-; CHECK-NEXT: [[U2:%.*]] = add i32 [[U0H]], [[T3]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i32 [[U0H]], [[T3]]
; CHECK-NEXT: [[LO:%.*]] = or disjoint i32 [[U1LS]], [[T0L]]
-; CHECK-NEXT: [[HI:%.*]] = add i32 [[U2]], [[U1H]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i32 [[U2]], [[U1H]]
; CHECK-NEXT: [[RES_LO:%.*]] = insertvalue { i32, i32 } undef, i32 [[LO]], 0
; CHECK-NEXT: [[RES:%.*]] = insertvalue { i32, i32 } [[RES_LO]], i32 [[HI]], 1
; CHECK-NEXT: ret { i32, i32 } [[RES]]
diff --git a/llvm/test/Transforms/InstCombine/mul_full_64.ll b/llvm/test/Transforms/InstCombine/mul_full_64.ll
index 1bec5bb927604..60ab4b8e23c01 100644
--- a/llvm/test/Transforms/InstCombine/mul_full_64.ll
+++ b/llvm/test/Transforms/InstCombine/mul_full_64.ll
@@ -16,15 +16,15 @@ define { i64, i64 } @mul_full_64_variant0(i64 %x, i64 %y) {
; CHECK-NEXT: [[T3:%.*]] = mul nuw i64 [[YH]], [[XH]]
; CHECK-NEXT: [[T0L:%.*]] = and i64 [[T0]], 4294967295
; CHECK-NEXT: [[T0H:%.*]] = lshr i64 [[T0]], 32
-; CHECK-NEXT: [[U0:%.*]] = add i64 [[T0H]], [[T1]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i64 [[T0H]], [[T1]]
; CHECK-NEXT: [[U0L:%.*]] = and i64 [[U0]], 4294967295
; CHECK-NEXT: [[U0H:%.*]] = lshr i64 [[U0]], 32
-; CHECK-NEXT: [[U1:%.*]] = add i64 [[U0L]], [[T2]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i64 [[U0L]], [[T2]]
; CHECK-NEXT: [[U1LS:%.*]] = shl i64 [[U1]], 32
; CHECK-NEXT: [[U1H:%.*]] = lshr i64 [[U1]], 32
-; CHECK-NEXT: [[U2:%.*]] = add i64 [[U0H]], [[T3]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i64 [[U0H]], [[T3]]
; CHECK-NEXT: [[LO:%.*]] = or disjoint i64 [[U1LS]], [[T0L]]
-; CHECK-NEXT: [[HI:%.*]] = add i64 [[U2]], [[U1H]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i64 [[U2]], [[U1H]]
; CHECK-NEXT: [[RES_LO:%.*]] = insertvalue { i64, i64 } undef, i64 [[LO]], 0
; CHECK-NEXT: [[RES:%.*]] = insertvalue { i64, i64 } [[RES_LO]], i64 [[HI]], 1
; CHECK-NEXT: ret { i64, i64 } [[RES]]
@@ -98,13 +98,13 @@ define i64 @mul_full_64_variant1(i64 %a, i64 %b, ptr nocapture %rhi) {
; CHECK-NEXT: [[MUL6:%.*]] = mul nuw i64 [[SHR_I41]], [[CONV]]
; CHECK-NEXT: [[MUL7:%.*]] = mul nuw i64 [[CONV3]], [[CONV]]
; CHECK-NEXT: [[SHR_I40:%.*]] = lshr i64 [[MUL7]], 32
-; CHECK-NEXT: [[ADD:%.*]] = add i64 [[SHR_I40]], [[MUL5]]
+; CHECK-NEXT: [[ADD:%.*]] = add nuw i64 [[SHR_I40]], [[MUL5]]
; CHECK-NEXT: [[SHR_I39:%.*]] = lshr i64 [[ADD]], 32
-; CHECK-NEXT: [[ADD10:%.*]] = add i64 [[SHR_I39]], [[MUL]]
+; CHECK-NEXT: [[ADD10:%.*]] = add nuw i64 [[SHR_I39]], [[MUL]]
; CHECK-NEXT: [[CONV14:%.*]] = and i64 [[ADD]], 4294967295
-; CHECK-NEXT: [[ADD15:%.*]] = add i64 [[CONV14]], [[MUL6]]
+; CHECK-NEXT: [[ADD15:%.*]] = add nuw i64 [[CONV14]], [[MUL6]]
; CHECK-NEXT: [[SHR_I:%.*]] = lshr i64 [[ADD15]], 32
-; CHECK-NEXT: [[ADD17:%.*]] = add i64 [[ADD10]], [[SHR_I]]
+; CHECK-NEXT: [[ADD17:%.*]] = add nuw i64 [[ADD10]], [[SHR_I]]
; CHECK-NEXT: store i64 [[ADD17]], ptr [[RHI:%.*]], align 8
; CHECK-NEXT: [[MULLO:%.*]] = mul i64 [[B]], [[A]]
; CHECK-NEXT: ret i64 [[MULLO]]
@@ -141,13 +141,13 @@ define i64 @mul_full_64_variant2(i64 %a, i64 %b, ptr nocapture %rhi) {
; CHECK-NEXT: [[MUL6:%.*]] = mul nuw i64 [[SHR_I56]], [[CONV]]
; CHECK-NEXT: [[MUL7:%.*]] = mul nuw i64 [[CONV3]], [[CONV]]
; CHECK-NEXT: [[SHR_I55:%.*]] = lshr i64 [[MUL7]], 32
-; CHECK-NEXT: [[ADD:%.*]] = add i64 [[SHR_I55]], [[MUL5]]
+; CHECK-NEXT: [[ADD:%.*]] = add nuw i64 [[SHR_I55]], [[MUL5]]
; CHECK-NEXT: [[SHR_I54:%.*]] = lshr i64 [[ADD]], 32
-; CHECK-NEXT: [[ADD10:%.*]] = add i64 [[SHR_I54]], [[MUL]]
+; CHECK-NEXT: [[ADD10:%.*]] = add nuw i64 [[SHR_I54]], [[MUL]]
; CHECK-NEXT: [[CONV14:%.*]] = and i64 [[ADD]], 4294967295
-; CHECK-NEXT: [[ADD15:%.*]] = add i64 [[CONV14]], [[MUL6]]
+; CHECK-NEXT: [[ADD15:%.*]] = add nuw i64 [[CONV14]], [[MUL6]]
; CHECK-NEXT: [[SHR_I51:%.*]] = lshr i64 [[ADD15]], 32
-; CHECK-NEXT: [[ADD17:%.*]] = add i64 [[ADD10]], [[SHR_I51]]
+; CHECK-NEXT: [[ADD17:%.*]] = add nuw i64 [[ADD10]], [[SHR_I51]]
; CHECK-NEXT: store i64 [[ADD17]], ptr [[RHI:%.*]], align 8
; CHECK-NEXT: [[CONV24:%.*]] = shl i64 [[ADD15]], 32
; CHECK-NEXT: [[CONV26:%.*]] = and i64 [[MUL7]], 4294967295
@@ -189,13 +189,13 @@ define i64 @mul_full_64_variant3(i64 %a, i64 %b, ptr nocapture %rhi) {
; CHECK-NEXT: [[MUL6:%.*]] = mul nuw i64 [[SHR_I43]], [[CONV]]
; CHECK-NEXT: [[MUL7:%.*]] = mul nuw i64 [[CONV3]], [[CONV]]
; CHECK-NEXT: [[SHR_I42:%.*]] = lshr i64 [[MUL7]], 32
-; CHECK-NEXT: [[ADD:%.*]] = add i64 [[SHR_I42]], [[MUL5]]
+; CHECK-NEXT: [[ADD:%.*]] = add nuw i64 [[SHR_I42]], [[MUL5]]
; CHECK-NEXT: [[SHR_I41:%.*]] = lshr i64 [[ADD]], 32
-; CHECK-NEXT: [[ADD10:%.*]] = add i64 [[SHR_I41]], [[MUL]]
+; CHECK-NEXT: [[ADD10:%.*]] = add nuw i64 [[SHR_I41]], [[MUL]]
; CHECK-NEXT: [[CONV14:%.*]] = and i64 [[ADD]], 4294967295
-; CHECK-NEXT: [[ADD15:%.*]] = add i64 [[CONV14]], [[MUL6]]
+; CHECK-NEXT: [[ADD15:%.*]] = add nuw i64 [[CONV14]], [[MUL6]]
; CHECK-NEXT: [[SHR_I:%.*]] = lshr i64 [[ADD15]], 32
-; CHECK-NEXT: [[ADD17:%.*]] = add i64 [[ADD10]], [[SHR_I]]
+; CHECK-NEXT: [[ADD17:%.*]] = add nuw i64 [[ADD10]], [[SHR_I]]
; CHECK-NEXT: store i64 [[ADD17]], ptr [[RHI:%.*]], align 8
; CHECK-NEXT: [[ADD18:%.*]] = add i64 [[MUL6]], [[MUL5]]
; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[ADD18]], 32
@@ -238,15 +238,15 @@ define { i32, i32 } @mul_full_32(i32 %x, i32 %y) {
; CHECK-NEXT: [[T3:%.*]] = mul nuw i32 [[YH]], [[XH]]
; CHECK-NEXT: [[T0L:%.*]] = and i32 [[T0]], 65535
; CHECK-NEXT: [[T0H:%.*]] = lshr i32 [[T0]], 16
-; CHECK-NEXT: [[U0:%.*]] = add i32 [[T0H]], [[T1]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i32 [[T0H]], [[T1]]
; CHECK-NEXT: [[U0L:%.*]] = and i32 [[U0]], 65535
; CHECK-NEXT: [[U0H:%.*]] = lshr i32 [[U0]], 16
-; CHECK-NEXT: [[U1:%.*]] = add i32 [[U0L]], [[T2]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i32 [[U0L]], [[T2]]
; CHECK-NEXT: [[U1LS:%.*]] = shl i32 [[U1]], 16
; CHECK-NEXT: [[U1H:%.*]] = lshr i32 [[U1]], 16
-; CHECK-NEXT: [[U2:%.*]] = add i32 [[U0H]], [[T3]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i32 [[U0H]], [[T3]]
; CHECK-NEXT: [[LO:%.*]] = or disjoint i32 [[U1LS]], [[T0L]]
-; CHECK-NEXT: [[HI:%.*]] = add i32 [[U2]], [[U1H]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i32 [[U2]], [[U1H]]
; CHECK-NEXT: [[RES_LO:%.*]] = insertvalue { i32, i32 } undef, i32 [[LO]], 0
; CHECK-NEXT: [[RES:%.*]] = insertvalue { i32, i32 } [[RES_LO]], i32 [[HI]], 1
; CHECK-NEXT: ret { i32, i32 } [[RES]]
@@ -302,13 +302,13 @@ define { i64, i64 } @mul_full_64_variant0_1() {
; CHECK-NEXT: [[T2:%.*]] = mul nuw i64 [[YH]], [[XL]]
; CHECK-NEXT: [[T0:%.*]] = mul nuw i64 [[YL]], [[XL]]
; CHECK-NEXT: [[T0H:%.*]] = lshr i64 [[T0]], 32
-; CHECK-NEXT: [[U0:%.*]] = add i64 [[T0H]], [[T1]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i64 [[T0H]], [[T1]]
; CHECK-NEXT: [[U0L:%.*]] = and i64 [[U0]], 4294967295
-; CHECK-NEXT: [[U1:%.*]] = add i64 [[U0L]], [[T2]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i64 [[U0L]], [[T2]]
; CHECK-NEXT: [[U0H:%.*]] = lshr i64 [[U0]], 32
-; CHECK-NEXT: [[U2:%.*]] = add i64 [[U0H]], [[T3]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i64 [[U0H]], [[T3]]
; CHECK-NEXT: [[U1H:%.*]] = lshr i64 [[U1]], 32
-; CHECK-NEXT: [[HI:%.*]] = add i64 [[U2]], [[U1H]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i64 [[U2]], [[U1H]]
; CHECK-NEXT: [[U1LS:%.*]] = shl i64 [[U1]], 32
; CHECK-NEXT: [[T0L:%.*]] = and i64 [[T0]], 4294967295
; CHECK-NEXT: [[LO:%.*]] = or disjoint i64 [[U1LS]], [[T0L]]
@@ -360,13 +360,13 @@ define { i64, i64 } @mul_full_64_variant0_2() {
; CHECK-NEXT: [[T1:%.*]] = mul nuw i64 [[XH]], [[YL]]
; CHECK-NEXT: [[T0:%.*]] = mul nuw i64 [[XL]], [[YL]]
; CHECK-NEXT: [[T0H:%.*]] = lshr i64 [[T0]], 32
-; CHECK-NEXT: [[U0:%.*]] = add i64 [[T1]], [[T0H]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i64 [[T1]], [[T0H]]
; CHECK-NEXT: [[U0L:%.*]] = and i64 [[U0]], 4294967295
-; CHECK-NEXT: [[U1:%.*]] = add i64 [[T2]], [[U0L]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i64 [[T2]], [[U0L]]
; CHECK-NEXT: [[U0H:%.*]] = lshr i64 [[U0]], 32
-; CHECK-NEXT: [[U2:%.*]] = add i64 [[U0H]], [[T3]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i64 [[U0H]], [[T3]]
; CHECK-NEXT: [[U1H:%.*]] = lshr i64 [[U1]], 32
-; CHECK-NEXT: [[HI:%.*]] = add i64 [[U1H]], [[U2]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i64 [[U1H]], [[U2]]
; CHECK-NEXT: [[U1LS:%.*]] = shl i64 [[U1]], 32
; CHECK-NEXT: [[T0L:%.*]] = and i64 [[T0]], 4294967295
; CHECK-NEXT: [[LO:%.*]] = or disjoint i64 [[T0L]], [[U1LS]]
@@ -417,13 +417,13 @@ define i64 @umulh_64(i64 %x, i64 %y) {
; CHECK-NEXT: [[T2:%.*]] = mul nuw i64 [[YH]], [[XL]]
; CHECK-NEXT: [[T3:%.*]] = mul nuw i64 [[YH]], [[XH]]
; CHECK-NEXT: [[T0H:%.*]] = lshr i64 [[T0]], 32
-; CHECK-NEXT: [[U0:%.*]] = add i64 [[T0H]], [[T1]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i64 [[T0H]], [[T1]]
; CHECK-NEXT: [[U0L:%.*]] = and i64 [[U0]], 4294967295
; CHECK-NEXT: [[U0H:%.*]] = lshr i64 [[U0]], 32
-; CHECK-NEXT: [[U1:%.*]] = add i64 [[U0L]], [[T2]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i64 [[U0L]], [[T2]]
; CHECK-NEXT: [[U1H:%.*]] = lshr i64 [[U1]], 32
-; CHECK-NEXT: [[U2:%.*]] = add i64 [[U0H]], [[T3]]
-; CHECK-NEXT: [[HI:%.*]] = add i64 [[U2]], [[U1H]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i64 [[U0H]], [[T3]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i64 [[U2]], [[U1H]]
; CHECK-NEXT: ret i64 [[HI]]
;
%xl = and i64 %x, 4294967295
@@ -577,15 +577,15 @@ define { i64, i64 } @mul_full_64_duplicate(i64 %x, i64 %y) {
; CHECK-NEXT: [[T3:%.*]] = mul nuw i64 [[YH]], [[XH]]
; CHECK-NEXT: [[T0L:%.*]] = and i64 [[T0]], 4294967295
; CHECK-NEXT: [[T0H:%.*]] = lshr i64 [[T0]], 32
-; CHECK-NEXT: [[U0:%.*]] = add i64 [[T0H]], [[T1]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i64 [[T0H]], [[T1]]
; CHECK-NEXT: [[U0L:%.*]] = and i64 [[U0]], 4294967295
; CHECK-NEXT: [[U0H:%.*]] = lshr i64 [[U0]], 32
-; CHECK-NEXT: [[U1:%.*]] = add i64 [[U0L]], [[T2]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i64 [[U0L]], [[T2]]
; CHECK-NEXT: [[U1LS:%.*]] = shl i64 [[U1]], 32
; CHECK-NEXT: [[U1H:%.*]] = lshr i64 [[U1]], 32
-; CHECK-NEXT: [[U2:%.*]] = add i64 [[U0H]], [[T3]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i64 [[U0H]], [[T3]]
; CHECK-NEXT: [[LO:%.*]] = or disjoint i64 [[U1LS]], [[T0L]]
-; CHECK-NEXT: [[HI:%.*]] = add i64 [[U2]], [[U1H]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i64 [[U2]], [[U1H]]
; CHECK-NEXT: [[RES_LO:%.*]] = insertvalue { i64, i64 } undef, i64 [[LO]], 0
; CHECK-NEXT: [[RES:%.*]] = insertvalue { i64, i64 } [[RES_LO]], i64 [[HI]], 1
; CHECK-NEXT: ret { i64, i64 } [[RES]]
@@ -640,13 +640,13 @@ define i64 @umulhi_64_v2() {
; CHECK-NEXT: [[T1:%.*]] = mul nuw i64 [[XH]], [[YL]]
; CHECK-NEXT: [[T0:%.*]] = mul nuw i64 [[XL]], [[YL]]
; CHECK-NEXT: [[T0H:%.*]] = lshr i64 [[T0]], 32
-; CHECK-NEXT: [[U0:%.*]] = add i64 [[T1]], [[T0H]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i64 [[T1]], [[T0H]]
; CHECK-NEXT: [[U0L:%.*]] = and i64 [[U0]], 4294967295
-; CHECK-NEXT: [[U1:%.*]] = add i64 [[T2]], [[U0L]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i64 [[T2]], [[U0L]]
; CHECK-NEXT: [[U0H:%.*]] = lshr i64 [[U0]], 32
-; CHECK-NEXT: [[U2:%.*]] = add i64 [[U0H]], [[T3]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i64 [[U0H]], [[T3]]
; CHECK-NEXT: [[U1H:%.*]] = lshr i64 [[U1]], 32
-; CHECK-NEXT: [[HI:%.*]] = add i64 [[U1H]], [[U2]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i64 [[U1H]], [[U2]]
; CHECK-NEXT: ret i64 [[HI]]
;
%x = call i64 @get_number()
@@ -688,13 +688,13 @@ define i64 @umulhi_64_v3() {
; CHECK-NEXT: [[T1:%.*]] = mul nuw i64 [[XH]], [[YL]]
; CHECK-NEXT: [[T0:%.*]] = mul nuw i64 [[XL]], [[YL]]
; CHECK-NEXT: [[T0H:%.*]] = lshr i64 [[T0]], 32
-; CHECK-NEXT: [[U0:%.*]] = add i64 [[T1]], [[T0H]]
+; CHECK-NEXT: [[U0:%.*]] = add nuw i64 [[T1]], [[T0H]]
; CHECK-NEXT: [[U0L:%.*]] = and i64 [[U0]], 4294967295
-; CHECK-NEXT: [[U1:%.*]] = add i64 [[T2]], [[U0L]]
+; CHECK-NEXT: [[U1:%.*]] = add nuw i64 [[T2]], [[U0L]]
; CHECK-NEXT: [[U0H:%.*]] = lshr i64 [[U0]], 32
-; CHECK-NEXT: [[U2:%.*]] = add i64 [[U0H]], [[T3]]
+; CHECK-NEXT: [[U2:%.*]] = add nuw i64 [[U0H]], [[T3]]
; CHECK-NEXT: [[U1H:%.*]] = lshr i64 [[U1]], 32
-; CHECK-NEXT: [[HI:%.*]] = add i64 [[U1H]], [[U2]]
+; CHECK-NEXT: [[HI:%.*]] = add nuw i64 [[U1H]], [[U2]]
; CHECK-NEXT: ret i64 [[HI]]
;
%x = call i64 @get_number()
diff --git a/llvm/test/Transforms/InstCombine/pr80597.ll b/llvm/test/Transforms/InstCombine/pr80597.ll
index 148da056486f9..bf536b9ecd133 100644
--- a/llvm/test/Transforms/InstCombine/pr80597.ll
+++ b/llvm/test/Transforms/InstCombine/pr80597.ll
@@ -5,14 +5,9 @@ define i64 @pr80597(i1 %cond) {
; CHECK-LABEL: define i64 @pr80597(
; CHECK-SAME: i1 [[COND:%.*]]) {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[ADD:%.*]] = select i1 [[COND]], i64 0, i64 -12884901888
-; CHECK-NEXT: [[SEXT1:%.*]] = add nsw i64 [[ADD]], 8836839514384105472
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[SEXT1]], -34359738368
-; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.else:
-; CHECK-NEXT: [[SEXT2:%.*]] = ashr exact i64 [[ADD]], 1
-; CHECK-NEXT: [[ASHR:%.*]] = or disjoint i64 [[SEXT2]], 4418419761487020032
-; CHECK-NEXT: ret i64 [[ASHR]]
+; CHECK-NEXT: ret i64 poison
; CHECK: if.then:
; CHECK-NEXT: ret i64 0
;
diff --git a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
index 5ac8588a0ed83..f79f98de4543d 100644
--- a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
+++ b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
@@ -1111,8 +1111,7 @@ define <3 x i8> @test_vector_usub_add_nuw_no_ov_nonsplat1_poison(<3 x i8> %a) {
; Can be optimized if the add nuw RHS constant range handles non-splat vectors.
define <2 x i8> @test_vector_usub_add_nuw_no_ov_nonsplat2(<2 x i8> %a) {
; CHECK-LABEL: @test_vector_usub_add_nuw_no_ov_nonsplat2(
-; CHECK-NEXT: [[B:%.*]] = add nuw <2 x i8> [[A:%.*]], <i8 10, i8 9>
-; CHECK-NEXT: [[R:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[B]], <2 x i8> splat (i8 9))
+; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[A:%.*]], <i8 1, i8 0>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%b = add nuw <2 x i8> %a, <i8 10, i8 9>
@@ -1188,7 +1187,7 @@ define <2 x i8> @test_vector_ssub_add_nsw_no_ov_nonsplat2(<2 x i8> %a, <2 x i8>
; CHECK-LABEL: @test_vector_ssub_add_nsw_no_ov_nonsplat2(
; CHECK-NEXT: [[AA:%.*]] = add nsw <2 x i8> [[A:%.*]], <i8 7, i8 8>
; CHECK-NEXT: [[BB:%.*]] = and <2 x i8> [[B:%.*]], splat (i8 7)
-; CHECK-NEXT: [[R:%.*]] = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> [[AA]], <2 x i8> [[BB]])
+; CHECK-NEXT: [[R:%.*]] = sub nsw <2 x i8> [[AA]], [[BB]]
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%aa = add nsw <2 x i8> %a, <i8 7, i8 8>
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index de481e39307cb..f0a3e607ba938 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -3561,6 +3561,237 @@ TEST_F(ValueTrackingTest, ComputeConstantRange) {
// If we don't know the value of x.2, we don't know the value of x.1.
EXPECT_TRUE(CR1.isFullSet());
}
+ {
+ // udiv with bounded operands:
+ // * x in [4, 8), y in [2, 4)
+ // * udiv x, y = [4/3, 8/2) = [1, 4)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %x, i32 %y) {
+ %x.lo = icmp uge i32 %x, 4
+ call void @llvm.assume(i1 %x.lo)
+ %x.hi = icmp ult i32 %x, 8
+ call void @llvm.assume(i1 %x.hi)
+ %y.lo = icmp uge i32 %y, 2
+ call void @llvm.assume(i1 %y.lo)
+ %y.hi = icmp ult i32 %y, 4
+ call void @llvm.assume(i1 %y.hi)
+ %div = udiv i32 %x, %y
+ ret i32 %div
+ })");
+ Function *F = M->getFunction("test");
+ AssumptionCache AC(*F);
+ Instruction *Div = &findInstructionByName(F, "div");
+ ConstantRange CR = computeConstantRange(Div, false, true, &AC, Div);
+ EXPECT_EQ(1, CR.getLower());
+ EXPECT_EQ(4, CR.getUpper());
+ }
+ {
+ // mul with bounded operands:
+ // * x in [2, 5), y in [3, 7)
+ // * mul x, y = [2*3, 4*6+1) = [6, 25)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %x, i32 %y) {
+ %x.lo = icmp uge i32 %x, 2
+ call void @llvm.assume(i1 %x.lo)
+ %x.hi = icmp ult i32 %x, 5
+ call void @llvm.assume(i1 %x.hi)
+ %y.lo = icmp uge i32 %y, 3
+ call void @llvm.assume(i1 %y.lo)
+ %y.hi = icmp ult i32 %y, 7
+ call void @llvm.assume(i1 %y.hi)
+ %mul = mul i32 %x, %y
+ ret i32 %mul
+ })");
+ Function *F = M->getFunction("test");
+ AssumptionCache AC(*F);
+ Instruction *Mul = &findInstructionByName(F, "mul");
+ ConstantRange CR = computeConstantRange(Mul, false, true, &AC, Mul);
+ EXPECT_EQ(6, CR.getLower());
+ EXPECT_EQ(25, CR.getUpper());
+ }
+ {
+ // sdiv with bounded signed operands:
+ // * x in [-8, -1], y in [2, 4)
+ // * sdiv x, y = [-4, 0) (most negative: -8/2=-4, most positive: -1/3=0)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %x, i32 %y) {
+ %x.lo = icmp sge i32 %x, -8
+ call void @llvm.assume(i1 %x.lo)
+ %x.hi = icmp sle i32 %x, -1
+ call void @llvm.assume(i1 %x.hi)
+ %y.lo = icmp sge i32 %y, 2
+ call void @llvm.assume(i1 %y.lo)
+ %y.hi = icmp slt i32 %y, 4
+ call void @llvm.assume(i1 %y.hi)
+ %div = sdiv i32 %x, %y
+ ret i32 %div
+ })");
+ Function *F = M->getFunction("test");
+ AssumptionCache AC(*F);
+ Instruction *Div = &findInstructionByName(F, "div");
+ ConstantRange CR = computeConstantRange(Div, true, true, &AC, Div);
+ // ConstantRange upper bound is exclusive: range is [-4, 0] = [-4, 1).
+ EXPECT_EQ(APInt(32, -4, true), CR.getLower());
+ EXPECT_EQ(APInt(32, 1, true), CR.getUpper());
+ }
+ {
+ // urem with bounded operands:
+ // * x in [5, 10), y in [3, 6)
+ // * urem x, y in [0, 5) (max remainder < max divisor)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %x, i32 %y) {
+ %x.lo = icmp uge i32 %x, 5
+ call void @llvm.assume(i1 %x.lo)
+ %x.hi = icmp ult i32 %x, 10
+ call void @llvm.assume(i1 %x.hi)
+ %y.lo = icmp uge i32 %y, 3
+ call void @llvm.assume(i1 %y.lo)
+ %y.hi = icmp ult i32 %y, 6
+ call void @llvm.assume(i1 %y.hi)
+ %rem = urem i32 %x, %y
+ ret i32 %rem
+ })");
+ Function *F = M->getFunction("test");
+ AssumptionCache AC(*F);
+ Instruction *Rem = &findInstructionByName(F, "rem");
+ ConstantRange CR = computeConstantRange(Rem, false, true, &AC, Rem);
+ EXPECT_FALSE(CR.isFullSet());
+ EXPECT_TRUE(CR.contains(APInt(32, 0)));
+ EXPECT_FALSE(CR.contains(APInt(32, 5)));
+ }
+ {
+ // srem with bounded signed operands:
+ // * x in [5, 10), y in [3, 6)
+ // * srem x, y in [0, 5)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %x, i32 %y) {
+ %x.lo = icmp sge i32 %x, 5
+ call void @llvm.assume(i1 %x.lo)
+ %x.hi = icmp slt i32 %x, 10
+ call void @llvm.assume(i1 %x.hi)
+ %y.lo = icmp sge i32 %y, 3
+ call void @llvm.assume(i1 %y.lo)
+ %y.hi = icmp slt i32 %y, 6
+ call void @llvm.assume(i1 %y.hi)
+ %rem = srem i32 %x, %y
+ ret i32 %rem
+ })");
+ Function *F = M->getFunction("test");
+ AssumptionCache AC(*F);
+ Instruction *Rem = &findInstructionByName(F, "rem");
+ ConstantRange CR = computeConstantRange(Rem, true, true, &AC, Rem);
+ EXPECT_FALSE(CR.isFullSet());
+ EXPECT_TRUE(CR.contains(APInt(32, 0)));
+ EXPECT_FALSE(CR.contains(APInt(32, 5)));
+ }
+ {
+ // add nuw with bounded operands:
+ // * x in [2, 5), y in [10, 20)
+ // * add nuw x, y in [12, 24)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %x, i32 %y) {
+ %x.lo = icmp uge i32 %x, 2
+ call void @llvm.assume(i1 %x.lo)
+ %x.hi = icmp ult i32 %x, 5
+ call void @llvm.assume(i1 %x.hi)
+ %y.lo = icmp uge i32 %y, 10
+ call void @llvm.assume(i1 %y.lo)
+ %y.hi = icmp ult i32 %y, 20
+ call void @llvm.assume(i1 %y.hi)
+ %add = add nuw i32 %x, %y
+ ret i32 %add
+ })");
+ Function *F = M->getFunction("test");
+ AssumptionCache AC(*F);
+ Instruction *Add = &findInstructionByName(F, "add");
+ ConstantRange CR = computeConstantRange(Add, false, true, &AC, Add);
+ EXPECT_EQ(12, CR.getLower());
+ EXPECT_EQ(24, CR.getUpper());
+ }
+ {
+ // sub nuw with bounded operands:
+ // * x in [10, 20), y in [2, 5)
+ // * sub nuw x, y in [6, 18)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %x, i32 %y) {
+ %x.lo = icmp uge i32 %x, 10
+ call void @llvm.assume(i1 %x.lo)
+ %x.hi = icmp ult i32 %x, 20
+ call void @llvm.assume(i1 %x.hi)
+ %y.lo = icmp uge i32 %y, 2
+ call void @llvm.assume(i1 %y.lo)
+ %y.hi = icmp ult i32 %y, 5
+ call void @llvm.assume(i1 %y.hi)
+ %sub = sub nuw i32 %x, %y
+ ret i32 %sub
+ })");
+ Function *F = M->getFunction("test");
+ AssumptionCache AC(*F);
+ Instruction *Sub = &findInstructionByName(F, "sub");
+ ConstantRange CR = computeConstantRange(Sub, false, true, &AC, Sub);
+ EXPECT_EQ(6, CR.getLower());
+ EXPECT_EQ(18, CR.getUpper());
+ }
+ {
+ // trunc propagates range from source:
+ // * x in [0, 256) (i16), trunc to i8 -> [0, 256) but capped at i8 max
+ // * actually x in [4, 8) -> trunc gives [4, 8) in i8
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i8 @test(i16 %x) {
+ %lo = icmp uge i16 %x, 4
+ call void @llvm.assume(i1 %lo)
+ %hi = icmp ult i16 %x, 8
+ call void @llvm.assume(i1 %hi)
+ %t = trunc i16 %x to i8
+ ret i8 %t
+ })");
+ Function *F = M->getFunction("test");
+ AssumptionCache AC(*F);
+ Instruction *T = &findInstructionByName(F, "t");
+ ConstantRange CR = computeConstantRange(T, false, true, &AC, T);
+ EXPECT_EQ(4, CR.getLower());
+ EXPECT_EQ(8, CR.getUpper());
+ }
+ {
+ // assume with signed comparison: ForSigned should be propagated.
+ // x in [-10, -1] (signed), stride = add nsw nuw x, 1
+ // With Cmp->isSigned() the RHS range for the signed icmp is computed
+ // in signed form, giving a tighter result.
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %x) {
+ %lo = icmp sge i32 %x, -10
+ call void @llvm.assume(i1 %lo)
+ %hi = icmp slt i32 %x, 0
+ call void @llvm.assume(i1 %hi)
+ %r = add nsw nuw i32 %x, 1
+ ret i32 %r
+ })");
+ Function *F = M->getFunction("test");
+ AssumptionCache AC(*F);
+ Value *X = &*F->arg_begin();
+ Instruction *I = &findInstructionByName(F, "r");
+ ConstantRange CR = computeConstantRange(X, true, true, &AC, I);
+ EXPECT_EQ(APInt(32, -10, true), CR.getLower());
+ EXPECT_EQ(APInt(32, 0, true), CR.getUpper());
+ }
}
struct FindAllocaForValueTestParams {
More information about the llvm-commits
mailing list