xref: /llvm-project/llvm/test/CodeGen/AArch64/mul_pow2.ll (revision 4a96803abda2ad74f326de0af6b16552067bda65)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=aarch64 | FileCheck %s
3; RUN: llc < %s -mtriple=aarch64 -global-isel -global-isel-abort=1 | FileCheck %s --check-prefix=GISEL
4
5; Convert mul x, pow2 to shift.
6; Convert mul x, pow2 +/- 1 to shift + add/sub.
7; Convert mul x, (pow2 + 1) * pow2 to shift + add + shift.
8; Lowering other positive constants are not supported yet.
9
10define i32 @test2(i32 %x) {
11; CHECK-LABEL: test2:
12; CHECK:       // %bb.0:
13; CHECK-NEXT:    lsl w0, w0, #1
14; CHECK-NEXT:    ret
15;
16; GISEL-LABEL: test2:
17; GISEL:       // %bb.0:
18; GISEL-NEXT:    lsl w0, w0, #1
19; GISEL-NEXT:    ret
20
21  %mul = shl nsw i32 %x, 1
22  ret i32 %mul
23}
24
25define i32 @test3(i32 %x) {
26; CHECK-LABEL: test3:
27; CHECK:       // %bb.0:
28; CHECK-NEXT:    add w0, w0, w0, lsl #1
29; CHECK-NEXT:    ret
30;
31; GISEL-LABEL: test3:
32; GISEL:       // %bb.0:
33; GISEL-NEXT:    add w0, w0, w0, lsl #1
34; GISEL-NEXT:    ret
35
36  %mul = mul nsw i32 %x, 3
37  ret i32 %mul
38}
39
40define i32 @test4(i32 %x) {
41; CHECK-LABEL: test4:
42; CHECK:       // %bb.0:
43; CHECK-NEXT:    lsl w0, w0, #2
44; CHECK-NEXT:    ret
45;
46; GISEL-LABEL: test4:
47; GISEL:       // %bb.0:
48; GISEL-NEXT:    lsl w0, w0, #2
49; GISEL-NEXT:    ret
50
51  %mul = shl nsw i32 %x, 2
52  ret i32 %mul
53}
54
55define i32 @test5(i32 %x) {
56; CHECK-LABEL: test5:
57; CHECK:       // %bb.0:
58; CHECK-NEXT:    add w0, w0, w0, lsl #2
59; CHECK-NEXT:    ret
60;
61; GISEL-LABEL: test5:
62; GISEL:       // %bb.0:
63; GISEL-NEXT:    add w0, w0, w0, lsl #2
64; GISEL-NEXT:    ret
65
66
67  %mul = mul nsw i32 %x, 5
68  ret i32 %mul
69}
70
71define i32 @test6_32b(i32 %x) {
72; CHECK-LABEL: test6_32b:
73; CHECK:       // %bb.0:
74; CHECK-NEXT:    add w8, w0, w0, lsl #1
75; CHECK-NEXT:    lsl w0, w8, #1
76; CHECK-NEXT:    ret
77;
78; GISEL-LABEL: test6_32b:
79; GISEL:       // %bb.0:
80; GISEL-NEXT:    add w8, w0, w0, lsl #1
81; GISEL-NEXT:    lsl w0, w8, #1
82; GISEL-NEXT:    ret
83
84  %mul = mul nsw i32 %x, 6
85  ret i32 %mul
86}
87
88define i64 @test6_64b(i64 %x) {
89; CHECK-LABEL: test6_64b:
90; CHECK:       // %bb.0:
91; CHECK-NEXT:    add x8, x0, x0, lsl #1
92; CHECK-NEXT:    lsl x0, x8, #1
93; CHECK-NEXT:    ret
94;
95; GISEL-LABEL: test6_64b:
96; GISEL:       // %bb.0:
97; GISEL-NEXT:    add x8, x0, x0, lsl #1
98; GISEL-NEXT:    lsl x0, x8, #1
99; GISEL-NEXT:    ret
100
101  %mul = mul nsw i64 %x, 6
102  ret i64 %mul
103}
104
105; mul that appears together with add, sub, s(z)ext is not supported to be
106; converted to the combination of lsl, add/sub yet.
107define i64 @test6_umull(i32 %x) {
108; CHECK-LABEL: test6_umull:
109; CHECK:       // %bb.0:
110; CHECK-NEXT:    mov w8, #6 // =0x6
111; CHECK-NEXT:    umull x0, w0, w8
112; CHECK-NEXT:    ret
113;
114; GISEL-LABEL: test6_umull:
115; GISEL:       // %bb.0:
116; GISEL-NEXT:    mov w8, #6 // =0x6
117; GISEL-NEXT:    umull x0, w0, w8
118; GISEL-NEXT:    ret
119
120  %ext = zext i32 %x to i64
121  %mul = mul nsw i64 %ext, 6
122  ret i64 %mul
123}
124
125define i64 @test6_smull(i32 %x) {
126; CHECK-LABEL: test6_smull:
127; CHECK:       // %bb.0:
128; CHECK-NEXT:    mov w8, #6 // =0x6
129; CHECK-NEXT:    smull x0, w0, w8
130; CHECK-NEXT:    ret
131;
132; GISEL-LABEL: test6_smull:
133; GISEL:       // %bb.0:
134; GISEL-NEXT:    mov w8, #6 // =0x6
135; GISEL-NEXT:    smull x0, w0, w8
136; GISEL-NEXT:    ret
137
138  %ext = sext i32 %x to i64
139  %mul = mul nsw i64 %ext, 6
140  ret i64 %mul
141}
142
143define i32 @test6_madd(i32 %x, i32 %y) {
144; CHECK-LABEL: test6_madd:
145; CHECK:       // %bb.0:
146; CHECK-NEXT:    mov w8, #6 // =0x6
147; CHECK-NEXT:    madd w0, w0, w8, w1
148; CHECK-NEXT:    ret
149;
150; GISEL-LABEL: test6_madd:
151; GISEL:       // %bb.0:
152; GISEL-NEXT:    mov w8, #6 // =0x6
153; GISEL-NEXT:    madd w0, w0, w8, w1
154; GISEL-NEXT:    ret
155
156  %mul = mul nsw i32 %x, 6
157  %add = add i32 %mul, %y
158  ret i32 %add
159}
160
161define i32 @test6_msub(i32 %x, i32 %y) {
162; CHECK-LABEL: test6_msub:
163; CHECK:       // %bb.0:
164; CHECK-NEXT:    mov w8, #6 // =0x6
165; CHECK-NEXT:    msub w0, w0, w8, w1
166; CHECK-NEXT:    ret
167;
168; GISEL-LABEL: test6_msub:
169; GISEL:       // %bb.0:
170; GISEL-NEXT:    mov w8, #6 // =0x6
171; GISEL-NEXT:    msub w0, w0, w8, w1
172; GISEL-NEXT:    ret
173
174  %mul = mul nsw i32 %x, 6
175  %sub = sub i32 %y, %mul
176  ret i32 %sub
177}
178
179define i64 @test6_umaddl(i32 %x, i64 %y) {
180; CHECK-LABEL: test6_umaddl:
181; CHECK:       // %bb.0:
182; CHECK-NEXT:    mov w8, #6 // =0x6
183; CHECK-NEXT:    umaddl x0, w0, w8, x1
184; CHECK-NEXT:    ret
185;
186; GISEL-LABEL: test6_umaddl:
187; GISEL:       // %bb.0:
188; GISEL-NEXT:    mov w8, #6 // =0x6
189; GISEL-NEXT:    umaddl x0, w0, w8, x1
190; GISEL-NEXT:    ret
191
192  %ext = zext i32 %x to i64
193  %mul = mul nsw i64 %ext, 6
194  %add = add i64 %mul, %y
195  ret i64 %add
196}
197
198define i64 @test6_smaddl(i32 %x, i64 %y) {
199; CHECK-LABEL: test6_smaddl:
200; CHECK:       // %bb.0:
201; CHECK-NEXT:    mov w8, #6 // =0x6
202; CHECK-NEXT:    smaddl x0, w0, w8, x1
203; CHECK-NEXT:    ret
204;
205; GISEL-LABEL: test6_smaddl:
206; GISEL:       // %bb.0:
207; GISEL-NEXT:    mov w8, #6 // =0x6
208; GISEL-NEXT:    smaddl x0, w0, w8, x1
209; GISEL-NEXT:    ret
210
211  %ext = sext i32 %x to i64
212  %mul = mul nsw i64 %ext, 6
213  %add = add i64 %mul, %y
214  ret i64 %add
215}
216
217define i64 @test6_umsubl(i32 %x, i64 %y) {
218; CHECK-LABEL: test6_umsubl:
219; CHECK:       // %bb.0:
220; CHECK-NEXT:    mov w8, #6 // =0x6
221; CHECK-NEXT:    umsubl x0, w0, w8, x1
222; CHECK-NEXT:    ret
223;
224; GISEL-LABEL: test6_umsubl:
225; GISEL:       // %bb.0:
226; GISEL-NEXT:    mov w8, #6 // =0x6
227; GISEL-NEXT:    umsubl x0, w0, w8, x1
228; GISEL-NEXT:    ret
229
230  %ext = zext i32 %x to i64
231  %mul = mul nsw i64 %ext, 6
232  %sub = sub i64 %y, %mul
233  ret i64 %sub
234}
235
236define i64 @test6_smsubl(i32 %x, i64 %y) {
237; CHECK-LABEL: test6_smsubl:
238; CHECK:       // %bb.0:
239; CHECK-NEXT:    mov w8, #6 // =0x6
240; CHECK-NEXT:    smsubl x0, w0, w8, x1
241; CHECK-NEXT:    ret
242;
243; GISEL-LABEL: test6_smsubl:
244; GISEL:       // %bb.0:
245; GISEL-NEXT:    mov w8, #6 // =0x6
246; GISEL-NEXT:    smsubl x0, w0, w8, x1
247; GISEL-NEXT:    ret
248
249  %ext = sext i32 %x to i64
250  %mul = mul nsw i64 %ext, 6
251  %sub = sub i64 %y, %mul
252  ret i64 %sub
253}
254
255define i64 @test6_umnegl(i32 %x) {
256; CHECK-LABEL: test6_umnegl:
257; CHECK:       // %bb.0:
258; CHECK-NEXT:    mov w8, #6 // =0x6
259; CHECK-NEXT:    umnegl x0, w0, w8
260; CHECK-NEXT:    ret
261;
262; GISEL-LABEL: test6_umnegl:
263; GISEL:       // %bb.0:
264; GISEL-NEXT:    mov w8, #6 // =0x6
265; GISEL-NEXT:    umnegl x0, w0, w8
266; GISEL-NEXT:    ret
267
268  %ext = zext i32 %x to i64
269  %mul = mul nsw i64 %ext, 6
270  %sub = sub i64 0, %mul
271  ret i64 %sub
272}
273
274define i64 @test6_smnegl(i32 %x) {
275; CHECK-LABEL: test6_smnegl:
276; CHECK:       // %bb.0:
277; CHECK-NEXT:    mov w8, #6 // =0x6
278; CHECK-NEXT:    smnegl x0, w0, w8
279; CHECK-NEXT:    ret
280;
281; GISEL-LABEL: test6_smnegl:
282; GISEL:       // %bb.0:
283; GISEL-NEXT:    mov w8, #6 // =0x6
284; GISEL-NEXT:    smnegl x0, w0, w8
285; GISEL-NEXT:    ret
286
287  %ext = sext i32 %x to i64
288  %mul = mul nsw i64 %ext, 6
289  %sub = sub i64 0, %mul
290  ret i64 %sub
291}
292
293; We may hoist the "mov" instructions out of a loop
294define i32 @mull6_sub(i32 %x) {
295; CHECK-LABEL: mull6_sub:
296; CHECK:       // %bb.0:
297; CHECK-NEXT:    mov w8, #6 // =0x6
298; CHECK-NEXT:    mov w9, #-1 // =0xffffffff
299; CHECK-NEXT:    madd w0, w0, w8, w9
300; CHECK-NEXT:    ret
301;
302; GISEL-LABEL: mull6_sub:
303; GISEL:       // %bb.0:
304; GISEL-NEXT:    mov w8, #6 // =0x6
305; GISEL-NEXT:    mov w9, #-1 // =0xffffffff
306; GISEL-NEXT:    madd w0, w0, w8, w9
307; GISEL-NEXT:    ret
308  %mul = mul nsw i32 %x, 6
309  %sub = add nsw i32 %mul, -1
310  ret i32 %sub
311}
312
313define i64 @mull6_sub_orr(i64 %x) {
314; CHECK-LABEL: mull6_sub_orr:
315; CHECK:       // %bb.0:
316; CHECK-NEXT:    mov w8, #6 // =0x6
317; CHECK-NEXT:    mov x9, #16773120 // =0xfff000
318; CHECK-NEXT:    madd x0, x0, x8, x9
319; CHECK-NEXT:    ret
320;
321; GISEL-LABEL: mull6_sub_orr:
322; GISEL:       // %bb.0:
323; GISEL-NEXT:    mov w8, #6 // =0x6
324; GISEL-NEXT:    mov x9, #16773120 // =0xfff000
325; GISEL-NEXT:    madd x0, x0, x8, x9
326; GISEL-NEXT:    ret
327  %mul = mul nsw i64 %x, 6
328  %sub = add nsw i64 %mul, 16773120
329  ret i64 %sub
330}
331
332define i32 @test7(i32 %x) {
333; CHECK-LABEL: test7:
334; CHECK:       // %bb.0:
335; CHECK-NEXT:    lsl w8, w0, #3
336; CHECK-NEXT:    sub w0, w8, w0
337; CHECK-NEXT:    ret
338;
339; GISEL-LABEL: test7:
340; GISEL:       // %bb.0:
341; GISEL-NEXT:    lsl w8, w0, #3
342; GISEL-NEXT:    sub w0, w8, w0
343; GISEL-NEXT:    ret
344
345  %mul = mul nsw i32 %x, 7
346  ret i32 %mul
347}
348
349define i32 @test8(i32 %x) {
350; CHECK-LABEL: test8:
351; CHECK:       // %bb.0:
352; CHECK-NEXT:    lsl w0, w0, #3
353; CHECK-NEXT:    ret
354;
355; GISEL-LABEL: test8:
356; GISEL:       // %bb.0:
357; GISEL-NEXT:    lsl w0, w0, #3
358; GISEL-NEXT:    ret
359
360  %mul = shl nsw i32 %x, 3
361  ret i32 %mul
362}
363
364define i32 @test9(i32 %x) {
365; CHECK-LABEL: test9:
366; CHECK:       // %bb.0:
367; CHECK-NEXT:    add w0, w0, w0, lsl #3
368; CHECK-NEXT:    ret
369;
370; GISEL-LABEL: test9:
371; GISEL:       // %bb.0:
372; GISEL-NEXT:    add w0, w0, w0, lsl #3
373; GISEL-NEXT:    ret
374
375  %mul = mul nsw i32 %x, 9
376  ret i32 %mul
377}
378
379define i32 @test10(i32 %x) {
380; CHECK-LABEL: test10:
381; CHECK:       // %bb.0:
382; CHECK-NEXT:    add w8, w0, w0, lsl #2
383; CHECK-NEXT:    lsl w0, w8, #1
384; CHECK-NEXT:    ret
385;
386; GISEL-LABEL: test10:
387; GISEL:       // %bb.0:
388; GISEL-NEXT:    add w8, w0, w0, lsl #2
389; GISEL-NEXT:    lsl w0, w8, #1
390; GISEL-NEXT:    ret
391
392  %mul = mul nsw i32 %x, 10
393  ret i32 %mul
394}
395
396define i32 @test11(i32 %x) {
397; CHECK-LABEL: test11:
398; CHECK:       // %bb.0:
399; CHECK-NEXT:    mov w8, #11 // =0xb
400; CHECK-NEXT:    mul w0, w0, w8
401; CHECK-NEXT:    ret
402;
403; GISEL-LABEL: test11:
404; GISEL:       // %bb.0:
405; GISEL-NEXT:    mov w8, #11 // =0xb
406; GISEL-NEXT:    mul w0, w0, w8
407; GISEL-NEXT:    ret
408
409  %mul = mul nsw i32 %x, 11
410  ret i32 %mul
411}
412
413define i32 @test11_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
414; CHECK-LABEL: test11_fast_shift:
415; CHECK:       // %bb.0:
416; CHECK-NEXT:    add w8, w0, w0, lsl #2
417; CHECK-NEXT:    add w0, w0, w8, lsl #1
418; CHECK-NEXT:    ret
419;
420; GISEL-LABEL: test11_fast_shift:
421; GISEL:       // %bb.0:
422; GISEL-NEXT:    mov w8, #11 // =0xb
423; GISEL-NEXT:    mul w0, w0, w8
424; GISEL-NEXT:    ret
425
426  %mul = mul nsw i32 %x, 11 ; 11 = (((1<<2) + 1) << 1) + 1
427  ret i32 %mul
428}
429
430define i32 @test12(i32 %x) {
431; CHECK-LABEL: test12:
432; CHECK:       // %bb.0:
433; CHECK-NEXT:    add w8, w0, w0, lsl #1
434; CHECK-NEXT:    lsl w0, w8, #2
435; CHECK-NEXT:    ret
436;
437; GISEL-LABEL: test12:
438; GISEL:       // %bb.0:
439; GISEL-NEXT:    add w8, w0, w0, lsl #1
440; GISEL-NEXT:    lsl w0, w8, #2
441; GISEL-NEXT:    ret
442
443  %mul = mul nsw i32 %x, 12
444  ret i32 %mul
445}
446
447define i32 @test13(i32 %x) {
448; CHECK-LABEL: test13:
449; CHECK:       // %bb.0:
450; CHECK-NEXT:    mov w8, #13 // =0xd
451; CHECK-NEXT:    mul w0, w0, w8
452; CHECK-NEXT:    ret
453;
454; GISEL-LABEL: test13:
455; GISEL:       // %bb.0:
456; GISEL-NEXT:    mov w8, #13 // =0xd
457; GISEL-NEXT:    mul w0, w0, w8
458; GISEL-NEXT:    ret
459
460  %mul = mul nsw i32 %x, 13
461  ret i32 %mul
462}
463
464define i32 @test14(i32 %x) {
465; CHECK-LABEL: test14:
466; CHECK:       // %bb.0:
467; CHECK-NEXT:    lsl w8, w0, #4
468; CHECK-NEXT:    sub w0, w8, w0, lsl #1
469; CHECK-NEXT:    ret
470;
471; GISEL-LABEL: test14:
472; GISEL:       // %bb.0:
473; GISEL-NEXT:    mov w8, #14 // =0xe
474; GISEL-NEXT:    mul w0, w0, w8
475; GISEL-NEXT:    ret
476
477  %mul = mul nsw i32 %x, 14
478  ret i32 %mul
479}
480
481define i32 @test15(i32 %x) {
482; CHECK-LABEL: test15:
483; CHECK:       // %bb.0:
484; CHECK-NEXT:    lsl w8, w0, #4
485; CHECK-NEXT:    sub w0, w8, w0
486; CHECK-NEXT:    ret
487;
488; GISEL-LABEL: test15:
489; GISEL:       // %bb.0:
490; GISEL-NEXT:    lsl w8, w0, #4
491; GISEL-NEXT:    sub w0, w8, w0
492; GISEL-NEXT:    ret
493
494  %mul = mul nsw i32 %x, 15
495  ret i32 %mul
496}
497
498define i32 @test16(i32 %x) {
499; CHECK-LABEL: test16:
500; CHECK:       // %bb.0:
501; CHECK-NEXT:    lsl w0, w0, #4
502; CHECK-NEXT:    ret
503;
504; GISEL-LABEL: test16:
505; GISEL:       // %bb.0:
506; GISEL-NEXT:    lsl w0, w0, #4
507; GISEL-NEXT:    ret
508
509  %mul = mul nsw i32 %x, 16
510  ret i32 %mul
511}
512
513define i32 @test25_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
514; CHECK-LABEL: test25_fast_shift:
515; CHECK:       // %bb.0:
516; CHECK-NEXT:    add w8, w0, w0, lsl #2
517; CHECK-NEXT:    add w0, w8, w8, lsl #2
518; CHECK-NEXT:    ret
519;
520; GISEL-LABEL: test25_fast_shift:
521; GISEL:       // %bb.0:
522; GISEL-NEXT:    mov w8, #25 // =0x19
523; GISEL-NEXT:    mul w0, w0, w8
524; GISEL-NEXT:    ret
525
526  %mul = mul nsw i32 %x, 25 ; 25 = (1+4)*(1+4)
527  ret i32 %mul
528}
529
530define i32 @test29_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
531; CHECK-LABEL: test29_fast_shift:
532; CHECK:       // %bb.0:
533; CHECK-NEXT:    sub w8, w0, w0, lsl #3
534; CHECK-NEXT:    sub w0, w0, w8, lsl #2
535; CHECK-NEXT:    ret
536;
537; GISEL-LABEL: test29_fast_shift:
538; GISEL:       // %bb.0:
539; GISEL-NEXT:    mov w8, #29 // =0x1d
540; GISEL-NEXT:    mul w0, w0, w8
541; GISEL-NEXT:    ret
542
543  %mul = mul nsw i32 %x, 29 ; 29 = 1 - (1-8) * 4
544  ret i32 %mul
545}
546
547define i32 @test45_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
548; CHECK-LABEL: test45_fast_shift:
549; CHECK:       // %bb.0:
550; CHECK-NEXT:    add w8, w0, w0, lsl #2
551; CHECK-NEXT:    add w0, w8, w8, lsl #3
552; CHECK-NEXT:    ret
553;
554; GISEL-LABEL: test45_fast_shift:
555; GISEL:       // %bb.0:
556; GISEL-NEXT:    mov w8, #45 // =0x2d
557; GISEL-NEXT:    mul w0, w0, w8
558; GISEL-NEXT:    ret
559
560  %mul = mul nsw i32 %x, 45 ; 45 = (1+4)*(1+8)
561  ret i32 %mul
562}
563
564; Negative test: Keep MUL as don't have the feature LSLFast
565define i32 @test45(i32 %x) {
566; CHECK-LABEL: test45:
567; CHECK:       // %bb.0:
568; CHECK-NEXT:    mov w8, #45 // =0x2d
569; CHECK-NEXT:    mul w0, w0, w8
570; CHECK-NEXT:    ret
571;
572; GISEL-LABEL: test45:
573; GISEL:       // %bb.0:
574; GISEL-NEXT:    mov w8, #45 // =0x2d
575; GISEL-NEXT:    mul w0, w0, w8
576; GISEL-NEXT:    ret
577
578  %mul = mul nsw i32 %x, 45 ; 45 = (1+4)*(1+8)
579  ret i32 %mul
580}
581
582; Negative test: The shift number 5 is out of bound
583define i32 @test67_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
584; CHECK-LABEL: test67_fast_shift:
585; CHECK:       // %bb.0:
586; CHECK-NEXT:    mov w8, #67 // =0x43
587; CHECK-NEXT:    mul w0, w0, w8
588; CHECK-NEXT:    ret
589;
590; GISEL-LABEL: test67_fast_shift:
591; GISEL:       // %bb.0:
592; GISEL-NEXT:    mov w8, #67 // =0x43
593; GISEL-NEXT:    mul w0, w0, w8
594; GISEL-NEXT:    ret
595
596  %mul = mul nsw i32 %x, 67 ; 67 = (((1<<5) + 1) << 1) + 1
597  ret i32 %mul
598}
599
600define i32 @test85_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
601; CHECK-LABEL: test85_fast_shift:
602; CHECK:       // %bb.0:
603; CHECK-NEXT:    add w8, w0, w0, lsl #2
604; CHECK-NEXT:    add w0, w8, w8, lsl #4
605; CHECK-NEXT:    ret
606;
607; GISEL-LABEL: test85_fast_shift:
608; GISEL:       // %bb.0:
609; GISEL-NEXT:    mov w8, #85 // =0x55
610; GISEL-NEXT:    mul w0, w0, w8
611; GISEL-NEXT:    ret
612
613  %mul = mul nsw i32 %x, 85 ; 85 = (1+4)*(1+16)
614  ret i32 %mul
615}
616
617; Negative test: The shift number 5 is out of bound
618define i32 @test97_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
619; CHECK-LABEL: test97_fast_shift:
620; CHECK:       // %bb.0:
621; CHECK-NEXT:    mov w8, #97 // =0x61
622; CHECK-NEXT:    mul w0, w0, w8
623; CHECK-NEXT:    ret
624;
625; GISEL-LABEL: test97_fast_shift:
626; GISEL:       // %bb.0:
627; GISEL-NEXT:    mov w8, #97 // =0x61
628; GISEL-NEXT:    mul w0, w0, w8
629; GISEL-NEXT:    ret
630
631  %mul = mul nsw i32 %x, 97 ; 97 = ((2 + 1) << 5) + 1
632  ret i32 %mul
633}
634
635; Negative test: The shift number 5 is out of bound
636define i32 @test125_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
637; CHECK-LABEL: test125_fast_shift:
638; CHECK:       // %bb.0:
639; CHECK-NEXT:    mov w8, #125 // =0x7d
640; CHECK-NEXT:    mul w0, w0, w8
641; CHECK-NEXT:    ret
642;
643; GISEL-LABEL: test125_fast_shift:
644; GISEL:       // %bb.0:
645; GISEL-NEXT:    mov w8, #125 // =0x7d
646; GISEL-NEXT:    mul w0, w0, w8
647; GISEL-NEXT:    ret
648
649  %mul = mul nsw i32 %x, 125 ; 125 = 1 - ((1-32) << 2)
650  ret i32 %mul
651}
652
653; TODO: (1 - 2^M) * (1 - 2^N)
654define i32 @test225_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
655; CHECK-LABEL: test225_fast_shift:
656; CHECK:       // %bb.0:
657; CHECK-NEXT:    mov w8, #225 // =0xe1
658; CHECK-NEXT:    mul w0, w0, w8
659; CHECK-NEXT:    ret
660;
661; GISEL-LABEL: test225_fast_shift:
662; GISEL:       // %bb.0:
663; GISEL-NEXT:    mov w8, #225 // =0xe1
664; GISEL-NEXT:    mul w0, w0, w8
665; GISEL-NEXT:    ret
666
667  %mul = mul nsw i32 %x, 225 ; 225 = (1-16)*(1-16)
668  ret i32 %mul
669}
670
671; Negative test: The shift amount 5 larger than 4
672define i32 @test297_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
673; CHECK-LABEL: test297_fast_shift:
674; CHECK:       // %bb.0:
675; CHECK-NEXT:    mov w8, #297 // =0x129
676; CHECK-NEXT:    mul w0, w0, w8
677; CHECK-NEXT:    ret
678;
679; GISEL-LABEL: test297_fast_shift:
680; GISEL:       // %bb.0:
681; GISEL-NEXT:    mov w8, #297 // =0x129
682; GISEL-NEXT:    mul w0, w0, w8
683; GISEL-NEXT:    ret
684
685  %mul = mul nsw i32 %x, 297 ; 297 = (1+8)*(1+32)
686  ret i32 %mul
687}
688
689; Negative test: The shift number 5 is out of bound
690define i32 @test481_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" {
691; CHECK-LABEL: test481_fast_shift:
692; CHECK:       // %bb.0:
693; CHECK-NEXT:    mov w8, #481 // =0x1e1
694; CHECK-NEXT:    mul w0, w0, w8
695; CHECK-NEXT:    ret
696;
697; GISEL-LABEL: test481_fast_shift:
698; GISEL:       // %bb.0:
699; GISEL-NEXT:    mov w8, #481 // =0x1e1
700; GISEL-NEXT:    mul w0, w0, w8
701; GISEL-NEXT:    ret
702
703  %mul = mul nsw i32 %x, 481 ; 481 = 1 - ((1-16) << 5)
704  ret i32 %mul
705}
706
707; Convert mul x, -pow2 to shift.
708; Convert mul x, -(pow2 +/- 1) to shift + add/sub.
709; Lowering other negative constants are not supported yet.
710
711define i32 @ntest2(i32 %x) {
712; CHECK-LABEL: ntest2:
713; CHECK:       // %bb.0:
714; CHECK-NEXT:    neg w0, w0, lsl #1
715; CHECK-NEXT:    ret
716;
717; GISEL-LABEL: ntest2:
718; GISEL:       // %bb.0:
719; GISEL-NEXT:    mov w8, #-2 // =0xfffffffe
720; GISEL-NEXT:    mul w0, w0, w8
721; GISEL-NEXT:    ret
722
723  %mul = mul nsw i32 %x, -2
724  ret i32 %mul
725}
726
727define i32 @ntest3(i32 %x) {
728; CHECK-LABEL: ntest3:
729; CHECK:       // %bb.0:
730; CHECK-NEXT:    sub w0, w0, w0, lsl #2
731; CHECK-NEXT:    ret
732;
733; GISEL-LABEL: ntest3:
734; GISEL:       // %bb.0:
735; GISEL-NEXT:    sub w0, w0, w0, lsl #2
736; GISEL-NEXT:    ret
737
738  %mul = mul nsw i32 %x, -3
739  ret i32 %mul
740}
741
742define i32 @ntest4(i32 %x) {
743; CHECK-LABEL: ntest4:
744; CHECK:       // %bb.0:
745; CHECK-NEXT:    neg w0, w0, lsl #2
746; CHECK-NEXT:    ret
747;
748; GISEL-LABEL: ntest4:
749; GISEL:       // %bb.0:
750; GISEL-NEXT:    mov w8, #-4 // =0xfffffffc
751; GISEL-NEXT:    mul w0, w0, w8
752; GISEL-NEXT:    ret
753
754  %mul = mul nsw i32 %x, -4
755  ret i32 %mul
756}
757
758define i32 @ntest5(i32 %x) {
759; CHECK-LABEL: ntest5:
760; CHECK:       // %bb.0:
761; CHECK-NEXT:    add w8, w0, w0, lsl #2
762; CHECK-NEXT:    neg w0, w8
763; CHECK-NEXT:    ret
764;
765; GISEL-LABEL: ntest5:
766; GISEL:       // %bb.0:
767; GISEL-NEXT:    add w8, w0, w0, lsl #2
768; GISEL-NEXT:    neg w0, w8
769; GISEL-NEXT:    ret
770  %mul = mul nsw i32 %x, -5
771  ret i32 %mul
772}
773
774define i32 @ntest6(i32 %x) {
775; CHECK-LABEL: ntest6:
776; CHECK:       // %bb.0:
777; CHECK-NEXT:    lsl w8, w0, #1
778; CHECK-NEXT:    sub w0, w8, w0, lsl #3
779; CHECK-NEXT:    ret
780;
781; GISEL-LABEL: ntest6:
782; GISEL:       // %bb.0:
783; GISEL-NEXT:    mov w8, #-6 // =0xfffffffa
784; GISEL-NEXT:    mul w0, w0, w8
785; GISEL-NEXT:    ret
786
787  %mul = mul nsw i32 %x, -6
788  ret i32 %mul
789}
790
791define i32 @ntest7(i32 %x) {
792; CHECK-LABEL: ntest7:
793; CHECK:       // %bb.0:
794; CHECK-NEXT:    sub w0, w0, w0, lsl #3
795; CHECK-NEXT:    ret
796;
797; GISEL-LABEL: ntest7:
798; GISEL:       // %bb.0:
799; GISEL-NEXT:    sub w0, w0, w0, lsl #3
800; GISEL-NEXT:    ret
801
802  %mul = mul nsw i32 %x, -7
803  ret i32 %mul
804}
805
806define i32 @ntest8(i32 %x) {
807; CHECK-LABEL: ntest8:
808; CHECK:       // %bb.0:
809; CHECK-NEXT:    neg w0, w0, lsl #3
810; CHECK-NEXT:    ret
811;
812; GISEL-LABEL: ntest8:
813; GISEL:       // %bb.0:
814; GISEL-NEXT:    mov w8, #-8 // =0xfffffff8
815; GISEL-NEXT:    mul w0, w0, w8
816; GISEL-NEXT:    ret
817
818  %mul = mul nsw i32 %x, -8
819  ret i32 %mul
820}
821
822define i32 @ntest9(i32 %x) {
823; CHECK-LABEL: ntest9:
824; CHECK:       // %bb.0:
825; CHECK-NEXT:    add w8, w0, w0, lsl #3
826; CHECK-NEXT:    neg w0, w8
827; CHECK-NEXT:    ret
828;
829; GISEL-LABEL: ntest9:
830; GISEL:       // %bb.0:
831; GISEL-NEXT:    add w8, w0, w0, lsl #3
832; GISEL-NEXT:    neg w0, w8
833; GISEL-NEXT:    ret
834
835  %mul = mul nsw i32 %x, -9
836  ret i32 %mul
837}
838
839define i32 @ntest10(i32 %x) {
840; CHECK-LABEL: ntest10:
841; CHECK:       // %bb.0:
842; CHECK-NEXT:    mov w8, #-10 // =0xfffffff6
843; CHECK-NEXT:    mul w0, w0, w8
844; CHECK-NEXT:    ret
845;
846; GISEL-LABEL: ntest10:
847; GISEL:       // %bb.0:
848; GISEL-NEXT:    mov w8, #-10 // =0xfffffff6
849; GISEL-NEXT:    mul w0, w0, w8
850; GISEL-NEXT:    ret
851
852  %mul = mul nsw i32 %x, -10
853  ret i32 %mul
854}
855
856define i32 @ntest11(i32 %x) {
857; CHECK-LABEL: ntest11:
858; CHECK:       // %bb.0:
859; CHECK-NEXT:    mov w8, #-11 // =0xfffffff5
860; CHECK-NEXT:    mul w0, w0, w8
861; CHECK-NEXT:    ret
862;
863; GISEL-LABEL: ntest11:
864; GISEL:       // %bb.0:
865; GISEL-NEXT:    mov w8, #-11 // =0xfffffff5
866; GISEL-NEXT:    mul w0, w0, w8
867; GISEL-NEXT:    ret
868
869  %mul = mul nsw i32 %x, -11
870  ret i32 %mul
871}
872
873define i32 @ntest12(i32 %x) {
874; CHECK-LABEL: ntest12:
875; CHECK:       // %bb.0:
876; CHECK-NEXT:    lsl w8, w0, #2
877; CHECK-NEXT:    sub w0, w8, w0, lsl #4
878; CHECK-NEXT:    ret
879;
880; GISEL-LABEL: ntest12:
881; GISEL:       // %bb.0:
882; GISEL-NEXT:    mov w8, #-12 // =0xfffffff4
883; GISEL-NEXT:    mul w0, w0, w8
884; GISEL-NEXT:    ret
885
886  %mul = mul nsw i32 %x, -12
887  ret i32 %mul
888}
889
890define i32 @ntest13(i32 %x) {
891; CHECK-LABEL: ntest13:
892; CHECK:       // %bb.0:
893; CHECK-NEXT:    mov w8, #-13 // =0xfffffff3
894; CHECK-NEXT:    mul w0, w0, w8
895; CHECK-NEXT:    ret
896;
897; GISEL-LABEL: ntest13:
898; GISEL:       // %bb.0:
899; GISEL-NEXT:    mov w8, #-13 // =0xfffffff3
900; GISEL-NEXT:    mul w0, w0, w8
901; GISEL-NEXT:    ret
902  %mul = mul nsw i32 %x, -13
903  ret i32 %mul
904}
905
906define i32 @ntest14(i32 %x) {
907; CHECK-LABEL: ntest14:
908; CHECK:       // %bb.0:
909; CHECK-NEXT:    lsl w8, w0, #1
910; CHECK-NEXT:    sub w0, w8, w0, lsl #4
911; CHECK-NEXT:    ret
912;
913; GISEL-LABEL: ntest14:
914; GISEL:       // %bb.0:
915; GISEL-NEXT:    mov w8, #-14 // =0xfffffff2
916; GISEL-NEXT:    mul w0, w0, w8
917; GISEL-NEXT:    ret
918
919  %mul = mul nsw i32 %x, -14
920  ret i32 %mul
921}
922
923define i32 @ntest15(i32 %x) {
924; CHECK-LABEL: ntest15:
925; CHECK:       // %bb.0:
926; CHECK-NEXT:    sub w0, w0, w0, lsl #4
927; CHECK-NEXT:    ret
928;
929; GISEL-LABEL: ntest15:
930; GISEL:       // %bb.0:
931; GISEL-NEXT:    sub w0, w0, w0, lsl #4
932; GISEL-NEXT:    ret
933
934  %mul = mul nsw i32 %x, -15
935  ret i32 %mul
936}
937
938define i32 @ntest16(i32 %x) {
939; CHECK-LABEL: ntest16:
940; CHECK:       // %bb.0:
941; CHECK-NEXT:    neg w0, w0, lsl #4
942; CHECK-NEXT:    ret
943;
944; GISEL-LABEL: ntest16:
945; GISEL:       // %bb.0:
946; GISEL-NEXT:    mov w8, #-16 // =0xfffffff0
947; GISEL-NEXT:    mul w0, w0, w8
948; GISEL-NEXT:    ret
949
950  %mul = mul nsw i32 %x, -16
951  ret i32 %mul
952}
953
954define i32 @muladd_demand(i32 %x, i32 %y) {
955; CHECK-LABEL: muladd_demand:
956; CHECK:       // %bb.0:
957; CHECK-NEXT:    sub w8, w1, w0, lsl #6
958; CHECK-NEXT:    and w0, w8, #0x1ffc0
959; CHECK-NEXT:    ret
960;
961; GISEL-LABEL: muladd_demand:
962; GISEL:       // %bb.0:
963; GISEL-NEXT:    mov w8, #131008 // =0x1ffc0
964; GISEL-NEXT:    madd w8, w0, w8, w1
965; GISEL-NEXT:    and w0, w8, #0x1ffc0
966; GISEL-NEXT:    ret
967  %m = mul i32 %x, 131008 ; 0x0001ffc0
968  %a = add i32 %y, %m
969  %r = and i32 %a, 131008
970  ret i32 %r
971}
972
973define <4 x i32> @muladd_demand_commute(<4 x i32> %x, <4 x i32> %y) {
974; CHECK-LABEL: muladd_demand_commute:
975; CHECK:       // %bb.0:
976; CHECK-NEXT:    shl v0.4s, v0.4s, #6
977; CHECK-NEXT:    movi v2.4s, #1, msl #16
978; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
979; CHECK-NEXT:    and v0.16b, v0.16b, v2.16b
980; CHECK-NEXT:    ret
981;
982; GISEL-LABEL: muladd_demand_commute:
983; GISEL:       // %bb.0:
984; GISEL-NEXT:    adrp x8, .LCPI56_0
985; GISEL-NEXT:    movi v3.4s, #1, msl #16
986; GISEL-NEXT:    ldr q2, [x8, :lo12:.LCPI56_0]
987; GISEL-NEXT:    mla v1.4s, v0.4s, v2.4s
988; GISEL-NEXT:    and v0.16b, v1.16b, v3.16b
989; GISEL-NEXT:    ret
990  %m = mul <4 x i32> %x, <i32 131008, i32 131008, i32 131008, i32 131008>
991  %a = add <4 x i32> %m, %y
992  %r = and <4 x i32> %a, <i32 131071, i32 131071, i32 131071, i32 131071>
993  ret <4 x i32> %r
994}
995
996; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))`
997; will cause overflow when N is 32 and M is 31.
998define i32 @shift_overflow(i32 %x) {
999; CHECK-LABEL: shift_overflow:
1000; CHECK:       // %bb.0:
1001; CHECK-NEXT:    mov w8, #-2147483648 // =0x80000000
1002; CHECK-NEXT:    mul w0, w0, w8
1003; CHECK-NEXT:    ret
1004;
1005; GISEL-LABEL: shift_overflow:
1006; GISEL:       // %bb.0:
1007; GISEL-NEXT:    mov w8, #-2147483648 // =0x80000000
1008; GISEL-NEXT:    mul w0, w0, w8
1009; GISEL-NEXT:    ret
1010  %const = bitcast i32 2147483648 to i32
1011  %r = mul i32 %x, %const
1012  ret i32 %r
1013}
1014
1015; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))`
1016; will not cause overflow when N is 31 and M is 30.
1017define i32 @shift_no_overflow(i32 %x) {
1018; CHECK-LABEL: shift_no_overflow:
1019; CHECK:       // %bb.0:
1020; CHECK-NEXT:    lsl w8, w0, #31
1021; CHECK-NEXT:    sub w0, w8, w0, lsl #30
1022; CHECK-NEXT:    ret
1023;
1024; GISEL-LABEL: shift_no_overflow:
1025; GISEL:       // %bb.0:
1026; GISEL-NEXT:    mov w8, #1073741824 // =0x40000000
1027; GISEL-NEXT:    mul w0, w0, w8
1028; GISEL-NEXT:    ret
1029  %const = bitcast i32 1073741824 to i32
1030  %r = mul i32 %x, %const
1031  ret i32 %r
1032}
1033