Skip to content

Commit cffbd01

Browse files
committed
[InstCombine] Add baseline tests for icmp with clamp operation
1 parent 1fcf481 commit cffbd01

File tree

1 file changed

+308
-0
lines changed

1 file changed

+308
-0
lines changed
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
2+
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3+
4+
declare void @use(i32)
5+
6+
define i1 @test_i32_eq(i32 %x) {
7+
; CHECK-LABEL: define i1 @test_i32_eq(
8+
; CHECK-SAME: i32 [[X:%.*]]) {
9+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 -95)
10+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
11+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
12+
; CHECK-NEXT: ret i1 [[CMP]]
13+
;
14+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
15+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
16+
%cmp = icmp eq i32 %v2, %x
17+
ret i1 %cmp
18+
}
19+
20+
define i1 @test_i32_ne(i32 %x) {
21+
; CHECK-LABEL: define i1 @test_i32_ne(
22+
; CHECK-SAME: i32 [[X:%.*]]) {
23+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 -95)
24+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
25+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[V2]], [[X]]
26+
; CHECK-NEXT: ret i1 [[CMP]]
27+
;
28+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
29+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
30+
%cmp = icmp ne i32 %v2, %x
31+
ret i1 %cmp
32+
}
33+
34+
define i1 @test_i32_eq_no_add(i32 %x) {
35+
; CHECK-LABEL: define i1 @test_i32_eq_no_add(
36+
; CHECK-SAME: i32 [[X:%.*]]) {
37+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 0)
38+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
39+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
40+
; CHECK-NEXT: ret i1 [[CMP]]
41+
;
42+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 0)
43+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
44+
%cmp = icmp eq i32 %v2, %x
45+
ret i1 %cmp
46+
}
47+
48+
define i1 @test_i32_ne_no_add(i32 %x) {
49+
; CHECK-LABEL: define i1 @test_i32_ne_no_add(
50+
; CHECK-SAME: i32 [[X:%.*]]) {
51+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 0)
52+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
53+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[V2]], [[X]]
54+
; CHECK-NEXT: ret i1 [[CMP]]
55+
;
56+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 0)
57+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
58+
%cmp = icmp ne i32 %v2, %x
59+
ret i1 %cmp
60+
}
61+
62+
define i1 @test_unsigned_eq(i32 %x) {
63+
; CHECK-LABEL: define i1 @test_unsigned_eq(
64+
; CHECK-SAME: i32 [[X:%.*]]) {
65+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.umax.i32(i32 [[X]], i32 10)
66+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.umin.i32(i32 [[V1]], i32 100)
67+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
68+
; CHECK-NEXT: ret i1 [[CMP]]
69+
;
70+
%v1 = tail call i32 @llvm.umax.i32(i32 %x, i32 10)
71+
%v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 100)
72+
%cmp = icmp eq i32 %v2, %x
73+
ret i1 %cmp
74+
}
75+
76+
define i1 @test_unsigned_ne(i32 %x) {
77+
; CHECK-LABEL: define i1 @test_unsigned_ne(
78+
; CHECK-SAME: i32 [[X:%.*]]) {
79+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.umax.i32(i32 [[X]], i32 10)
80+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.umin.i32(i32 [[V1]], i32 100)
81+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[V2]], [[X]]
82+
; CHECK-NEXT: ret i1 [[CMP]]
83+
;
84+
%v1 = tail call i32 @llvm.umax.i32(i32 %x, i32 10)
85+
%v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 100)
86+
%cmp = icmp ne i32 %v2, %x
87+
ret i1 %cmp
88+
}
89+
90+
91+
; Different bit widths
92+
define i1 @test_i8_eq(i8 %x) {
93+
; CHECK-LABEL: define i1 @test_i8_eq(
94+
; CHECK-SAME: i8 [[X:%.*]]) {
95+
; CHECK-NEXT: [[V1:%.*]] = tail call i8 @llvm.smax.i8(i8 [[X]], i8 -50)
96+
; CHECK-NEXT: [[V2:%.*]] = tail call i8 @llvm.smin.i8(i8 [[V1]], i8 50)
97+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[V2]], [[X]]
98+
; CHECK-NEXT: ret i1 [[CMP]]
99+
;
100+
%v1 = tail call i8 @llvm.smax.i8(i8 %x, i8 -50)
101+
%v2 = tail call i8 @llvm.smin.i8(i8 %v1, i8 50)
102+
%cmp = icmp eq i8 %v2, %x
103+
ret i1 %cmp
104+
}
105+
106+
define i1 @test_i16_eq(i16 %x) {
107+
; CHECK-LABEL: define i1 @test_i16_eq(
108+
; CHECK-SAME: i16 [[X:%.*]]) {
109+
; CHECK-NEXT: [[V1:%.*]] = tail call i16 @llvm.smax.i16(i16 [[X]], i16 -1000)
110+
; CHECK-NEXT: [[V2:%.*]] = tail call i16 @llvm.smin.i16(i16 [[V1]], i16 1000)
111+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[V2]], [[X]]
112+
; CHECK-NEXT: ret i1 [[CMP]]
113+
;
114+
%v1 = tail call i16 @llvm.smax.i16(i16 %x, i16 -1000)
115+
%v2 = tail call i16 @llvm.smin.i16(i16 %v1, i16 1000)
116+
%cmp = icmp eq i16 %v2, %x
117+
ret i1 %cmp
118+
}
119+
120+
define i1 @test_i64_eq(i64 %x) {
121+
; CHECK-LABEL: define i1 @test_i64_eq(
122+
; CHECK-SAME: i64 [[X:%.*]]) {
123+
; CHECK-NEXT: [[V1:%.*]] = tail call i64 @llvm.smax.i64(i64 [[X]], i64 -1)
124+
; CHECK-NEXT: [[V2:%.*]] = tail call i64 @llvm.smin.i64(i64 [[V1]], i64 9223372036854775806)
125+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[V2]], [[X]]
126+
; CHECK-NEXT: ret i1 [[CMP]]
127+
;
128+
%v1 = tail call i64 @llvm.smax.i64(i64 %x, i64 -1)
129+
%v2 = tail call i64 @llvm.smin.i64(i64 %v1, i64 9223372036854775806)
130+
%cmp = icmp eq i64 %v2, %x
131+
ret i1 %cmp
132+
}
133+
134+
; Negative tests - wrong predicate
135+
define i1 @test_wrong_pred_slt(i32 %x) {
136+
; CHECK-LABEL: define i1 @test_wrong_pred_slt(
137+
; CHECK-SAME: i32 [[X:%.*]]) {
138+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], 160
139+
; CHECK-NEXT: ret i1 [[CMP]]
140+
;
141+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
142+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
143+
%cmp = icmp slt i32 %v2, %x
144+
ret i1 %cmp
145+
}
146+
147+
148+
; Negative tests - not a clamp pattern
149+
define i1 @test_not_clamp_pattern(i32 %x, i32 %y) {
150+
; CHECK-LABEL: define i1 @test_not_clamp_pattern(
151+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
152+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[Y]], i32 -95)
153+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
154+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
155+
; CHECK-NEXT: ret i1 [[CMP]]
156+
;
157+
%v1 = tail call i32 @llvm.smax.i32(i32 %y, i32 -95)
158+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
159+
%cmp = icmp eq i32 %v2, %x
160+
ret i1 %cmp
161+
}
162+
163+
; Negative tests - Lo >= Hi
164+
define i1 @test_invalid_range(i32 %x) {
165+
; CHECK-LABEL: define i1 @test_invalid_range(
166+
; CHECK-SAME: i32 [[X:%.*]]) {
167+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], 50
168+
; CHECK-NEXT: ret i1 [[CMP]]
169+
;
170+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 100)
171+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 50)
172+
%cmp = icmp eq i32 %v2, %x
173+
ret i1 %cmp
174+
}
175+
176+
; Negative tests - Lo is minimum signed value
177+
define i1 @test_lo_min_signed(i32 %x) {
178+
; CHECK-LABEL: define i1 @test_lo_min_signed(
179+
; CHECK-SAME: i32 [[X:%.*]]) {
180+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], 161
181+
; CHECK-NEXT: ret i1 [[CMP]]
182+
;
183+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -2147483648)
184+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
185+
%cmp = icmp eq i32 %v2, %x
186+
ret i1 %cmp
187+
}
188+
189+
; Negative tests - Hi is maximum signed value
190+
define i1 @test_hi_max_signed(i32 %x) {
191+
; CHECK-LABEL: define i1 @test_hi_max_signed(
192+
; CHECK-SAME: i32 [[X:%.*]]) {
193+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], -96
194+
; CHECK-NEXT: ret i1 [[CMP]]
195+
;
196+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
197+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 2147483647)
198+
%cmp = icmp eq i32 %v2, %x
199+
ret i1 %cmp
200+
}
201+
202+
; Negative tests - Hi is maximum unsigned value
203+
define i1 @test_hi_max_unsigned(i32 %x) {
204+
; CHECK-LABEL: define i1 @test_hi_max_unsigned(
205+
; CHECK-SAME: i32 [[X:%.*]]) {
206+
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 9
207+
; CHECK-NEXT: ret i1 [[CMP]]
208+
;
209+
%v1 = tail call i32 @llvm.umax.i32(i32 %x, i32 10)
210+
%v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 4294967295)
211+
%cmp = icmp eq i32 %v2, %x
212+
ret i1 %cmp
213+
}
214+
215+
; Multi-use tests - multiple uses of max
216+
define i1 @test_multi_use_max(i32 %x) {
217+
; CHECK-LABEL: define i1 @test_multi_use_max(
218+
; CHECK-SAME: i32 [[X:%.*]]) {
219+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 -95)
220+
; CHECK-NEXT: call void @use(i32 [[V1]])
221+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
222+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
223+
; CHECK-NEXT: ret i1 [[CMP]]
224+
;
225+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
226+
call void @use(i32 %v1)
227+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
228+
%cmp = icmp eq i32 %v2, %x
229+
ret i1 %cmp
230+
}
231+
232+
; Multi-use tests - multiple uses of min
233+
define i1 @test_multi_use_min(i32 %x) {
234+
; CHECK-LABEL: define i1 @test_multi_use_min(
235+
; CHECK-SAME: i32 [[X:%.*]]) {
236+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 -95)
237+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
238+
; CHECK-NEXT: call void @use(i32 [[V2]])
239+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
240+
; CHECK-NEXT: ret i1 [[CMP]]
241+
;
242+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
243+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
244+
call void @use(i32 %v2)
245+
%cmp = icmp eq i32 %v2, %x
246+
ret i1 %cmp
247+
}
248+
249+
; Commuted tests
250+
define i1 @test_commuted_eq(i32 %x) {
251+
; CHECK-LABEL: define i1 @test_commuted_eq(
252+
; CHECK-SAME: i32 [[X:%.*]]) {
253+
; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 -95)
254+
; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
255+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], [[V2]]
256+
; CHECK-NEXT: ret i1 [[CMP]]
257+
;
258+
%v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
259+
%v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
260+
%cmp = icmp eq i32 %x, %v2
261+
ret i1 %cmp
262+
}
263+
264+
265+
; Vector tests - splat constants
266+
define <2 x i1> @test_vec_splat_eq(<2 x i32> %x) {
267+
; CHECK-LABEL: define <2 x i1> @test_vec_splat_eq(
268+
; CHECK-SAME: <2 x i32> [[X:%.*]]) {
269+
; CHECK-NEXT: [[V1:%.*]] = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[X]], <2 x i32> splat (i32 -50))
270+
; CHECK-NEXT: [[V2:%.*]] = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[V1]], <2 x i32> splat (i32 50))
271+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[V2]], [[X]]
272+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
273+
;
274+
%v1 = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 -50, i32 -50>)
275+
%v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> <i32 50, i32 50>)
276+
%cmp = icmp eq <2 x i32> %v2, %x
277+
ret <2 x i1> %cmp
278+
}
279+
280+
; Vector tests - poison elements
281+
define <2 x i1> @test_vec_poison_eq(<2 x i32> %x) {
282+
; CHECK-LABEL: define <2 x i1> @test_vec_poison_eq(
283+
; CHECK-SAME: <2 x i32> [[X:%.*]]) {
284+
; CHECK-NEXT: [[V1:%.*]] = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[X]], <2 x i32> <i32 -50, i32 poison>)
285+
; CHECK-NEXT: [[V2:%.*]] = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[V1]], <2 x i32> <i32 50, i32 poison>)
286+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[V2]], [[X]]
287+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
288+
;
289+
%v1 = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 -50, i32 poison>)
290+
%v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> <i32 50, i32 poison>)
291+
%cmp = icmp eq <2 x i32> %v2, %x
292+
ret <2 x i1> %cmp
293+
}
294+
295+
; Vector tests - non-splat
296+
define <2 x i1> @test_vec_non_splat_eq(<2 x i32> %x) {
297+
; CHECK-LABEL: define <2 x i1> @test_vec_non_splat_eq(
298+
; CHECK-SAME: <2 x i32> [[X:%.*]]) {
299+
; CHECK-NEXT: [[V1:%.*]] = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[X]], <2 x i32> <i32 -50, i32 -30>)
300+
; CHECK-NEXT: [[V2:%.*]] = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[V1]], <2 x i32> <i32 50, i32 70>)
301+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[V2]], [[X]]
302+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
303+
;
304+
%v1 = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 -50, i32 -30>)
305+
%v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> <i32 50, i32 70>)
306+
%cmp = icmp eq <2 x i32> %v2, %x
307+
ret <2 x i1> %cmp
308+
}

0 commit comments

Comments
 (0)