[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / InstCombine / trunc-binop-ext.ll
blob570153163ab9337103fa0580ff12743df25e60c0
1 ; RUN: opt < %s -instcombine -S | FileCheck %s
3 define i16 @narrow_sext_and(i16 %x16, i32 %y32) {
4 ; CHECK-LABEL: @narrow_sext_and(
5 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
6 ; CHECK-NEXT:    [[R:%.*]] = and i16 [[TMP1]], %x16
7 ; CHECK-NEXT:    ret i16 [[R]]
9   %x32 = sext i16 %x16 to i32
10   %b = and i32 %x32, %y32
11   %r = trunc i32 %b to i16
12   ret i16 %r
15 define i16 @narrow_zext_and(i16 %x16, i32 %y32) {
16 ; CHECK-LABEL: @narrow_zext_and(
17 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
18 ; CHECK-NEXT:    [[R:%.*]] = and i16 [[TMP1]], %x16
19 ; CHECK-NEXT:    ret i16 [[R]]
21   %x32 = zext i16 %x16 to i32
22   %b = and i32 %x32, %y32
23   %r = trunc i32 %b to i16
24   ret i16 %r
27 define i16 @narrow_sext_or(i16 %x16, i32 %y32) {
28 ; CHECK-LABEL: @narrow_sext_or(
29 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
30 ; CHECK-NEXT:    [[R:%.*]] = or i16 [[TMP1]], %x16
31 ; CHECK-NEXT:    ret i16 [[R]]
33   %x32 = sext i16 %x16 to i32
34   %b = or i32 %x32, %y32
35   %r = trunc i32 %b to i16
36   ret i16 %r
39 define i16 @narrow_zext_or(i16 %x16, i32 %y32) {
40 ; CHECK-LABEL: @narrow_zext_or(
41 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
42 ; CHECK-NEXT:    [[R:%.*]] = or i16 [[TMP1]], %x16
43 ; CHECK-NEXT:    ret i16 [[R]]
45   %x32 = zext i16 %x16 to i32
46   %b = or i32 %x32, %y32
47   %r = trunc i32 %b to i16
48   ret i16 %r
51 define i16 @narrow_sext_xor(i16 %x16, i32 %y32) {
52 ; CHECK-LABEL: @narrow_sext_xor(
53 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
54 ; CHECK-NEXT:    [[R:%.*]] = xor i16 [[TMP1]], %x16
55 ; CHECK-NEXT:    ret i16 [[R]]
57   %x32 = sext i16 %x16 to i32
58   %b = xor i32 %x32, %y32
59   %r = trunc i32 %b to i16
60   ret i16 %r
63 define i16 @narrow_zext_xor(i16 %x16, i32 %y32) {
64 ; CHECK-LABEL: @narrow_zext_xor(
65 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
66 ; CHECK-NEXT:    [[R:%.*]] = xor i16 [[TMP1]], %x16
67 ; CHECK-NEXT:    ret i16 [[R]]
69   %x32 = zext i16 %x16 to i32
70   %b = xor i32 %x32, %y32
71   %r = trunc i32 %b to i16
72   ret i16 %r
75 define i16 @narrow_sext_add(i16 %x16, i32 %y32) {
76 ; CHECK-LABEL: @narrow_sext_add(
77 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
78 ; CHECK-NEXT:    [[R:%.*]] = add i16 [[TMP1]], %x16
79 ; CHECK-NEXT:    ret i16 [[R]]
81   %x32 = sext i16 %x16 to i32
82   %b = add i32 %x32, %y32
83   %r = trunc i32 %b to i16
84   ret i16 %r
87 define i16 @narrow_zext_add(i16 %x16, i32 %y32) {
88 ; CHECK-LABEL: @narrow_zext_add(
89 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
90 ; CHECK-NEXT:    [[R:%.*]] = add i16 [[TMP1]], %x16
91 ; CHECK-NEXT:    ret i16 [[R]]
93   %x32 = zext i16 %x16 to i32
94   %b = add i32 %x32, %y32
95   %r = trunc i32 %b to i16
96   ret i16 %r
99 define i16 @narrow_sext_sub(i16 %x16, i32 %y32) {
100 ; CHECK-LABEL: @narrow_sext_sub(
101 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
102 ; CHECK-NEXT:    [[R:%.*]] = sub i16 %x16, [[TMP1]]
103 ; CHECK-NEXT:    ret i16 [[R]]
105   %x32 = sext i16 %x16 to i32
106   %b = sub i32 %x32, %y32
107   %r = trunc i32 %b to i16
108   ret i16 %r
111 define i16 @narrow_zext_sub(i16 %x16, i32 %y32) {
112 ; CHECK-LABEL: @narrow_zext_sub(
113 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
114 ; CHECK-NEXT:    [[R:%.*]] = sub i16 %x16, [[TMP1]]
115 ; CHECK-NEXT:    ret i16 [[R]]
117   %x32 = zext i16 %x16 to i32
118   %b = sub i32 %x32, %y32
119   %r = trunc i32 %b to i16
120   ret i16 %r
123 define i16 @narrow_sext_mul(i16 %x16, i32 %y32) {
124 ; CHECK-LABEL: @narrow_sext_mul(
125 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
126 ; CHECK-NEXT:    [[R:%.*]] = mul i16 [[TMP1]], %x16
127 ; CHECK-NEXT:    ret i16 [[R]]
129   %x32 = sext i16 %x16 to i32
130   %b = mul i32 %x32, %y32
131   %r = trunc i32 %b to i16
132   ret i16 %r
135 define i16 @narrow_zext_mul(i16 %x16, i32 %y32) {
136 ; CHECK-LABEL: @narrow_zext_mul(
137 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
138 ; CHECK-NEXT:    [[R:%.*]] = mul i16 [[TMP1]], %x16
139 ; CHECK-NEXT:    ret i16 [[R]]
141   %x32 = zext i16 %x16 to i32
142   %b = mul i32 %x32, %y32
143   %r = trunc i32 %b to i16
144   ret i16 %r
147 ; Verify that the commuted patterns work. The div is to ensure that complexity-based
148 ; canonicalization doesn't swap the binop operands. Use vector types to show those work too.
150 define <2 x i16> @narrow_sext_and_commute(<2 x i16> %x16, <2 x i32> %y32) {
151 ; CHECK-LABEL: @narrow_sext_and_commute(
152 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
153 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
154 ; CHECK-NEXT:    [[R:%.*]] = and <2 x i16> [[TMP1]], %x16
155 ; CHECK-NEXT:    ret <2 x i16> [[R]]
157   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
158   %x32 = sext <2 x i16> %x16 to <2 x i32>
159   %b = and <2 x i32> %y32op0, %x32
160   %r = trunc <2 x i32> %b to <2 x i16>
161   ret <2 x i16> %r
164 define <2 x i16> @narrow_zext_and_commute(<2 x i16> %x16, <2 x i32> %y32) {
165 ; CHECK-LABEL: @narrow_zext_and_commute(
166 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
167 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
168 ; CHECK-NEXT:    [[R:%.*]] = and <2 x i16> [[TMP1]], %x16
169 ; CHECK-NEXT:    ret <2 x i16> [[R]]
171   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
172   %x32 = zext <2 x i16> %x16 to <2 x i32>
173   %b = and <2 x i32> %y32op0, %x32
174   %r = trunc <2 x i32> %b to <2 x i16>
175   ret <2 x i16> %r
178 define <2 x i16> @narrow_sext_or_commute(<2 x i16> %x16, <2 x i32> %y32) {
179 ; CHECK-LABEL: @narrow_sext_or_commute(
180 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
181 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
182 ; CHECK-NEXT:    [[R:%.*]] = or <2 x i16> [[TMP1]], %x16
183 ; CHECK-NEXT:    ret <2 x i16> [[R]]
185   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
186   %x32 = sext <2 x i16> %x16 to <2 x i32>
187   %b = or <2 x i32> %y32op0, %x32
188   %r = trunc <2 x i32> %b to <2 x i16>
189   ret <2 x i16> %r
192 define <2 x i16> @narrow_zext_or_commute(<2 x i16> %x16, <2 x i32> %y32) {
193 ; CHECK-LABEL: @narrow_zext_or_commute(
194 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
195 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
196 ; CHECK-NEXT:    [[R:%.*]] = or <2 x i16> [[TMP1]], %x16
197 ; CHECK-NEXT:    ret <2 x i16> [[R]]
199   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
200   %x32 = zext <2 x i16> %x16 to <2 x i32>
201   %b = or <2 x i32> %y32op0, %x32
202   %r = trunc <2 x i32> %b to <2 x i16>
203   ret <2 x i16> %r
206 define <2 x i16> @narrow_sext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) {
207 ; CHECK-LABEL: @narrow_sext_xor_commute(
208 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
209 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
210 ; CHECK-NEXT:    [[R:%.*]] = xor <2 x i16> [[TMP1]], %x16
211 ; CHECK-NEXT:    ret <2 x i16> [[R]]
213   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
214   %x32 = sext <2 x i16> %x16 to <2 x i32>
215   %b = xor <2 x i32> %y32op0, %x32
216   %r = trunc <2 x i32> %b to <2 x i16>
217   ret <2 x i16> %r
220 define <2 x i16> @narrow_zext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) {
221 ; CHECK-LABEL: @narrow_zext_xor_commute(
222 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
223 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
224 ; CHECK-NEXT:    [[R:%.*]] = xor <2 x i16> [[TMP1]], %x16
225 ; CHECK-NEXT:    ret <2 x i16> [[R]]
227   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
228   %x32 = zext <2 x i16> %x16 to <2 x i32>
229   %b = xor <2 x i32> %y32op0, %x32
230   %r = trunc <2 x i32> %b to <2 x i16>
231   ret <2 x i16> %r
234 define <2 x i16> @narrow_sext_add_commute(<2 x i16> %x16, <2 x i32> %y32) {
235 ; CHECK-LABEL: @narrow_sext_add_commute(
236 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
237 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
238 ; CHECK-NEXT:    [[R:%.*]] = add <2 x i16> [[TMP1]], %x16
239 ; CHECK-NEXT:    ret <2 x i16> [[R]]
241   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
242   %x32 = sext <2 x i16> %x16 to <2 x i32>
243   %b = add <2 x i32> %y32op0, %x32
244   %r = trunc <2 x i32> %b to <2 x i16>
245   ret <2 x i16> %r
248 define <2 x i16> @narrow_zext_add_commute(<2 x i16> %x16, <2 x i32> %y32) {
249 ; CHECK-LABEL: @narrow_zext_add_commute(
250 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
251 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
252 ; CHECK-NEXT:    [[R:%.*]] = add <2 x i16> [[TMP1]], %x16
253 ; CHECK-NEXT:    ret <2 x i16> [[R]]
255   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
256   %x32 = zext <2 x i16> %x16 to <2 x i32>
257   %b = add <2 x i32> %y32op0, %x32
258   %r = trunc <2 x i32> %b to <2 x i16>
259   ret <2 x i16> %r
262 define <2 x i16> @narrow_sext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) {
263 ; CHECK-LABEL: @narrow_sext_sub_commute(
264 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
265 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
266 ; CHECK-NEXT:    [[R:%.*]] = sub <2 x i16> [[TMP1]], %x16
267 ; CHECK-NEXT:    ret <2 x i16> [[R]]
269   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
270   %x32 = sext <2 x i16> %x16 to <2 x i32>
271   %b = sub <2 x i32> %y32op0, %x32
272   %r = trunc <2 x i32> %b to <2 x i16>
273   ret <2 x i16> %r
276 define <2 x i16> @narrow_zext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) {
277 ; CHECK-LABEL: @narrow_zext_sub_commute(
278 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
279 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
280 ; CHECK-NEXT:    [[R:%.*]] = sub <2 x i16> [[TMP1]], %x16
281 ; CHECK-NEXT:    ret <2 x i16> [[R]]
283   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
284   %x32 = zext <2 x i16> %x16 to <2 x i32>
285   %b = sub <2 x i32> %y32op0, %x32
286   %r = trunc <2 x i32> %b to <2 x i16>
287   ret <2 x i16> %r
290 define <2 x i16> @narrow_sext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) {
291 ; CHECK-LABEL: @narrow_sext_mul_commute(
292 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
293 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
294 ; CHECK-NEXT:    [[R:%.*]] = mul <2 x i16> [[TMP1]], %x16
295 ; CHECK-NEXT:    ret <2 x i16> [[R]]
297   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
298   %x32 = sext <2 x i16> %x16 to <2 x i32>
299   %b = mul <2 x i32> %y32op0, %x32
300   %r = trunc <2 x i32> %b to <2 x i16>
301   ret <2 x i16> %r
304 define <2 x i16> @narrow_zext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) {
305 ; CHECK-LABEL: @narrow_zext_mul_commute(
306 ; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
307 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
308 ; CHECK-NEXT:    [[R:%.*]] = mul <2 x i16> [[TMP1]], %x16
309 ; CHECK-NEXT:    ret <2 x i16> [[R]]
311   %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
312   %x32 = zext <2 x i16> %x16 to <2 x i32>
313   %b = mul <2 x i32> %y32op0, %x32
314   %r = trunc <2 x i32> %b to <2 x i16>
315   ret <2 x i16> %r
318 ; Test cases for PR43580
319 define i8 @narrow_zext_ashr_keep_trunc(i8 %i1, i8 %i2) {
320 ; CHECK-LABEL: @narrow_zext_ashr_keep_trunc(
321 ; CHECK-NEXT:    [[I1_EXT:%.*]] = sext i8 [[I1:%.*]] to i16
322 ; CHECK-NEXT:    [[I2_EXT:%.*]] = sext i8 [[I2:%.*]] to i16
323 ; CHECK-NEXT:    [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]]
324 ; CHECK-NEXT:    [[TMP1:%.*]] = lshr i16 [[SUB]], 1
325 ; CHECK-NEXT:    [[T:%.*]] = trunc i16 [[TMP1]] to i8
326 ; CHECK-NEXT:    ret i8 [[T]]
328   %i1.ext = sext i8 %i1 to i32
329   %i2.ext = sext i8 %i2 to i32
330   %sub = add nsw i32 %i1.ext, %i2.ext
331   %shift = ashr i32 %sub, 1
332   %t = trunc i32 %shift to i8
333   ret i8 %t
336 define i8 @narrow_zext_ashr_keep_trunc2(i9 %i1, i9 %i2) {
337 ; CHECK-LABEL: @narrow_zext_ashr_keep_trunc2(
338 ; CHECK-NEXT:    [[I1_EXT1:%.*]] = zext i9 [[I1:%.*]] to i16
339 ; CHECK-NEXT:    [[I2_EXT2:%.*]] = zext i9 [[I2:%.*]] to i16
340 ; CHECK-NEXT:    [[SUB:%.*]] = add nuw nsw i16 [[I1_EXT1]], [[I2_EXT2]]
341 ; CHECK-NEXT:    [[TMP1:%.*]] = lshr i16 [[SUB]], 1
342 ; CHECK-NEXT:    [[T:%.*]] = trunc i16 [[TMP1]] to i8
343 ; CHECK-NEXT:    ret i8 [[T]]
345   %i1.ext = sext i9 %i1 to i64
346   %i2.ext = sext i9 %i2 to i64
347   %sub = add nsw i64 %i1.ext, %i2.ext
348   %shift = ashr i64 %sub, 1
349   %t = trunc i64 %shift to i8
350   ret i8 %t
353 define i7 @narrow_zext_ashr_keep_trunc3(i8 %i1, i8 %i2) {
354 ; CHECK-LABEL: @narrow_zext_ashr_keep_trunc3(
355 ; CHECK-NEXT:    [[I1_EXT1:%.*]] = zext i8 [[I1:%.*]] to i14
356 ; CHECK-NEXT:    [[I2_EXT2:%.*]] = zext i8 [[I2:%.*]] to i14
357 ; CHECK-NEXT:    [[SUB:%.*]] = add nuw nsw i14 [[I1_EXT1]], [[I2_EXT2]]
358 ; CHECK-NEXT:    [[TMP1:%.*]] = lshr i14 [[SUB]], 1
359 ; CHECK-NEXT:    [[T:%.*]] = trunc i14 [[TMP1]] to i7
360 ; CHECK-NEXT:    ret i7 [[T]]
362   %i1.ext = sext i8 %i1 to i64
363   %i2.ext = sext i8 %i2 to i64
364   %sub = add nsw i64 %i1.ext, %i2.ext
365   %shift = ashr i64 %sub, 1
366   %t = trunc i64 %shift to i7
367   ret i7 %t
370 define <8 x i8> @narrow_zext_ashr_keep_trunc_vector(<8 x i8> %i1, <8 x i8> %i2) {
371 ; CHECK-LABEL: @narrow_zext_ashr_keep_trunc_vector(
372 ; CHECK-NEXT:    [[I1_EXT:%.*]] = sext <8 x i8> [[I1:%.*]] to <8 x i32>
373 ; CHECK-NEXT:    [[I2_EXT:%.*]] = sext <8 x i8> [[I2:%.*]] to <8 x i32>
374 ; CHECK-NEXT:    [[SUB:%.*]] = add nsw <8 x i32> [[I1_EXT]], [[I2_EXT]]
375 ; CHECK-NEXT:    [[TMP1:%.*]] = lshr <8 x i32> [[SUB]], <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
376 ; CHECK-NEXT:    [[T:%.*]] = trunc <8 x i32> [[TMP1]] to <8 x i8>
377 ; CHECK-NEXT:    ret <8 x i8> [[T]]
379   %i1.ext = sext <8 x i8> %i1 to <8 x i32>
380   %i2.ext = sext <8 x i8> %i2 to <8 x i32>
381   %sub = add nsw <8 x i32> %i1.ext, %i2.ext
382   %shift = ashr <8 x i32> %sub, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
383   %t = trunc <8 x i32> %shift to <8 x i8>
384   ret <8 x i8> %t
387 define i8 @dont_narrow_zext_ashr_keep_trunc(i8 %i1, i8 %i2) {
388 ; CHECK-LABEL: @dont_narrow_zext_ashr_keep_trunc(
389 ; CHECK-NEXT:    [[I1_EXT:%.*]] = sext i8 [[I1:%.*]] to i16
390 ; CHECK-NEXT:    [[I2_EXT:%.*]] = sext i8 [[I2:%.*]] to i16
391 ; CHECK-NEXT:    [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]]
392 ; CHECK-NEXT:    [[TMP1:%.*]] = lshr i16 [[SUB]], 1
393 ; CHECK-NEXT:    [[T:%.*]] = trunc i16 [[TMP1]] to i8
394 ; CHECK-NEXT:    ret i8 [[T]]
396   %i1.ext = sext i8 %i1 to i16
397   %i2.ext = sext i8 %i2 to i16
398   %sub = add nsw i16 %i1.ext, %i2.ext
399   %shift = ashr i16 %sub, 1
400   %t = trunc i16 %shift to i8
401   ret i8 %t