xref: /llvm-project/llvm/test/CodeGen/AArch64/rotate-extract.ll (revision db158c7c830807caeeb0691739c41f1d522029e9)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=aarch64-unknown-unknown | FileCheck %s
3
4; Check that under certain conditions we can factor out a rotate
5; from the following idioms:
6;   (a*c0) >> s1 | (a*c1)
7;   (a/c0) << s1 | (a/c1)
8; This targets cases where instcombine has folded a shl/srl/mul/udiv
9; with one of the shifts from the rotate idiom
10
11define i64 @ror_extract_shl(i64 %i) nounwind {
12; CHECK-LABEL: ror_extract_shl:
13; CHECK:       // %bb.0:
14; CHECK-NEXT:    lsl x8, x0, #3
15; CHECK-NEXT:    ror x0, x8, #57
16; CHECK-NEXT:    ret
17  %lhs_mul = shl i64 %i, 3
18  %rhs_mul = shl i64 %i, 10
19  %lhs_shift = lshr i64 %lhs_mul, 57
20  %out = or i64 %lhs_shift, %rhs_mul
21  ret i64 %out
22}
23
24define i32 @ror_extract_shrl(i32 %i) nounwind {
25; CHECK-LABEL: ror_extract_shrl:
26; CHECK:       // %bb.0:
27; CHECK-NEXT:    lsr w8, w0, #3
28; CHECK-NEXT:    ror w0, w8, #4
29; CHECK-NEXT:    ret
30  %lhs_div = lshr i32 %i, 7
31  %rhs_div = lshr i32 %i, 3
32  %rhs_shift = shl i32 %rhs_div, 28
33  %out = or i32 %lhs_div, %rhs_shift
34  ret i32 %out
35}
36
37define i32 @ror_extract_mul(i32 %i) nounwind {
38; CHECK-LABEL: ror_extract_mul:
39; CHECK:       // %bb.0:
40; CHECK-NEXT:    add w8, w0, w0, lsl #3
41; CHECK-NEXT:    ror w0, w8, #25
42; CHECK-NEXT:    ret
43  %lhs_mul = mul i32 %i, 9
44  %rhs_mul = mul i32 %i, 1152
45  %lhs_shift = lshr i32 %lhs_mul, 25
46  %out = or i32 %lhs_shift, %rhs_mul
47  ret i32 %out
48}
49
50define i64 @ror_extract_udiv(i64 %i) nounwind {
51; CHECK-LABEL: ror_extract_udiv:
52; CHECK:       // %bb.0:
53; CHECK-NEXT:    mov x8, #-6148914691236517206 // =0xaaaaaaaaaaaaaaaa
54; CHECK-NEXT:    movk x8, #43691
55; CHECK-NEXT:    umulh x8, x0, x8
56; CHECK-NEXT:    lsr x8, x8, #1
57; CHECK-NEXT:    ror x0, x8, #4
58; CHECK-NEXT:    ret
59  %lhs_div = udiv i64 %i, 3
60  %rhs_div = udiv i64 %i, 48
61  %lhs_shift = shl i64 %lhs_div, 60
62  %out = or i64 %lhs_shift, %rhs_div
63  ret i64 %out
64}
65
66define i64 @ror_extract_mul_with_mask(i64 %i) nounwind {
67; CHECK-LABEL: ror_extract_mul_with_mask:
68; CHECK:       // %bb.0:
69; CHECK-NEXT:    add x8, x0, x0, lsl #3
70; CHECK-NEXT:    ror x8, x8, #57
71; CHECK-NEXT:    and x0, x8, #0xff
72; CHECK-NEXT:    ret
73  %lhs_mul = mul i64 %i, 1152
74  %rhs_mul = mul i64 %i, 9
75  %lhs_and = and i64 %lhs_mul, 160
76  %rhs_shift = lshr i64 %rhs_mul, 57
77  %out = or i64 %lhs_and, %rhs_shift
78  ret i64 %out
79}
80
81; Result would undershift
82define i64 @no_extract_shl(i64 %i) nounwind {
83; CHECK-LABEL: no_extract_shl:
84; CHECK:       // %bb.0:
85; CHECK-NEXT:    lsl x8, x0, #10
86; CHECK-NEXT:    bfxil x8, x0, #52, #7
87; CHECK-NEXT:    mov x0, x8
88; CHECK-NEXT:    ret
89  %lhs_mul = shl i64 %i, 5
90  %rhs_mul = shl i64 %i, 10
91  %lhs_shift = lshr i64 %lhs_mul, 57
92  %out = or i64 %lhs_shift, %rhs_mul
93  ret i64 %out
94}
95
96; Result would overshift
97define i32 @no_extract_shrl(i32 %i) nounwind {
98; CHECK-LABEL: no_extract_shrl:
99; CHECK:       // %bb.0:
100; CHECK-NEXT:    lsr w8, w0, #3
101; CHECK-NEXT:    lsr w0, w0, #9
102; CHECK-NEXT:    bfi w0, w8, #28, #4
103; CHECK-NEXT:    ret
104  %lhs_div = lshr i32 %i, 3
105  %rhs_div = lshr i32 %i, 9
106  %lhs_shift = shl i32 %lhs_div, 28
107  %out = or i32 %lhs_shift, %rhs_div
108  ret i32 %out
109}
110
111; Can factor 128 from 2304, but result is 18 instead of 9
112define i64 @no_extract_mul(i64 %i) nounwind {
113; CHECK-LABEL: no_extract_mul:
114; CHECK:       // %bb.0:
115; CHECK-NEXT:    add x8, x0, x0, lsl #3
116; CHECK-NEXT:    lsr x9, x8, #57
117; CHECK-NEXT:    orr x0, x9, x8, lsl #8
118; CHECK-NEXT:    ret
119  %lhs_mul = mul i64 %i, 2304
120  %rhs_mul = mul i64 %i, 9
121  %rhs_shift = lshr i64 %rhs_mul, 57
122  %out = or i64 %lhs_mul, %rhs_shift
123  ret i64 %out
124}
125
126; Can't evenly factor 16 from 49
127define i32 @no_extract_udiv(i32 %i) nounwind {
128; CHECK-LABEL: no_extract_udiv:
129; CHECK:       // %bb.0:
130; CHECK-NEXT:    mov w8, #43691 // =0xaaab
131; CHECK-NEXT:    mov w9, #33437 // =0x829d
132; CHECK-NEXT:    movk w8, #43690, lsl #16
133; CHECK-NEXT:    movk w9, #21399, lsl #16
134; CHECK-NEXT:    umull x8, w0, w8
135; CHECK-NEXT:    umull x9, w0, w9
136; CHECK-NEXT:    lsr x8, x8, #33
137; CHECK-NEXT:    lsr x9, x9, #32
138; CHECK-NEXT:    extr w0, w8, w9, #4
139; CHECK-NEXT:    ret
140  %lhs_div = udiv i32 %i, 3
141  %rhs_div = udiv i32 %i, 49
142  %lhs_shift = shl i32 %lhs_div, 28
143  %out = or i32 %lhs_shift, %rhs_div
144  ret i32 %out
145}
146