xref: /llvm-project/llvm/test/Transforms/InstCombine/canonicalize-or-with-overflow-icmp.ll (revision c59ea32f82128f550b471ed96b7ac093ff448c60)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32)
5declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32)
6declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32)
7declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32)
8
9declare void @use(i1)
10
11; Tests from PR75360
12define i1 @ckd_add_unsigned(i31 %num) {
13; CHECK-LABEL: define i1 @ckd_add_unsigned(
14; CHECK-SAME: i31 [[NUM:%.*]]) {
15; CHECK-NEXT:    [[A2:%.*]] = icmp eq i31 [[NUM]], -1
16; CHECK-NEXT:    ret i1 [[A2]]
17;
18  %a0 = zext i31 %num to i32
19  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1)
20  %a2 = extractvalue { i32, i1 } %a1, 1
21  %a3 = extractvalue { i32, i1 } %a1, 0
22  %a4 = icmp slt i32 %a3, 0
23  %a5 = or i1 %a2, %a4
24  ret i1 %a5
25}
26
27define i1 @ckd_add_unsigned_commuted(i31 %num) {
28; CHECK-LABEL: define i1 @ckd_add_unsigned_commuted(
29; CHECK-SAME: i31 [[NUM:%.*]]) {
30; CHECK-NEXT:    [[A2:%.*]] = icmp eq i31 [[NUM]], -1
31; CHECK-NEXT:    ret i1 [[A2]]
32;
33  %a0 = zext i31 %num to i32
34  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1)
35  %a2 = extractvalue { i32, i1 } %a1, 1
36  %a3 = extractvalue { i32, i1 } %a1, 0
37  %a4 = icmp slt i32 %a3, 0
38  %a5 = or i1 %a4, %a2
39  ret i1 %a5
40}
41
42define i1 @ckd_add_unsigned_imply_true(i31 %num) {
43; CHECK-LABEL: define i1 @ckd_add_unsigned_imply_true(
44; CHECK-SAME: i31 [[NUM:%.*]]) {
45; CHECK-NEXT:    ret i1 true
46;
47  %a0 = zext i31 %num to i32
48  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1)
49  %a2 = extractvalue { i32, i1 } %a1, 1
50  %a3 = extractvalue { i32, i1 } %a1, 0
51  %a4 = icmp sgt i32 %a3, -1
52  %a5 = or i1 %a2, %a4
53  ret i1 %a5
54}
55
56define i1 @canonicalize_or_sadd_with_overflow_icmp(i32 %a0) {
57; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp(
58; CHECK-SAME: i32 [[A0:%.*]]) {
59; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[A0]], -2147483647
60; CHECK-NEXT:    [[A5:%.*]] = icmp sgt i32 [[TMP1]], -1
61; CHECK-NEXT:    ret i1 [[A5]]
62;
63  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1)
64  %a2 = extractvalue { i32, i1 } %a1, 1
65  %a3 = extractvalue { i32, i1 } %a1, 0
66  %a4 = icmp slt i32 %a3, 0
67  %a5 = or i1 %a2, %a4
68  ret i1 %a5
69}
70
71define i1 @canonicalize_or_ssub_with_overflow_icmp(i32 %a0) {
72; CHECK-LABEL: define i1 @canonicalize_or_ssub_with_overflow_icmp(
73; CHECK-SAME: i32 [[A0:%.*]]) {
74; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[A0]], 1
75; CHECK-NEXT:    ret i1 [[TMP1]]
76;
77  %a1 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a0, i32 1)
78  %a2 = extractvalue { i32, i1 } %a1, 1
79  %a3 = extractvalue { i32, i1 } %a1, 0
80  %a4 = icmp slt i32 %a3, 0
81  %a5 = or i1 %a2, %a4
82  ret i1 %a5
83}
84
85define i1 @canonicalize_or_uadd_with_overflow_icmp(i32 %a0) {
86; CHECK-LABEL: define i1 @canonicalize_or_uadd_with_overflow_icmp(
87; CHECK-SAME: i32 [[A0:%.*]]) {
88; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[A0]], 1
89; CHECK-NEXT:    [[A5:%.*]] = icmp ult i32 [[TMP1]], 10
90; CHECK-NEXT:    ret i1 [[A5]]
91;
92  %a1 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a0, i32 1)
93  %a2 = extractvalue { i32, i1 } %a1, 1
94  %a3 = extractvalue { i32, i1 } %a1, 0
95  %a4 = icmp ult i32 %a3, 10
96  %a5 = or i1 %a2, %a4
97  ret i1 %a5
98}
99
100define i1 @canonicalize_or_sadd_with_overflow_icmp_eq(i32 %a0) {
101; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_eq(
102; CHECK-SAME: i32 [[A0:%.*]]) {
103; CHECK-NEXT:    [[A2:%.*]] = icmp eq i32 [[A0]], 2147483647
104; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[A0]], 9
105; CHECK-NEXT:    [[A5:%.*]] = or i1 [[A2]], [[TMP1]]
106; CHECK-NEXT:    ret i1 [[A5]]
107;
108  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1)
109  %a2 = extractvalue { i32, i1 } %a1, 1
110  %a3 = extractvalue { i32, i1 } %a1, 0
111  %a4 = icmp eq i32 %a3, 10
112  %a5 = or i1 %a2, %a4
113  ret i1 %a5
114}
115
116define i1 @canonicalize_or_uadd_with_overflow_icmp_ne(i32 %a0) {
117; CHECK-LABEL: define i1 @canonicalize_or_uadd_with_overflow_icmp_ne(
118; CHECK-SAME: i32 [[A0:%.*]]) {
119; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i32 [[A0]], 9
120; CHECK-NEXT:    ret i1 [[TMP1]]
121;
122  %a1 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a0, i32 1)
123  %a2 = extractvalue { i32, i1 } %a1, 1
124  %a3 = extractvalue { i32, i1 } %a1, 0
125  %a4 = icmp ne i32 %a3, 10
126  %a5 = or i1 %a2, %a4
127  ret i1 %a5
128}
129
130; Negative tests
131define i1 @canonicalize_or_sadd_with_overflow_icmp_mismatched_pred(i32 %a0) {
132; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_mismatched_pred(
133; CHECK-SAME: i32 [[A0:%.*]]) {
134; CHECK-NEXT:    [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 1)
135; CHECK-NEXT:    [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1
136; CHECK-NEXT:    [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0
137; CHECK-NEXT:    [[A4:%.*]] = icmp ult i32 [[A3]], 2
138; CHECK-NEXT:    [[A5:%.*]] = or i1 [[A2]], [[A4]]
139; CHECK-NEXT:    ret i1 [[A5]]
140;
141  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1)
142  %a2 = extractvalue { i32, i1 } %a1, 1
143  %a3 = extractvalue { i32, i1 } %a1, 0
144  %a4 = icmp ult i32 %a3, 2
145  %a5 = or i1 %a2, %a4
146  ret i1 %a5
147}
148
149define i1 @canonicalize_or_sadd_with_overflow_icmp_non_constant1(i32 %a0, i32 %c) {
150; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_non_constant1(
151; CHECK-SAME: i32 [[A0:%.*]], i32 [[C:%.*]]) {
152; CHECK-NEXT:    [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 [[C]])
153; CHECK-NEXT:    [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1
154; CHECK-NEXT:    [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0
155; CHECK-NEXT:    [[A4:%.*]] = icmp slt i32 [[A3]], 0
156; CHECK-NEXT:    [[A5:%.*]] = or i1 [[A2]], [[A4]]
157; CHECK-NEXT:    ret i1 [[A5]]
158;
159  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 %c)
160  %a2 = extractvalue { i32, i1 } %a1, 1
161  %a3 = extractvalue { i32, i1 } %a1, 0
162  %a4 = icmp slt i32 %a3, 0
163  %a5 = or i1 %a2, %a4
164  ret i1 %a5
165}
166
167define i1 @canonicalize_or_sadd_with_overflow_icmp_non_constant2(i32 %a0, i32 %c) {
168; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_non_constant2(
169; CHECK-SAME: i32 [[A0:%.*]], i32 [[C:%.*]]) {
170; CHECK-NEXT:    [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 1)
171; CHECK-NEXT:    [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1
172; CHECK-NEXT:    [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0
173; CHECK-NEXT:    [[A4:%.*]] = icmp slt i32 [[A3]], [[C]]
174; CHECK-NEXT:    [[A5:%.*]] = or i1 [[A2]], [[A4]]
175; CHECK-NEXT:    ret i1 [[A5]]
176;
177  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1)
178  %a2 = extractvalue { i32, i1 } %a1, 1
179  %a3 = extractvalue { i32, i1 } %a1, 0
180  %a4 = icmp slt i32 %a3, %c
181  %a5 = or i1 %a2, %a4
182  ret i1 %a5
183}
184
185define i1 @canonicalize_or_sadd_with_overflow_icmp_multiuse(i32 %a0) {
186; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_multiuse(
187; CHECK-SAME: i32 [[A0:%.*]]) {
188; CHECK-NEXT:    [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 1)
189; CHECK-NEXT:    [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1
190; CHECK-NEXT:    [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0
191; CHECK-NEXT:    [[A4:%.*]] = icmp slt i32 [[A3]], 0
192; CHECK-NEXT:    call void @use(i1 [[A4]])
193; CHECK-NEXT:    [[A5:%.*]] = or i1 [[A2]], [[A4]]
194; CHECK-NEXT:    ret i1 [[A5]]
195;
196  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 1)
197  %a2 = extractvalue { i32, i1 } %a1, 1
198  %a3 = extractvalue { i32, i1 } %a1, 0
199  %a4 = icmp slt i32 %a3, 0
200  call void @use(i1 %a4)
201  %a5 = or i1 %a2, %a4
202  ret i1 %a5
203}
204
205define i1 @canonicalize_or_sadd_with_overflow_icmp_overflow(i32 %a0) {
206; CHECK-LABEL: define i1 @canonicalize_or_sadd_with_overflow_icmp_overflow(
207; CHECK-SAME: i32 [[A0:%.*]]) {
208; CHECK-NEXT:    [[A1:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A0]], i32 -2147483647)
209; CHECK-NEXT:    [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1
210; CHECK-NEXT:    [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0
211; CHECK-NEXT:    [[A4:%.*]] = icmp slt i32 [[A3]], 2
212; CHECK-NEXT:    [[A5:%.*]] = or i1 [[A2]], [[A4]]
213; CHECK-NEXT:    ret i1 [[A5]]
214;
215  %a1 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a0, i32 -2147483647)
216  %a2 = extractvalue { i32, i1 } %a1, 1
217  %a3 = extractvalue { i32, i1 } %a1, 0
218  %a4 = icmp slt i32 %a3, 2
219  %a5 = or i1 %a2, %a4
220  ret i1 %a5
221}
222
223define i1 @canonicalize_or_uadd_with_overflow_icmp_overflow(i32 %a0) {
224; CHECK-LABEL: define i1 @canonicalize_or_uadd_with_overflow_icmp_overflow(
225; CHECK-SAME: i32 [[A0:%.*]]) {
226; CHECK-NEXT:    [[A1:%.*]] = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[A0]], i32 3)
227; CHECK-NEXT:    [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1
228; CHECK-NEXT:    [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0
229; CHECK-NEXT:    [[A4:%.*]] = icmp ult i32 [[A3]], 2
230; CHECK-NEXT:    [[A5:%.*]] = or i1 [[A2]], [[A4]]
231; CHECK-NEXT:    ret i1 [[A5]]
232;
233  %a1 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a0, i32 3)
234  %a2 = extractvalue { i32, i1 } %a1, 1
235  %a3 = extractvalue { i32, i1 } %a1, 0
236  %a4 = icmp ult i32 %a3, 2
237  %a5 = or i1 %a2, %a4
238  ret i1 %a5
239}
240
241define i1 @canonicalize_or_ssub_with_overflow_icmp_overflow(i32 %a0) {
242; CHECK-LABEL: define i1 @canonicalize_or_ssub_with_overflow_icmp_overflow(
243; CHECK-SAME: i32 [[A0:%.*]]) {
244; CHECK-NEXT:    [[A1:%.*]] = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[A0]], i32 -2147483648)
245; CHECK-NEXT:    [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1
246; CHECK-NEXT:    [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0
247; CHECK-NEXT:    [[A4:%.*]] = icmp slt i32 [[A3]], -1
248; CHECK-NEXT:    [[A5:%.*]] = or i1 [[A2]], [[A4]]
249; CHECK-NEXT:    ret i1 [[A5]]
250;
251  %a1 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %a0, i32 -2147483648)
252  %a2 = extractvalue { i32, i1 } %a1, 1
253  %a3 = extractvalue { i32, i1 } %a1, 0
254  %a4 = icmp slt i32 %a3, -1
255  %a5 = or i1 %a2, %a4
256  ret i1 %a5
257}
258
259define i1 @canonicalize_or_smul_with_overflow_icmp(i32 %a0) {
260; CHECK-LABEL: define i1 @canonicalize_or_smul_with_overflow_icmp(
261; CHECK-SAME: i32 [[A0:%.*]]) {
262; CHECK-NEXT:    [[A1:%.*]] = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[A0]], i32 3)
263; CHECK-NEXT:    [[A2:%.*]] = extractvalue { i32, i1 } [[A1]], 1
264; CHECK-NEXT:    [[A3:%.*]] = extractvalue { i32, i1 } [[A1]], 0
265; CHECK-NEXT:    [[A4:%.*]] = icmp slt i32 [[A3]], 10
266; CHECK-NEXT:    [[A5:%.*]] = or i1 [[A2]], [[A4]]
267; CHECK-NEXT:    ret i1 [[A5]]
268;
269  %a1 = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %a0, i32 3)
270  %a2 = extractvalue { i32, i1 } %a1, 1
271  %a3 = extractvalue { i32, i1 } %a1, 0
272  %a4 = icmp slt i32 %a3, 10
273  %a5 = or i1 %a2, %a4
274  ret i1 %a5
275}
276