xref: /llvm-project/llvm/test/Transforms/InstCombine/ucmp.ll (revision d4798498c4a30efb03eebb56415a69fa60107414)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4declare void @use(i8 %value)
5
6define i1 @ucmp_eq_0(i32 %x, i32 %y) {
7; CHECK-LABEL: define i1 @ucmp_eq_0(
8; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
9; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[X]], [[Y]]
10; CHECK-NEXT:    ret i1 [[TMP2]]
11;
12  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
13  %2 = icmp eq i8 %1, 0
14  ret i1 %2
15}
16
17define i1 @ucmp_ne_0(i32 %x, i32 %y) {
18; CHECK-LABEL: define i1 @ucmp_ne_0(
19; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
20; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[X]], [[Y]]
21; CHECK-NEXT:    ret i1 [[TMP2]]
22;
23  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
24  %2 = icmp ne i8 %1, 0
25  ret i1 %2
26}
27
28define i1 @ucmp_eq_1(i32 %x, i32 %y) {
29; CHECK-LABEL: define i1 @ucmp_eq_1(
30; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
31; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i32 [[X]], [[Y]]
32; CHECK-NEXT:    ret i1 [[TMP2]]
33;
34  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
35  %2 = icmp eq i8 %1, 1
36  ret i1 %2
37}
38
39define i1 @ucmp_ne_1(i32 %x, i32 %y) {
40; CHECK-LABEL: define i1 @ucmp_ne_1(
41; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
42; CHECK-NEXT:    [[TMP2:%.*]] = icmp ule i32 [[X]], [[Y]]
43; CHECK-NEXT:    ret i1 [[TMP2]]
44;
45  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
46  %2 = icmp ne i8 %1, 1
47  ret i1 %2
48}
49
50define i1 @ucmp_eq_negative_1(i32 %x, i32 %y) {
51; CHECK-LABEL: define i1 @ucmp_eq_negative_1(
52; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
53; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[X]], [[Y]]
54; CHECK-NEXT:    ret i1 [[TMP2]]
55;
56  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
57  %2 = icmp eq i8 %1, -1
58  ret i1 %2
59}
60
61define i1 @ucmp_ne_negative_1(i32 %x, i32 %y) {
62; CHECK-LABEL: define i1 @ucmp_ne_negative_1(
63; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
64; CHECK-NEXT:    [[TMP2:%.*]] = icmp uge i32 [[X]], [[Y]]
65; CHECK-NEXT:    ret i1 [[TMP2]]
66;
67  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
68  %2 = icmp ne i8 %1, -1
69  ret i1 %2
70}
71
72define i1 @ucmp_sgt_0(i32 %x, i32 %y) {
73; CHECK-LABEL: define i1 @ucmp_sgt_0(
74; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
75; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i32 [[X]], [[Y]]
76; CHECK-NEXT:    ret i1 [[TMP2]]
77;
78  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
79  %2 = icmp sgt i8 %1, 0
80  ret i1 %2
81}
82
83define i1 @ucmp_sgt_neg_1(i32 %x, i32 %y) {
84; CHECK-LABEL: define i1 @ucmp_sgt_neg_1(
85; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
86; CHECK-NEXT:    [[TMP2:%.*]] = icmp uge i32 [[X]], [[Y]]
87; CHECK-NEXT:    ret i1 [[TMP2]]
88;
89  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
90  %2 = icmp sgt i8 %1, -1
91  ret i1 %2
92}
93
94define i1 @ucmp_sge_0(i32 %x, i32 %y) {
95; CHECK-LABEL: define i1 @ucmp_sge_0(
96; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
97; CHECK-NEXT:    [[TMP2:%.*]] = icmp uge i32 [[X]], [[Y]]
98; CHECK-NEXT:    ret i1 [[TMP2]]
99;
100  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
101  %2 = icmp sge i8 %1, 0
102  ret i1 %2
103}
104
105define i1 @ucmp_sge_1(i32 %x, i32 %y) {
106; CHECK-LABEL: define i1 @ucmp_sge_1(
107; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
108; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i32 [[X]], [[Y]]
109; CHECK-NEXT:    ret i1 [[TMP2]]
110;
111  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
112  %2 = icmp sge i8 %1, 1
113  ret i1 %2
114}
115
116define i1 @ucmp_slt_0(i32 %x, i32 %y) {
117; CHECK-LABEL: define i1 @ucmp_slt_0(
118; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
119; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[X]], [[Y]]
120; CHECK-NEXT:    ret i1 [[TMP2]]
121;
122  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
123  %2 = icmp slt i8 %1, 0
124  ret i1 %2
125}
126
127define i1 @ucmp_slt_1(i32 %x, i32 %y) {
128; CHECK-LABEL: define i1 @ucmp_slt_1(
129; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
130; CHECK-NEXT:    [[TMP2:%.*]] = icmp ule i32 [[X]], [[Y]]
131; CHECK-NEXT:    ret i1 [[TMP2]]
132;
133  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
134  %2 = icmp slt i8 %1, 1
135  ret i1 %2
136}
137
138define i1 @ucmp_sle_0(i32 %x, i32 %y) {
139; CHECK-LABEL: define i1 @ucmp_sle_0(
140; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
141; CHECK-NEXT:    [[TMP2:%.*]] = icmp ule i32 [[X]], [[Y]]
142; CHECK-NEXT:    ret i1 [[TMP2]]
143;
144  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
145  %2 = icmp sle i8 %1, 0
146  ret i1 %2
147}
148
149define i1 @ucmp_sle_neg_1(i32 %x, i32 %y) {
150; CHECK-LABEL: define i1 @ucmp_sle_neg_1(
151; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
152; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[X]], [[Y]]
153; CHECK-NEXT:    ret i1 [[TMP2]]
154;
155  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
156  %2 = icmp sle i8 %1, -1
157  ret i1 %2
158}
159
160; ucmp(x, y) u< C => x u>= y when C u> 1 and C != -1
161define i1 @ucmp_ult_positive_const_gt_than_1_lt_than_umax(i32 %x, i32 %y) {
162; CHECK-LABEL: define i1 @ucmp_ult_positive_const_gt_than_1_lt_than_umax(
163; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
164; CHECK-NEXT:    [[TMP1:%.*]] = icmp uge i32 [[X]], [[Y]]
165; CHECK-NEXT:    ret i1 [[TMP1]]
166;
167  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
168  %2 = icmp ult i8 %1, 4
169  ret i1 %2
170}
171
172; ucmp(x, y) u> C => x u< y when C != 0 and C != -1
173define i1 @ucmp_ugt_const_not_0_or_neg1(i32 %x, i32 %y) {
174; CHECK-LABEL: define i1 @ucmp_ugt_const_not_0_or_neg1(
175; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
176; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[X]], [[Y]]
177; CHECK-NEXT:    ret i1 [[TMP2]]
178;
179  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
180  %2 = icmp ugt i8 %1, 12
181  ret i1 %2
182}
183
184; ========== Fold -ucmp(x, y) => ucmp(y, x) ==========
185define i8 @ucmp_negated(i32 %x, i32 %y) {
186; CHECK-LABEL: define i8 @ucmp_negated(
187; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
188; CHECK-NEXT:    [[TMP2:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[Y]], i32 [[X]])
189; CHECK-NEXT:    ret i8 [[TMP2]]
190;
191  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
192  %2 = sub i8 0, %1
193  ret i8 %2
194}
195
196; Negative test: do not fold if the original ucmp result is already used
197define i8 @ucmp_negated_multiuse(i32 %x, i32 %y) {
198; CHECK-LABEL: define i8 @ucmp_negated_multiuse(
199; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
200; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
201; CHECK-NEXT:    call void @use(i8 [[TMP1]])
202; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i8 0, [[TMP1]]
203; CHECK-NEXT:    ret i8 [[TMP2]]
204;
205  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
206  call void @use(i8 %1)
207  %2 = sub i8 0, %1
208  ret i8 %2
209}
210
211; Fold ((x u< y) ? -1 : (x != y)) into ucmp(x, y)
212define i8 @ucmp_from_select_lt(i32 %x, i32 %y) {
213; CHECK-LABEL: define i8 @ucmp_from_select_lt(
214; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
215; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
216; CHECK-NEXT:    ret i8 [[R]]
217;
218  %ne_bool = icmp ne i32 %x, %y
219  %ne = zext i1 %ne_bool to i8
220  %lt = icmp ult i32 %x, %y
221  %r = select i1 %lt, i8 -1, i8 %ne
222  ret i8 %r
223}
224
225; Fold (x u< y) ? -1 : zext(x u> y) into ucmp(x, y)
226define i8 @ucmp_from_select_lt_and_gt(i32 %x, i32 %y) {
227; CHECK-LABEL: define i8 @ucmp_from_select_lt_and_gt(
228; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
229; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
230; CHECK-NEXT:    ret i8 [[R]]
231;
232  %gt_bool = icmp ugt i32 %x, %y
233  %gt = zext i1 %gt_bool to i8
234  %lt = icmp ult i32 %x, %y
235  %r = select i1 %lt, i8 -1, i8 %gt
236  ret i8 %r
237}
238
239; Vector version
240define <4 x i8> @ucmp_from_select_vec_lt(<4 x i32> %x, <4 x i32> %y) {
241; CHECK-LABEL: define <4 x i8> @ucmp_from_select_vec_lt(
242; CHECK-SAME: <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]) {
243; CHECK-NEXT:    [[R:%.*]] = call <4 x i8> @llvm.ucmp.v4i8.v4i32(<4 x i32> [[X]], <4 x i32> [[Y]])
244; CHECK-NEXT:    ret <4 x i8> [[R]]
245;
246  %ne_bool = icmp ne <4 x i32> %x, %y
247  %ne = zext <4 x i1> %ne_bool to <4 x i8>
248  %lt = icmp ult <4 x i32> %x, %y
249  %r = select <4 x i1> %lt, <4 x i8> splat(i8 -1), <4 x i8> %ne
250  ret <4 x i8> %r
251}
252
253; Commuted operands
254define i8 @ucmp_from_select_lt_commuted_ops1(i32 %x, i32 %y) {
255; CHECK-LABEL: define i8 @ucmp_from_select_lt_commuted_ops1(
256; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
257; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
258; CHECK-NEXT:    ret i8 [[R]]
259;
260  %ne_bool = icmp ne i32 %y, %x
261  %ne = zext i1 %ne_bool to i8
262  %lt = icmp ult i32 %x, %y
263  %r = select i1 %lt, i8 -1, i8 %ne
264  ret i8 %r
265}
266
267define i8 @ucmp_from_select_lt_commuted_ops2(i32 %x, i32 %y) {
268; CHECK-LABEL: define i8 @ucmp_from_select_lt_commuted_ops2(
269; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
270; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
271; CHECK-NEXT:    ret i8 [[R]]
272;
273  %ne_bool = icmp ne i32 %x, %y
274  %ne = zext i1 %ne_bool to i8
275  %lt = icmp ugt i32 %y, %x
276  %r = select i1 %lt, i8 -1, i8 %ne
277  ret i8 %r
278}
279
280; Negative test: false value of the select is not `icmp ne x, y`
281define i8 @ucmp_from_select_lt_neg1(i32 %x, i32 %y) {
282; CHECK-LABEL: define i8 @ucmp_from_select_lt_neg1(
283; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
284; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp eq i32 [[X]], [[Y]]
285; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
286; CHECK-NEXT:    [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
287; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
288; CHECK-NEXT:    ret i8 [[R]]
289;
290  %ne_bool = icmp eq i32 %x, %y
291  %ne = zext i1 %ne_bool to i8
292  %lt = icmp ult i32 %x, %y
293  %r = select i1 %lt, i8 -1, i8 %ne
294  ret i8 %r
295}
296
297; Negative test: true value of select is not -1
298define i8 @ucmp_from_select_lt_neg2(i32 %x, i32 %y) {
299; CHECK-LABEL: define i8 @ucmp_from_select_lt_neg2(
300; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
301; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
302; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
303; CHECK-NEXT:    [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
304; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 2, i8 [[NE]]
305; CHECK-NEXT:    ret i8 [[R]]
306;
307  %ne_bool = icmp ne i32 %x, %y
308  %ne = zext i1 %ne_bool to i8
309  %lt = icmp ult i32 %x, %y
310  %r = select i1 %lt, i8 2, i8 %ne
311  ret i8 %r
312}
313
314; Negative test: false value of select is sign-extended instead of zero-extended
315define i8 @ucmp_from_select_lt_neg3(i32 %x, i32 %y) {
316; CHECK-LABEL: define i8 @ucmp_from_select_lt_neg3(
317; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
318; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
319; CHECK-NEXT:    [[R:%.*]] = sext i1 [[NE_BOOL]] to i8
320; CHECK-NEXT:    ret i8 [[R]]
321;
322  %ne_bool = icmp ne i32 %x, %y
323  %ne = sext i1 %ne_bool to i8
324  %lt = icmp ult i32 %x, %y
325  %r = select i1 %lt, i8 -1, i8 %ne
326  ret i8 %r
327}
328
329; Negative test: condition of select is not (x u< y)
330define i8 @ucmp_from_select_lt_neg4(i32 %x, i32 %y) {
331; CHECK-LABEL: define i8 @ucmp_from_select_lt_neg4(
332; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
333; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
334; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
335; CHECK-NEXT:    [[LT_NOT:%.*]] = icmp ugt i32 [[X]], [[Y]]
336; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT_NOT]], i8 [[NE]], i8 -1
337; CHECK-NEXT:    ret i8 [[R]]
338;
339  %ne_bool = icmp ne i32 %x, %y
340  %ne = zext i1 %ne_bool to i8
341  %lt = icmp ule i32 %x, %y
342  %r = select i1 %lt, i8 -1, i8 %ne
343  ret i8 %r
344}
345
346; Fold (x u<= y) ? sext(x != y) : 1 into ucmp(x, y)
347define i8 @ucmp_from_select_le(i32 %x, i32 %y) {
348; CHECK-LABEL: define i8 @ucmp_from_select_le(
349; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
350; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
351; CHECK-NEXT:    ret i8 [[R]]
352;
353  %ne_bool = icmp ne i32 %x, %y
354  %ne = sext i1 %ne_bool to i8
355  %le = icmp ule i32 %x, %y
356  %r = select i1 %le, i8 %ne, i8 1
357  ret i8 %r
358}
359
360; Negative test: condition of select is not (x u<= y)
361define i8 @ucmp_from_select_le_neg1(i32 %x, i32 %y) {
362; CHECK-LABEL: define i8 @ucmp_from_select_le_neg1(
363; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
364; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ult i32 [[X]], [[Y]]
365; CHECK-NEXT:    [[NE:%.*]] = sext i1 [[NE_BOOL]] to i8
366; CHECK-NEXT:    [[LE_NOT:%.*]] = icmp ult i32 [[X]], [[Y]]
367; CHECK-NEXT:    [[R:%.*]] = select i1 [[LE_NOT]], i8 1, i8 [[NE]]
368; CHECK-NEXT:    ret i8 [[R]]
369;
370  %ne_bool = icmp ult i32 %x, %y
371  %ne = sext i1 %ne_bool to i8
372  %le = icmp uge i32 %x, %y
373  %r = select i1 %le, i8 %ne, i8 1
374  ret i8 %r
375}
376
377; Negative test: true value of select is zero-extended instead of sign-extended
378define i8 @ucmp_from_select_le_neg2(i32 %x, i32 %y) {
379; CHECK-LABEL: define i8 @ucmp_from_select_le_neg2(
380; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
381; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
382; CHECK-NEXT:    [[R:%.*]] = zext i1 [[NE_BOOL]] to i8
383; CHECK-NEXT:    ret i8 [[R]]
384;
385  %ne_bool = icmp ne i32 %x, %y
386  %ne = zext i1 %ne_bool to i8
387  %le = icmp ule i32 %x, %y
388  %r = select i1 %le, i8 %ne, i8 1
389  ret i8 %r
390}
391
392; Negative test: true value is not x != y
393define i8 @ucmp_from_select_le_neg3(i32 %x, i32 %y) {
394; CHECK-LABEL: define i8 @ucmp_from_select_le_neg3(
395; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
396; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp sgt i32 [[X]], [[Y]]
397; CHECK-NEXT:    [[NE:%.*]] = sext i1 [[NE_BOOL]] to i8
398; CHECK-NEXT:    [[LE_NOT:%.*]] = icmp ugt i32 [[X]], [[Y]]
399; CHECK-NEXT:    [[R:%.*]] = select i1 [[LE_NOT]], i8 1, i8 [[NE]]
400; CHECK-NEXT:    ret i8 [[R]]
401;
402  %ne_bool = icmp sgt i32 %x, %y
403  %ne = sext i1 %ne_bool to i8
404  %le = icmp ule i32 %x, %y
405  %r = select i1 %le, i8 %ne, i8 1
406  ret i8 %r
407}
408
409; Negative test: false value is not 1
410define i8 @ucmp_from_select_le_neg4(i32 %x, i32 %y) {
411; CHECK-LABEL: define i8 @ucmp_from_select_le_neg4(
412; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
413; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
414; CHECK-NEXT:    [[R:%.*]] = sext i1 [[NE_BOOL]] to i8
415; CHECK-NEXT:    ret i8 [[R]]
416;
417  %ne_bool = icmp ne i32 %x, %y
418  %ne = sext i1 %ne_bool to i8
419  %le = icmp ule i32 %x, %y
420  %r = select i1 %le, i8 %ne, i8 -1
421  ret i8 %r
422}
423
424; Fold (x u>= y) ? zext(x != y) : -1 into ucmp(x, y)
425define i8 @ucmp_from_select_ge(i32 %x, i32 %y) {
426; CHECK-LABEL: define i8 @ucmp_from_select_ge(
427; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
428; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
429; CHECK-NEXT:    ret i8 [[R]]
430;
431  %ne_bool = icmp ne i32 %x, %y
432  %ne = zext i1 %ne_bool to i8
433  %ge = icmp uge i32 %x, %y
434  %r = select i1 %ge, i8 %ne, i8 -1
435  ret i8 %r
436}
437
438; Commuted operands
439define i8 @ucmp_from_select_ge_commuted_ops1(i32 %x, i32 %y) {
440; CHECK-LABEL: define i8 @ucmp_from_select_ge_commuted_ops1(
441; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
442; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
443; CHECK-NEXT:    ret i8 [[R]]
444;
445  %ne_bool = icmp ne i32 %y, %x
446  %ne = zext i1 %ne_bool to i8
447  %ge = icmp uge i32 %x, %y
448  %r = select i1 %ge, i8 %ne, i8 -1
449  ret i8 %r
450}
451
452define i8 @ucmp_from_select_ge_commuted_ops2(i32 %x, i32 %y) {
453; CHECK-LABEL: define i8 @ucmp_from_select_ge_commuted_ops2(
454; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
455; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
456; CHECK-NEXT:    ret i8 [[R]]
457;
458  %ne_bool = icmp ne i32 %x, %y
459  %ne = zext i1 %ne_bool to i8
460  %ge = icmp ule i32 %y, %x
461  %r = select i1 %ge, i8 %ne, i8 -1
462  ret i8 %r
463}
464
465; Negative test: condition is not x u>= y
466define i8 @ucmp_from_select_ge_neg1(i32 %x, i32 %y) {
467; CHECK-LABEL: define i8 @ucmp_from_select_ge_neg1(
468; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
469; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
470; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
471; CHECK-NEXT:    [[GE:%.*]] = icmp ult i32 [[X]], [[Y]]
472; CHECK-NEXT:    [[R:%.*]] = select i1 [[GE]], i8 [[NE]], i8 -1
473; CHECK-NEXT:    ret i8 [[R]]
474;
475  %ne_bool = icmp ne i32 %x, %y
476  %ne = zext i1 %ne_bool to i8
477  %ge = icmp ult i32 %x, %y
478  %r = select i1 %ge, i8 %ne, i8 -1
479  ret i8 %r
480}
481
482; Negative test: true value is sign-extended instead of zero-extended
483define i8 @ucmp_from_select_ge_neg2(i32 %x, i32 %y) {
484; CHECK-LABEL: define i8 @ucmp_from_select_ge_neg2(
485; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
486; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
487; CHECK-NEXT:    [[R:%.*]] = sext i1 [[NE_BOOL]] to i8
488; CHECK-NEXT:    ret i8 [[R]]
489;
490  %ne_bool = icmp ne i32 %x, %y
491  %ne = sext i1 %ne_bool to i8
492  %ge = icmp uge i32 %x, %y
493  %r = select i1 %ge, i8 %ne, i8 -1
494  ret i8 %r
495}
496
497; Negative test: true value is not x != y
498define i8 @ucmp_from_select_ge_neg3(i32 %x, i32 %y) {
499; CHECK-LABEL: define i8 @ucmp_from_select_ge_neg3(
500; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
501; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp sgt i32 [[X]], [[Y]]
502; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
503; CHECK-NEXT:    [[GE_NOT:%.*]] = icmp ult i32 [[X]], [[Y]]
504; CHECK-NEXT:    [[R:%.*]] = select i1 [[GE_NOT]], i8 -1, i8 [[NE]]
505; CHECK-NEXT:    ret i8 [[R]]
506;
507  %ne_bool = icmp sgt i32 %x, %y
508  %ne = zext i1 %ne_bool to i8
509  %ge = icmp uge i32 %x, %y
510  %r = select i1 %ge, i8 %ne, i8 -1
511  ret i8 %r
512}
513
514; Negative test: false value is not -1
515define i8 @ucmp_from_select_ge_neg4(i32 %x, i32 %y) {
516; CHECK-LABEL: define i8 @ucmp_from_select_ge_neg4(
517; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
518; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
519; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
520; CHECK-NEXT:    [[GE_NOT:%.*]] = icmp ult i32 [[X]], [[Y]]
521; CHECK-NEXT:    [[R:%.*]] = select i1 [[GE_NOT]], i8 3, i8 [[NE]]
522; CHECK-NEXT:    ret i8 [[R]]
523;
524  %ne_bool = icmp ne i32 %x, %y
525  %ne = zext i1 %ne_bool to i8
526  %ge = icmp uge i32 %x, %y
527  %r = select i1 %ge, i8 %ne, i8 3
528  ret i8 %r
529}
530
531; Fold (x > y) ? 1 : sext(x < y)
532define i8 @ucmp_from_select_gt_and_lt(i32 %x, i32 %y) {
533; CHECK-LABEL: define i8 @ucmp_from_select_gt_and_lt(
534; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
535; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
536; CHECK-NEXT:    ret i8 [[R]]
537;
538  %lt_bool = icmp ult i32 %x, %y
539  %lt = sext i1 %lt_bool to i8
540  %gt = icmp ugt i32 %x, %y
541  %r = select i1 %gt, i8 1, i8 %lt
542  ret i8 %r
543}
544
545; (x == y) ? 0 : (x u> y ? 1 : -1) into ucmp(x, y)
546define i8 @scmp_from_select_eq_and_gt(i32 %x, i32 %y) {
547; CHECK-LABEL: define i8 @scmp_from_select_eq_and_gt(
548; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
549; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
550; CHECK-NEXT:    ret i8 [[R]]
551;
552  %eq = icmp eq i32 %x, %y
553  %gt = icmp ugt i32 %x, %y
554  %sel1 = select i1 %gt, i8 1, i8 -1
555  %r = select i1 %eq, i8 0, i8 %sel1
556  ret i8 %r
557}
558