1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
4 ; https://bugs.llvm.org/show_bug.cgi?id=38123
7 ; x & ((-1 << y) >> y) == x
8 ; Should be transformed into:
9 ; x u<= ((-1 << y) >> y)
11 ; This pattern is uncanonical, but we can not canonicalize it due to extra uses.
13 declare void @use8(i8)
14 declare void @use2i8(<2 x i8>)
15 declare void @use3i8(<3 x i8>)
17 ; ============================================================================ ;
18 ; Basic positive tests
19 ; ============================================================================ ;
21 define i1 @p0(i8 %x, i8 %y) {
23 ; CHECK-NEXT: [[T0:%.*]] = shl nsw i8 -1, [[Y:%.*]]
24 ; CHECK-NEXT: call void @use8(i8 [[T0]])
25 ; CHECK-NEXT: [[T1:%.*]] = lshr exact i8 [[T0]], [[Y]]
26 ; CHECK-NEXT: [[RET:%.*]] = icmp uge i8 [[T1]], [[X:%.*]]
27 ; CHECK-NEXT: ret i1 [[RET]]
30 call void @use8(i8 %t0)
33 %ret = icmp eq i8 %t2, %x
37 ; ============================================================================ ;
39 ; ============================================================================ ;
41 define <2 x i1> @p1_vec(<2 x i8> %x, <2 x i8> %y) {
42 ; CHECK-LABEL: @p1_vec(
43 ; CHECK-NEXT: [[T0:%.*]] = shl nsw <2 x i8> <i8 -1, i8 -1>, [[Y:%.*]]
44 ; CHECK-NEXT: call void @use2i8(<2 x i8> [[T0]])
45 ; CHECK-NEXT: [[T1:%.*]] = lshr exact <2 x i8> [[T0]], [[Y]]
46 ; CHECK-NEXT: [[RET:%.*]] = icmp uge <2 x i8> [[T1]], [[X:%.*]]
47 ; CHECK-NEXT: ret <2 x i1> [[RET]]
49 %t0 = shl <2 x i8> <i8 -1, i8 -1>, %y
50 call void @use2i8(<2 x i8> %t0)
51 %t1 = lshr <2 x i8> %t0, %y
52 %t2 = and <2 x i8> %t1, %x
53 %ret = icmp eq <2 x i8> %t2, %x
57 define <3 x i1> @p2_vec_undef0(<3 x i8> %x, <3 x i8> %y) {
58 ; CHECK-LABEL: @p2_vec_undef0(
59 ; CHECK-NEXT: [[T0:%.*]] = shl <3 x i8> <i8 -1, i8 undef, i8 -1>, [[Y:%.*]]
60 ; CHECK-NEXT: call void @use3i8(<3 x i8> [[T0]])
61 ; CHECK-NEXT: [[T1:%.*]] = lshr exact <3 x i8> [[T0]], [[Y]]
62 ; CHECK-NEXT: [[RET:%.*]] = icmp uge <3 x i8> [[T1]], [[X:%.*]]
63 ; CHECK-NEXT: ret <3 x i1> [[RET]]
65 %t0 = shl <3 x i8> <i8 -1, i8 undef, i8 -1>, %y
66 call void @use3i8(<3 x i8> %t0)
67 %t1 = lshr <3 x i8> %t0, %y
68 %t2 = and <3 x i8> %t1, %x
69 %ret = icmp eq <3 x i8> %t2, %x
73 ; ============================================================================ ;
74 ; Commutativity tests.
75 ; ============================================================================ ;
79 define i1 @c0(i8 %y) {
81 ; CHECK-NEXT: [[T0:%.*]] = shl nsw i8 -1, [[Y:%.*]]
82 ; CHECK-NEXT: call void @use8(i8 [[T0]])
83 ; CHECK-NEXT: [[T1:%.*]] = lshr exact i8 [[T0]], [[Y]]
84 ; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
85 ; CHECK-NEXT: [[RET:%.*]] = icmp ule i8 [[X]], [[T1]]
86 ; CHECK-NEXT: ret i1 [[RET]]
89 call void @use8(i8 %t0)
92 %t2 = and i8 %x, %t1 ; swapped order
93 %ret = icmp eq i8 %t2, %x
97 define i1 @c1(i8 %y) {
99 ; CHECK-NEXT: [[T0:%.*]] = shl nsw i8 -1, [[Y:%.*]]
100 ; CHECK-NEXT: call void @use8(i8 [[T0]])
101 ; CHECK-NEXT: [[T1:%.*]] = lshr exact i8 [[T0]], [[Y]]
102 ; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
103 ; CHECK-NEXT: [[RET:%.*]] = icmp ule i8 [[X]], [[T1]]
104 ; CHECK-NEXT: ret i1 [[RET]]
107 call void @use8(i8 %t0)
108 %t1 = lshr i8 %t0, %y
111 %ret = icmp eq i8 %x, %t2 ; swapped order
115 define i1 @c2(i8 %y) {
117 ; CHECK-NEXT: [[T0:%.*]] = shl nsw i8 -1, [[Y:%.*]]
118 ; CHECK-NEXT: call void @use8(i8 [[T0]])
119 ; CHECK-NEXT: [[T1:%.*]] = lshr exact i8 [[T0]], [[Y]]
120 ; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
121 ; CHECK-NEXT: [[RET:%.*]] = icmp ule i8 [[X]], [[T1]]
122 ; CHECK-NEXT: ret i1 [[RET]]
125 call void @use8(i8 %t0)
126 %t1 = lshr i8 %t0, %y
128 %t2 = and i8 %x, %t1 ; swapped order
129 %ret = icmp eq i8 %x, %t2 ; swapped order
133 ; ============================================================================ ;
134 ; One-use tests. We don't care about multi-uses here.
135 ; ============================================================================ ;
137 define i1 @oneuse0(i8 %x, i8 %y) {
138 ; CHECK-LABEL: @oneuse0(
139 ; CHECK-NEXT: [[T0:%.*]] = shl nsw i8 -1, [[Y:%.*]]
140 ; CHECK-NEXT: call void @use8(i8 [[T0]])
141 ; CHECK-NEXT: [[T1:%.*]] = lshr exact i8 [[T0]], [[Y]]
142 ; CHECK-NEXT: call void @use8(i8 [[T1]])
143 ; CHECK-NEXT: [[RET:%.*]] = icmp uge i8 [[T1]], [[X:%.*]]
144 ; CHECK-NEXT: ret i1 [[RET]]
147 call void @use8(i8 %t0) ; needed anyway
148 %t1 = lshr i8 %t0, %y
149 call void @use8(i8 %t1)
151 %ret = icmp eq i8 %t2, %x
155 define i1 @oneuse1(i8 %x, i8 %y) {
156 ; CHECK-LABEL: @oneuse1(
157 ; CHECK-NEXT: [[T0:%.*]] = shl nsw i8 -1, [[Y:%.*]]
158 ; CHECK-NEXT: call void @use8(i8 [[T0]])
159 ; CHECK-NEXT: [[T1:%.*]] = lshr exact i8 [[T0]], [[Y]]
160 ; CHECK-NEXT: [[T2:%.*]] = and i8 [[T1]], [[X:%.*]]
161 ; CHECK-NEXT: call void @use8(i8 [[T2]])
162 ; CHECK-NEXT: [[RET:%.*]] = icmp uge i8 [[T1]], [[X]]
163 ; CHECK-NEXT: ret i1 [[RET]]
166 call void @use8(i8 %t0) ; needed anyway
167 %t1 = lshr i8 %t0, %y
169 call void @use8(i8 %t2)
170 %ret = icmp eq i8 %t2, %x
174 define i1 @oneuse2(i8 %x, i8 %y) {
175 ; CHECK-LABEL: @oneuse2(
176 ; CHECK-NEXT: [[T0:%.*]] = shl nsw i8 -1, [[Y:%.*]]
177 ; CHECK-NEXT: call void @use8(i8 [[T0]])
178 ; CHECK-NEXT: [[T1:%.*]] = lshr exact i8 [[T0]], [[Y]]
179 ; CHECK-NEXT: call void @use8(i8 [[T1]])
180 ; CHECK-NEXT: [[T2:%.*]] = and i8 [[T1]], [[X:%.*]]
181 ; CHECK-NEXT: call void @use8(i8 [[T2]])
182 ; CHECK-NEXT: [[RET:%.*]] = icmp uge i8 [[T1]], [[X]]
183 ; CHECK-NEXT: ret i1 [[RET]]
186 call void @use8(i8 %t0)
187 %t1 = lshr i8 %t0, %y
188 call void @use8(i8 %t1)
190 call void @use8(i8 %t2)
191 %ret = icmp eq i8 %t2, %x
195 ; ============================================================================ ;
197 ; ============================================================================ ;
199 define i1 @n0(i8 %x, i8 %y, i8 %notx) {
201 ; CHECK-NEXT: [[T0:%.*]] = shl nsw i8 -1, [[Y:%.*]]
202 ; CHECK-NEXT: call void @use8(i8 [[T0]])
203 ; CHECK-NEXT: [[T1:%.*]] = lshr exact i8 [[T0]], [[Y]]
204 ; CHECK-NEXT: [[T2:%.*]] = and i8 [[T1]], [[X:%.*]]
205 ; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[T2]], [[NOTX:%.*]]
206 ; CHECK-NEXT: ret i1 [[RET]]
209 call void @use8(i8 %t0)
210 %t1 = lshr i8 %t0, %y
212 %ret = icmp eq i8 %t2, %notx ; not %x
216 define i1 @n1(i8 %x, i8 %y) {
218 ; CHECK-NEXT: [[T0:%.*]] = shl nuw i8 1, [[Y:%.*]]
219 ; CHECK-NEXT: call void @use8(i8 [[T0]])
220 ; CHECK-NEXT: [[RET:%.*]] = icmp ult i8 [[X:%.*]], 2
221 ; CHECK-NEXT: ret i1 [[RET]]
223 %t0 = shl i8 1, %y ; not -1
224 call void @use8(i8 %t0)
225 %t1 = lshr i8 %t0, %y
227 %ret = icmp eq i8 %t2, %x
231 define i1 @n2(i8 %x, i8 %y1, i8 %y2) {
233 ; CHECK-NEXT: [[T0:%.*]] = shl nsw i8 -1, [[Y1:%.*]]
234 ; CHECK-NEXT: call void @use8(i8 [[T0]])
235 ; CHECK-NEXT: [[T1:%.*]] = lshr i8 [[T0]], [[Y2:%.*]]
236 ; CHECK-NEXT: [[T2:%.*]] = and i8 [[T1]], [[X:%.*]]
237 ; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[T2]], [[X]]
238 ; CHECK-NEXT: ret i1 [[RET]]
240 %t0 = shl i8 -1, %y1 ; not %y2
241 call void @use8(i8 %t0)
242 %t1 = lshr i8 %t0, %y2 ; not %y1
244 %ret = icmp eq i8 %t2, %x