xref: /llvm-project/llvm/test/Transforms/VectorCombine/load-insert-store.ll (revision e2fc68c3db8862ef90c1c8f31a314eac1f79633b)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes=vector-combine -data-layout=e < %s | FileCheck %s
3; RUN: opt -S -passes=vector-combine -data-layout=E < %s | FileCheck %s
4
5define void @insert_store(ptr %q, i8 zeroext %s) {
6; CHECK-LABEL: @insert_store(
7; CHECK-NEXT:  entry:
8; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 3
9; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
10; CHECK-NEXT:    ret void
11;
12entry:
13  %0 = load <16 x i8>, ptr %q
14  %vecins = insertelement <16 x i8> %0, i8 %s, i32 3
15  store <16 x i8> %vecins, ptr %q, align 16
16  ret void
17}
18
19define void @insert_store_i16_align1(ptr %q, i16 zeroext %s) {
20; CHECK-LABEL: @insert_store_i16_align1(
21; CHECK-NEXT:  entry:
22; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 3
23; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
24; CHECK-NEXT:    ret void
25;
26entry:
27  %0 = load <8 x i16>, ptr %q
28  %vecins = insertelement <8 x i16> %0, i16 %s, i32 3
29  store <8 x i16> %vecins, ptr %q, align 1
30  ret void
31}
32
33; To verify case when index is out of bounds
34define void @insert_store_outofbounds(ptr %q, i16 zeroext %s) {
35; CHECK-LABEL: @insert_store_outofbounds(
36; CHECK-NEXT:  entry:
37; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
38; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 9
39; CHECK-NEXT:    store <8 x i16> [[VECINS]], ptr [[Q]], align 16
40; CHECK-NEXT:    ret void
41;
42entry:
43  %0 = load <8 x i16>, ptr %q
44  %vecins = insertelement <8 x i16> %0, i16 %s, i32 9
45  store <8 x i16> %vecins, ptr %q
46  ret void
47}
48
49define void @insert_store_vscale(ptr %q, i16 zeroext %s) {
50; CHECK-LABEL: @insert_store_vscale(
51; CHECK-NEXT:  entry:
52; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 8 x i16>, ptr [[Q:%.*]], i32 0, i32 3
53; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
54; CHECK-NEXT:    ret void
55;
56entry:
57  %0 = load <vscale x 8 x i16>, ptr %q
58  %vecins = insertelement <vscale x 8 x i16> %0, i16 %s, i32 3
59  store <vscale x 8 x i16> %vecins, ptr %q
60  ret void
61}
62
63; To verify the case that index exceeds the minimum number
64; of elements of a scalable vector type.
65define void @insert_store_vscale_exceeds(ptr %q, i16 zeroext %s) {
66; CHECK-LABEL: @insert_store_vscale_exceeds(
67; CHECK-NEXT:  entry:
68; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 8 x i16>, ptr [[Q:%.*]], align 16
69; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <vscale x 8 x i16> [[TMP0]], i16 [[S:%.*]], i32 9
70; CHECK-NEXT:    store <vscale x 8 x i16> [[VECINS]], ptr [[Q]], align 16
71; CHECK-NEXT:    ret void
72;
73entry:
74  %0 = load <vscale x 8 x i16>, ptr %q
75  %vecins = insertelement <vscale x 8 x i16> %0, i16 %s, i32 9
76  store <vscale x 8 x i16> %vecins, ptr %q
77  ret void
78}
79
80define void @insert_store_v9i4(ptr %q, i4 zeroext %s) {
81; CHECK-LABEL: @insert_store_v9i4(
82; CHECK-NEXT:  entry:
83; CHECK-NEXT:    [[TMP0:%.*]] = load <9 x i4>, ptr [[Q:%.*]], align 8
84; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <9 x i4> [[TMP0]], i4 [[S:%.*]], i32 3
85; CHECK-NEXT:    store <9 x i4> [[VECINS]], ptr [[Q]], align 1
86; CHECK-NEXT:    ret void
87;
88entry:
89  %0 = load <9 x i4>, ptr %q
90  %vecins = insertelement <9 x i4> %0, i4 %s, i32 3
91  store <9 x i4> %vecins, ptr %q, align 1
92  ret void
93}
94
95define void @insert_store_v4i27(ptr %q, i27 zeroext %s) {
96; CHECK-LABEL: @insert_store_v4i27(
97; CHECK-NEXT:  entry:
98; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i27>, ptr [[Q:%.*]], align 16
99; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <4 x i27> [[TMP0]], i27 [[S:%.*]], i32 3
100; CHECK-NEXT:    store <4 x i27> [[VECINS]], ptr [[Q]], align 1
101; CHECK-NEXT:    ret void
102;
103entry:
104  %0 = load <4 x i27>, ptr %q
105  %vecins = insertelement <4 x i27> %0, i27 %s, i32 3
106  store <4 x i27> %vecins, ptr %q, align 1
107  ret void
108}
109
110define void @insert_store_v32i1(ptr %p) {
111; CHECK-LABEL: @insert_store_v32i1(
112; CHECK-NEXT:    [[VEC:%.*]] = load <32 x i1>, ptr [[P:%.*]], align 4
113; CHECK-NEXT:    [[INS:%.*]] = insertelement <32 x i1> [[VEC]], i1 true, i64 0
114; CHECK-NEXT:    store <32 x i1> [[INS]], ptr [[P]], align 4
115; CHECK-NEXT:    ret void
116;
117  %vec = load <32 x i1>, ptr %p
118  %ins = insertelement <32 x i1> %vec, i1 true, i64 0
119  store <32 x i1> %ins, ptr %p
120  ret void
121}
122
123define void @insert_store_blk_differ(ptr %q, i16 zeroext %s) {
124; CHECK-LABEL: @insert_store_blk_differ(
125; CHECK-NEXT:  entry:
126; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
127; CHECK-NEXT:    br label [[CONT:%.*]]
128; CHECK:       cont:
129; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 3
130; CHECK-NEXT:    store <8 x i16> [[VECINS]], ptr [[Q]], align 16
131; CHECK-NEXT:    ret void
132;
133entry:
134  %0 = load <8 x i16>, ptr %q
135  br label %cont
136cont:
137  %vecins = insertelement <8 x i16> %0, i16 %s, i32 3
138  store <8 x i16> %vecins, ptr %q
139  ret void
140}
141
142define void @insert_store_nonconst(ptr %q, i8 zeroext %s, i32 %idx) {
143; CHECK-LABEL: @insert_store_nonconst(
144; CHECK-NEXT:  entry:
145; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
146; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX:%.*]]
147; CHECK-NEXT:    store <16 x i8> [[VECINS]], ptr [[Q]], align 16
148; CHECK-NEXT:    ret void
149;
150entry:
151  %0 = load <16 x i8>, ptr %q
152  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx
153  store <16 x i8> %vecins, ptr %q
154  ret void
155}
156
157; To verify the case that the index is not a constant, and
158; the vector type is scalable.
159define void @insert_store_vscale_nonconst(ptr %q, i8 zeroext %s, i32 %idx) {
160; CHECK-LABEL: @insert_store_vscale_nonconst(
161; CHECK-NEXT:  entry:
162; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 16 x i8>, ptr [[Q:%.*]], align 16
163; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <vscale x 16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX:%.*]]
164; CHECK-NEXT:    store <vscale x 16 x i8> [[VECINS]], ptr [[Q]], align 16
165; CHECK-NEXT:    ret void
166;
167entry:
168  %0 = load <vscale x 16 x i8>, ptr %q
169  %vecins = insertelement <vscale x 16 x i8> %0, i8 %s, i32 %idx
170  store <vscale x 16 x i8> %vecins, ptr %q
171  ret void
172}
173
174; To verify align here is narrowed to scalar store size
175define void @insert_store_nonconst_large_alignment(ptr %q, i32 zeroext %s, i32 %idx) {
176; CHECK-LABEL: @insert_store_nonconst_large_alignment(
177; CHECK-NEXT:  entry:
178; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 4
179; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
180; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
181; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 4
182; CHECK-NEXT:    ret void
183;
184entry:
185  %cmp = icmp ult i32 %idx, 4
186  call void @llvm.assume(i1 %cmp)
187  %i = load <4 x i32>, ptr %q, align 128
188  %vecins = insertelement <4 x i32> %i, i32 %s, i32 %idx
189  store <4 x i32> %vecins, ptr %q, align 128
190  ret void
191}
192
193define void @insert_store_nonconst_align_maximum_8(ptr %q, i64 %s, i32 %idx) {
194; CHECK-LABEL: @insert_store_nonconst_align_maximum_8(
195; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 2
196; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
197; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
198; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 8
199; CHECK-NEXT:    ret void
200;
201  %cmp = icmp ult i32 %idx, 2
202  call void @llvm.assume(i1 %cmp)
203  %i = load <8 x i64>, ptr %q, align 8
204  %vecins = insertelement <8 x i64> %i, i64 %s, i32 %idx
205  store <8 x i64> %vecins, ptr %q, align 8
206  ret void
207}
208
209define void @insert_store_nonconst_align_maximum_4(ptr %q, i64 %s, i32 %idx) {
210; CHECK-LABEL: @insert_store_nonconst_align_maximum_4(
211; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 2
212; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
213; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
214; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
215; CHECK-NEXT:    ret void
216;
217  %cmp = icmp ult i32 %idx, 2
218  call void @llvm.assume(i1 %cmp)
219  %i = load <8 x i64>, ptr %q, align 4
220  %vecins = insertelement <8 x i64> %i, i64 %s, i32 %idx
221  store <8 x i64> %vecins, ptr %q, align 4
222  ret void
223}
224
225define void @insert_store_nonconst_align_larger(ptr %q, i64 %s, i32 %idx) {
226; CHECK-LABEL: @insert_store_nonconst_align_larger(
227; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 2
228; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
229; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
230; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
231; CHECK-NEXT:    ret void
232;
233  %cmp = icmp ult i32 %idx, 2
234  call void @llvm.assume(i1 %cmp)
235  %i = load <8 x i64>, ptr %q, align 4
236  %vecins = insertelement <8 x i64> %i, i64 %s, i32 %idx
237  store <8 x i64> %vecins, ptr %q, align 2
238  ret void
239}
240
241define void @insert_store_nonconst_index_known_valid_by_assume(ptr %q, i8 zeroext %s, i32 %idx) {
242; CHECK-LABEL: @insert_store_nonconst_index_known_valid_by_assume(
243; CHECK-NEXT:  entry:
244; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 4
245; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
246; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
247; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
248; CHECK-NEXT:    ret void
249;
250entry:
251  %cmp = icmp ult i32 %idx, 4
252  call void @llvm.assume(i1 %cmp)
253  %0 = load <16 x i8>, ptr %q
254  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx
255  store <16 x i8> %vecins, ptr %q
256  ret void
257}
258
259; To verify the index is not a constant but valid by assume,
260; for scalable vector types.
261define void @insert_store_vscale_nonconst_index_known_valid_by_assume(ptr %q, i8 zeroext %s, i32 %idx) {
262; CHECK-LABEL: @insert_store_vscale_nonconst_index_known_valid_by_assume(
263; CHECK-NEXT:  entry:
264; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 4
265; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
266; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
267; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
268; CHECK-NEXT:    ret void
269;
270entry:
271  %cmp = icmp ult i32 %idx, 4
272  call void @llvm.assume(i1 %cmp)
273  %0 = load <vscale x 16 x i8>, ptr %q
274  %vecins = insertelement <vscale x 16 x i8> %0, i8 %s, i32 %idx
275  store <vscale x 16 x i8> %vecins, ptr %q
276  ret void
277}
278
279declare void @maythrow() readnone
280
281define void @insert_store_nonconst_index_not_known_valid_by_assume_after_load(ptr %q, i8 zeroext %s, i32 %idx) {
282; CHECK-LABEL: @insert_store_nonconst_index_not_known_valid_by_assume_after_load(
283; CHECK-NEXT:  entry:
284; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 4
285; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
286; CHECK-NEXT:    call void @maythrow()
287; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
288; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX]]
289; CHECK-NEXT:    store <16 x i8> [[VECINS]], ptr [[Q]], align 16
290; CHECK-NEXT:    ret void
291;
292entry:
293  %cmp = icmp ult i32 %idx, 4
294  %0 = load <16 x i8>, ptr %q
295  call void @maythrow()
296  call void @llvm.assume(i1 %cmp)
297  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx
298  store <16 x i8> %vecins, ptr %q
299  ret void
300}
301
302define void @insert_store_nonconst_index_not_known_valid_by_assume(ptr %q, i8 zeroext %s, i32 %idx) {
303; CHECK-LABEL: @insert_store_nonconst_index_not_known_valid_by_assume(
304; CHECK-NEXT:  entry:
305; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 17
306; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
307; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
308; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX]]
309; CHECK-NEXT:    store <16 x i8> [[VECINS]], ptr [[Q]], align 16
310; CHECK-NEXT:    ret void
311;
312entry:
313  %cmp = icmp ult i32 %idx, 17
314  call void @llvm.assume(i1 %cmp)
315  %0 = load <16 x i8>, ptr %q
316  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx
317  store <16 x i8> %vecins, ptr %q
318  ret void
319}
320
321; To verify the index is not a constant and may not be valid by assume,
322; for scalable vector types.
323define void @insert_store_vscale_nonconst_index_not_known_valid_by_assume(ptr %q, i8 zeroext %s, i32 %idx) {
324; CHECK-LABEL: @insert_store_vscale_nonconst_index_not_known_valid_by_assume(
325; CHECK-NEXT:  entry:
326; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 17
327; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
328; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 16 x i8>, ptr [[Q:%.*]], align 16
329; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <vscale x 16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX]]
330; CHECK-NEXT:    store <vscale x 16 x i8> [[VECINS]], ptr [[Q]], align 16
331; CHECK-NEXT:    ret void
332;
333entry:
334  %cmp = icmp ult i32 %idx, 17
335  call void @llvm.assume(i1 %cmp)
336  %0 = load <vscale x 16 x i8>, ptr %q
337  %vecins = insertelement <vscale x 16 x i8> %0, i8 %s, i32 %idx
338  store <vscale x 16 x i8> %vecins, ptr %q
339  ret void
340}
341
342declare void @llvm.assume(i1)
343
344define void @insert_store_nonconst_index_known_noundef_and_valid_by_and(ptr %q, i8 zeroext %s, i32 noundef %idx) {
345; CHECK-LABEL: @insert_store_nonconst_index_known_noundef_and_valid_by_and(
346; CHECK-NEXT:  entry:
347; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX:%.*]], 7
348; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
349; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
350; CHECK-NEXT:    ret void
351;
352entry:
353  %0 = load <16 x i8>, ptr %q
354  %idx.clamped = and i32 %idx, 7
355  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
356  store <16 x i8> %vecins, ptr %q
357  ret void
358}
359
360; To verify the index is not a constant but valid by and,
361; for scalable vector types.
362define void @insert_store_vscale_nonconst_index_known_noundef_and_valid_by_and(ptr %q, i8 zeroext %s, i32 noundef %idx) {
363; CHECK-LABEL: @insert_store_vscale_nonconst_index_known_noundef_and_valid_by_and(
364; CHECK-NEXT:  entry:
365; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX:%.*]], 7
366; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
367; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
368; CHECK-NEXT:    ret void
369;
370entry:
371  %0 = load <vscale x 16 x i8>, ptr %q
372  %idx.clamped = and i32 %idx, 7
373  %vecins = insertelement <vscale x 16 x i8> %0, i8 %s, i32 %idx.clamped
374  store <vscale x 16 x i8> %vecins, ptr %q
375  ret void
376}
377
378define void @insert_store_nonconst_index_base_frozen_and_valid_by_and(ptr %q, i8 zeroext %s, i32 %idx) {
379; CHECK-LABEL: @insert_store_nonconst_index_base_frozen_and_valid_by_and(
380; CHECK-NEXT:  entry:
381; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i32 [[IDX:%.*]]
382; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX_FROZEN]], 7
383; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
384; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
385; CHECK-NEXT:    ret void
386;
387entry:
388  %0 = load <16 x i8>, ptr %q
389  %idx.frozen = freeze i32 %idx
390  %idx.clamped = and i32 %idx.frozen, 7
391  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
392  store <16 x i8> %vecins, ptr %q
393  ret void
394}
395
396define void @insert_store_nonconst_index_frozen_and_valid_by_and(ptr %q, i8 zeroext %s, i32 %idx) {
397; CHECK-LABEL: @insert_store_nonconst_index_frozen_and_valid_by_and(
398; CHECK-NEXT:  entry:
399; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
400; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX:%.*]], 7
401; CHECK-NEXT:    [[IDX_CLAMPED_FROZEN:%.*]] = freeze i32 [[IDX_CLAMPED]]
402; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX_CLAMPED_FROZEN]]
403; CHECK-NEXT:    store <16 x i8> [[VECINS]], ptr [[Q]], align 16
404; CHECK-NEXT:    ret void
405;
406entry:
407  %0 = load <16 x i8>, ptr %q
408  %idx.clamped = and i32 %idx, 7
409  %idx.clamped.frozen = freeze i32 %idx.clamped
410  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped.frozen
411  store <16 x i8> %vecins, ptr %q
412  ret void
413}
414
415define void @insert_store_nonconst_index_known_valid_by_and_but_may_be_poison(ptr %q, i8 zeroext %s, i32 %idx) {
416; CHECK-LABEL: @insert_store_nonconst_index_known_valid_by_and_but_may_be_poison(
417; CHECK-NEXT:  entry:
418; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i32 [[IDX:%.*]]
419; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX_FROZEN]], 7
420; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
421; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
422; CHECK-NEXT:    ret void
423;
424entry:
425  %0 = load <16 x i8>, ptr %q
426  %idx.clamped = and i32 %idx, 7
427  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
428  store <16 x i8> %vecins, ptr %q
429  ret void
430}
431
432define void @insert_store_nonconst_index_not_known_valid_by_and(ptr %q, i8 zeroext %s, i32 %idx) {
433; CHECK-LABEL: @insert_store_nonconst_index_not_known_valid_by_and(
434; CHECK-NEXT:  entry:
435; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
436; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX:%.*]], 16
437; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX_CLAMPED]]
438; CHECK-NEXT:    store <16 x i8> [[VECINS]], ptr [[Q]], align 16
439; CHECK-NEXT:    ret void
440;
441entry:
442  %0 = load <16 x i8>, ptr %q
443  %idx.clamped = and i32 %idx, 16
444  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
445  store <16 x i8> %vecins, ptr %q
446  ret void
447}
448
449define void @insert_store_nonconst_index_known_noundef_not_known_valid_by_and(ptr %q, i8 zeroext %s, i32 noundef %idx) {
450; CHECK-LABEL: @insert_store_nonconst_index_known_noundef_not_known_valid_by_and(
451; CHECK-NEXT:  entry:
452; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
453; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX:%.*]], 16
454; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX_CLAMPED]]
455; CHECK-NEXT:    store <16 x i8> [[VECINS]], ptr [[Q]], align 16
456; CHECK-NEXT:    ret void
457;
458entry:
459  %0 = load <16 x i8>, ptr %q
460  %idx.clamped = and i32 %idx, 16
461  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
462  store <16 x i8> %vecins, ptr %q
463  ret void
464}
465
466; To verify the index is not a constant and may not be valid by and,
467; for scalable vector types.
468define void @insert_store_vscale_nonconst_index_not_known_valid_by_and(ptr %q, i8 zeroext %s, i32 %idx) {
469; CHECK-LABEL: @insert_store_vscale_nonconst_index_not_known_valid_by_and(
470; CHECK-NEXT:  entry:
471; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 16 x i8>, ptr [[Q:%.*]], align 16
472; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX:%.*]], 31
473; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <vscale x 16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX_CLAMPED]]
474; CHECK-NEXT:    store <vscale x 16 x i8> [[VECINS]], ptr [[Q]], align 16
475; CHECK-NEXT:    ret void
476;
477entry:
478  %0 = load <vscale x 16 x i8>, ptr %q
479  %idx.clamped = and i32 %idx, 31
480  %vecins = insertelement <vscale x 16 x i8> %0, i8 %s, i32 %idx.clamped
481  store <vscale x 16 x i8> %vecins, ptr %q
482  ret void
483}
484
485define void @insert_store_nonconst_index_known_noundef_and_valid_by_urem(ptr %q, i8 zeroext %s, i32 noundef %idx) {
486; CHECK-LABEL: @insert_store_nonconst_index_known_noundef_and_valid_by_urem(
487; CHECK-NEXT:  entry:
488; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX:%.*]], 16
489; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
490; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
491; CHECK-NEXT:    ret void
492;
493entry:
494  %0 = load <16 x i8>, ptr %q
495  %idx.clamped = urem i32 %idx, 16
496  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
497  store <16 x i8> %vecins, ptr %q
498  ret void
499}
500
501; To verify the index is not a constant but valid by urem,
502; for scalable vector types.
503define void @insert_store_vscale_nonconst_index_known_noundef_and_valid_by_urem(ptr %q, i8 zeroext %s, i32 noundef %idx) {
504; CHECK-LABEL: @insert_store_vscale_nonconst_index_known_noundef_and_valid_by_urem(
505; CHECK-NEXT:  entry:
506; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX:%.*]], 16
507; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
508; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
509; CHECK-NEXT:    ret void
510;
511entry:
512  %0 = load <vscale x 16 x i8>, ptr %q
513  %idx.clamped = urem i32 %idx, 16
514  %vecins = insertelement <vscale x 16 x i8> %0, i8 %s, i32 %idx.clamped
515  store <vscale x 16 x i8> %vecins, ptr %q
516  ret void
517}
518
519define void @insert_store_nonconst_index_base_frozen_and_valid_by_urem(ptr %q, i8 zeroext %s, i32 %idx) {
520; CHECK-LABEL: @insert_store_nonconst_index_base_frozen_and_valid_by_urem(
521; CHECK-NEXT:  entry:
522; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i32 [[IDX:%.*]]
523; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX_FROZEN]], 16
524; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
525; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
526; CHECK-NEXT:    ret void
527;
528entry:
529  %0 = load <16 x i8>, ptr %q
530  %idx.frozen = freeze i32 %idx
531  %idx.clamped = urem i32 %idx.frozen, 16
532  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
533  store <16 x i8> %vecins, ptr %q
534  ret void
535}
536
537define void @insert_store_nonconst_index_frozen_and_valid_by_urem(ptr %q, i8 zeroext %s, i32 %idx) {
538; CHECK-LABEL: @insert_store_nonconst_index_frozen_and_valid_by_urem(
539; CHECK-NEXT:  entry:
540; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
541; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX:%.*]], 16
542; CHECK-NEXT:    [[IDX_CLAMPED_FROZEN:%.*]] = freeze i32 [[IDX_CLAMPED]]
543; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX_CLAMPED_FROZEN]]
544; CHECK-NEXT:    store <16 x i8> [[VECINS]], ptr [[Q]], align 16
545; CHECK-NEXT:    ret void
546;
547entry:
548  %0 = load <16 x i8>, ptr %q
549  %idx.clamped = urem i32 %idx, 16
550  %idx.clamped.frozen = freeze i32 %idx.clamped
551  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped.frozen
552  store <16 x i8> %vecins, ptr %q
553  ret void
554}
555
556define void @insert_store_nonconst_index_known_valid_by_urem_but_may_be_poison(ptr %q, i8 zeroext %s, i32 %idx) {
557; CHECK-LABEL: @insert_store_nonconst_index_known_valid_by_urem_but_may_be_poison(
558; CHECK-NEXT:  entry:
559; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i32 [[IDX:%.*]]
560; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX_FROZEN]], 16
561; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
562; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
563; CHECK-NEXT:    ret void
564;
565entry:
566  %0 = load <16 x i8>, ptr %q
567  %idx.clamped = urem i32 %idx, 16
568  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
569  store <16 x i8> %vecins, ptr %q
570  ret void
571}
572
573define void @insert_store_nonconst_index_not_known_valid_by_urem(ptr %q, i8 zeroext %s, i32 %idx) {
574; CHECK-LABEL: @insert_store_nonconst_index_not_known_valid_by_urem(
575; CHECK-NEXT:  entry:
576; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
577; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX:%.*]], 17
578; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX_CLAMPED]]
579; CHECK-NEXT:    store <16 x i8> [[VECINS]], ptr [[Q]], align 16
580; CHECK-NEXT:    ret void
581;
582entry:
583  %0 = load <16 x i8>, ptr %q
584  %idx.clamped = urem i32 %idx, 17
585  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
586  store <16 x i8> %vecins, ptr %q
587  ret void
588}
589
590; To verify the index is not a constant and may not be vaild by urem,
591; for scalable vector types.
592define void @insert_store_vscale_nonconst_index_not_known_valid_by_urem(ptr %q, i8 zeroext %s, i32 %idx) {
593; CHECK-LABEL: @insert_store_vscale_nonconst_index_not_known_valid_by_urem(
594; CHECK-NEXT:  entry:
595; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 16 x i8>, ptr [[Q:%.*]], align 16
596; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX:%.*]], 17
597; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <vscale x 16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX_CLAMPED]]
598; CHECK-NEXT:    store <vscale x 16 x i8> [[VECINS]], ptr [[Q]], align 16
599; CHECK-NEXT:    ret void
600;
601entry:
602  %0 = load <vscale x 16 x i8>, ptr %q
603  %idx.clamped = urem i32 %idx, 17
604  %vecins = insertelement <vscale x 16 x i8> %0, i8 %s, i32 %idx.clamped
605  store <vscale x 16 x i8> %vecins, ptr %q
606  ret void
607}
608
609define void @insert_store_nonconst_index_known_noundef_not_known_valid_by_urem(ptr %q, i8 zeroext %s, i32 noundef %idx) {
610; CHECK-LABEL: @insert_store_nonconst_index_known_noundef_not_known_valid_by_urem(
611; CHECK-NEXT:  entry:
612; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
613; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX:%.*]], 17
614; CHECK-NEXT:    [[VECINS:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX_CLAMPED]]
615; CHECK-NEXT:    store <16 x i8> [[VECINS]], ptr [[Q]], align 16
616; CHECK-NEXT:    ret void
617;
618entry:
619  %0 = load <16 x i8>, ptr %q
620  %idx.clamped = urem i32 %idx, 17
621  %vecins = insertelement <16 x i8> %0, i8 %s, i32 %idx.clamped
622  store <16 x i8> %vecins, ptr %q
623  ret void
624}
625
626define void @insert_store_ptr_strip(ptr %q, i8 zeroext %s) {
627; CHECK-LABEL: @insert_store_ptr_strip(
628; CHECK-NEXT:  entry:
629; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 3
630; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
631; CHECK-NEXT:    ret void
632;
633entry:
634  %0 = load <16 x i8>, ptr %q
635  %vecins = insertelement <16 x i8> %0, i8 %s, i32 3
636  store <16 x i8> %vecins, ptr %q
637  ret void
638}
639
640define void @volatile_update(ptr %q, ptr %p, i8 zeroext %s) {
641; CHECK-LABEL: @volatile_update(
642; CHECK-NEXT:  entry:
643; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
644; CHECK-NEXT:    [[VECINS0:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 3
645; CHECK-NEXT:    store volatile <16 x i8> [[VECINS0]], ptr [[Q]], align 16
646; CHECK-NEXT:    [[TMP1:%.*]] = load volatile <16 x i8>, ptr [[P:%.*]], align 16
647; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <16 x i8> [[TMP1]], i8 [[S]], i32 1
648; CHECK-NEXT:    store <16 x i8> [[VECINS1]], ptr [[P]], align 16
649; CHECK-NEXT:    ret void
650;
651entry:
652  %0 = load <16 x i8>, ptr %q
653  %vecins0 = insertelement <16 x i8> %0, i8 %s, i32 3
654  store volatile <16 x i8> %vecins0, ptr %q
655
656  %1 = load volatile <16 x i8>, ptr %p
657  %vecins1 = insertelement <16 x i8> %1, i8 %s, i32 1
658  store <16 x i8> %vecins1, ptr %p
659  ret void
660}
661
662define void @insert_store_addr_differ(ptr %p, ptr %q, i8 %s) {
663; CHECK-LABEL: @insert_store_addr_differ(
664; CHECK-NEXT:  entry:
665; CHECK-NEXT:    [[LD:%.*]] = load <16 x i8>, ptr [[P:%.*]], align 16
666; CHECK-NEXT:    [[INS:%.*]] = insertelement <16 x i8> [[LD]], i8 [[S:%.*]], i32 3
667; CHECK-NEXT:    store <16 x i8> [[INS]], ptr [[Q:%.*]], align 16
668; CHECK-NEXT:    ret void
669;
670entry:
671  %ld = load <16 x i8>, ptr %p
672  %ins = insertelement <16 x i8> %ld, i8 %s, i32 3
673  store <16 x i8> %ins, ptr %q
674  ret void
675}
676
677; We can't transform if any instr could modify memory in between.
678define void @insert_store_mem_modify(ptr %p, ptr %q, ptr noalias %r, i8 %s, i32 %m) {
679; CHECK-LABEL: @insert_store_mem_modify(
680; CHECK-NEXT:  entry:
681; CHECK-NEXT:    [[LD:%.*]] = load <16 x i8>, ptr [[P:%.*]], align 16
682; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[Q:%.*]], align 16
683; CHECK-NEXT:    [[INS:%.*]] = insertelement <16 x i8> [[LD]], i8 [[S:%.*]], i32 3
684; CHECK-NEXT:    store <16 x i8> [[INS]], ptr [[P]], align 16
685; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[R:%.*]], align 16
686; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q]], i32 0, i32 7
687; CHECK-NEXT:    store i8 [[S]], ptr [[TMP0]], align 1
688; CHECK-NEXT:    [[LD3:%.*]] = load <4 x i32>, ptr [[P]], align 16
689; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[P]], align 16
690; CHECK-NEXT:    [[INS3:%.*]] = insertelement <4 x i32> [[LD3]], i32 [[M:%.*]], i32 0
691; CHECK-NEXT:    store <4 x i32> [[INS3]], ptr [[P]], align 16
692; CHECK-NEXT:    ret void
693;
694entry:
695  ; p may alias q
696  %ld = load <16 x i8>, ptr %p
697  store <16 x i8> zeroinitializer, ptr %q
698  %ins = insertelement <16 x i8> %ld, i8 %s, i32 3
699  store <16 x i8> %ins, ptr %p
700
701  ; p never aliases r
702  %ld2 = load <16 x i8>, ptr %q
703  store <16 x i8> zeroinitializer, ptr %r
704  %ins2 = insertelement <16 x i8> %ld2, i8 %s, i32 7
705  store <16 x i8> %ins2, ptr %q
706
707  ; p must alias ptr0
708  %ld3 = load <4 x i32>, ptr %p
709  store <16 x i8> zeroinitializer, ptr %p
710  %ins3 = insertelement <4 x i32> %ld3, i32 %m, i32 0
711  store <4 x i32> %ins3, ptr %p
712
713  ret void
714}
715
716; Check cases when calls may modify memory
717define void @insert_store_with_call(ptr %p, ptr %q, i8 %s) {
718; CHECK-LABEL: @insert_store_with_call(
719; CHECK-NEXT:  entry:
720; CHECK-NEXT:    [[LD:%.*]] = load <16 x i8>, ptr [[P:%.*]], align 16
721; CHECK-NEXT:    call void @maywrite(ptr [[P]])
722; CHECK-NEXT:    [[INS:%.*]] = insertelement <16 x i8> [[LD]], i8 [[S:%.*]], i32 3
723; CHECK-NEXT:    store <16 x i8> [[INS]], ptr [[P]], align 16
724; CHECK-NEXT:    call void @foo()
725; CHECK-NEXT:    call void @nowrite(ptr [[P]])
726; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[P]], i32 0, i32 7
727; CHECK-NEXT:    store i8 [[S]], ptr [[TMP0]], align 1
728; CHECK-NEXT:    ret void
729;
730entry:
731  %ld = load <16 x i8>, ptr %p
732  call void @maywrite(ptr %p)
733  %ins = insertelement <16 x i8> %ld, i8 %s, i32 3
734  store <16 x i8> %ins, ptr %p
735  call void @foo()  ; Barrier
736  %ld2 = load <16 x i8>, ptr %p
737  call void @nowrite(ptr %p)
738  %ins2 = insertelement <16 x i8> %ld2, i8 %s, i32 7
739  store <16 x i8> %ins2, ptr %p
740  ret void
741}
742
743declare void @foo()
744declare void @maywrite(ptr)
745declare void @nowrite(ptr) readonly
746
747; To test if number of instructions in-between exceeds the limit (default 30),
748; the combine will quit.
749define i32 @insert_store_maximum_scan_instrs(i32 %arg, ptr %arg1, ptr %arg2, i8 zeroext %arg3) {
750; CHECK-LABEL: @insert_store_maximum_scan_instrs(
751; CHECK-NEXT:  bb:
752; CHECK-NEXT:    [[I:%.*]] = or i32 [[ARG:%.*]], 1
753; CHECK-NEXT:    [[I4:%.*]] = load <16 x i8>, ptr [[ARG2:%.*]], align 16
754; CHECK-NEXT:    [[I5:%.*]] = tail call i32 @bar(i32 [[I]], i1 true)
755; CHECK-NEXT:    [[I6:%.*]] = shl i32 [[ARG]], [[I5]]
756; CHECK-NEXT:    [[I7:%.*]] = lshr i32 [[I6]], 26
757; CHECK-NEXT:    [[I8:%.*]] = trunc i32 [[I7]] to i8
758; CHECK-NEXT:    [[I9:%.*]] = and i8 [[I8]], 31
759; CHECK-NEXT:    [[I10:%.*]] = lshr i32 [[I6]], 11
760; CHECK-NEXT:    [[I11:%.*]] = and i32 [[I10]], 32767
761; CHECK-NEXT:    [[I12:%.*]] = zext i8 [[I9]] to i64
762; CHECK-NEXT:    [[I13:%.*]] = getelementptr inbounds i16, ptr [[ARG1:%.*]], i64 [[I12]]
763; CHECK-NEXT:    [[I14:%.*]] = load i16, ptr [[I13]], align 2
764; CHECK-NEXT:    [[I15:%.*]] = zext i16 [[I14]] to i32
765; CHECK-NEXT:    [[I16:%.*]] = add nuw nsw i8 [[I9]], 1
766; CHECK-NEXT:    [[I17:%.*]] = zext i8 [[I16]] to i64
767; CHECK-NEXT:    [[I18:%.*]] = getelementptr inbounds i16, ptr [[ARG1]], i64 [[I17]]
768; CHECK-NEXT:    [[I19:%.*]] = load i16, ptr [[I18]], align 2
769; CHECK-NEXT:    [[I20:%.*]] = zext i16 [[I19]] to i32
770; CHECK-NEXT:    [[I21:%.*]] = sub nsw i32 [[I20]], [[I15]]
771; CHECK-NEXT:    [[I22:%.*]] = mul nsw i32 [[I11]], [[I21]]
772; CHECK-NEXT:    [[I23:%.*]] = ashr i32 [[I22]], 15
773; CHECK-NEXT:    [[I24:%.*]] = shl nuw nsw i32 [[I5]], 15
774; CHECK-NEXT:    [[I25:%.*]] = xor i32 [[I24]], 1015808
775; CHECK-NEXT:    [[I26:%.*]] = add nuw nsw i32 [[I25]], [[I15]]
776; CHECK-NEXT:    [[I27:%.*]] = add nsw i32 [[I26]], [[I23]]
777; CHECK-NEXT:    [[I28:%.*]] = sitofp i32 [[ARG]] to double
778; CHECK-NEXT:    [[I29:%.*]] = tail call double @llvm.log2.f64(double [[I28]])
779; CHECK-NEXT:    [[I30:%.*]] = fptosi double [[I29]] to i32
780; CHECK-NEXT:    [[I31:%.*]] = shl nsw i32 [[I30]], 15
781; CHECK-NEXT:    [[I32:%.*]] = or i32 [[I31]], 4
782; CHECK-NEXT:    [[I33:%.*]] = icmp eq i32 [[I27]], [[I32]]
783; CHECK-NEXT:    [[I34:%.*]] = select i1 [[I33]], i32 [[ARG]], i32 [[I31]]
784; CHECK-NEXT:    [[I35:%.*]] = lshr i32 [[I34]], 1
785; CHECK-NEXT:    [[I36:%.*]] = insertelement <16 x i8> [[I4]], i8 [[ARG3:%.*]], i32 3
786; CHECK-NEXT:    store <16 x i8> [[I36]], ptr [[ARG2]], align 16
787; CHECK-NEXT:    ret i32 [[I35]]
788;
789bb:
790  %i = or i32 %arg, 1
791  %i4 = load <16 x i8>, ptr %arg2, align 16
792  %i5 = tail call i32 @bar(i32 %i, i1 true)
793  %i6 = shl i32 %arg, %i5
794  %i7 = lshr i32 %i6, 26
795  %i8 = trunc i32 %i7 to i8
796  %i9 = and i8 %i8, 31
797  %i10 = lshr i32 %i6, 11
798  %i11 = and i32 %i10, 32767
799  %i12 = zext i8 %i9 to i64
800  %i13 = getelementptr inbounds i16, ptr %arg1, i64 %i12
801  %i14 = load i16, ptr %i13, align 2
802  %i15 = zext i16 %i14 to i32
803  %i16 = add nuw nsw i8 %i9, 1
804  %i17 = zext i8 %i16 to i64
805  %i18 = getelementptr inbounds i16, ptr %arg1, i64 %i17
806  %i19 = load i16, ptr %i18, align 2
807  %i20 = zext i16 %i19 to i32
808  %i21 = sub nsw i32 %i20, %i15
809  %i22 = mul nsw i32 %i11, %i21
810  %i23 = ashr i32 %i22, 15
811  %i24 = shl nuw nsw i32 %i5, 15
812  %i25 = xor i32 %i24, 1015808
813  %i26 = add nuw nsw i32 %i25, %i15
814  %i27 = add nsw i32 %i26, %i23
815  %i28 = sitofp i32 %arg to double
816  %i29 = tail call double @llvm.log2.f64(double %i28)
817  %i30 = fptosi double %i29 to i32
818  %i31 = shl nsw i32 %i30, 15
819  %i32 = or i32 %i31, 4
820  %i33 = icmp eq i32 %i27, %i32
821  %i34 = select i1 %i33, i32 %arg, i32 %i31
822  %i35 = lshr i32 %i34, 1
823  %i36 = insertelement <16 x i8> %i4, i8 %arg3, i32 3
824  store <16 x i8> %i36, ptr %arg2, align 16
825  ret i32 %i35
826}
827
828declare i32 @bar(i32, i1) readonly
829declare double @llvm.log2.f64(double)
830