1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -vector-combine -mtriple=arm64-apple-darwinos -S %s | FileCheck --check-prefixes=CHECK,LIMIT-DEFAULT %s
3; RUN: opt -vector-combine -enable-new-pm=false -mtriple=arm64-apple-darwinos -S %s | FileCheck --check-prefixes=CHECK,LIMIT-DEFAULT %s
4; RUN: opt -vector-combine -mtriple=arm64-apple-darwinos -vector-combine-max-scan-instrs=2 -S %s | FileCheck --check-prefixes=CHECK,LIMIT2 %s
5
6define i32 @load_extract_idx_0(<4 x i32>* %x) {
7; CHECK-LABEL: @load_extract_idx_0(
8; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 3
9; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
10; CHECK-NEXT:    ret i32 [[R]]
11;
12  %lv = load <4 x i32>, <4 x i32>* %x
13  %r = extractelement <4 x i32> %lv, i32 3
14  ret i32 %r
15}
16
17; If the original load had a smaller alignment than the scalar type, the
18; smaller alignment should be used.
19define i32 @load_extract_idx_0_small_alignment(<4 x i32>* %x) {
20; CHECK-LABEL: @load_extract_idx_0_small_alignment(
21; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 3
22; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 2
23; CHECK-NEXT:    ret i32 [[R]]
24;
25  %lv = load <4 x i32>, <4 x i32>* %x, align 2
26  %r = extractelement <4 x i32> %lv, i32 3
27  ret i32 %r
28}
29
30define i32 @load_extract_idx_1(<4 x i32>* %x) {
31; CHECK-LABEL: @load_extract_idx_1(
32; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 1
33; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
34; CHECK-NEXT:    ret i32 [[R]]
35;
36  %lv = load <4 x i32>, <4 x i32>* %x
37  %r = extractelement <4 x i32> %lv, i32 1
38  ret i32 %r
39}
40
41define i32 @load_extract_idx_2(<4 x i32>* %x) {
42; CHECK-LABEL: @load_extract_idx_2(
43; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2
44; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
45; CHECK-NEXT:    ret i32 [[R]]
46;
47  %lv = load <4 x i32>, <4 x i32>* %x
48  %r = extractelement <4 x i32> %lv, i32 2
49  ret i32 %r
50}
51
52define i32 @load_extract_idx_3(<4 x i32>* %x) {
53; CHECK-LABEL: @load_extract_idx_3(
54; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 3
55; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
56; CHECK-NEXT:    ret i32 [[R]]
57;
58  %lv = load <4 x i32>, <4 x i32>* %x
59  %r = extractelement <4 x i32> %lv, i32 3
60  ret i32 %r
61}
62
63; Out-of-bounds index for extractelement, should not be converted to narrow
64; load, because it would introduce a dereference of a poison pointer.
65define i32 @load_extract_idx_4(<4 x i32>* %x) {
66; CHECK-LABEL: @load_extract_idx_4(
67; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
68; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 4
69; CHECK-NEXT:    ret i32 [[R]]
70;
71  %lv = load <4 x i32>, <4 x i32>* %x
72  %r = extractelement <4 x i32> %lv, i32 4
73  ret i32 %r
74}
75
76define i32 @load_extract_idx_var_i64(<4 x i32>* %x, i64 %idx) {
77; CHECK-LABEL: @load_extract_idx_var_i64(
78; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
79; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX:%.*]]
80; CHECK-NEXT:    ret i32 [[R]]
81;
82  %lv = load <4 x i32>, <4 x i32>* %x
83  %r = extractelement <4 x i32> %lv, i64 %idx
84  ret i32 %r
85}
86
87declare void @maythrow() readnone
88
89define i32 @load_extract_idx_var_i64_known_valid_by_assume(<4 x i32>* %x, i64 %idx) {
90; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_assume(
91; CHECK-NEXT:  entry:
92; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4
93; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
94; CHECK-NEXT:    call void @maythrow()
95; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX]]
96; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP0]], align 4
97; CHECK-NEXT:    ret i32 [[R]]
98;
99entry:
100  %cmp = icmp ult i64 %idx, 4
101  call void @llvm.assume(i1 %cmp)
102  %lv = load <4 x i32>, <4 x i32>* %x
103  call void @maythrow()
104  %r = extractelement <4 x i32> %lv, i64 %idx
105  ret i32 %r
106}
107
108define i32 @load_extract_idx_var_i64_not_known_valid_by_assume_after_load(<4 x i32>* %x, i64 %idx) {
109; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume_after_load(
110; CHECK-NEXT:  entry:
111; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4
112; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
113; CHECK-NEXT:    call void @maythrow()
114; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
115; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]]
116; CHECK-NEXT:    ret i32 [[R]]
117;
118entry:
119  %cmp = icmp ult i64 %idx, 4
120  %lv = load <4 x i32>, <4 x i32>* %x
121  call void @maythrow()
122  call void @llvm.assume(i1 %cmp)
123  %r = extractelement <4 x i32> %lv, i64 %idx
124  ret i32 %r
125}
126
127define i32 @load_extract_idx_var_i64_not_known_valid_by_assume(<4 x i32>* %x, i64 %idx) {
128; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume(
129; CHECK-NEXT:  entry:
130; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 5
131; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
132; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
133; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]]
134; CHECK-NEXT:    ret i32 [[R]]
135;
136entry:
137  %cmp = icmp ult i64 %idx, 5
138  call void @llvm.assume(i1 %cmp)
139  %lv = load <4 x i32>, <4 x i32>* %x
140  %r = extractelement <4 x i32> %lv, i64 %idx
141  ret i32 %r
142}
143
144declare void @llvm.assume(i1)
145
146define i32 @load_extract_idx_var_i64_known_valid_by_and(<4 x i32>* %x, i64 %idx) {
147; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_and(
148; CHECK-NEXT:  entry:
149; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 3
150; CHECK-NEXT:    [[TMP0:%.*]] = freeze i64 [[IDX_CLAMPED]]
151; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[TMP0]]
152; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
153; CHECK-NEXT:    ret i32 [[R]]
154;
155entry:
156  %idx.clamped = and i64 %idx, 3
157  %lv = load <4 x i32>, <4 x i32>* %x
158  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
159  ret i32 %r
160}
161
162define i32 @load_extract_idx_var_i64_known_valid_by_and_noundef(<4 x i32>* %x, i64 noundef %idx) {
163; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_and_noundef(
164; CHECK-NEXT:  entry:
165; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 3
166; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
167; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP0]], align 4
168; CHECK-NEXT:    ret i32 [[R]]
169;
170entry:
171  %idx.clamped = and i64 %idx, 3
172  %lv = load <4 x i32>, <4 x i32>* %x
173  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
174  ret i32 %r
175}
176
177define i32 @load_extract_idx_var_i64_not_known_valid_by_and(<4 x i32>* %x, i64 %idx) {
178; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_and(
179; CHECK-NEXT:  entry:
180; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 4
181; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
182; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]]
183; CHECK-NEXT:    ret i32 [[R]]
184;
185entry:
186  %idx.clamped = and i64 %idx, 4
187  %lv = load <4 x i32>, <4 x i32>* %x
188  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
189  ret i32 %r
190}
191
192define i32 @load_extract_idx_var_i64_known_valid_by_urem(<4 x i32>* %x, i64 %idx) {
193; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_urem(
194; CHECK-NEXT:  entry:
195; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 4
196; CHECK-NEXT:    [[TMP0:%.*]] = freeze i64 [[IDX_CLAMPED]]
197; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[TMP0]]
198; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
199; CHECK-NEXT:    ret i32 [[R]]
200;
201entry:
202  %idx.clamped = urem i64 %idx, 4
203  %lv = load <4 x i32>, <4 x i32>* %x
204  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
205  ret i32 %r
206}
207
208define i32 @load_extract_idx_var_i64_known_valid_by_urem_noundef(<4 x i32>* %x, i64 noundef %idx) {
209; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_urem_noundef(
210; CHECK-NEXT:  entry:
211; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 4
212; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
213; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP0]], align 4
214; CHECK-NEXT:    ret i32 [[R]]
215;
216entry:
217  %idx.clamped = urem i64 %idx, 4
218  %lv = load <4 x i32>, <4 x i32>* %x
219  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
220  ret i32 %r
221}
222
223define i32 @load_extract_idx_var_i64_not_known_valid_by_urem(<4 x i32>* %x, i64 %idx) {
224; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_urem(
225; CHECK-NEXT:  entry:
226; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 5
227; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
228; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]]
229; CHECK-NEXT:    ret i32 [[R]]
230;
231entry:
232  %idx.clamped = urem i64 %idx, 5
233  %lv = load <4 x i32>, <4 x i32>* %x
234  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
235  ret i32 %r
236}
237
238define i32 @load_extract_idx_var_i32(<4 x i32>* %x, i32 %idx) {
239; CHECK-LABEL: @load_extract_idx_var_i32(
240; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
241; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 [[IDX:%.*]]
242; CHECK-NEXT:    ret i32 [[R]]
243;
244  %lv = load <4 x i32>, <4 x i32>* %x
245  %r = extractelement <4 x i32> %lv, i32 %idx
246  ret i32 %r
247}
248
249declare void @clobber()
250
251define i32 @load_extract_clobber_call_before(<4 x i32>* %x) {
252; CHECK-LABEL: @load_extract_clobber_call_before(
253; CHECK-NEXT:    call void @clobber()
254; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2
255; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
256; CHECK-NEXT:    ret i32 [[R]]
257;
258  call void @clobber()
259  %lv = load <4 x i32>, <4 x i32>* %x
260  %r = extractelement <4 x i32> %lv, i32 2
261  ret i32 %r
262}
263
264define i32 @load_extract_clobber_call_between(<4 x i32>* %x) {
265; CHECK-LABEL: @load_extract_clobber_call_between(
266; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
267; CHECK-NEXT:    call void @clobber()
268; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
269; CHECK-NEXT:    ret i32 [[R]]
270;
271  %lv = load <4 x i32>, <4 x i32>* %x
272  call void @clobber()
273  %r = extractelement <4 x i32> %lv, i32 2
274  ret i32 %r
275}
276
277define i32 @load_extract_clobber_call_after(<4 x i32>* %x) {
278; CHECK-LABEL: @load_extract_clobber_call_after(
279; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2
280; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
281; CHECK-NEXT:    call void @clobber()
282; CHECK-NEXT:    ret i32 [[R]]
283;
284  %lv = load <4 x i32>, <4 x i32>* %x
285  %r = extractelement <4 x i32> %lv, i32 2
286  call void @clobber()
287  ret i32 %r
288}
289
290define i32 @load_extract_clobber_store_before(<4 x i32>* %x, i8* %y) {
291; CHECK-LABEL: @load_extract_clobber_store_before(
292; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
293; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2
294; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
295; CHECK-NEXT:    ret i32 [[R]]
296;
297  store i8 0, i8* %y
298  %lv = load <4 x i32>, <4 x i32>* %x
299  %r = extractelement <4 x i32> %lv, i32 2
300  ret i32 %r
301}
302
303define i32 @load_extract_clobber_store_between(<4 x i32>* %x, i8* %y) {
304; CHECK-LABEL: @load_extract_clobber_store_between(
305; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
306; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
307; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
308; CHECK-NEXT:    ret i32 [[R]]
309;
310  %lv = load <4 x i32>, <4 x i32>* %x
311  store i8 0, i8* %y
312  %r = extractelement <4 x i32> %lv, i32 2
313  ret i32 %r
314}
315
316define i32 @load_extract_clobber_store_between_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) {
317; CHECK-LABEL: @load_extract_clobber_store_between_limit(
318; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
319; CHECK-NEXT:    [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0
320; CHECK-NEXT:    [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1
321; CHECK-NEXT:    [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]]
322; CHECK-NEXT:    [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2
323; CHECK-NEXT:    [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]]
324; CHECK-NEXT:    [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3
325; CHECK-NEXT:    [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]]
326; CHECK-NEXT:    [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4
327; CHECK-NEXT:    [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]]
328; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
329; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
330; CHECK-NEXT:    [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]]
331; CHECK-NEXT:    ret i32 [[ADD_4]]
332;
333  %lv = load <4 x i32>, <4 x i32>* %x
334  %z.0 = extractelement <8 x i32> %z, i32 0
335  %z.1 = extractelement <8 x i32> %z, i32 1
336  %add.0 = add i32 %z.0, %z.1
337  %z.2 = extractelement <8 x i32> %z, i32 2
338  %add.1 = add i32 %add.0, %z.2
339  %z.3 = extractelement <8 x i32> %z, i32 3
340  %add.2 = add i32 %add.1, %z.3
341  %z.4 = extractelement <8 x i32> %z, i32 4
342  %add.3 = add i32 %add.2, %z.4
343  store i8 0, i8* %y
344  %r = extractelement <4 x i32> %lv, i32 2
345  %add.4 = add i32 %add.3, %r
346  ret i32 %add.4
347}
348
349define i32 @load_extract_clobber_store_after_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) {
350; LIMIT-DEFAULT-LABEL: @load_extract_clobber_store_after_limit(
351; LIMIT-DEFAULT-NEXT:    [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0
352; LIMIT-DEFAULT-NEXT:    [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1
353; LIMIT-DEFAULT-NEXT:    [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]]
354; LIMIT-DEFAULT-NEXT:    [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2
355; LIMIT-DEFAULT-NEXT:    [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]]
356; LIMIT-DEFAULT-NEXT:    [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3
357; LIMIT-DEFAULT-NEXT:    [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]]
358; LIMIT-DEFAULT-NEXT:    [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4
359; LIMIT-DEFAULT-NEXT:    [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]]
360; LIMIT-DEFAULT-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2
361; LIMIT-DEFAULT-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 4
362; LIMIT-DEFAULT-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
363; LIMIT-DEFAULT-NEXT:    [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]]
364; LIMIT-DEFAULT-NEXT:    ret i32 [[ADD_4]]
365;
366; LIMIT2-LABEL: @load_extract_clobber_store_after_limit(
367; LIMIT2-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
368; LIMIT2-NEXT:    [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0
369; LIMIT2-NEXT:    [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1
370; LIMIT2-NEXT:    [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]]
371; LIMIT2-NEXT:    [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2
372; LIMIT2-NEXT:    [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]]
373; LIMIT2-NEXT:    [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3
374; LIMIT2-NEXT:    [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]]
375; LIMIT2-NEXT:    [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4
376; LIMIT2-NEXT:    [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]]
377; LIMIT2-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
378; LIMIT2-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
379; LIMIT2-NEXT:    [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]]
380; LIMIT2-NEXT:    ret i32 [[ADD_4]]
381;
382  %lv = load <4 x i32>, <4 x i32>* %x
383  %z.0 = extractelement <8 x i32> %z, i32 0
384  %z.1 = extractelement <8 x i32> %z, i32 1
385  %add.0 = add i32 %z.0, %z.1
386  %z.2 = extractelement <8 x i32> %z, i32 2
387  %add.1 = add i32 %add.0, %z.2
388  %z.3 = extractelement <8 x i32> %z, i32 3
389  %add.2 = add i32 %add.1, %z.3
390  %z.4 = extractelement <8 x i32> %z, i32 4
391  %add.3 = add i32 %add.2, %z.4
392  %r = extractelement <4 x i32> %lv, i32 2
393  store i8 0, i8* %y
394  %add.4 = add i32 %add.3, %r
395  ret i32 %add.4
396}
397
398declare void @use.v4i32(<4 x i32>)
399
400define i32 @load_extract_idx_different_bbs(<4 x i32>* %x, i1 %c) {
401; CHECK-LABEL: @load_extract_idx_different_bbs(
402; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
403; CHECK-NEXT:    br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
404; CHECK:       then:
405; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 1
406; CHECK-NEXT:    ret i32 [[R]]
407; CHECK:       else:
408; CHECK-NEXT:    call void @use.v4i32(<4 x i32> [[LV]])
409; CHECK-NEXT:    ret i32 20
410;
411  %lv = load <4 x i32>, <4 x i32>* %x
412  br i1 %c, label %then, label %else
413
414then:
415  %r = extractelement <4 x i32> %lv, i32 1
416  ret i32 %r
417
418else:
419  call void @use.v4i32(<4 x i32> %lv)
420  ret i32 20
421}
422
423define i31 @load_with_non_power_of_2_element_type(<4 x i31>* %x) {
424; CHECK-LABEL: @load_with_non_power_of_2_element_type(
425; CHECK-NEXT:    [[LV:%.*]] = load <4 x i31>, <4 x i31>* [[X:%.*]], align 16
426; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i31> [[LV]], i32 1
427; CHECK-NEXT:    ret i31 [[R]]
428;
429  %lv = load <4 x i31>, <4 x i31>* %x
430  %r = extractelement <4 x i31> %lv, i32 1
431  ret i31 %r
432}
433
434; Scalarizing the load for multiple constant indices may not be profitable.
435define i32 @load_multiple_extracts_with_constant_idx(<4 x i32>* %x) {
436; CHECK-LABEL: @load_multiple_extracts_with_constant_idx(
437; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
438; CHECK-NEXT:    [[SHIFT:%.*]] = shufflevector <4 x i32> [[LV]], <4 x i32> poison, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef>
439; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[LV]], [[SHIFT]]
440; CHECK-NEXT:    [[RES:%.*]] = extractelement <4 x i32> [[TMP1]], i32 0
441; CHECK-NEXT:    ret i32 [[RES]]
442;
443  %lv = load <4 x i32>, <4 x i32>* %x
444  %e.0 = extractelement <4 x i32> %lv, i32 0
445  %e.1 = extractelement <4 x i32> %lv, i32 1
446  %res = add i32 %e.0, %e.1
447  ret i32 %res
448}
449
450; Scalarizing the load for multiple extracts is profitable in this case,
451; because the vector large vector requires 2 vector registers.
452define i32 @load_multiple_extracts_with_constant_idx_profitable(<8 x i32>* %x) {
453; CHECK-LABEL: @load_multiple_extracts_with_constant_idx_profitable(
454; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i32>, <8 x i32>* [[X:%.*]], i32 0, i32 0
455; CHECK-NEXT:    [[E_0:%.*]] = load i32, i32* [[TMP1]], align 16
456; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i32>, <8 x i32>* [[X]], i32 0, i32 6
457; CHECK-NEXT:    [[E_1:%.*]] = load i32, i32* [[TMP2]], align 4
458; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
459; CHECK-NEXT:    ret i32 [[RES]]
460;
461  %lv = load <8 x i32>, <8 x i32>* %x, align 16
462  %e.0 = extractelement <8 x i32> %lv, i32 0
463  %e.1 = extractelement <8 x i32> %lv, i32 6
464  %res = add i32 %e.0, %e.1
465  ret i32 %res
466}
467
468; Scalarizing may or may not be profitable, depending on the target.
469define i32 @load_multiple_2_with_variable_indices(<4 x i32>* %x, i64 %idx.0, i64 %idx.1) {
470; CHECK-LABEL: @load_multiple_2_with_variable_indices(
471; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
472; CHECK-NEXT:    [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]]
473; CHECK-NEXT:    [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]]
474; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
475; CHECK-NEXT:    ret i32 [[RES]]
476;
477  %lv = load <4 x i32>, <4 x i32>* %x
478  %e.0 = extractelement <4 x i32> %lv, i64 %idx.0
479  %e.1 = extractelement <4 x i32> %lv, i64 %idx.1
480  %res = add i32 %e.0, %e.1
481  ret i32 %res
482}
483
484define i32 @load_4_extracts_with_variable_indices_short_vector(<4 x i32>* %x, i64 %idx.0, i64 %idx.1, i64 %idx.2, i64 %idx.3) {
485; CHECK-LABEL: @load_4_extracts_with_variable_indices_short_vector(
486; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
487; CHECK-NEXT:    [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]]
488; CHECK-NEXT:    [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]]
489; CHECK-NEXT:    [[E_2:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_2:%.*]]
490; CHECK-NEXT:    [[E_3:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_3:%.*]]
491; CHECK-NEXT:    [[RES_0:%.*]] = add i32 [[E_0]], [[E_1]]
492; CHECK-NEXT:    [[RES_1:%.*]] = add i32 [[RES_0]], [[E_2]]
493; CHECK-NEXT:    [[RES_2:%.*]] = add i32 [[RES_1]], [[E_3]]
494; CHECK-NEXT:    ret i32 [[RES_2]]
495;
496  %lv = load <4 x i32>, <4 x i32>* %x
497  %e.0 = extractelement <4 x i32> %lv, i64 %idx.0
498  %e.1 = extractelement <4 x i32> %lv, i64 %idx.1
499  %e.2 = extractelement <4 x i32> %lv, i64 %idx.2
500  %e.3 = extractelement <4 x i32> %lv, i64 %idx.3
501  %res.0 = add i32 %e.0, %e.1
502  %res.1 = add i32 %res.0, %e.2
503  %res.2 = add i32 %res.1, %e.3
504  ret i32 %res.2
505}
506
507define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) {
508; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid(
509; CHECK-NEXT:    [[CMP_IDX_0:%.*]] = icmp ult i64 [[IDX_0:%.*]], 16
510; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_0]])
511; CHECK-NEXT:    [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64
512; CHECK-NEXT:    [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0]]
513; CHECK-NEXT:    [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]]
514; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
515; CHECK-NEXT:    ret i32 [[RES]]
516;
517  %cmp.idx.0 = icmp ult i64 %idx.0, 16
518  call void @llvm.assume(i1 %cmp.idx.0)
519
520  %lv = load <16 x i32>, <16 x i32>* %x
521  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0
522  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1
523  %res = add i32 %e.0, %e.1
524  ret i32 %res
525}
526
527define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_all_valid(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) {
528; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_all_valid(
529; CHECK-NEXT:    [[CMP_IDX_0:%.*]] = icmp ult i64 [[IDX_0:%.*]], 16
530; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_0]])
531; CHECK-NEXT:    [[CMP_IDX_1:%.*]] = icmp ult i64 [[IDX_1:%.*]], 16
532; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_1]])
533; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X:%.*]], i32 0, i64 [[IDX_0]]
534; CHECK-NEXT:    [[E_0:%.*]] = load i32, i32* [[TMP1]], align 4
535; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X]], i32 0, i64 [[IDX_1]]
536; CHECK-NEXT:    [[E_1:%.*]] = load i32, i32* [[TMP2]], align 4
537; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
538; CHECK-NEXT:    ret i32 [[RES]]
539;
540  %cmp.idx.0 = icmp ult i64 %idx.0, 16
541  call void @llvm.assume(i1 %cmp.idx.0)
542  %cmp.idx.1 = icmp ult i64 %idx.1, 16
543  call void @llvm.assume(i1 %cmp.idx.1)
544
545  %lv = load <16 x i32>, <16 x i32>* %x
546  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0
547  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1
548  %res = add i32 %e.0, %e.1
549  ret i32 %res
550}
551
552define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid_by_and(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) {
553; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid_by_and(
554; CHECK-NEXT:    [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15
555; CHECK-NEXT:    [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64
556; CHECK-NEXT:    [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]]
557; CHECK-NEXT:    [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]]
558; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
559; CHECK-NEXT:    ret i32 [[RES]]
560;
561  %idx.0.clamped = and i64 %idx.0, 15
562
563  %lv = load <16 x i32>, <16 x i32>* %x
564  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped
565  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1
566  %res = add i32 %e.0, %e.1
567  ret i32 %res
568}
569
570define i32 @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) {
571; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and(
572; CHECK-NEXT:    [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15
573; CHECK-NEXT:    [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1:%.*]], 15
574; CHECK-NEXT:    [[TMP1:%.*]] = freeze i64 [[IDX_0_CLAMPED]]
575; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X:%.*]], i32 0, i64 [[TMP1]]
576; CHECK-NEXT:    [[E_0:%.*]] = load i32, i32* [[TMP2]], align 4
577; CHECK-NEXT:    [[TMP3:%.*]] = freeze i64 [[IDX_1_CLAMPED]]
578; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X]], i32 0, i64 [[TMP3]]
579; CHECK-NEXT:    [[E_1:%.*]] = load i32, i32* [[TMP4]], align 4
580; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
581; CHECK-NEXT:    ret i32 [[RES]]
582;
583  %idx.0.clamped = and i64 %idx.0, 15
584  %idx.1.clamped = and i64 %idx.1, 15
585
586  %lv = load <16 x i32>, <16 x i32>* %x
587  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped
588  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1.clamped
589  %res = add i32 %e.0, %e.1
590  ret i32 %res
591}
592
593define i32 @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and_some_noundef(<16 x i32>* %x, i64 %idx.0, i64 noundef %idx.1) {
594; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and_some_noundef(
595; CHECK-NEXT:    [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15
596; CHECK-NEXT:    [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1:%.*]], 15
597; CHECK-NEXT:    [[TMP1:%.*]] = freeze i64 [[IDX_0_CLAMPED]]
598; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X:%.*]], i32 0, i64 [[TMP1]]
599; CHECK-NEXT:    [[E_0:%.*]] = load i32, i32* [[TMP2]], align 4
600; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X]], i32 0, i64 [[IDX_1_CLAMPED]]
601; CHECK-NEXT:    [[E_1:%.*]] = load i32, i32* [[TMP3]], align 4
602; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
603; CHECK-NEXT:    ret i32 [[RES]]
604;
605  %idx.0.clamped = and i64 %idx.0, 15
606  %idx.1.clamped = and i64 %idx.1, 15
607
608  %lv = load <16 x i32>, <16 x i32>* %x
609  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped
610  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1.clamped
611  %res = add i32 %e.0, %e.1
612  ret i32 %res
613}
614