xref: /llvm-project/llvm/test/CodeGen/AVR/shift32.ll (revision 2a528760bf20004066effcf8f91fedaabd261903)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=avr -mattr=movw -verify-machineinstrs | FileCheck %s
3
4define i32 @shl_i32_1(i32 %a) {
5; CHECK-LABEL: shl_i32_1:
6; CHECK:       ; %bb.0:
7; CHECK-NEXT:    lsl r22
8; CHECK-NEXT:    rol r23
9; CHECK-NEXT:    rol r24
10; CHECK-NEXT:    rol r25
11; CHECK-NEXT:    ret
12  %res = shl i32 %a, 1
13  ret i32 %res
14}
15
16define i32 @shl_i32_2(i32 %a) {
17; CHECK-LABEL: shl_i32_2:
18; CHECK:       ; %bb.0:
19; CHECK-NEXT:    lsl r22
20; CHECK-NEXT:    rol r23
21; CHECK-NEXT:    rol r24
22; CHECK-NEXT:    rol r25
23; CHECK-NEXT:    lsl r22
24; CHECK-NEXT:    rol r23
25; CHECK-NEXT:    rol r24
26; CHECK-NEXT:    rol r25
27; CHECK-NEXT:    ret
28  %res = shl i32 %a, 2
29  ret i32 %res
30}
31
32define i32 @shl_i32_4(i32 %a) {
33; CHECK-LABEL: shl_i32_4:
34; CHECK:       ; %bb.0:
35; CHECK-NEXT:    swap r25
36; CHECK-NEXT:    andi r25, 240
37; CHECK-NEXT:    swap r24
38; CHECK-NEXT:    eor r25, r24
39; CHECK-NEXT:    andi r24, 240
40; CHECK-NEXT:    eor r25, r24
41; CHECK-NEXT:    swap r23
42; CHECK-NEXT:    eor r24, r23
43; CHECK-NEXT:    andi r23, 240
44; CHECK-NEXT:    eor r24, r23
45; CHECK-NEXT:    swap r22
46; CHECK-NEXT:    eor r23, r22
47; CHECK-NEXT:    andi r22, 240
48; CHECK-NEXT:    eor r23, r22
49; CHECK-NEXT:    ret
50  %res = shl i32 %a, 4
51  ret i32 %res
52}
53
54; shift four bits and then shift one bit
55define i32 @shl_i32_5(i32 %a) {
56; CHECK-LABEL: shl_i32_5:
57; CHECK:       ; %bb.0:
58; CHECK-NEXT:    swap r25
59; CHECK-NEXT:    andi r25, 240
60; CHECK-NEXT:    swap r24
61; CHECK-NEXT:    eor r25, r24
62; CHECK-NEXT:    andi r24, 240
63; CHECK-NEXT:    eor r25, r24
64; CHECK-NEXT:    swap r23
65; CHECK-NEXT:    eor r24, r23
66; CHECK-NEXT:    andi r23, 240
67; CHECK-NEXT:    eor r24, r23
68; CHECK-NEXT:    swap r22
69; CHECK-NEXT:    eor r23, r22
70; CHECK-NEXT:    andi r22, 240
71; CHECK-NEXT:    eor r23, r22
72; CHECK-NEXT:    lsl r22
73; CHECK-NEXT:    rol r23
74; CHECK-NEXT:    rol r24
75; CHECK-NEXT:    rol r25
76; CHECK-NEXT:    ret
77  %res = shl i32 %a, 5
78  ret i32 %res
79}
80
81; shift two to the right and move the registers around
82define i32 @shl_i32_6(i32 %a) {
83; CHECK-LABEL: shl_i32_6:
84; CHECK:       ; %bb.0:
85; CHECK-NEXT:    lsr r25
86; CHECK-NEXT:    ror r24
87; CHECK-NEXT:    ror r23
88; CHECK-NEXT:    ror r22
89; CHECK-NEXT:    mov r18, r1
90; CHECK-NEXT:    ror r18
91; CHECK-NEXT:    lsr r25
92; CHECK-NEXT:    ror r24
93; CHECK-NEXT:    ror r23
94; CHECK-NEXT:    ror r22
95; CHECK-NEXT:    ror r18
96; CHECK-NEXT:    mov r25, r24
97; CHECK-NEXT:    mov r24, r23
98; CHECK-NEXT:    mov r19, r22
99; CHECK-NEXT:    movw r22, r18
100; CHECK-NEXT:    ret
101  %res = shl i32 %a, 6
102  ret i32 %res
103}
104
105
106; shift one to the right and move registers around
107define i32 @shl_i32_7(i32 %a) {
108; CHECK-LABEL: shl_i32_7:
109; CHECK:       ; %bb.0:
110; CHECK-NEXT:    lsr r25
111; CHECK-NEXT:    ror r24
112; CHECK-NEXT:    ror r23
113; CHECK-NEXT:    ror r22
114; CHECK-NEXT:    mov r18, r1
115; CHECK-NEXT:    ror r18
116; CHECK-NEXT:    mov r25, r24
117; CHECK-NEXT:    mov r24, r23
118; CHECK-NEXT:    mov r19, r22
119; CHECK-NEXT:    movw r22, r18
120; CHECK-NEXT:    ret
121  %res = shl i32 %a, 7
122  ret i32 %res
123}
124
125define i32 @shl_i32_8(i32 %a) {
126; CHECK-LABEL: shl_i32_8:
127; CHECK:       ; %bb.0:
128; CHECK-NEXT:    mov r25, r24
129; CHECK-NEXT:    mov r24, r23
130; CHECK-NEXT:    mov r23, r22
131; CHECK-NEXT:    mov r22, r1
132; CHECK-NEXT:    ret
133  %res = shl i32 %a, 8
134  ret i32 %res
135}
136
137define i32 @shl_i32_9(i32 %a) {
138; CHECK-LABEL: shl_i32_9:
139; CHECK:       ; %bb.0:
140; CHECK-NEXT:    lsl r22
141; CHECK-NEXT:    rol r23
142; CHECK-NEXT:    rol r24
143; CHECK-NEXT:    mov r25, r24
144; CHECK-NEXT:    mov r24, r23
145; CHECK-NEXT:    mov r23, r22
146; CHECK-NEXT:    mov r22, r1
147; CHECK-NEXT:    ret
148  %res = shl i32 %a, 9
149  ret i32 %res
150}
151
152; shift 3 of 4 registers and move the others around
153define i32 @shl_i32_12(i32 %a) {
154; CHECK-LABEL: shl_i32_12:
155; CHECK:       ; %bb.0:
156; CHECK-NEXT:    swap r24
157; CHECK-NEXT:    andi r24, 240
158; CHECK-NEXT:    swap r23
159; CHECK-NEXT:    eor r24, r23
160; CHECK-NEXT:    andi r23, 240
161; CHECK-NEXT:    eor r24, r23
162; CHECK-NEXT:    swap r22
163; CHECK-NEXT:    eor r23, r22
164; CHECK-NEXT:    andi r22, 240
165; CHECK-NEXT:    eor r23, r22
166; CHECK-NEXT:    mov r25, r24
167; CHECK-NEXT:    mov r24, r23
168; CHECK-NEXT:    mov r23, r22
169; CHECK-NEXT:    mov r22, r1
170; CHECK-NEXT:    ret
171  %res = shl i32 %a, 12
172  ret i32 %res
173}
174
175define i32 @shl_i32_15(i32 %a) {
176; CHECK-LABEL: shl_i32_15:
177; CHECK:       ; %bb.0:
178; CHECK-NEXT:    movw r18, r22
179; CHECK-NEXT:    lsr r24
180; CHECK-NEXT:    ror r19
181; CHECK-NEXT:    ror r18
182; CHECK-NEXT:    mov r23, r1
183; CHECK-NEXT:    ror r23
184; CHECK-NEXT:    mov r22, r1
185; CHECK-NEXT:    movw r24, r18
186; CHECK-NEXT:    ret
187  %res = shl i32 %a, 15
188  ret i32 %res
189}
190
191; This is a special case: this shift is performed directly inside SelectionDAG
192; instead of as a custom lowering like the other shift operations.
193define i32 @shl_i32_16(i32 %a) {
194; CHECK-LABEL: shl_i32_16:
195; CHECK:       ; %bb.0:
196; CHECK-NEXT:    movw r24, r22
197; CHECK-NEXT:    ldi r22, 0
198; CHECK-NEXT:    ldi r23, 0
199; CHECK-NEXT:    ret
200  %res = shl i32 %a, 16
201  ret i32 %res
202}
203
204; Combined with the register allocator, shift instructions can sometimes be
205; optimized away entirely. The least significant registers are simply stored
206; directly instead of moving them first.
207define void @shl_i32_16_ptr(i32 %a, ptr %ptr) {
208; CHECK-LABEL: shl_i32_16_ptr:
209; CHECK:       ; %bb.0:
210; CHECK-NEXT:    movw r30, r20
211; CHECK-NEXT:    std Z+3, r23
212; CHECK-NEXT:    std Z+2, r22
213; CHECK-NEXT:    ldi r24, 0
214; CHECK-NEXT:    ldi r25, 0
215; CHECK-NEXT:    std Z+1, r25
216; CHECK-NEXT:    st Z, r24
217; CHECK-NEXT:    ret
218  %res = shl i32 %a, 16
219  store i32 %res, ptr %ptr
220  ret void
221}
222
223; shift only the most significant byte and then move it
224define i32 @shl_i32_28(i32 %a) {
225; CHECK-LABEL: shl_i32_28:
226; CHECK:       ; %bb.0:
227; CHECK-NEXT:    swap r22
228; CHECK-NEXT:    andi r22, 240
229; CHECK-NEXT:    mov r25, r22
230; CHECK-NEXT:    mov r24, r1
231; CHECK-NEXT:    mov r23, r1
232; CHECK-NEXT:    mov r22, r1
233; CHECK-NEXT:    ret
234  %res = shl i32 %a, 28
235  ret i32 %res
236}
237
238; move the rightmost bit to the leftmost bit and clear the rest
239define i32 @shl_i32_31(i32 %a) {
240; CHECK-LABEL: shl_i32_31:
241; CHECK:       ; %bb.0:
242; CHECK-NEXT:    lsr r22
243; CHECK-NEXT:    mov r25, r1
244; CHECK-NEXT:    ror r25
245; CHECK-NEXT:    mov r24, r1
246; CHECK-NEXT:    mov r23, r1
247; CHECK-NEXT:    mov r22, r1
248; CHECK-NEXT:    ret
249  %res = shl i32 %a, 31
250  ret i32 %res
251}
252
253define i32 @lshr_i32_1(i32 %a) {
254; CHECK-LABEL: lshr_i32_1:
255; CHECK:       ; %bb.0:
256; CHECK-NEXT:    lsr r25
257; CHECK-NEXT:    ror r24
258; CHECK-NEXT:    ror r23
259; CHECK-NEXT:    ror r22
260; CHECK-NEXT:    ret
261  %res = lshr i32 %a, 1
262  ret i32 %res
263}
264
265define i32 @lshr_i32_2(i32 %a) {
266; CHECK-LABEL: lshr_i32_2:
267; CHECK:       ; %bb.0:
268; CHECK-NEXT:    lsr r25
269; CHECK-NEXT:    ror r24
270; CHECK-NEXT:    ror r23
271; CHECK-NEXT:    ror r22
272; CHECK-NEXT:    lsr r25
273; CHECK-NEXT:    ror r24
274; CHECK-NEXT:    ror r23
275; CHECK-NEXT:    ror r22
276; CHECK-NEXT:    ret
277  %res = lshr i32 %a, 2
278  ret i32 %res
279}
280
281define i32 @lshr_i32_4(i32 %a) {
282; CHECK-LABEL: lshr_i32_4:
283; CHECK:       ; %bb.0:
284; CHECK-NEXT:    swap r22
285; CHECK-NEXT:    andi r22, 15
286; CHECK-NEXT:    swap r23
287; CHECK-NEXT:    eor r22, r23
288; CHECK-NEXT:    andi r23, 15
289; CHECK-NEXT:    eor r22, r23
290; CHECK-NEXT:    swap r24
291; CHECK-NEXT:    eor r23, r24
292; CHECK-NEXT:    andi r24, 15
293; CHECK-NEXT:    eor r23, r24
294; CHECK-NEXT:    swap r25
295; CHECK-NEXT:    eor r24, r25
296; CHECK-NEXT:    andi r25, 15
297; CHECK-NEXT:    eor r24, r25
298; CHECK-NEXT:    ret
299  %res = lshr i32 %a, 4
300  ret i32 %res
301}
302
303define i32 @lshr_i32_6(i32 %a) {
304; CHECK-LABEL: lshr_i32_6:
305; CHECK:       ; %bb.0:
306; CHECK-NEXT:    lsl r22
307; CHECK-NEXT:    rol r23
308; CHECK-NEXT:    rol r24
309; CHECK-NEXT:    rol r25
310; CHECK-NEXT:    mov r19, r1
311; CHECK-NEXT:    rol r19
312; CHECK-NEXT:    lsl r22
313; CHECK-NEXT:    rol r23
314; CHECK-NEXT:    rol r24
315; CHECK-NEXT:    rol r25
316; CHECK-NEXT:    rol r19
317; CHECK-NEXT:    mov r22, r23
318; CHECK-NEXT:    mov r23, r24
319; CHECK-NEXT:    mov r18, r25
320; CHECK-NEXT:    movw r24, r18
321; CHECK-NEXT:    ret
322  %res = lshr i32 %a, 6
323  ret i32 %res
324}
325
326define i32 @lshr_i32_7(i32 %a) {
327; CHECK-LABEL: lshr_i32_7:
328; CHECK:       ; %bb.0:
329; CHECK-NEXT:    lsl r22
330; CHECK-NEXT:    rol r23
331; CHECK-NEXT:    rol r24
332; CHECK-NEXT:    rol r25
333; CHECK-NEXT:    mov r19, r1
334; CHECK-NEXT:    rol r19
335; CHECK-NEXT:    mov r22, r23
336; CHECK-NEXT:    mov r23, r24
337; CHECK-NEXT:    mov r18, r25
338; CHECK-NEXT:    movw r24, r18
339; CHECK-NEXT:    ret
340  %res = lshr i32 %a, 7
341  ret i32 %res
342}
343
344define i32 @lshr_i32_8(i32 %a) {
345; CHECK-LABEL: lshr_i32_8:
346; CHECK:       ; %bb.0:
347; CHECK-NEXT:    mov r22, r23
348; CHECK-NEXT:    mov r23, r24
349; CHECK-NEXT:    mov r24, r25
350; CHECK-NEXT:    mov r25, r1
351; CHECK-NEXT:    ret
352  %res = lshr i32 %a, 8
353  ret i32 %res
354}
355
356define i32 @lshr_i32_9(i32 %a) {
357; CHECK-LABEL: lshr_i32_9:
358; CHECK:       ; %bb.0:
359; CHECK-NEXT:    lsr r25
360; CHECK-NEXT:    ror r24
361; CHECK-NEXT:    ror r23
362; CHECK-NEXT:    mov r22, r23
363; CHECK-NEXT:    mov r23, r24
364; CHECK-NEXT:    mov r24, r25
365; CHECK-NEXT:    mov r25, r1
366; CHECK-NEXT:    ret
367  %res = lshr i32 %a, 9
368  ret i32 %res
369}
370
371define i32 @lshr_i32_16(i32 %a) {
372; CHECK-LABEL: lshr_i32_16:
373; CHECK:       ; %bb.0:
374; CHECK-NEXT:    movw r22, r24
375; CHECK-NEXT:    ldi r24, 0
376; CHECK-NEXT:    ldi r25, 0
377; CHECK-NEXT:    ret
378  %res = lshr i32 %a, 16
379  ret i32 %res
380}
381
382define i32 @lshr_i32_24(i32 %a) {
383; CHECK-LABEL: lshr_i32_24:
384; CHECK:       ; %bb.0:
385; CHECK-NEXT:    mov r22, r25
386; CHECK-NEXT:    mov r23, r1
387; CHECK-NEXT:    mov r24, r1
388; CHECK-NEXT:    mov r25, r1
389; CHECK-NEXT:    ret
390  %res = lshr i32 %a, 24
391  ret i32 %res
392}
393
394define i32 @lshr_i32_31(i32 %a) {
395; CHECK-LABEL: lshr_i32_31:
396; CHECK:       ; %bb.0:
397; CHECK-NEXT:    lsl r25
398; CHECK-NEXT:    mov r22, r1
399; CHECK-NEXT:    rol r22
400; CHECK-NEXT:    mov r23, r1
401; CHECK-NEXT:    mov r24, r1
402; CHECK-NEXT:    mov r25, r1
403; CHECK-NEXT:    ret
404  %res = lshr i32 %a, 31
405  ret i32 %res
406}
407
408define i32 @ashr_i32_1(i32 %a) {
409; CHECK-LABEL: ashr_i32_1:
410; CHECK:       ; %bb.0:
411; CHECK-NEXT:    asr r25
412; CHECK-NEXT:    ror r24
413; CHECK-NEXT:    ror r23
414; CHECK-NEXT:    ror r22
415; CHECK-NEXT:    ret
416  %res = ashr i32 %a, 1
417  ret i32 %res
418}
419
420define i32 @ashr_i32_2(i32 %a) {
421; CHECK-LABEL: ashr_i32_2:
422; CHECK:       ; %bb.0:
423; CHECK-NEXT:    asr r25
424; CHECK-NEXT:    ror r24
425; CHECK-NEXT:    ror r23
426; CHECK-NEXT:    ror r22
427; CHECK-NEXT:    asr r25
428; CHECK-NEXT:    ror r24
429; CHECK-NEXT:    ror r23
430; CHECK-NEXT:    ror r22
431; CHECK-NEXT:    ret
432  %res = ashr i32 %a, 2
433  ret i32 %res
434}
435
436; can't use the swap/andi/eor trick here
437define i32 @ashr_i32_4(i32 %a) {
438; CHECK-LABEL: ashr_i32_4:
439; CHECK:       ; %bb.0:
440; CHECK-NEXT:    asr r25
441; CHECK-NEXT:    ror r24
442; CHECK-NEXT:    ror r23
443; CHECK-NEXT:    ror r22
444; CHECK-NEXT:    asr r25
445; CHECK-NEXT:    ror r24
446; CHECK-NEXT:    ror r23
447; CHECK-NEXT:    ror r22
448; CHECK-NEXT:    asr r25
449; CHECK-NEXT:    ror r24
450; CHECK-NEXT:    ror r23
451; CHECK-NEXT:    ror r22
452; CHECK-NEXT:    asr r25
453; CHECK-NEXT:    ror r24
454; CHECK-NEXT:    ror r23
455; CHECK-NEXT:    ror r22
456; CHECK-NEXT:    ret
457  %res = ashr i32 %a, 4
458  ret i32 %res
459}
460
461define i32 @ashr_i32_7(i32 %a) {
462; CHECK-LABEL: ashr_i32_7:
463; CHECK:       ; %bb.0:
464; CHECK-NEXT:    lsl r22
465; CHECK-NEXT:    rol r23
466; CHECK-NEXT:    rol r24
467; CHECK-NEXT:    rol r25
468; CHECK-NEXT:    sbc r19, r19
469; CHECK-NEXT:    mov r22, r23
470; CHECK-NEXT:    mov r23, r24
471; CHECK-NEXT:    mov r18, r25
472; CHECK-NEXT:    movw r24, r18
473; CHECK-NEXT:    ret
474  %res = ashr i32 %a, 7
475  ret i32 %res
476}
477
478; TODO: this could be optimized to 4 movs, instead of 5.
479define i32 @ashr_i32_8(i32 %a) {
480; CHECK-LABEL: ashr_i32_8:
481; CHECK:       ; %bb.0:
482; CHECK-NEXT:    mov r19, r25
483; CHECK-NEXT:    lsl r19
484; CHECK-NEXT:    sbc r19, r19
485; CHECK-NEXT:    mov r22, r23
486; CHECK-NEXT:    mov r23, r24
487; CHECK-NEXT:    mov r18, r25
488; CHECK-NEXT:    movw r24, r18
489; CHECK-NEXT:    ret
490  %res = ashr i32 %a, 8
491  ret i32 %res
492}
493
494define i32 @ashr_i32_16(i32 %a) {
495; CHECK-LABEL: ashr_i32_16:
496; CHECK:       ; %bb.0:
497; CHECK-NEXT:    movw r22, r24
498; CHECK-NEXT:    lsl r25
499; CHECK-NEXT:    sbc r25, r25
500; CHECK-NEXT:    mov r24, r25
501; CHECK-NEXT:    ret
502  %res = ashr i32 %a, 16
503  ret i32 %res
504}
505
506define i32 @ashr_i32_17(i32 %a) {
507; CHECK-LABEL: ashr_i32_17:
508; CHECK:       ; %bb.0:
509; CHECK-NEXT:    movw r22, r24
510; CHECK-NEXT:    lsl r25
511; CHECK-NEXT:    sbc r25, r25
512; CHECK-NEXT:    asr r23
513; CHECK-NEXT:    ror r22
514; CHECK-NEXT:    mov r24, r25
515; CHECK-NEXT:    ret
516  %res = ashr i32 %a, 17
517  ret i32 %res
518}
519
520define i32 @ashr_i32_22(i32 %a) {
521; CHECK-LABEL: ashr_i32_22:
522; CHECK:       ; %bb.0:
523; CHECK-NEXT:    lsl r24
524; CHECK-NEXT:    rol r25
525; CHECK-NEXT:    sbc r18, r18
526; CHECK-NEXT:    lsl r24
527; CHECK-NEXT:    rol r25
528; CHECK-NEXT:    mov r19, r18
529; CHECK-NEXT:    mov r23, r18
530; CHECK-NEXT:    rol r23
531; CHECK-NEXT:    mov r22, r25
532; CHECK-NEXT:    movw r24, r18
533; CHECK-NEXT:    ret
534  %res = ashr i32 %a, 22
535  ret i32 %res
536}
537
538define i32 @ashr_i32_23(i32 %a) {
539; CHECK-LABEL: ashr_i32_23:
540; CHECK:       ; %bb.0:
541; CHECK-NEXT:    lsl r24
542; CHECK-NEXT:    rol r25
543; CHECK-NEXT:    sbc r23, r23
544; CHECK-NEXT:    mov r22, r25
545; CHECK-NEXT:    mov r24, r23
546; CHECK-NEXT:    mov r25, r23
547; CHECK-NEXT:    ret
548  %res = ashr i32 %a, 23
549  ret i32 %res
550}
551
552define i32 @ashr_i32_30(i32 %a) {
553; CHECK-LABEL: ashr_i32_30:
554; CHECK:       ; %bb.0:
555; CHECK-NEXT:    lsl r25
556; CHECK-NEXT:    sbc r23, r23
557; CHECK-NEXT:    lsl r25
558; CHECK-NEXT:    mov r22, r23
559; CHECK-NEXT:    rol r22
560; CHECK-NEXT:    mov r24, r23
561; CHECK-NEXT:    mov r25, r23
562; CHECK-NEXT:    ret
563  %res = ashr i32 %a, 30
564  ret i32 %res
565}
566
567define i32 @ashr_i32_31(i32 %a) {
568; CHECK-LABEL: ashr_i32_31:
569; CHECK:       ; %bb.0:
570; CHECK-NEXT:    lsl r25
571; CHECK-NEXT:    sbc r22, r22
572; CHECK-NEXT:    mov r23, r22
573; CHECK-NEXT:    movw r24, r22
574; CHECK-NEXT:    ret
575  %res = ashr i32 %a, 31
576  ret i32 %res
577}
578