Skip to content

Commit 3f302ea

Browse files
authored
[InstCombine] Fold usub_sat((sub nuw C1, A), C2) to usub_sat(C1 - C2, A) or 0 (#82280)
- Fixes: #82177 - Alive2: https://alive2.llvm.org/ce/z/Q7mMC3
1 parent b1be69f commit 3f302ea

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2164,8 +2164,22 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
21642164
}
21652165
}
21662166

2167+
// usub_sat((sub nuw C, A), C1) -> usub_sat(usub_sat(C, C1), A)
2168+
// which after that:
2169+
// usub_sat((sub nuw C, A), C1) -> usub_sat(C - C1, A) if C1 u< C
2170+
// usub_sat((sub nuw C, A), C1) -> 0 otherwise
2171+
Constant *C, *C1;
2172+
Value *A;
2173+
if (IID == Intrinsic::usub_sat &&
2174+
match(Arg0, m_NUWSub(m_ImmConstant(C), m_Value(A))) &&
2175+
match(Arg1, m_ImmConstant(C1))) {
2176+
auto *NewC = Builder.CreateBinaryIntrinsic(Intrinsic::usub_sat, C, C1);
2177+
auto *NewSub =
2178+
Builder.CreateBinaryIntrinsic(Intrinsic::usub_sat, NewC, A);
2179+
return replaceInstUsesWith(*SI, NewSub);
2180+
}
2181+
21672182
// ssub.sat(X, C) -> sadd.sat(X, -C) if C != MIN
2168-
Constant *C;
21692183
if (IID == Intrinsic::ssub_sat && match(Arg1, m_Constant(C)) &&
21702184
C->isNotMinSignedValue()) {
21712185
Value *NegVal = ConstantExpr::getNeg(C);

llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,95 @@ declare void @use(i64)
88
declare void @usei32(i32)
99
declare void @usei1(i1)
1010

11+
; usub_sat((sub nuw C1, A), C2) to usub_sat(usub_sat(C1 - C2), A)
12+
define i32 @usub_sat_C1_C2(i32 %a){
13+
; CHECK-LABEL: @usub_sat_C1_C2(
14+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 50, i32 [[A:%.*]])
15+
; CHECK-NEXT: ret i32 [[COND]]
16+
;
17+
%add = sub nuw i32 64, %a
18+
%cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
19+
ret i32 %cond
20+
}
21+
22+
define i32 @usub_sat_C1_C2_produce_0(i32 %a){
23+
; CHECK-LABEL: @usub_sat_C1_C2_produce_0(
24+
; CHECK-NEXT: ret i32 0
25+
;
26+
%add = sub nuw i32 14, %a
27+
%cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
28+
ret i32 %cond
29+
}
30+
31+
define i32 @usub_sat_C1_C2_produce_0_too(i32 %a){
32+
; CHECK-LABEL: @usub_sat_C1_C2_produce_0_too(
33+
; CHECK-NEXT: ret i32 0
34+
;
35+
%add = sub nuw i32 12, %a
36+
%cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
37+
ret i32 %cond
38+
}
39+
40+
; vector tests
41+
define <2 x i16> @usub_sat_C1_C2_splat(<2 x i16> %a) {
42+
; CHECK-LABEL: @usub_sat_C1_C2_splat(
43+
; CHECK-NEXT: [[COND:%.*]] = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> <i16 50, i16 50>, <2 x i16> [[A:%.*]])
44+
; CHECK-NEXT: ret <2 x i16> [[COND]]
45+
;
46+
%add = sub nuw <2 x i16> <i16 64, i16 64>, %a
47+
%cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 14, i16 14>)
48+
ret <2 x i16> %cond
49+
}
50+
51+
define <2 x i16> @usub_sat_C1_C2_non_splat(<2 x i16> %a) {
52+
; CHECK-LABEL: @usub_sat_C1_C2_non_splat(
53+
; CHECK-NEXT: [[COND:%.*]] = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> <i16 30, i16 50>, <2 x i16> [[A:%.*]])
54+
; CHECK-NEXT: ret <2 x i16> [[COND]]
55+
;
56+
%add = sub nuw <2 x i16> <i16 50, i16 64>, %a
57+
%cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 20, i16 14>)
58+
ret <2 x i16> %cond
59+
}
60+
61+
define <2 x i16> @usub_sat_C1_C2_splat_produce_0(<2 x i16> %a){
62+
; CHECK-LABEL: @usub_sat_C1_C2_splat_produce_0(
63+
; CHECK-NEXT: ret <2 x i16> zeroinitializer
64+
;
65+
%add = sub nuw <2 x i16> <i16 14, i16 14>, %a
66+
%cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 14, i16 14>)
67+
ret <2 x i16> %cond
68+
}
69+
70+
define <2 x i16> @usub_sat_C1_C2_splat_produce_0_too(<2 x i16> %a){
71+
; CHECK-LABEL: @usub_sat_C1_C2_splat_produce_0_too(
72+
; CHECK-NEXT: ret <2 x i16> zeroinitializer
73+
;
74+
%add = sub nuw <2 x i16> <i16 12, i16 12>, %a
75+
%cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 14, i16 14>)
76+
ret <2 x i16> %cond
77+
}
78+
79+
define <2 x i16> @usub_sat_C1_C2_non_splat_produce_0_too(<2 x i16> %a){
80+
; CHECK-LABEL: @usub_sat_C1_C2_non_splat_produce_0_too(
81+
; CHECK-NEXT: ret <2 x i16> zeroinitializer
82+
;
83+
%add = sub nuw <2 x i16> <i16 12, i16 13>, %a
84+
%cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 14, i16 15>)
85+
ret <2 x i16> %cond
86+
}
87+
88+
; negative tests this souldn't work
89+
define i32 @usub_sat_C1_C2_without_nuw(i32 %a){
90+
; CHECK-LABEL: @usub_sat_C1_C2_without_nuw(
91+
; CHECK-NEXT: [[ADD:%.*]] = sub i32 12, [[A:%.*]]
92+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[ADD]], i32 14)
93+
; CHECK-NEXT: ret i32 [[COND]]
94+
;
95+
%add = sub i32 12, %a
96+
%cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
97+
ret i32 %cond
98+
}
99+
11100
; (a > b) ? a - b : 0 -> usub.sat(a, b)
12101

13102
define i64 @max_sub_ugt(i64 %a, i64 %b) {

0 commit comments

Comments
 (0)