xref: /llvm-project/llvm/test/Transforms/InstSimplify/shift-knownbits.ll (revision 38fffa630ee80163dc65e759392ad29798905679)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instsimplify -S -data-layout="E" | FileCheck %s --check-prefixes=CHECK,BIGENDIAN
3; RUN: opt < %s -passes=instsimplify -S -data-layout="e" | FileCheck %s --check-prefixes=CHECK,LITTLEENDIAN
4
5; If any bits of the shift amount are known to make it exceed or equal
6; the number of bits in the type, the shift causes undefined behavior.
7
8define i32 @shl_amount_is_known_bogus(i32 %a, i32 %b) {
9; CHECK-LABEL: @shl_amount_is_known_bogus(
10; CHECK-NEXT:    ret i32 poison
11;
12  %or = or i32 %b, 32
13  %shl = shl i32 %a, %or
14  ret i32 %shl
15}
16
17define i32 @shl_amount_is_known_bogus_range_attr(i32 %a, i32 range(i32 32, 64) %b) {
18; CHECK-LABEL: @shl_amount_is_known_bogus_range_attr(
19; CHECK-NEXT:    ret i32 poison
20;
21  %shl = shl i32 %a, %b
22  ret i32 %shl
23}
24
25define i32 @neg_shl_amount_is_known_bogus_range_attr(i32 %a, i32 range(i32 0, 32) %b) {
26; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_attr(
27; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[B:%.*]]
28; CHECK-NEXT:    ret i32 [[SHL]]
29;
30  %shl = shl i32 %a, %b
31  ret i32 %shl
32}
33
34declare range(i32 32, 64) i32 @returns_out_of_range_helper()
35declare range(i32 0, 32) i32 @returns_in_range_helper()
36
37define i32 @shl_amount_is_known_bogus_range_return(i32 %a) {
38; CHECK-LABEL: @shl_amount_is_known_bogus_range_return(
39; CHECK-NEXT:    [[B:%.*]] = call i32 @returns_out_of_range_helper()
40; CHECK-NEXT:    ret i32 poison
41;
42  %b = call i32 @returns_out_of_range_helper()
43  %shl = shl i32 %a, %b
44  ret i32 %shl
45}
46
47define i32 @neg_shl_amount_is_known_bogus_range_return(i32 %a) {
48; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_return(
49; CHECK-NEXT:    [[B:%.*]] = call i32 @returns_in_range_helper()
50; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
51; CHECK-NEXT:    ret i32 [[SHL]]
52;
53  %b = call i32 @returns_in_range_helper()
54  %shl = shl i32 %a, %b
55  ret i32 %shl
56}
57
58declare i32 @returns_i32_helper()
59
60define i32 @shl_amount_is_known_bogus_range_call(i32 %a) {
61; CHECK-LABEL: @shl_amount_is_known_bogus_range_call(
62; CHECK-NEXT:    [[B:%.*]] = call range(i32 32, 64) i32 @returns_i32_helper()
63; CHECK-NEXT:    ret i32 poison
64;
65  %b = call range(i32 32, 64) i32 @returns_i32_helper()
66  %shl = shl i32 %a, %b
67  ret i32 %shl
68}
69
70define i32 @neg_shl_amount_is_known_bogus_range_call(i32 %a) {
71; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_call(
72; CHECK-NEXT:    [[B:%.*]] = call range(i32 0, 32) i32 @returns_i32_helper()
73; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
74; CHECK-NEXT:    ret i32 [[SHL]]
75;
76  %b = call range(i32 0, 32) i32 @returns_i32_helper()
77  %shl = shl i32 %a, %b
78  ret i32 %shl
79}
80
81define <2 x i32> @shl_amount_is_known_bogus_range_attr_vec(<2 x i32> %a, <2 x i32> range(i32 32, 64) %b) {
82; CHECK-LABEL: @shl_amount_is_known_bogus_range_attr_vec(
83; CHECK-NEXT:    ret <2 x i32> poison
84;
85  %shl = shl <2 x i32> %a, %b
86  ret <2 x i32> %shl
87}
88
89define <2 x i32> @neg_shl_amount_is_known_bogus_range_attr_vec(<2 x i32> %a, <2 x i32> range(i32 0, 32) %b) {
90; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_attr_vec(
91; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B:%.*]]
92; CHECK-NEXT:    ret <2 x i32> [[SHL]]
93;
94  %shl = shl <2 x i32> %a, %b
95  ret <2 x i32> %shl
96}
97
98declare range(i32 32, 64) <2 x i32> @returns_out_of_range_helper_vec()
99declare range(i32 0, 32) <2 x i32> @returns_in_range_helper_vec()
100
101define <2 x i32> @shl_amount_is_known_bogus_range_return_vec(<2 x i32> %a) {
102; CHECK-LABEL: @shl_amount_is_known_bogus_range_return_vec(
103; CHECK-NEXT:    [[B:%.*]] = call <2 x i32> @returns_out_of_range_helper_vec()
104; CHECK-NEXT:    ret <2 x i32> poison
105;
106  %b = call <2 x i32> @returns_out_of_range_helper_vec()
107  %shl = shl <2 x i32> %a, %b
108  ret <2 x i32> %shl
109}
110
111define <2 x i32> @neg_shl_amount_is_known_bogus_range_return_vec(<2 x i32> %a) {
112; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_return_vec(
113; CHECK-NEXT:    [[B:%.*]] = call <2 x i32> @returns_in_range_helper_vec()
114; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
115; CHECK-NEXT:    ret <2 x i32> [[SHL]]
116;
117  %b = call <2 x i32> @returns_in_range_helper_vec()
118  %shl = shl <2 x i32> %a, %b
119  ret <2 x i32> %shl
120}
121
122declare <2 x i32> @returns_i32_helper_vec()
123
124define <2 x i32> @shl_amount_is_known_bogus_range_call_vec(<2 x i32> %a) {
125; CHECK-LABEL: @shl_amount_is_known_bogus_range_call_vec(
126; CHECK-NEXT:    [[B:%.*]] = call range(i32 32, 64) <2 x i32> @returns_i32_helper_vec()
127; CHECK-NEXT:    ret <2 x i32> poison
128;
129  %b = call range(i32 32, 64) <2 x i32> @returns_i32_helper_vec()
130  %shl = shl <2 x i32> %a, %b
131  ret <2 x i32> %shl
132}
133
134define <2 x i32> @neg_shl_amount_is_known_bogus_range_call_vec(<2 x i32> %a) {
135; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_call_vec(
136; CHECK-NEXT:    [[B:%.*]] = call range(i32 0, 32) <2 x i32> @returns_i32_helper_vec()
137; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]]
138; CHECK-NEXT:    ret <2 x i32> [[SHL]]
139;
140  %b = call range(i32 0, 32) <2 x i32> @returns_i32_helper_vec()
141  %shl = shl <2 x i32> %a, %b
142  ret <2 x i32> %shl
143}
144
145define i32 @shl_amount_is_not_known_bogus_range_call_and_range_metadata(i32 %a) {
146; CHECK-LABEL: @shl_amount_is_not_known_bogus_range_call_and_range_metadata(
147; CHECK-NEXT:    [[B:%.*]] = call range(i32 0, 32) i32 @returns_i32_helper(), !range [[RNG0:![0-9]+]]
148; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]]
149; CHECK-NEXT:    ret i32 [[SHL]]
150;
151  %b = call range(i32 0, 32) i32 @returns_i32_helper(), !range !{ i32 32, i32 64 }
152  %shl = shl i32 %a, %b
153  ret i32 %shl
154}
155
156; Check some weird types and the other shift ops.
157
158define i31 @lshr_amount_is_known_bogus(i31 %a, i31 %b) {
159; CHECK-LABEL: @lshr_amount_is_known_bogus(
160; CHECK-NEXT:    ret i31 poison
161;
162  %or = or i31 %b, 31
163  %shr = lshr i31 %a, %or
164  ret i31 %shr
165}
166
167define i33 @ashr_amount_is_known_bogus(i33 %a, i33 %b) {
168; CHECK-LABEL: @ashr_amount_is_known_bogus(
169; CHECK-NEXT:    ret i33 poison
170;
171  %or = or i33 %b, 33
172  %shr = ashr i33 %a, %or
173  ret i33 %shr
174}
175
176
177; If all valid bits of the shift amount are known 0, there's no shift.
178; It doesn't matter if high bits are set because that would be undefined.
179; Therefore, the only possible valid result of these shifts is %a.
180
181define i16 @ashr_amount_is_zero(i16 %a, i16 %b) {
182; CHECK-LABEL: @ashr_amount_is_zero(
183; CHECK-NEXT:    ret i16 [[A:%.*]]
184;
185  %and = and i16 %b, 65520 ; 0xfff0
186  %shr = ashr i16 %a, %and
187  ret i16 %shr
188}
189
190define i300 @lshr_amount_is_zero(i300 %a, i300 %b) {
191; CHECK-LABEL: @lshr_amount_is_zero(
192; CHECK-NEXT:    ret i300 [[A:%.*]]
193;
194  %and = and i300 %b, 2048
195  %shr = lshr i300 %a, %and
196  ret i300 %shr
197}
198
199define i9 @shl_amount_is_zero(i9 %a, i9 %b) {
200; CHECK-LABEL: @shl_amount_is_zero(
201; CHECK-NEXT:    ret i9 [[A:%.*]]
202;
203  %and = and i9 %b, 496 ; 0x1f0
204  %shl = shl i9 %a, %and
205  ret i9 %shl
206}
207
208
209; Verify that we've calculated the log2 boundary of valid bits correctly for a weird type.
210
211define i9 @shl_amount_is_not_known_zero(i9 %a, i9 %b) {
212; CHECK-LABEL: @shl_amount_is_not_known_zero(
213; CHECK-NEXT:    [[AND:%.*]] = and i9 [[B:%.*]], -8
214; CHECK-NEXT:    [[SHL:%.*]] = shl i9 [[A:%.*]], [[AND]]
215; CHECK-NEXT:    ret i9 [[SHL]]
216;
217  %and = and i9 %b, 504 ; 0x1f8
218  %shl = shl i9 %a, %and
219  ret i9 %shl
220}
221
222
223; For vectors, we need all scalar elements to meet the requirements to optimize.
224
225define <2 x i32> @ashr_vector_bogus(<2 x i32> %a, <2 x i32> %b) {
226; CHECK-LABEL: @ashr_vector_bogus(
227; CHECK-NEXT:    ret <2 x i32> poison
228;
229  %or = or <2 x i32> %b, <i32 32, i32 32>
230  %shr = ashr <2 x i32> %a, %or
231  ret <2 x i32> %shr
232}
233
234; FIXME: This is undef, but computeKnownBits doesn't handle the union.
235define <2 x i32> @shl_vector_bogus(<2 x i32> %a, <2 x i32> %b) {
236; CHECK-LABEL: @shl_vector_bogus(
237; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[B:%.*]], <i32 32, i32 64>
238; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[OR]]
239; CHECK-NEXT:    ret <2 x i32> [[SHL]]
240;
241  %or = or <2 x i32> %b, <i32 32, i32 64>
242  %shl = shl <2 x i32> %a, %or
243  ret <2 x i32> %shl
244}
245
246define <2 x i32> @lshr_vector_zero(<2 x i32> %a, <2 x i32> %b) {
247; CHECK-LABEL: @lshr_vector_zero(
248; CHECK-NEXT:    ret <2 x i32> [[A:%.*]]
249;
250  %and = and <2 x i32> %b, <i32 64, i32 256>
251  %shr = lshr <2 x i32> %a, %and
252  ret <2 x i32> %shr
253}
254
255; Make sure that weird vector types work too.
256define <2 x i15> @shl_vector_zero(<2 x i15> %a, <2 x i15> %b) {
257; CHECK-LABEL: @shl_vector_zero(
258; CHECK-NEXT:    ret <2 x i15> [[A:%.*]]
259;
260  %and = and <2 x i15> %b, <i15 1024, i15 1024>
261  %shl = shl <2 x i15> %a, %and
262  ret <2 x i15> %shl
263}
264
265define <2 x i32> @shl_vector_for_real(<2 x i32> %a, <2 x i32> %b) {
266; CHECK-LABEL: @shl_vector_for_real(
267; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[B:%.*]], splat (i32 3)
268; CHECK-NEXT:    [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[AND]]
269; CHECK-NEXT:    ret <2 x i32> [[SHL]]
270;
271  %and = and <2 x i32> %b, <i32 3, i32 3> ; a necessary mask op
272  %shl = shl <2 x i32> %a, %and
273  ret <2 x i32> %shl
274}
275
276
277; We calculate the valid bits of the shift using log2, and log2 of 1 (the type width) is 0.
278; That should be ok. Either the shift amount is 0 or invalid (1), so we can always return %a.
279
280define i1 @shl_i1(i1 %a, i1 %b) {
281; CHECK-LABEL: @shl_i1(
282; CHECK-NEXT:    ret i1 [[A:%.*]]
283;
284  %shl = shl i1 %a, %b
285  ret i1 %shl
286}
287
288; The following cases only get folded by InstCombine,
289; see InstCombine/lshr.ll.
290
291declare i32 @llvm.cttz.i32(i32, i1) nounwind readnone
292declare i32 @llvm.ctlz.i32(i32, i1) nounwind readnone
293declare <2 x i8> @llvm.cttz.v2i8(<2 x i8>, i1) nounwind readnone
294declare <2 x i8> @llvm.ctlz.v2i8(<2 x i8>, i1) nounwind readnone
295
296define i32 @lshr_ctlz_zero_is_undef(i32 %x) {
297; CHECK-LABEL: @lshr_ctlz_zero_is_undef(
298; CHECK-NEXT:    [[CT:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 true)
299; CHECK-NEXT:    [[SH:%.*]] = lshr i32 [[CT]], 5
300; CHECK-NEXT:    ret i32 [[SH]]
301;
302  %ct = call i32 @llvm.ctlz.i32(i32 %x, i1 true)
303  %sh = lshr i32 %ct, 5
304  ret i32 %sh
305}
306
307define i32 @lshr_cttz_zero_is_undef(i32 %x) {
308; CHECK-LABEL: @lshr_cttz_zero_is_undef(
309; CHECK-NEXT:    [[CT:%.*]] = call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
310; CHECK-NEXT:    [[SH:%.*]] = lshr i32 [[CT]], 5
311; CHECK-NEXT:    ret i32 [[SH]]
312;
313  %ct = call i32 @llvm.cttz.i32(i32 %x, i1 true)
314  %sh = lshr i32 %ct, 5
315  ret i32 %sh
316}
317
318define <2 x i8> @lshr_ctlz_zero_is_undef_splat_vec(<2 x i8> %x) {
319; CHECK-LABEL: @lshr_ctlz_zero_is_undef_splat_vec(
320; CHECK-NEXT:    [[CT:%.*]] = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> [[X:%.*]], i1 true)
321; CHECK-NEXT:    [[SH:%.*]] = lshr <2 x i8> [[CT]], splat (i8 3)
322; CHECK-NEXT:    ret <2 x i8> [[SH]]
323;
324  %ct = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %x, i1 true)
325  %sh = lshr <2 x i8> %ct, <i8 3, i8 3>
326  ret <2 x i8> %sh
327}
328
329define i8 @lshr_ctlz_zero_is_undef_vec(<2 x i8> %x) {
330; CHECK-LABEL: @lshr_ctlz_zero_is_undef_vec(
331; CHECK-NEXT:    [[CT:%.*]] = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> [[X:%.*]], i1 true)
332; CHECK-NEXT:    [[SH:%.*]] = lshr <2 x i8> [[CT]], <i8 3, i8 0>
333; CHECK-NEXT:    [[EX:%.*]] = extractelement <2 x i8> [[SH]], i32 0
334; CHECK-NEXT:    ret i8 [[EX]]
335;
336  %ct = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %x, i1 true)
337  %sh = lshr <2 x i8> %ct, <i8 3, i8 0>
338  %ex = extractelement <2 x i8> %sh, i32 0
339  ret i8 %ex
340}
341
342define <2 x i8> @lshr_cttz_zero_is_undef_splat_vec(<2 x i8> %x) {
343; CHECK-LABEL: @lshr_cttz_zero_is_undef_splat_vec(
344; CHECK-NEXT:    [[CT:%.*]] = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> [[X:%.*]], i1 true)
345; CHECK-NEXT:    [[SH:%.*]] = lshr <2 x i8> [[CT]], splat (i8 3)
346; CHECK-NEXT:    ret <2 x i8> [[SH]]
347;
348  %ct = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> %x, i1 true)
349  %sh = lshr <2 x i8> %ct, <i8 3, i8 3>
350  ret <2 x i8> %sh
351}
352
353define i8 @lshr_cttz_zero_is_undef_vec(<2 x i8> %x) {
354; CHECK-LABEL: @lshr_cttz_zero_is_undef_vec(
355; CHECK-NEXT:    [[CT:%.*]] = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> [[X:%.*]], i1 true)
356; CHECK-NEXT:    [[SH:%.*]] = lshr <2 x i8> [[CT]], <i8 3, i8 0>
357; CHECK-NEXT:    [[EX:%.*]] = extractelement <2 x i8> [[SH]], i32 0
358; CHECK-NEXT:    ret i8 [[EX]]
359;
360  %ct = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> %x, i1 true)
361  %sh = lshr <2 x i8> %ct, <i8 3, i8 0>
362  %ex = extractelement <2 x i8> %sh, i32 0
363  ret i8 %ex
364}
365
366; The shift amount is 0 on either of high/low bytes. The middle byte doesn't matter.
367
368define i24 @bitcast_noshift_scalar(<3 x i8> %v1, i24 %v2) {
369; CHECK-LABEL: @bitcast_noshift_scalar(
370; CHECK-NEXT:    ret i24 [[V2:%.*]]
371;
372  %c = insertelement <3 x i8> poison, i8 0, i64 0
373  %s = shufflevector <3 x i8> %v1, <3 x i8> %c, <3 x i32> <i32 3, i32 1, i32 3>
374  %b = bitcast <3 x i8> %s to i24
375  %r = shl i24 %v2, %b
376  ret i24 %r
377}
378
379; The shift amount is 0 on low byte of big-endian and unknown on little-endian.
380
381define i24 @bitcast_noshift_scalar_bigend(<3 x i8> %v1, i24 %v2) {
382; BIGENDIAN-LABEL: @bitcast_noshift_scalar_bigend(
383; BIGENDIAN-NEXT:    ret i24 [[V2:%.*]]
384;
385; LITTLEENDIAN-LABEL: @bitcast_noshift_scalar_bigend(
386; LITTLEENDIAN-NEXT:    [[S:%.*]] = shufflevector <3 x i8> [[V1:%.*]], <3 x i8> <i8 0, i8 poison, i8 poison>, <3 x i32> <i32 0, i32 1, i32 3>
387; LITTLEENDIAN-NEXT:    [[B:%.*]] = bitcast <3 x i8> [[S]] to i24
388; LITTLEENDIAN-NEXT:    [[R:%.*]] = shl i24 [[V2:%.*]], [[B]]
389; LITTLEENDIAN-NEXT:    ret i24 [[R]]
390;
391  %c = insertelement <3 x i8> poison, i8 0, i64 0
392  %s = shufflevector <3 x i8> %v1, <3 x i8> %c, <3 x i32> <i32 0, i32 1, i32 3>
393  %b = bitcast <3 x i8> %s to i24
394  %r = shl i24 %v2, %b
395  ret i24 %r
396}
397
398; The shift amount is 0 on low byte of little-endian and unknown on big-endian.
399
400define i24 @bitcast_noshift_scalar_littleend(<3 x i8> %v1, i24 %v2) {
401; BIGENDIAN-LABEL: @bitcast_noshift_scalar_littleend(
402; BIGENDIAN-NEXT:    [[S:%.*]] = shufflevector <3 x i8> [[V1:%.*]], <3 x i8> <i8 0, i8 poison, i8 poison>, <3 x i32> <i32 3, i32 1, i32 2>
403; BIGENDIAN-NEXT:    [[B:%.*]] = bitcast <3 x i8> [[S]] to i24
404; BIGENDIAN-NEXT:    [[R:%.*]] = shl i24 [[V2:%.*]], [[B]]
405; BIGENDIAN-NEXT:    ret i24 [[R]]
406;
407; LITTLEENDIAN-LABEL: @bitcast_noshift_scalar_littleend(
408; LITTLEENDIAN-NEXT:    ret i24 [[V2:%.*]]
409;
410  %c = insertelement <3 x i8> poison, i8 0, i64 0
411  %s = shufflevector <3 x i8> %v1, <3 x i8> %c, <3 x i32> <i32 3, i32 1, i32 2>
412  %b = bitcast <3 x i8> %s to i24
413  %r = shl i24 %v2, %b
414  ret i24 %r
415}
416
417; The shift amount is known 24 on little-endian and known 24<<16 on big-endian
418; across all vector elements, so it's an overshift either way.
419
420define <3 x i24> @bitcast_overshift_vector(<9 x i8> %v1, <3 x i24> %v2) {
421; CHECK-LABEL: @bitcast_overshift_vector(
422; CHECK-NEXT:    ret <3 x i24> poison
423;
424  %c = insertelement <9 x i8> poison, i8 24, i64 0
425  %s = shufflevector <9 x i8> %v1, <9 x i8> %c, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 9, i32 7, i32 8>
426  %b = bitcast <9 x i8> %s to <3 x i24>
427  %r = shl <3 x i24> %v2, %b
428  ret <3 x i24> %r
429}
430
431; The shift amount is known 23 on little-endian and known 23<<16 on big-endian
432; across all vector elements, so it's an overshift for big-endian.
433
434define <3 x i24> @bitcast_overshift_vector_bigend(<9 x i8> %v1, <3 x i24> %v2) {
435; BIGENDIAN-LABEL: @bitcast_overshift_vector_bigend(
436; BIGENDIAN-NEXT:    ret <3 x i24> poison
437;
438; LITTLEENDIAN-LABEL: @bitcast_overshift_vector_bigend(
439; LITTLEENDIAN-NEXT:    [[S:%.*]] = shufflevector <9 x i8> [[V1:%.*]], <9 x i8> <i8 23, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison>, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 9, i32 7, i32 8>
440; LITTLEENDIAN-NEXT:    [[B:%.*]] = bitcast <9 x i8> [[S]] to <3 x i24>
441; LITTLEENDIAN-NEXT:    [[R:%.*]] = shl <3 x i24> [[V2:%.*]], [[B]]
442; LITTLEENDIAN-NEXT:    ret <3 x i24> [[R]]
443;
444  %c = insertelement <9 x i8> poison, i8 23, i64 0
445  %s = shufflevector <9 x i8> %v1, <9 x i8> %c, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 9, i32 7, i32 8>
446  %b = bitcast <9 x i8> %s to <3 x i24>
447  %r = shl <3 x i24> %v2, %b
448  ret <3 x i24> %r
449}
450
451; The shift amount is known 23 on big-endian and known 23<<16 on little-endian
452; across all vector elements, so it's an overshift for little-endian.
453
454define <3 x i24> @bitcast_overshift_vector_littleend(<9 x i8> %v1, <3 x i24> %v2) {
455; BIGENDIAN-LABEL: @bitcast_overshift_vector_littleend(
456; BIGENDIAN-NEXT:    [[S:%.*]] = shufflevector <9 x i8> [[V1:%.*]], <9 x i8> <i8 23, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison>, <9 x i32> <i32 0, i32 1, i32 9, i32 3, i32 4, i32 9, i32 6, i32 7, i32 9>
457; BIGENDIAN-NEXT:    [[B:%.*]] = bitcast <9 x i8> [[S]] to <3 x i24>
458; BIGENDIAN-NEXT:    [[R:%.*]] = shl <3 x i24> [[V2:%.*]], [[B]]
459; BIGENDIAN-NEXT:    ret <3 x i24> [[R]]
460;
461; LITTLEENDIAN-LABEL: @bitcast_overshift_vector_littleend(
462; LITTLEENDIAN-NEXT:    ret <3 x i24> poison
463;
464  %c = insertelement <9 x i8> poison, i8 23, i64 0
465  %s = shufflevector <9 x i8> %v1, <9 x i8> %c, <9 x i32> <i32 0, i32 1, i32 9, i32 3, i32 4, i32 9, i32 6, i32 7, i32 9>
466  %b = bitcast <9 x i8> %s to <3 x i24>
467  %r = shl <3 x i24> %v2, %b
468  ret <3 x i24> %r
469}
470
471; Negative test - the shift amount is known 24 or 24<<16 on only 2 out of 3 elements.
472
473define <3 x i24> @bitcast_partial_overshift_vector(<9 x i8> %v1, <3 x i24> %v2) {
474; CHECK-LABEL: @bitcast_partial_overshift_vector(
475; CHECK-NEXT:    [[S:%.*]] = shufflevector <9 x i8> [[V1:%.*]], <9 x i8> <i8 24, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison>, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 6, i32 7, i32 8>
476; CHECK-NEXT:    [[B:%.*]] = bitcast <9 x i8> [[S]] to <3 x i24>
477; CHECK-NEXT:    [[R:%.*]] = shl <3 x i24> [[V2:%.*]], [[B]]
478; CHECK-NEXT:    ret <3 x i24> [[R]]
479;
480  %c = insertelement <9 x i8> poison, i8 24, i64 0
481  %s = shufflevector <9 x i8> %v1, <9 x i8> %c, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 6, i32 7, i32 8>
482  %b = bitcast <9 x i8> %s to <3 x i24>
483  %r = shl <3 x i24> %v2, %b
484  ret <3 x i24> %r
485}
486
487; Negative test - don't know how to look through a cast with non-integer type (but we could handle this...).
488
489define <1 x i64> @bitcast_noshift_vector_wrong_type(<2 x float> %v1, <1 x i64> %v2) {
490; CHECK-LABEL: @bitcast_noshift_vector_wrong_type(
491; CHECK-NEXT:    [[S:%.*]] = shufflevector <2 x float> [[V1:%.*]], <2 x float> <float 0.000000e+00, float poison>, <2 x i32> <i32 2, i32 1>
492; CHECK-NEXT:    [[B:%.*]] = bitcast <2 x float> [[S]] to <1 x i64>
493; CHECK-NEXT:    [[R:%.*]] = shl <1 x i64> [[V2:%.*]], [[B]]
494; CHECK-NEXT:    ret <1 x i64> [[R]]
495;
496  %c = insertelement <2 x float> poison, float 0.0, i64 0
497  %s = shufflevector <2 x float> %v1, <2 x float> %c, <2 x i32> <i32 2, i32 1>
498  %b = bitcast <2 x float> %s to <1 x i64>
499  %r = shl <1 x i64> %v2, %b
500  ret <1 x i64> %r
501}
502