Skip to content

Commit e6f2a79

Browse files
committed
[InstCombine] canonicalizeSaturatedAdd(): last fold is only valid for strict comparison (PR48390)
We could create uadd.sat under incorrect circumstances if a select with -1 as the false value was canonicalized by swapping the T/F values. Unlike the other transforms in the same function, it is not invariant to equality. Some alive proofs: https://alive2.llvm.org/ce/z/emmKKL Based on original patch by David Green! Fixes https://bugs.llvm.org/show_bug.cgi?id=48390 Differential Revision: https://reviews.llvm.org/D92717
1 parent f16320b commit e6f2a79

File tree

2 files changed

+27
-17
lines changed

2 files changed

+27
-17
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -765,25 +765,24 @@ static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal,
765765

766766
// Match unsigned saturated add of 2 variables with an unnecessary 'not'.
767767
// There are 8 commuted variants.
768-
// Canonicalize -1 (saturated result) to true value of the select. Just
769-
// swapping the compare operands is legal, because the selected value is the
770-
// same in case of equality, so we can interchange u< and u<=.
768+
// Canonicalize -1 (saturated result) to true value of the select.
771769
if (match(FVal, m_AllOnes())) {
772770
std::swap(TVal, FVal);
773-
std::swap(Cmp0, Cmp1);
771+
Pred = CmpInst::getInversePredicate(Pred);
774772
}
775773
if (!match(TVal, m_AllOnes()))
776774
return nullptr;
777775

778-
// Canonicalize predicate to 'ULT'.
779-
if (Pred == ICmpInst::ICMP_UGT) {
780-
Pred = ICmpInst::ICMP_ULT;
776+
// Canonicalize predicate to less-than or less-or-equal-than.
777+
if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE) {
781778
std::swap(Cmp0, Cmp1);
779+
Pred = CmpInst::getSwappedPredicate(Pred);
782780
}
783-
if (Pred != ICmpInst::ICMP_ULT)
781+
if (Pred != ICmpInst::ICMP_ULT && Pred != ICmpInst::ICMP_ULE)
784782
return nullptr;
785783

786784
// Match unsigned saturated add of 2 variables with an unnecessary 'not'.
785+
// Strictness of the comparison is irrelevant.
787786
Value *Y;
788787
if (match(Cmp0, m_Not(m_Value(X))) &&
789788
match(FVal, m_c_Add(m_Specific(X), m_Value(Y))) && Y == Cmp1) {
@@ -792,6 +791,7 @@ static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal,
792791
return Builder.CreateBinaryIntrinsic(Intrinsic::uadd_sat, X, Y);
793792
}
794793
// The 'not' op may be included in the sum but not the compare.
794+
// Strictness of the comparison is irrelevant.
795795
X = Cmp0;
796796
Y = Cmp1;
797797
if (match(FVal, m_c_Add(m_Not(m_Specific(X)), m_Specific(Y)))) {
@@ -802,7 +802,9 @@ static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal,
802802
Intrinsic::uadd_sat, BO->getOperand(0), BO->getOperand(1));
803803
}
804804
// The overflow may be detected via the add wrapping round.
805-
if (match(Cmp0, m_c_Add(m_Specific(Cmp1), m_Value(Y))) &&
805+
// This is only valid for strict comparison!
806+
if (Pred == ICmpInst::ICMP_ULT &&
807+
match(Cmp0, m_c_Add(m_Specific(Cmp1), m_Value(Y))) &&
806808
match(FVal, m_c_Add(m_Specific(Cmp1), m_Specific(Y)))) {
807809
// ((X + Y) u< X) ? -1 : (X + Y) --> uadd.sat(X, Y)
808810
// ((X + Y) u< Y) ? -1 : (X + Y) --> uadd.sat(X, Y)

llvm/test/Transforms/InstCombine/saturating-add-sub.ll

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,8 +1801,10 @@ define i32 @uadd_sat_via_add(i32 %x, i32 %y) {
18011801

18021802
define i32 @uadd_sat_via_add_nonstrict(i32 %x, i32 %y) {
18031803
; CHECK-LABEL: @uadd_sat_via_add_nonstrict(
1804-
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[Y:%.*]], i32 [[X:%.*]])
1805-
; CHECK-NEXT: ret i32 [[TMP1]]
1804+
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], [[Y:%.*]]
1805+
; CHECK-NEXT: [[C_NOT:%.*]] = icmp ugt i32 [[A]], [[Y]]
1806+
; CHECK-NEXT: [[R:%.*]] = select i1 [[C_NOT]], i32 [[A]], i32 -1
1807+
; CHECK-NEXT: ret i32 [[R]]
18061808
;
18071809
%a = add i32 %x, %y
18081810
%c = icmp ule i32 %a, %y
@@ -1823,8 +1825,10 @@ define i32 @uadd_sat_via_add_swapped_select(i32 %x, i32 %y) {
18231825

18241826
define i32 @uadd_sat_via_add_swapped_select_strict(i32 %x, i32 %y) {
18251827
; CHECK-LABEL: @uadd_sat_via_add_swapped_select_strict(
1826-
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[Y:%.*]], i32 [[X:%.*]])
1827-
; CHECK-NEXT: ret i32 [[TMP1]]
1828+
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], [[Y:%.*]]
1829+
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[A]], [[Y]]
1830+
; CHECK-NEXT: [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 -1
1831+
; CHECK-NEXT: ret i32 [[R]]
18281832
;
18291833
%a = add i32 %x, %y
18301834
%c = icmp ugt i32 %a, %y
@@ -1845,8 +1849,10 @@ define i32 @uadd_sat_via_add_swapped_cmp(i32 %x, i32 %y) {
18451849

18461850
define i32 @uadd_sat_via_add_swapped_cmp_nonstrict(i32 %x, i32 %y) {
18471851
; CHECK-LABEL: @uadd_sat_via_add_swapped_cmp_nonstrict(
1848-
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[Y:%.*]], i32 [[X:%.*]])
1849-
; CHECK-NEXT: ret i32 [[TMP1]]
1852+
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], [[Y:%.*]]
1853+
; CHECK-NEXT: [[C_NOT:%.*]] = icmp ugt i32 [[A]], [[Y]]
1854+
; CHECK-NEXT: [[R:%.*]] = select i1 [[C_NOT]], i32 [[A]], i32 -1
1855+
; CHECK-NEXT: ret i32 [[R]]
18501856
;
18511857
%a = add i32 %x, %y
18521858
%c = icmp uge i32 %y, %a
@@ -1867,8 +1873,10 @@ define i32 @uadd_sat_via_add_swapped_cmp_nonstric(i32 %x, i32 %y) {
18671873

18681874
define i32 @uadd_sat_via_add_swapped_cmp_select_nonstrict(i32 %x, i32 %y) {
18691875
; CHECK-LABEL: @uadd_sat_via_add_swapped_cmp_select_nonstrict(
1870-
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[Y:%.*]], i32 [[X:%.*]])
1871-
; CHECK-NEXT: ret i32 [[TMP1]]
1876+
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], [[Y:%.*]]
1877+
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[A]], [[Y]]
1878+
; CHECK-NEXT: [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 -1
1879+
; CHECK-NEXT: ret i32 [[R]]
18721880
;
18731881
%a = add i32 %x, %y
18741882
%c = icmp ult i32 %y, %a

0 commit comments

Comments
 (0)