[llvm] 58cffea - [InstCombine] Canonicalize signed saturated additions (#153053)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 18 09:15:29 PST 2025
Author: AZero13
Date: 2025-11-19T01:15:26+08:00
New Revision: 58cffea94a31e52d6492ce7103e04c6b073dee16
URL: https://github.com/llvm/llvm-project/commit/58cffea94a31e52d6492ce7103e04c6b073dee16
DIFF: https://github.com/llvm/llvm-project/commit/58cffea94a31e52d6492ce7103e04c6b073dee16.diff
LOG: [InstCombine] Canonicalize signed saturated additions (#153053)
https://alive2.llvm.org/ce/z/YGT5SN
https://alive2.llvm.org/ce/z/PVDxCw
https://alive2.llvm.org/ce/z/8buR2N
This is tricky because with positive numbers, we only go up, so we can
in fact always hit the signed_max boundary. This is important because
the intrinsic we use has the behavior of going the OTHER way, aka clamp
to INT_MIN if it goes in that direction.
And the range checking we do only works for positive numbers.
Because of this issue, we can only do this for constants as well.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
llvm/test/Transforms/InstCombine/saturating-add-sub.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 9572f9d702e1b..e7dc366b13798 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1027,10 +1027,9 @@ static Value *canonicalizeSaturatedSubtract(const ICmpInst *ICI,
return Result;
}
-static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal,
- InstCombiner::BuilderTy &Builder) {
- if (!Cmp->hasOneUse())
- return nullptr;
+static Value *
+canonicalizeSaturatedAddUnsigned(ICmpInst *Cmp, Value *TVal, Value *FVal,
+ InstCombiner::BuilderTy &Builder) {
// Match unsigned saturated add with constant.
Value *Cmp0 = Cmp->getOperand(0);
@@ -1130,6 +1129,94 @@ static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal,
return nullptr;
}
+static Value *canonicalizeSaturatedAddSigned(ICmpInst *Cmp, Value *TVal,
+ Value *FVal,
+ InstCombiner::BuilderTy &Builder) {
+ // Match saturated add with constant.
+ Value *Cmp0 = Cmp->getOperand(0);
+ Value *Cmp1 = Cmp->getOperand(1);
+ ICmpInst::Predicate Pred = Cmp->getPredicate();
+ Value *X;
+ const APInt *C;
+
+ // Canonicalize INT_MAX to true value of the select.
+ if (match(FVal, m_MaxSignedValue())) {
+ std::swap(TVal, FVal);
+ Pred = CmpInst::getInversePredicate(Pred);
+ }
+
+ if (!match(TVal, m_MaxSignedValue()))
+ return nullptr;
+
+ // sge maximum signed value is canonicalized to eq maximum signed value and
+ // requires special handling (a == INT_MAX) ? INT_MAX : a + 1 -> sadd.sat(a,
+ // 1)
+ if (Pred == ICmpInst::ICMP_EQ) {
+ if (match(FVal, m_Add(m_Specific(Cmp0), m_One())) && Cmp1 == TVal) {
+ return Builder.CreateBinaryIntrinsic(
+ Intrinsic::sadd_sat, Cmp0, ConstantInt::get(Cmp0->getType(), 1));
+ }
+ return nullptr;
+ }
+
+ // (X > Y) ? INT_MAX : (X + C) --> sadd.sat(X, C)
+ // (X >= Y) ? INT_MAX : (X + C) --> sadd.sat(X, C)
+ // where Y is INT_MAX - C or INT_MAX - C - 1, and C > 0
+ if ((Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE) &&
+ match(FVal, m_Add(m_Specific(Cmp0), m_StrictlyPositive(C)))) {
+ APInt IntMax =
+ APInt::getSignedMaxValue(Cmp1->getType()->getScalarSizeInBits());
+
+ // For SGE, try to flip to SGT to normalize the comparison constant.
+ if (Pred == ICmpInst::ICMP_SGE) {
+ if (auto Flipped = getFlippedStrictnessPredicateAndConstant(
+ Pred, cast<Constant>(Cmp1))) {
+ Pred = Flipped->first;
+ Cmp1 = Flipped->second;
+ }
+ }
+
+ // Check the pattern: X > INT_MAX - C or X > INT_MAX - C - 1
+ if (Pred == ICmpInst::ICMP_SGT &&
+ (match(Cmp1, m_SpecificIntAllowPoison(IntMax - *C)) ||
+ match(Cmp1, m_SpecificIntAllowPoison(IntMax - *C - 1))))
+ return Builder.CreateBinaryIntrinsic(
+ Intrinsic::sadd_sat, Cmp0, ConstantInt::get(Cmp0->getType(), *C));
+ }
+
+ // Canonicalize predicate to less-than or less-or-equal-than.
+ if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE) {
+ std::swap(Cmp0, Cmp1);
+ Pred = CmpInst::getSwappedPredicate(Pred);
+ }
+
+ if (Pred != ICmpInst::ICMP_SLT && Pred != ICmpInst::ICMP_SLE)
+ return nullptr;
+
+ if (match(Cmp0, m_NSWSub(m_MaxSignedValue(), m_Value(X))) &&
+ match(FVal, m_c_Add(m_Specific(X), m_Specific(Cmp1)))) {
+ // (INT_MAX - X s< Y) ? INT_MAX : (X + Y) --> sadd.sat(X, Y)
+ // (INT_MAX - X s< Y) ? INT_MAX : (Y + X) --> sadd.sat(X, Y)
+ return Builder.CreateBinaryIntrinsic(Intrinsic::sadd_sat, X, Cmp1);
+ }
+
+ return nullptr;
+}
+
+static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal,
+ InstCombiner::BuilderTy &Builder) {
+ if (!Cmp->hasOneUse())
+ return nullptr;
+
+ if (Value *V = canonicalizeSaturatedAddUnsigned(Cmp, TVal, FVal, Builder))
+ return V;
+
+ if (Value *V = canonicalizeSaturatedAddSigned(Cmp, TVal, FVal, Builder))
+ return V;
+
+ return nullptr;
+}
+
/// Try to match patterns with select and subtract as absolute
diff erence.
static Value *foldAbsDiff(ICmpInst *Cmp, Value *TVal, Value *FVal,
InstCombiner::BuilderTy &Builder) {
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll b/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
index b3093a92624ae..f0e40f4ede161 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
@@ -123,8 +123,7 @@ define i8 @udiv_slt_exact(i8 %x) {
define i8 @canonicalize_icmp_operands(i8 %x) {
; CHECK-LABEL: define i8 @canonicalize_icmp_operands(
; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 119)
-; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], 8
+; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[X]], i8 8)
; CHECK-NEXT: ret i8 [[S]]
;
%add = add nsw i8 %x, 8
diff --git a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
index cfd679c0cc592..c0ad5818e448a 100644
--- a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
+++ b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
@@ -2351,3 +2351,323 @@ define i8 @fold_add_umax_to_usub_multiuse(i8 %a) {
}
declare void @usei8(i8)
+
+define i8 @sadd_sat_uge_int_max(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_uge_int_max(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 127
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp sge i8 %x, 127
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_ugt_int_max(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_ugt_int_max(
+; CHECK-NEXT: [[R:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp sgt i8 %x, 127
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_eq_int_max(i8 %x) {
+; CHECK-LABEL: @sadd_sat_eq_int_max(
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[X:%.*]], i8 1)
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp eq i8 %x, 127
+ %add = add i8 %x, 1
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_constant(i8 %x) {
+; CHECK-LABEL: @sadd_sat_constant(
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[X:%.*]], i8 10)
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp sge i8 %x, 118
+ %add = add i8 %x, 10
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_negative_no_fold(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_negative_no_fold(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 127
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp sge i8 %x, 127
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_wrong_predicate(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_wrong_predicate(
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[X:%.*]], 127
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[Y:%.*]], 127
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP_NOT]], i8 [[ADD]], i8 127
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp slt i8 %x, 127
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_wrong_constant(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_wrong_constant(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], 125
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp sge i8 %x, 126
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define <2 x i8> @sadd_sat_vector(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @sadd_sat_vector(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], splat (i8 127)
+; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[CMP]], <2 x i8> splat (i8 127), <2 x i8> [[ADD]]
+; CHECK-NEXT: ret <2 x i8> [[R]]
+;
+ %cmp = icmp sge <2 x i8> %x, <i8 127, i8 127>
+ %add = add <2 x i8> %x, %y
+ %r = select <2 x i1> %cmp, <2 x i8> <i8 127, i8 127>, <2 x i8> %add
+ ret <2 x i8> %r
+}
+
+define <2 x i8> @sadd_sat_vector_constant(<2 x i8> %x) {
+; CHECK-LABEL: @sadd_sat_vector_constant(
+; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.smin.v2i8(<2 x i8> [[X:%.*]], <2 x i8> <i8 117, i8 107>)
+; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[TMP1]], <i8 10, i8 20>
+; CHECK-NEXT: ret <2 x i8> [[R]]
+;
+ %cmp = icmp sge <2 x i8> %x, <i8 118, i8 108>
+ %add = add <2 x i8> %x, <i8 10, i8 20>
+ %r = select <2 x i1> %cmp, <2 x i8> <i8 127, i8 127>, <2 x i8> %add
+ ret <2 x i8> %r
+}
+
+define i8 @sadd_sat_int_max_minus_x(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x(
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 127, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SUB]], [[Y:%.*]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub i8 127, %x
+ %cmp = icmp slt i8 %sub, %y
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_int_max_minus_x_commuted(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x_commuted(
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 127, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[Y:%.*]], [[SUB]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub i8 127, %x
+ %cmp = icmp sgt i8 %y, %sub
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_int_max_minus_x_nonstrict(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x_nonstrict(
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 127, [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i8 [[SUB]], [[Y:%.*]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP_NOT]], i8 [[ADD]], i8 127
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub i8 127, %x
+ %cmp = icmp sle i8 %sub, %y
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_int_max_minus_x_commuted_nonstrict(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x_commuted_nonstrict(
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 127, [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp slt i8 [[Y:%.*]], [[SUB]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP_NOT]], i8 [[ADD]], i8 127
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub i8 127, %x
+ %cmp = icmp sge i8 %y, %sub
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_int_max_minus_x_wrong_constant(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x_wrong_constant(
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 126, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SUB]], [[Y:%.*]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub i8 126, %x
+ %cmp = icmp slt i8 %sub, %y
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_int_max_minus_x_wrong_predicate(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x_wrong_predicate(
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 127, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[SUB]], [[Y:%.*]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub i8 127, %x
+ %cmp = icmp sgt i8 %sub, %y
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define <2 x i8> @sadd_sat_int_max_minus_x_vector(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x_vector(
+; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i8> splat (i8 127), [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[SUB]], [[Y:%.*]]
+; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[CMP]], <2 x i8> splat (i8 127), <2 x i8> [[ADD]]
+; CHECK-NEXT: ret <2 x i8> [[R]]
+;
+ %sub = sub <2 x i8> <i8 127, i8 127>, %x
+ %cmp = icmp slt <2 x i8> %sub, %y
+ %add = add <2 x i8> %x, %y
+ %r = select <2 x i1> %cmp, <2 x i8> <i8 127, i8 127>, <2 x i8> %add
+ ret <2 x i8> %r
+}
+
+define i8 @sadd_sat_commuted_select(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_commuted_select(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 127
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[Y:%.*]], 127
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 127
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp sge i8 %x, 127
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 %add, i8 127
+ ret i8 %r
+}
+
+define i8 @sadd_sat_commuted_add(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_commuted_add(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 127
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[Y:%.*]], [[X]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp sge i8 %x, 127
+ %add = add i8 %y, %x
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_commuted_both(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_commuted_both(
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 127
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[Y:%.*]], 127
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 127
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %cmp = icmp sge i8 %x, 127
+ %add = add i8 %y, %x
+ %r = select i1 %cmp, i8 %add, i8 127
+ ret i8 %r
+}
+
+define i8 @sadd_sat_int_max_minus_x_nsw_slt(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x_nsw_slt(
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub nsw i8 127, %x
+ %cmp = icmp slt i8 %sub, %y
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_int_max_minus_x_nsw_sge_commuted(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x_nsw_sge_commuted(
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub nsw i8 127, %x
+ %cmp = icmp sge i8 %y, %sub
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @sadd_sat_int_max_minus_x_no_nsw_neg(i8 %x, i8 %y) {
+; CHECK-LABEL: @sadd_sat_int_max_minus_x_no_nsw_neg(
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 127, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[SUB]], [[Y:%.*]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub i8 127, %x
+ %cmp = icmp slt i8 %sub, %y
+ %add = add i8 %x, %y
+ %r = select i1 %cmp, i8 127, i8 %add
+ ret i8 %r
+}
+
+define i8 @neg_no_nsw(i8 %x, i8 %y) {
+; CHECK-LABEL: @neg_no_nsw(
+; CHECK-NEXT: [[ADD:%.*]] = sub i8 127, [[Y:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], [[ADD]]
+; CHECK-NEXT: [[D:%.*]] = add i8 [[X]], [[Y]]
+; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 127, i8 [[D]]
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %add = sub i8 127, %y
+ %cmp = icmp sgt i8 %x, %add
+ %d = add i8 %x, %y
+ %s = select i1 %cmp, i8 127, i8 %d
+ ret i8 %s
+}
+
+define i8 @neg_neg_constant(i8 %x, i8 %y) {
+; CHECK-LABEL: @neg_neg_constant(
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 -1)
+; CHECK-NEXT: [[S:%.*]] = and i8 [[TMP1]], 127
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %cmp = icmp sgt i8 %x, -2
+ %d = add i8 %x, -128
+ %s = select i1 %cmp, i8 127, i8 %d
+ ret i8 %s
+}
More information about the llvm-commits
mailing list