1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4; If we have:
5;   (data & (-1 << nbits)) outer>> nbits
6; Or
7;   ((data inner>> nbits) << nbits) outer>> nbits
8; The mask is redundant, and can be dropped:
9;   data outer>> nbits
10; This is valid for both lshr and ashr in both positions and any combination.
11; We must *not* preserve 'exact' on that final right-shift.
12
13define i32 @t0_lshr(i32 %data, i32 %nbits) {
14; CHECK-LABEL: @t0_lshr(
15; CHECK-NEXT:    [[T0:%.*]] = shl i32 -1, [[NBITS:%.*]]
16; CHECK-NEXT:    [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]
17; CHECK-NEXT:    [[T2:%.*]] = lshr exact i32 [[T1]], [[NBITS]]
18; CHECK-NEXT:    ret i32 [[T2]]
19;
20  %t0 = shl i32 -1, %nbits
21  %t1 = and i32 %t0, %data
22  %t2 = lshr exact i32 %t1, %nbits ; while there, test that we *don't* propagate 'exact'
23  ret i32 %t2
24}
25define i32 @t1_sshr(i32 %data, i32 %nbits) {
26; CHECK-LABEL: @t1_sshr(
27; CHECK-NEXT:    [[T0:%.*]] = shl i32 -1, [[NBITS:%.*]]
28; CHECK-NEXT:    [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]
29; CHECK-NEXT:    [[T2:%.*]] = ashr exact i32 [[T1]], [[NBITS]]
30; CHECK-NEXT:    ret i32 [[T2]]
31;
32  %t0 = shl i32 -1, %nbits
33  %t1 = and i32 %t0, %data
34  %t2 = ashr exact i32 %t1, %nbits ; while there, test that we *don't* propagate 'exact'
35  ret i32 %t2
36}
37
38; Vectors
39
40define <4 x i32> @t2_vec(<4 x i32> %data, <4 x i32> %nbits) {
41; CHECK-LABEL: @t2_vec(
42; CHECK-NEXT:    [[T0:%.*]] = shl <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, [[NBITS:%.*]]
43; CHECK-NEXT:    [[T1:%.*]] = and <4 x i32> [[T0]], [[DATA:%.*]]
44; CHECK-NEXT:    [[T2:%.*]] = lshr <4 x i32> [[T1]], [[NBITS]]
45; CHECK-NEXT:    ret <4 x i32> [[T2]]
46;
47  %t0 = shl <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>, %nbits
48  %t1 = and <4 x i32> %t0, %data
49  %t2 = lshr <4 x i32> %t1, %nbits
50  ret <4 x i32> %t2
51}
52
53define <4 x i32> @t3_vec_undef(<4 x i32> %data, <4 x i32> %nbits) {
54; CHECK-LABEL: @t3_vec_undef(
55; CHECK-NEXT:    [[T0:%.*]] = shl <4 x i32> <i32 -1, i32 -1, i32 undef, i32 -1>, [[NBITS:%.*]]
56; CHECK-NEXT:    [[T1:%.*]] = and <4 x i32> [[T0]], [[DATA:%.*]]
57; CHECK-NEXT:    [[T2:%.*]] = lshr <4 x i32> [[T1]], [[NBITS]]
58; CHECK-NEXT:    ret <4 x i32> [[T2]]
59;
60  %t0 = shl <4 x i32> <i32 -1, i32 -1, i32 undef, i32 -1>, %nbits
61  %t1 = and <4 x i32> %t0, %data
62  %t2 = lshr <4 x i32> %t1, %nbits
63  ret <4 x i32> %t2
64}
65
66; Extra uses
67
68declare void @use32(i32)
69
70define i32 @t4_extrause0(i32 %data, i32 %nbits) {
71; CHECK-LABEL: @t4_extrause0(
72; CHECK-NEXT:    [[T0:%.*]] = shl i32 -1, [[NBITS:%.*]]
73; CHECK-NEXT:    call void @use32(i32 [[T0]])
74; CHECK-NEXT:    [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]
75; CHECK-NEXT:    [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]
76; CHECK-NEXT:    ret i32 [[T2]]
77;
78  %t0 = shl i32 -1, %nbits
79  call void @use32(i32 %t0)
80  %t1 = and i32 %t0, %data
81  %t2 = lshr i32 %t1, %nbits
82  ret i32 %t2
83}
84
85define i32 @t5_extrause1(i32 %data, i32 %nbits) {
86; CHECK-LABEL: @t5_extrause1(
87; CHECK-NEXT:    [[T0:%.*]] = shl i32 -1, [[NBITS:%.*]]
88; CHECK-NEXT:    [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]
89; CHECK-NEXT:    call void @use32(i32 [[T1]])
90; CHECK-NEXT:    [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]
91; CHECK-NEXT:    ret i32 [[T2]]
92;
93  %t0 = shl i32 -1, %nbits
94  %t1 = and i32 %t0, %data
95  call void @use32(i32 %t1)
96  %t2 = lshr i32 %t1, %nbits
97  ret i32 %t2
98}
99
100define i32 @t6_extrause2(i32 %data, i32 %nbits) {
101; CHECK-LABEL: @t6_extrause2(
102; CHECK-NEXT:    [[T0:%.*]] = shl i32 -1, [[NBITS:%.*]]
103; CHECK-NEXT:    call void @use32(i32 [[T0]])
104; CHECK-NEXT:    [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]
105; CHECK-NEXT:    call void @use32(i32 [[T1]])
106; CHECK-NEXT:    [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]
107; CHECK-NEXT:    ret i32 [[T2]]
108;
109  %t0 = shl i32 -1, %nbits
110  call void @use32(i32 %t0)
111  %t1 = and i32 %t0, %data
112  call void @use32(i32 %t1)
113  %t2 = lshr i32 %t1, %nbits
114  ret i32 %t2
115}
116
117; Non-canonical mask pattern. Let's just test a single case with all-extra uses.
118
119define i32 @t7_noncanonical_lshr_lshr_extrauses(i32 %data, i32 %nbits) {
120; CHECK-LABEL: @t7_noncanonical_lshr_lshr_extrauses(
121; CHECK-NEXT:    [[T0:%.*]] = lshr i32 [[DATA:%.*]], [[NBITS:%.*]]
122; CHECK-NEXT:    call void @use32(i32 [[T0]])
123; CHECK-NEXT:    [[T1:%.*]] = shl i32 [[T0]], [[NBITS]]
124; CHECK-NEXT:    call void @use32(i32 [[T1]])
125; CHECK-NEXT:    [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]
126; CHECK-NEXT:    ret i32 [[T2]]
127;
128  %t0 = lshr i32 %data, %nbits
129  call void @use32(i32 %t0)
130  %t1 = shl i32 %t0, %nbits
131  call void @use32(i32 %t1)
132  %t2 = lshr i32 %t1, %nbits
133  ret i32 %t2
134}
135
136define i32 @t8_noncanonical_lshr_ashr_extrauses(i32 %data, i32 %nbits) {
137; CHECK-LABEL: @t8_noncanonical_lshr_ashr_extrauses(
138; CHECK-NEXT:    [[T0:%.*]] = lshr i32 [[DATA:%.*]], [[NBITS:%.*]]
139; CHECK-NEXT:    call void @use32(i32 [[T0]])
140; CHECK-NEXT:    [[T1:%.*]] = shl i32 [[T0]], [[NBITS]]
141; CHECK-NEXT:    call void @use32(i32 [[T1]])
142; CHECK-NEXT:    [[T2:%.*]] = ashr i32 [[T1]], [[NBITS]]
143; CHECK-NEXT:    ret i32 [[T2]]
144;
145  %t0 = lshr i32 %data, %nbits
146  call void @use32(i32 %t0)
147  %t1 = shl i32 %t0, %nbits
148  call void @use32(i32 %t1)
149  %t2 = ashr i32 %t1, %nbits
150  ret i32 %t2
151}
152
153define i32 @t9_noncanonical_ashr_lshr_extrauses(i32 %data, i32 %nbits) {
154; CHECK-LABEL: @t9_noncanonical_ashr_lshr_extrauses(
155; CHECK-NEXT:    [[T0:%.*]] = ashr i32 [[DATA:%.*]], [[NBITS:%.*]]
156; CHECK-NEXT:    call void @use32(i32 [[T0]])
157; CHECK-NEXT:    [[T1:%.*]] = shl i32 [[T0]], [[NBITS]]
158; CHECK-NEXT:    call void @use32(i32 [[T1]])
159; CHECK-NEXT:    [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]
160; CHECK-NEXT:    ret i32 [[T2]]
161;
162  %t0 = ashr i32 %data, %nbits
163  call void @use32(i32 %t0)
164  %t1 = shl i32 %t0, %nbits
165  call void @use32(i32 %t1)
166  %t2 = lshr i32 %t1, %nbits
167  ret i32 %t2
168}
169
170define i32 @t10_noncanonical_ashr_ashr_extrauses(i32 %data, i32 %nbits) {
171; CHECK-LABEL: @t10_noncanonical_ashr_ashr_extrauses(
172; CHECK-NEXT:    [[T0:%.*]] = ashr i32 [[DATA:%.*]], [[NBITS:%.*]]
173; CHECK-NEXT:    call void @use32(i32 [[T0]])
174; CHECK-NEXT:    [[T1:%.*]] = shl i32 [[T0]], [[NBITS]]
175; CHECK-NEXT:    call void @use32(i32 [[T1]])
176; CHECK-NEXT:    [[T2:%.*]] = ashr i32 [[T1]], [[NBITS]]
177; CHECK-NEXT:    ret i32 [[T2]]
178;
179  %t0 = ashr i32 %data, %nbits
180  call void @use32(i32 %t0)
181  %t1 = shl i32 %t0, %nbits
182  call void @use32(i32 %t1)
183  %t2 = ashr i32 %t1, %nbits
184  ret i32 %t2
185}
186
187; Commutativity
188
189declare i32 @gen32()
190
191define i32 @t11_commutative(i32 %nbits) {
192; CHECK-LABEL: @t11_commutative(
193; CHECK-NEXT:    [[DATA:%.*]] = call i32 @gen32()
194; CHECK-NEXT:    [[T0:%.*]] = shl i32 -1, [[NBITS:%.*]]
195; CHECK-NEXT:    [[T1:%.*]] = and i32 [[DATA]], [[T0]]
196; CHECK-NEXT:    [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]
197; CHECK-NEXT:    ret i32 [[T2]]
198;
199  %data = call i32 @gen32()
200  %t0 = shl i32 -1, %nbits
201  %t1 = and i32 %data, %t0 ; swapped
202  %t2 = lshr i32 %t1, %nbits
203  ret i32 %t2
204}
205
206; Negative tests
207
208define i32 @n12(i32 %data, i32 %nbits) {
209; CHECK-LABEL: @n12(
210; CHECK-NEXT:    [[T0:%.*]] = shl i32 2147483647, [[NBITS:%.*]]
211; CHECK-NEXT:    [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]
212; CHECK-NEXT:    [[T2:%.*]] = lshr i32 [[T1]], [[NBITS]]
213; CHECK-NEXT:    ret i32 [[T2]]
214;
215  %t0 = shl i32 2147483647, %nbits ; must be shifting -1
216  %t1 = and i32 %t0, %data
217  %t2 = lshr i32 %t1, %nbits
218  ret i32 %t2
219}
220
221define i32 @n13(i32 %data, i32 %nbits0, i32 %nbits1) {
222; CHECK-LABEL: @n13(
223; CHECK-NEXT:    [[T0:%.*]] = shl i32 -1, [[NBITS0:%.*]]
224; CHECK-NEXT:    [[T1:%.*]] = and i32 [[T0]], [[DATA:%.*]]
225; CHECK-NEXT:    [[T2:%.*]] = lshr i32 [[T1]], [[NBITS1:%.*]]
226; CHECK-NEXT:    ret i32 [[T2]]
227;
228  %t0 = shl i32 -1, %nbits0
229  %t1 = and i32 %t0, %data
230  %t2 = lshr i32 %t1, %nbits1 ; different shift amounts
231  ret i32 %t2
232}
233
234define i32 @n14(i32 %data, i32 %nbits0, i32 %nbits1, i32 %nbits2) {
235; CHECK-LABEL: @n14(
236; CHECK-NEXT:    [[T0:%.*]] = lshr i32 [[DATA:%.*]], [[NBITS0:%.*]]
237; CHECK-NEXT:    call void @use32(i32 [[T0]])
238; CHECK-NEXT:    [[T1:%.*]] = shl i32 [[T0]], [[NBITS1:%.*]]
239; CHECK-NEXT:    call void @use32(i32 [[T1]])
240; CHECK-NEXT:    [[T2:%.*]] = lshr i32 [[T1]], [[NBITS2:%.*]]
241; CHECK-NEXT:    ret i32 [[T2]]
242;
243  %t0 = lshr i32 %data, %nbits0
244  call void @use32(i32 %t0)
245  %t1 = shl i32 %t0, %nbits1 ; different shift amounts
246  call void @use32(i32 %t1)
247  %t2 = lshr i32 %t1, %nbits2 ; different shift amounts
248  ret i32 %t2
249}
250