1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
4 ; PR53610 - sub(0,and(lshr(X,C1),1)) --> ashr(shl(X,(BW-1)-C1),BW-1)
5 ; PR53610 - sub(C2,and(lshr(X,C1),1)) --> add(ashr(shl(X,(BW-1)-C1),BW-1),C2)
7 define i8 @neg_mask1_lshr(i8 %a0) {
8 ; CHECK-LABEL: @neg_mask1_lshr(
9 ; CHECK-NEXT: [[TMP1:%.*]] = shl i8 [[A0:%.*]], 4
10 ; CHECK-NEXT: [[TMP2:%.*]] = ashr i8 [[TMP1]], 7
11 ; CHECK-NEXT: ret i8 [[TMP2]]
13 %shift = lshr i8 %a0, 3
14 %mask = and i8 %shift, 1
15 %neg = sub i8 0, %mask
19 define i8 @sub_mask1_lshr(i8 %a0) {
20 ; CHECK-LABEL: @sub_mask1_lshr(
21 ; CHECK-NEXT: [[TMP1:%.*]] = shl i8 [[A0:%.*]], 6
22 ; CHECK-NEXT: [[TMP2:%.*]] = ashr i8 [[TMP1]], 7
23 ; CHECK-NEXT: [[NEG:%.*]] = add nsw i8 [[TMP2]], 10
24 ; CHECK-NEXT: ret i8 [[NEG]]
26 %shift = lshr i8 %a0, 1
27 %mask = and i8 %shift, 1
28 %neg = sub i8 10, %mask
32 define <4 x i32> @neg_mask1_lshr_vector_uniform(<4 x i32> %a0) {
33 ; CHECK-LABEL: @neg_mask1_lshr_vector_uniform(
34 ; CHECK-NEXT: [[TMP1:%.*]] = shl <4 x i32> [[A0:%.*]], <i32 28, i32 28, i32 28, i32 28>
35 ; CHECK-NEXT: [[TMP2:%.*]] = ashr <4 x i32> [[TMP1]], <i32 31, i32 31, i32 31, i32 31>
36 ; CHECK-NEXT: ret <4 x i32> [[TMP2]]
38 %shift = lshr <4 x i32> %a0, <i32 3, i32 3, i32 3, i32 3>
39 %mask = and <4 x i32> %shift, <i32 1, i32 1, i32 1, i32 1>
40 %neg = sub <4 x i32> zeroinitializer, %mask
44 define <4 x i32> @neg_mask1_lshr_vector_nonuniform(<4 x i32> %a0) {
45 ; CHECK-LABEL: @neg_mask1_lshr_vector_nonuniform(
46 ; CHECK-NEXT: [[TMP1:%.*]] = shl <4 x i32> [[A0:%.*]], <i32 28, i32 27, i32 26, i32 25>
47 ; CHECK-NEXT: [[TMP2:%.*]] = ashr <4 x i32> [[TMP1]], <i32 31, i32 31, i32 31, i32 31>
48 ; CHECK-NEXT: ret <4 x i32> [[TMP2]]
50 %shift = lshr <4 x i32> %a0, <i32 3, i32 4, i32 5, i32 6>
51 %mask = and <4 x i32> %shift, <i32 1, i32 1, i32 1, i32 1>
52 %neg = sub <4 x i32> zeroinitializer, %mask
56 define <4 x i32> @sub_mask1_lshr_vector_nonuniform(<4 x i32> %a0) {
57 ; CHECK-LABEL: @sub_mask1_lshr_vector_nonuniform(
58 ; CHECK-NEXT: [[TMP1:%.*]] = shl <4 x i32> [[A0:%.*]], <i32 28, i32 27, i32 26, i32 25>
59 ; CHECK-NEXT: [[TMP2:%.*]] = ashr <4 x i32> [[TMP1]], <i32 31, i32 31, i32 31, i32 31>
60 ; CHECK-NEXT: [[NEG:%.*]] = add nsw <4 x i32> [[TMP2]], <i32 5, i32 0, i32 -1, i32 65556>
61 ; CHECK-NEXT: ret <4 x i32> [[NEG]]
63 %shift = lshr <4 x i32> %a0, <i32 3, i32 4, i32 5, i32 6>
64 %mask = and <4 x i32> %shift, <i32 1, i32 1, i32 1, i32 1>
65 %neg = sub <4 x i32> <i32 5, i32 0, i32 -1, i32 65556>, %mask
69 define i8 @sub_mask1_trunc_lshr(i64 %a0) {
70 ; CHECK-LABEL: @sub_mask1_trunc_lshr(
71 ; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[A0:%.*]], 48
72 ; CHECK-NEXT: [[TMP2:%.*]] = ashr i64 [[TMP1]], 63
73 ; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP2]] to i8
74 ; CHECK-NEXT: [[NEG:%.*]] = add nsw i8 [[TMP3]], 10
75 ; CHECK-NEXT: ret i8 [[NEG]]
77 %shift = lshr i64 %a0, 15
78 %trunc = trunc i64 %shift to i8
79 %mask = and i8 %trunc, 1
80 %neg = sub i8 10, %mask
84 define i32 @sub_sext_mask1_trunc_lshr(i64 %a0) {
85 ; CHECK-LABEL: @sub_sext_mask1_trunc_lshr(
86 ; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[A0:%.*]], 48
87 ; CHECK-NEXT: [[TMP2:%.*]] = ashr i64 [[TMP1]], 63
88 ; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP2]] to i8
89 ; CHECK-NEXT: [[NARROW:%.*]] = add nsw i8 [[TMP3]], 10
90 ; CHECK-NEXT: [[NEG:%.*]] = zext i8 [[NARROW]] to i32
91 ; CHECK-NEXT: ret i32 [[NEG]]
93 %shift = lshr i64 %a0, 15
94 %trunc = trunc i64 %shift to i8
95 %mask = and i8 %trunc, 1
96 %sext = sext i8 %mask to i32
97 %neg = sub i32 10, %sext
101 define i32 @sub_zext_trunc_lshr(i64 %a0) {
102 ; CHECK-LABEL: @sub_zext_trunc_lshr(
103 ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[A0:%.*]] to i32
104 ; CHECK-NEXT: [[TMP2:%.*]] = shl i32 [[TMP1]], 16
105 ; CHECK-NEXT: [[TMP3:%.*]] = ashr i32 [[TMP2]], 31
106 ; CHECK-NEXT: [[NEG:%.*]] = add nsw i32 [[TMP3]], 10
107 ; CHECK-NEXT: ret i32 [[NEG]]
109 %shift = lshr i64 %a0, 15
110 %trunc = trunc i64 %shift to i1
111 %sext = zext i1 %trunc to i32
112 %neg = sub i32 10, %sext
116 ; Negative Test - wrong mask
117 define i8 @neg_mask2_lshr(i8 %a0) {
118 ; CHECK-LABEL: @neg_mask2_lshr(
119 ; CHECK-NEXT: [[SHIFT:%.*]] = lshr i8 [[A0:%.*]], 3
120 ; CHECK-NEXT: [[MASK:%.*]] = and i8 [[SHIFT]], 2
121 ; CHECK-NEXT: [[NEG:%.*]] = sub nsw i8 0, [[MASK]]
122 ; CHECK-NEXT: ret i8 [[NEG]]
124 %shift = lshr i8 %a0, 3
125 %mask = and i8 %shift, 2
126 %neg = sub i8 0, %mask
130 ; Negative Test - bad shift amount
131 define i8 @neg_mask2_lshr_outofbounds(i8 %a0) {
132 ; CHECK-LABEL: @neg_mask2_lshr_outofbounds(
133 ; CHECK-NEXT: ret i8 poison
135 %shift = lshr i8 %a0, 8
136 %mask = and i8 %shift, 2
137 %neg = sub i8 0, %mask
141 ; Negative Test - non-constant shift amount
142 define <2 x i32> @neg_mask1_lshr_vector_var(<2 x i32> %a0, <2 x i32> %a1) {
143 ; CHECK-LABEL: @neg_mask1_lshr_vector_var(
144 ; CHECK-NEXT: [[SHIFT:%.*]] = lshr <2 x i32> [[A0:%.*]], [[A1:%.*]]
145 ; CHECK-NEXT: [[MASK:%.*]] = and <2 x i32> [[SHIFT]], <i32 1, i32 1>
146 ; CHECK-NEXT: [[NEG:%.*]] = sub nsw <2 x i32> zeroinitializer, [[MASK]]
147 ; CHECK-NEXT: ret <2 x i32> [[NEG]]
149 %shift = lshr <2 x i32> %a0, %a1
150 %mask = and <2 x i32> %shift, <i32 1, i32 1>
151 %neg = sub <2 x i32> zeroinitializer, %mask
156 define i8 @neg_mask1_lshr_extrause_mask(i8 %a0) {
157 ; CHECK-LABEL: @neg_mask1_lshr_extrause_mask(
158 ; CHECK-NEXT: [[SHIFT:%.*]] = lshr i8 [[A0:%.*]], 3
159 ; CHECK-NEXT: [[MASK:%.*]] = and i8 [[SHIFT]], 1
160 ; CHECK-NEXT: [[NEG:%.*]] = sub nsw i8 0, [[MASK]]
161 ; CHECK-NEXT: call void @usei8(i8 [[MASK]])
162 ; CHECK-NEXT: ret i8 [[NEG]]
164 %shift = lshr i8 %a0, 3
165 %mask = and i8 %shift, 1
166 %neg = sub i8 0, %mask
167 call void @usei8(i8 %mask)
172 define <2 x i32> @neg_mask1_lshr_extrause_lshr(<2 x i32> %a0) {
173 ; CHECK-LABEL: @neg_mask1_lshr_extrause_lshr(
174 ; CHECK-NEXT: [[SHIFT:%.*]] = lshr <2 x i32> [[A0:%.*]], <i32 3, i32 3>
175 ; CHECK-NEXT: [[MASK:%.*]] = and <2 x i32> [[SHIFT]], <i32 1, i32 1>
176 ; CHECK-NEXT: [[NEG:%.*]] = sub nsw <2 x i32> zeroinitializer, [[MASK]]
177 ; CHECK-NEXT: call void @usev2i32(<2 x i32> [[SHIFT]])
178 ; CHECK-NEXT: ret <2 x i32> [[NEG]]
180 %shift = lshr <2 x i32> %a0, <i32 3, i32 3>
181 %mask = and <2 x i32> %shift, <i32 1, i32 1>
182 %neg = sub <2 x i32> zeroinitializer, %mask
183 call void @usev2i32(<2 x i32> %shift)
187 define i32 @neg_signbit(i8 %x) {
188 ; CHECK-LABEL: @neg_signbit(
189 ; CHECK-NEXT: [[TMP1:%.*]] = ashr i8 [[X:%.*]], 7
190 ; CHECK-NEXT: [[TMP2:%.*]] = sext i8 [[TMP1]] to i32
191 ; CHECK-NEXT: ret i32 [[TMP2]]
194 %z = zext i8 %s to i32
199 define <2 x i64> @neg_signbit_use1(<2 x i32> %x) {
200 ; CHECK-LABEL: @neg_signbit_use1(
201 ; CHECK-NEXT: [[S:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 31, i32 poison>
202 ; CHECK-NEXT: call void @usev2i32(<2 x i32> [[S]])
203 ; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[X]], <i32 31, i32 31>
204 ; CHECK-NEXT: [[TMP2:%.*]] = sext <2 x i32> [[TMP1]] to <2 x i64>
205 ; CHECK-NEXT: ret <2 x i64> [[TMP2]]
207 %s = lshr <2 x i32> %x, <i32 31, i32 poison>
208 call void @usev2i32(<2 x i32> %s)
209 %z = zext <2 x i32> %s to <2 x i64>
210 %r = sub <2 x i64> zeroinitializer, %z
214 ; negative test - extra use
216 define i8 @neg_signbit_use2(i5 %x) {
217 ; CHECK-LABEL: @neg_signbit_use2(
218 ; CHECK-NEXT: [[S:%.*]] = lshr i5 [[X:%.*]], 4
219 ; CHECK-NEXT: [[Z:%.*]] = zext nneg i5 [[S]] to i8
220 ; CHECK-NEXT: call void @usei8(i8 [[Z]])
221 ; CHECK-NEXT: [[R:%.*]] = sub nsw i8 0, [[Z]]
222 ; CHECK-NEXT: ret i8 [[R]]
225 %z = zext i5 %s to i8
226 call void @usei8(i8 %z)
231 ; negative test - not negation
232 ; TODO: reduce to zext(x s> -1)
234 define i32 @neg_not_signbit1(i8 %x) {
235 ; CHECK-LABEL: @neg_not_signbit1(
236 ; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
237 ; CHECK-NEXT: [[R:%.*]] = zext i1 [[ISNOTNEG]] to i32
238 ; CHECK-NEXT: ret i32 [[R]]
241 %z = zext i8 %s to i32
246 ; negative test - wrong shift amount
248 define i32 @neg_not_signbit2(i8 %x) {
249 ; CHECK-LABEL: @neg_not_signbit2(
250 ; CHECK-NEXT: [[S:%.*]] = lshr i8 [[X:%.*]], 6
251 ; CHECK-NEXT: [[Z:%.*]] = zext nneg i8 [[S]] to i32
252 ; CHECK-NEXT: [[R:%.*]] = sub nsw i32 0, [[Z]]
253 ; CHECK-NEXT: ret i32 [[R]]
256 %z = zext i8 %s to i32
261 ; negative test - wrong shift opcode
263 define i32 @neg_not_signbit3(i8 %x) {
264 ; CHECK-LABEL: @neg_not_signbit3(
265 ; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 7
266 ; CHECK-NEXT: [[Z:%.*]] = zext i8 [[S]] to i32
267 ; CHECK-NEXT: [[R:%.*]] = sub nsw i32 0, [[Z]]
268 ; CHECK-NEXT: ret i32 [[R]]
271 %z = zext i8 %s to i32
276 define i32 @neg_mask(i32 %x, i16 %y) {
277 ; CHECK-LABEL: @neg_mask(
278 ; CHECK-NEXT: [[S:%.*]] = sext i16 [[Y:%.*]] to i32
279 ; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 [[X:%.*]], [[S]]
280 ; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i16 [[Y]], 0
281 ; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNEG]], i32 [[SUB1]], i32 0
282 ; CHECK-NEXT: ret i32 [[R]]
284 %s = sext i16 %y to i32
285 %sub1 = sub nsw i32 %x, %s
286 %sh = lshr i16 %y, 15
287 %z = zext i16 %sh to i32
288 %sub2 = sub nsw i32 0, %z
289 %r = and i32 %sub1, %sub2
293 define i32 @neg_mask_const(i16 %x) {
294 ; CHECK-LABEL: @neg_mask_const(
295 ; CHECK-NEXT: [[S:%.*]] = sext i16 [[X:%.*]] to i32
296 ; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 1000, [[S]]
297 ; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i16 [[X]], 0
298 ; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNEG]], i32 [[SUB1]], i32 0
299 ; CHECK-NEXT: ret i32 [[R]]
301 %s = sext i16 %x to i32
302 %sub1 = sub nsw i32 1000, %s
303 %sh = lshr i16 %x, 15
304 %z = zext i16 %sh to i32
305 %sub2 = sub nsw i32 0, %z
306 %r = and i32 %sub1, %sub2
310 declare void @usei8(i8)
311 declare void @usev2i32(<2 x i32>)