1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4; https://bugs.llvm.org/show_bug.cgi?id=38708
5
6; Pattern:
7;   ((1 << bits)+(-1)) u< val
8; Should be transformed into:
9;   (val l>> bits) != 0
10
11; NOTE: the innermost shl is not one-use. Else canonicalization happens.
12
13declare void @use8(i8)
14declare void @use2i8(<2 x i8>)
15declare void @use3i8(<3 x i8>)
16
17; ============================================================================ ;
18; Basic positive tests
19; ============================================================================ ;
20
21define i1 @p0(i8 %val, i8 %bits) {
22; CHECK-LABEL: @p0(
23; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
24; CHECK-NEXT:    call void @use8(i8 [[T0]])
25; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL:%.*]], [[BITS]]
26; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0
27; CHECK-NEXT:    ret i1 [[R]]
28;
29  %t0 = shl i8 1, %bits
30  call void @use8(i8 %t0)
31  %t1 = add i8 %t0, -1
32  %r = icmp ult i8 %t1, %val
33  ret i1 %r
34}
35
36; ============================================================================ ;
37; Vector tests
38; ============================================================================ ;
39
40define <2 x i1> @p1_vec(<2 x i8> %val, <2 x i8> %bits) {
41; CHECK-LABEL: @p1_vec(
42; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[BITS:%.*]]
43; CHECK-NEXT:    call void @use2i8(<2 x i8> [[T0]])
44; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <2 x i8> [[VAL:%.*]], [[BITS]]
45; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[VAL_HIGHBITS]], zeroinitializer
46; CHECK-NEXT:    ret <2 x i1> [[R]]
47;
48  %t0 = shl <2 x i8> <i8 1, i8 1>, %bits
49  call void @use2i8(<2 x i8> %t0)
50  %t1 = add <2 x i8> %t0, <i8 -1, i8 -1>
51  %r = icmp ult <2 x i8> %t1, %val
52  ret <2 x i1> %r
53}
54
55define <3 x i1> @p2_vec_undef0(<3 x i8> %val, <3 x i8> %bits) {
56; CHECK-LABEL: @p2_vec_undef0(
57; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
58; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
59; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
60; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
61; CHECK-NEXT:    ret <3 x i1> [[R]]
62;
63  %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits
64  call void @use3i8(<3 x i8> %t0)
65  %t1 = add <3 x i8> %t0, <i8 -1, i8 -1, i8 -1>
66  %r = icmp ult <3 x i8> %t1, %val
67  ret <3 x i1> %r
68}
69
70define <3 x i1> @p2_vec_undef1(<3 x i8> %val, <3 x i8> %bits) {
71; CHECK-LABEL: @p2_vec_undef1(
72; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 1, i8 1>, [[BITS:%.*]]
73; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
74; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
75; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
76; CHECK-NEXT:    ret <3 x i1> [[R]]
77;
78  %t0 = shl <3 x i8> <i8 1, i8 1, i8 1>, %bits
79  call void @use3i8(<3 x i8> %t0)
80  %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
81  %r = icmp ult <3 x i8> %t1, %val
82  ret <3 x i1> %r
83}
84
85define <3 x i1> @p2_vec_undef2(<3 x i8> %val, <3 x i8> %bits) {
86; CHECK-LABEL: @p2_vec_undef2(
87; CHECK-NEXT:    [[T0:%.*]] = shl <3 x i8> <i8 1, i8 undef, i8 1>, [[BITS:%.*]]
88; CHECK-NEXT:    call void @use3i8(<3 x i8> [[T0]])
89; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr <3 x i8> [[VAL:%.*]], [[BITS]]
90; CHECK-NEXT:    [[R:%.*]] = icmp ne <3 x i8> [[VAL_HIGHBITS]], zeroinitializer
91; CHECK-NEXT:    ret <3 x i1> [[R]]
92;
93  %t0 = shl <3 x i8> <i8 1, i8 undef, i8 1>, %bits
94  call void @use3i8(<3 x i8> %t0)
95  %t1 = add <3 x i8> %t0, <i8 -1, i8 undef, i8 -1>
96  %r = icmp ult <3 x i8> %t1, %val
97  ret <3 x i1> %r
98}
99
100; ============================================================================ ;
101; Commutativity tests.
102; ============================================================================ ;
103
104declare i8 @gen8()
105
106define i1 @c0(i8 %bits) {
107; CHECK-LABEL: @c0(
108; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
109; CHECK-NEXT:    call void @use8(i8 [[T0]])
110; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
111; CHECK-NEXT:    [[VAL_HIGHBITS:%.*]] = lshr i8 [[VAL]], [[BITS]]
112; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[VAL_HIGHBITS]], 0
113; CHECK-NEXT:    ret i1 [[R]]
114;
115  %t0 = shl i8 1, %bits
116  call void @use8(i8 %t0)
117  %t1 = add i8 %t0, -1
118  %val = call i8 @gen8()
119  %r = icmp ugt i8 %val, %t1 ; swapped order and predicate
120  ret i1 %r
121}
122
123; What if we have the same pattern on both sides?
124define i1 @both(i8 %bits0, i8 %bits1) {
125; CHECK-LABEL: @both(
126; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS0:%.*]]
127; CHECK-NEXT:    call void @use8(i8 [[T0]])
128; CHECK-NEXT:    [[T2:%.*]] = shl i8 1, [[BITS1:%.*]]
129; CHECK-NEXT:    call void @use8(i8 [[T2]])
130; CHECK-NEXT:    [[T3:%.*]] = add i8 [[T2]], -1
131; CHECK-NEXT:    [[T3_HIGHBITS:%.*]] = lshr i8 [[T3]], [[BITS0]]
132; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[T3_HIGHBITS]], 0
133; CHECK-NEXT:    ret i1 [[R]]
134;
135  %t0 = shl i8 1, %bits0
136  call void @use8(i8 %t0)
137  %t1 = add i8 %t0, -1
138  %t2 = shl i8 1, %bits1
139  call void @use8(i8 %t2)
140  %t3 = add i8 %t2, -1
141  %r = icmp ult i8 %t1, %t3
142  ret i1 %r
143}
144
145; ============================================================================ ;
146; One-use tests.
147; ============================================================================ ;
148
149define i1 @oneuse(i8 %val, i8 %bits) {
150; CHECK-LABEL: @oneuse(
151; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
152; CHECK-NEXT:    call void @use8(i8 [[T0]])
153; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
154; CHECK-NEXT:    call void @use8(i8 [[T1]])
155; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
156; CHECK-NEXT:    ret i1 [[R]]
157;
158  %t0 = shl i8 1, %bits
159  call void @use8(i8 %t0) ; this is needed anyway
160  %t1 = add i8 %t0, -1
161  call void @use8(i8 %t1)
162  %r = icmp ult i8 %t1, %val
163  ret i1 %r
164}
165
166; ============================================================================ ;
167; Negative tests
168; ============================================================================ ;
169
170define i1 @n0(i8 %val, i8 %bits) {
171; CHECK-LABEL: @n0(
172; CHECK-NEXT:    [[T0:%.*]] = shl i8 -1, [[BITS:%.*]]
173; CHECK-NEXT:    call void @use8(i8 [[T0]])
174; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
175; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
176; CHECK-NEXT:    ret i1 [[R]]
177;
178  %t0 = shl i8 -1, %bits ; constant is not 1
179  call void @use8(i8 %t0)
180  %t1 = add i8 %t0, -1
181  %r = icmp ult i8 %t1, %val
182  ret i1 %r
183}
184
185define i1 @n1(i8 %val, i8 %bits) {
186; CHECK-LABEL: @n1(
187; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
188; CHECK-NEXT:    call void @use8(i8 [[T0]])
189; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], 1
190; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T1]], [[VAL:%.*]]
191; CHECK-NEXT:    ret i1 [[R]]
192;
193  %t0 = shl i8 1, %bits
194  call void @use8(i8 %t0)
195  %t1 = add i8 %t0, 1 ; constant is not -1
196  %r = icmp ult i8 %t1, %val
197  ret i1 %r
198}
199
200define <2 x i1> @n2_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
201; CHECK-LABEL: @n2_vec_nonsplat(
202; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 -1>, [[BITS:%.*]]
203; CHECK-NEXT:    call void @use2i8(<2 x i8> [[T0]])
204; CHECK-NEXT:    [[T1:%.*]] = add <2 x i8> [[T0]], <i8 -1, i8 -1>
205; CHECK-NEXT:    [[R:%.*]] = icmp ult <2 x i8> [[T1]], [[VAL:%.*]]
206; CHECK-NEXT:    ret <2 x i1> [[R]]
207;
208  %t0 = shl <2 x i8> <i8 1, i8 -1>, %bits ; again, wrong constant
209  call void @use2i8(<2 x i8> %t0)
210  %t1 = add <2 x i8> %t0, <i8 -1, i8 -1>
211  %r = icmp ult <2 x i8> %t1, %val
212  ret <2 x i1> %r
213}
214
215define <2 x i1> @n3_vec_nonsplat(<2 x i8> %val, <2 x i8> %bits) {
216; CHECK-LABEL: @n3_vec_nonsplat(
217; CHECK-NEXT:    [[T0:%.*]] = shl <2 x i8> <i8 1, i8 1>, [[BITS:%.*]]
218; CHECK-NEXT:    call void @use2i8(<2 x i8> [[T0]])
219; CHECK-NEXT:    [[T1:%.*]] = add <2 x i8> [[T0]], <i8 -1, i8 1>
220; CHECK-NEXT:    [[R:%.*]] = icmp ult <2 x i8> [[T1]], [[VAL:%.*]]
221; CHECK-NEXT:    ret <2 x i1> [[R]]
222;
223  %t0 = shl <2 x i8> <i8 1, i8 1>, %bits
224  call void @use2i8(<2 x i8> %t0)
225  %t1 = add <2 x i8> %t0, <i8 -1, i8 1> ; again, wrong constant
226  %r = icmp ult <2 x i8> %t1, %val
227  ret <2 x i1> %r
228}
229
230define i1 @n3(i8 %val, i8 %bits) {
231; CHECK-LABEL: @n3(
232; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
233; CHECK-NEXT:    call void @use8(i8 [[T0]])
234; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
235; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[T1]], [[VAL:%.*]]
236; CHECK-NEXT:    ret i1 [[R]]
237;
238  %t0 = shl i8 1, %bits
239  call void @use8(i8 %t0)
240  %t1 = add i8 %t0, -1
241  %r = icmp ule i8 %t1, %val ; wrong predicate
242  ret i1 %r
243}
244
245define i1 @n4(i8 %bits) {
246; CHECK-LABEL: @n4(
247; CHECK-NEXT:    [[T0:%.*]] = shl i8 1, [[BITS:%.*]]
248; CHECK-NEXT:    call void @use8(i8 [[T0]])
249; CHECK-NEXT:    [[T1:%.*]] = add i8 [[T0]], -1
250; CHECK-NEXT:    [[VAL:%.*]] = call i8 @gen8()
251; CHECK-NEXT:    [[R:%.*]] = icmp uge i8 [[VAL]], [[T1]]
252; CHECK-NEXT:    ret i1 [[R]]
253;
254  %t0 = shl i8 1, %bits
255  call void @use8(i8 %t0)
256  %t1 = add i8 %t0, -1
257  %val = call i8 @gen8()
258  %r = icmp uge i8 %val, %t1 ; swapped order and [wrong] predicate
259  ret i1 %r
260}
261