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 8
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:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
151; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]]
152; CHECK-NEXT:    ret i32 [[R]]
153;
154entry:
155  %idx.clamped = and i64 %idx, 3
156  %lv = load <4 x i32>, <4 x i32>* %x
157  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
158  ret i32 %r
159}
160
161define i32 @load_extract_idx_var_i64_known_valid_by_and_noundef(<4 x i32>* %x, i64 noundef %idx) {
162; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_and_noundef(
163; CHECK-NEXT:  entry:
164; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 3
165; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
166; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP0]], align 4
167; CHECK-NEXT:    ret i32 [[R]]
168;
169entry:
170  %idx.clamped = and i64 %idx, 3
171  %lv = load <4 x i32>, <4 x i32>* %x
172  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
173  ret i32 %r
174}
175
176define i32 @load_extract_idx_var_i64_not_known_valid_by_and(<4 x i32>* %x, i64 %idx) {
177; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_and(
178; CHECK-NEXT:  entry:
179; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 4
180; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
181; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]]
182; CHECK-NEXT:    ret i32 [[R]]
183;
184entry:
185  %idx.clamped = and i64 %idx, 4
186  %lv = load <4 x i32>, <4 x i32>* %x
187  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
188  ret i32 %r
189}
190
191define i32 @load_extract_idx_var_i64_known_valid_by_urem(<4 x i32>* %x, i64 %idx) {
192; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_urem(
193; CHECK-NEXT:  entry:
194; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 4
195; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
196; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]]
197; CHECK-NEXT:    ret i32 [[R]]
198;
199entry:
200  %idx.clamped = urem i64 %idx, 4
201  %lv = load <4 x i32>, <4 x i32>* %x
202  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
203  ret i32 %r
204}
205
206define i32 @load_extract_idx_var_i64_known_valid_by_urem_noundef(<4 x i32>* %x, i64 noundef %idx) {
207; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_urem_noundef(
208; CHECK-NEXT:  entry:
209; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 4
210; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
211; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP0]], align 4
212; CHECK-NEXT:    ret i32 [[R]]
213;
214entry:
215  %idx.clamped = urem i64 %idx, 4
216  %lv = load <4 x i32>, <4 x i32>* %x
217  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
218  ret i32 %r
219}
220
221define i32 @load_extract_idx_var_i64_not_known_valid_by_urem(<4 x i32>* %x, i64 %idx) {
222; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_urem(
223; CHECK-NEXT:  entry:
224; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 5
225; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
226; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_CLAMPED]]
227; CHECK-NEXT:    ret i32 [[R]]
228;
229entry:
230  %idx.clamped = urem i64 %idx, 5
231  %lv = load <4 x i32>, <4 x i32>* %x
232  %r = extractelement <4 x i32> %lv, i64 %idx.clamped
233  ret i32 %r
234}
235
236define i32 @load_extract_idx_var_i32(<4 x i32>* %x, i32 %idx) {
237; CHECK-LABEL: @load_extract_idx_var_i32(
238; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
239; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 [[IDX:%.*]]
240; CHECK-NEXT:    ret i32 [[R]]
241;
242  %lv = load <4 x i32>, <4 x i32>* %x
243  %r = extractelement <4 x i32> %lv, i32 %idx
244  ret i32 %r
245}
246
247declare void @clobber()
248
249define i32 @load_extract_clobber_call_before(<4 x i32>* %x) {
250; CHECK-LABEL: @load_extract_clobber_call_before(
251; CHECK-NEXT:    call void @clobber()
252; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2
253; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 8
254; CHECK-NEXT:    ret i32 [[R]]
255;
256  call void @clobber()
257  %lv = load <4 x i32>, <4 x i32>* %x
258  %r = extractelement <4 x i32> %lv, i32 2
259  ret i32 %r
260}
261
262define i32 @load_extract_clobber_call_between(<4 x i32>* %x) {
263; CHECK-LABEL: @load_extract_clobber_call_between(
264; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
265; CHECK-NEXT:    call void @clobber()
266; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
267; CHECK-NEXT:    ret i32 [[R]]
268;
269  %lv = load <4 x i32>, <4 x i32>* %x
270  call void @clobber()
271  %r = extractelement <4 x i32> %lv, i32 2
272  ret i32 %r
273}
274
275define i32 @load_extract_clobber_call_after(<4 x i32>* %x) {
276; CHECK-LABEL: @load_extract_clobber_call_after(
277; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2
278; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 8
279; CHECK-NEXT:    call void @clobber()
280; CHECK-NEXT:    ret i32 [[R]]
281;
282  %lv = load <4 x i32>, <4 x i32>* %x
283  %r = extractelement <4 x i32> %lv, i32 2
284  call void @clobber()
285  ret i32 %r
286}
287
288define i32 @load_extract_clobber_store_before(<4 x i32>* %x, i8* %y) {
289; CHECK-LABEL: @load_extract_clobber_store_before(
290; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
291; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2
292; CHECK-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 8
293; CHECK-NEXT:    ret i32 [[R]]
294;
295  store i8 0, i8* %y
296  %lv = load <4 x i32>, <4 x i32>* %x
297  %r = extractelement <4 x i32> %lv, i32 2
298  ret i32 %r
299}
300
301define i32 @load_extract_clobber_store_between(<4 x i32>* %x, i8* %y) {
302; CHECK-LABEL: @load_extract_clobber_store_between(
303; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
304; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
305; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
306; CHECK-NEXT:    ret i32 [[R]]
307;
308  %lv = load <4 x i32>, <4 x i32>* %x
309  store i8 0, i8* %y
310  %r = extractelement <4 x i32> %lv, i32 2
311  ret i32 %r
312}
313
314define i32 @load_extract_clobber_store_between_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) {
315; CHECK-LABEL: @load_extract_clobber_store_between_limit(
316; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
317; CHECK-NEXT:    [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0
318; CHECK-NEXT:    [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1
319; CHECK-NEXT:    [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]]
320; CHECK-NEXT:    [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2
321; CHECK-NEXT:    [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]]
322; CHECK-NEXT:    [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3
323; CHECK-NEXT:    [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]]
324; CHECK-NEXT:    [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4
325; CHECK-NEXT:    [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]]
326; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
327; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
328; CHECK-NEXT:    [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]]
329; CHECK-NEXT:    ret i32 [[ADD_4]]
330;
331  %lv = load <4 x i32>, <4 x i32>* %x
332  %z.0 = extractelement <8 x i32> %z, i32 0
333  %z.1 = extractelement <8 x i32> %z, i32 1
334  %add.0 = add i32 %z.0, %z.1
335  %z.2 = extractelement <8 x i32> %z, i32 2
336  %add.1 = add i32 %add.0, %z.2
337  %z.3 = extractelement <8 x i32> %z, i32 3
338  %add.2 = add i32 %add.1, %z.3
339  %z.4 = extractelement <8 x i32> %z, i32 4
340  %add.3 = add i32 %add.2, %z.4
341  store i8 0, i8* %y
342  %r = extractelement <4 x i32> %lv, i32 2
343  %add.4 = add i32 %add.3, %r
344  ret i32 %add.4
345}
346
347define i32 @load_extract_clobber_store_after_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) {
348; LIMIT-DEFAULT-LABEL: @load_extract_clobber_store_after_limit(
349; LIMIT-DEFAULT-NEXT:    [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0
350; LIMIT-DEFAULT-NEXT:    [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1
351; LIMIT-DEFAULT-NEXT:    [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]]
352; LIMIT-DEFAULT-NEXT:    [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2
353; LIMIT-DEFAULT-NEXT:    [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]]
354; LIMIT-DEFAULT-NEXT:    [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3
355; LIMIT-DEFAULT-NEXT:    [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]]
356; LIMIT-DEFAULT-NEXT:    [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4
357; LIMIT-DEFAULT-NEXT:    [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]]
358; LIMIT-DEFAULT-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, <4 x i32>* [[X:%.*]], i32 0, i32 2
359; LIMIT-DEFAULT-NEXT:    [[R:%.*]] = load i32, i32* [[TMP1]], align 8
360; LIMIT-DEFAULT-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
361; LIMIT-DEFAULT-NEXT:    [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]]
362; LIMIT-DEFAULT-NEXT:    ret i32 [[ADD_4]]
363;
364; LIMIT2-LABEL: @load_extract_clobber_store_after_limit(
365; LIMIT2-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
366; LIMIT2-NEXT:    [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0
367; LIMIT2-NEXT:    [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1
368; LIMIT2-NEXT:    [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]]
369; LIMIT2-NEXT:    [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2
370; LIMIT2-NEXT:    [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]]
371; LIMIT2-NEXT:    [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3
372; LIMIT2-NEXT:    [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]]
373; LIMIT2-NEXT:    [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4
374; LIMIT2-NEXT:    [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]]
375; LIMIT2-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
376; LIMIT2-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
377; LIMIT2-NEXT:    [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]]
378; LIMIT2-NEXT:    ret i32 [[ADD_4]]
379;
380  %lv = load <4 x i32>, <4 x i32>* %x
381  %z.0 = extractelement <8 x i32> %z, i32 0
382  %z.1 = extractelement <8 x i32> %z, i32 1
383  %add.0 = add i32 %z.0, %z.1
384  %z.2 = extractelement <8 x i32> %z, i32 2
385  %add.1 = add i32 %add.0, %z.2
386  %z.3 = extractelement <8 x i32> %z, i32 3
387  %add.2 = add i32 %add.1, %z.3
388  %z.4 = extractelement <8 x i32> %z, i32 4
389  %add.3 = add i32 %add.2, %z.4
390  %r = extractelement <4 x i32> %lv, i32 2
391  store i8 0, i8* %y
392  %add.4 = add i32 %add.3, %r
393  ret i32 %add.4
394}
395
396declare void @use.v4i32(<4 x i32>)
397
398define i32 @load_extract_idx_different_bbs(<4 x i32>* %x, i1 %c) {
399; CHECK-LABEL: @load_extract_idx_different_bbs(
400; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
401; CHECK-NEXT:    br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
402; CHECK:       then:
403; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 1
404; CHECK-NEXT:    ret i32 [[R]]
405; CHECK:       else:
406; CHECK-NEXT:    call void @use.v4i32(<4 x i32> [[LV]])
407; CHECK-NEXT:    ret i32 20
408;
409  %lv = load <4 x i32>, <4 x i32>* %x
410  br i1 %c, label %then, label %else
411
412then:
413  %r = extractelement <4 x i32> %lv, i32 1
414  ret i32 %r
415
416else:
417  call void @use.v4i32(<4 x i32> %lv)
418  ret i32 20
419}
420
421define i31 @load_with_non_power_of_2_element_type(<4 x i31>* %x) {
422; CHECK-LABEL: @load_with_non_power_of_2_element_type(
423; CHECK-NEXT:    [[LV:%.*]] = load <4 x i31>, <4 x i31>* [[X:%.*]], align 16
424; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i31> [[LV]], i32 1
425; CHECK-NEXT:    ret i31 [[R]]
426;
427  %lv = load <4 x i31>, <4 x i31>* %x
428  %r = extractelement <4 x i31> %lv, i32 1
429  ret i31 %r
430}
431
432; Scalarizing the load for multiple constant indices may not be profitable.
433define i32 @load_multiple_extracts_with_constant_idx(<4 x i32>* %x) {
434; CHECK-LABEL: @load_multiple_extracts_with_constant_idx(
435; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
436; CHECK-NEXT:    [[SHIFT:%.*]] = shufflevector <4 x i32> [[LV]], <4 x i32> poison, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef>
437; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[LV]], [[SHIFT]]
438; CHECK-NEXT:    [[RES:%.*]] = extractelement <4 x i32> [[TMP1]], i32 0
439; CHECK-NEXT:    ret i32 [[RES]]
440;
441  %lv = load <4 x i32>, <4 x i32>* %x
442  %e.0 = extractelement <4 x i32> %lv, i32 0
443  %e.1 = extractelement <4 x i32> %lv, i32 1
444  %res = add i32 %e.0, %e.1
445  ret i32 %res
446}
447
448; Scalarizing the load for multiple extracts is profitable in this case,
449; because the vector large vector requires 2 vector registers.
450define i32 @load_multiple_extracts_with_constant_idx_profitable(<8 x i32>* %x) {
451; CHECK-LABEL: @load_multiple_extracts_with_constant_idx_profitable(
452; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i32>, <8 x i32>* [[X:%.*]], i32 0, i32 0
453; CHECK-NEXT:    [[E_0:%.*]] = load i32, i32* [[TMP1]], align 16
454; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i32>, <8 x i32>* [[X]], i32 0, i32 6
455; CHECK-NEXT:    [[E_1:%.*]] = load i32, i32* [[TMP2]], align 8
456; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
457; CHECK-NEXT:    ret i32 [[RES]]
458;
459  %lv = load <8 x i32>, <8 x i32>* %x, align 16
460  %e.0 = extractelement <8 x i32> %lv, i32 0
461  %e.1 = extractelement <8 x i32> %lv, i32 6
462  %res = add i32 %e.0, %e.1
463  ret i32 %res
464}
465
466; Scalarizing may or may not be profitable, depending on the target.
467define i32 @load_multiple_2_with_variable_indices(<4 x i32>* %x, i64 %idx.0, i64 %idx.1) {
468; CHECK-LABEL: @load_multiple_2_with_variable_indices(
469; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
470; CHECK-NEXT:    [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]]
471; CHECK-NEXT:    [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]]
472; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
473; CHECK-NEXT:    ret i32 [[RES]]
474;
475  %lv = load <4 x i32>, <4 x i32>* %x
476  %e.0 = extractelement <4 x i32> %lv, i64 %idx.0
477  %e.1 = extractelement <4 x i32> %lv, i64 %idx.1
478  %res = add i32 %e.0, %e.1
479  ret i32 %res
480}
481
482define 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) {
483; CHECK-LABEL: @load_4_extracts_with_variable_indices_short_vector(
484; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
485; CHECK-NEXT:    [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]]
486; CHECK-NEXT:    [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]]
487; CHECK-NEXT:    [[E_2:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_2:%.*]]
488; CHECK-NEXT:    [[E_3:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_3:%.*]]
489; CHECK-NEXT:    [[RES_0:%.*]] = add i32 [[E_0]], [[E_1]]
490; CHECK-NEXT:    [[RES_1:%.*]] = add i32 [[RES_0]], [[E_2]]
491; CHECK-NEXT:    [[RES_2:%.*]] = add i32 [[RES_1]], [[E_3]]
492; CHECK-NEXT:    ret i32 [[RES_2]]
493;
494  %lv = load <4 x i32>, <4 x i32>* %x
495  %e.0 = extractelement <4 x i32> %lv, i64 %idx.0
496  %e.1 = extractelement <4 x i32> %lv, i64 %idx.1
497  %e.2 = extractelement <4 x i32> %lv, i64 %idx.2
498  %e.3 = extractelement <4 x i32> %lv, i64 %idx.3
499  %res.0 = add i32 %e.0, %e.1
500  %res.1 = add i32 %res.0, %e.2
501  %res.2 = add i32 %res.1, %e.3
502  ret i32 %res.2
503}
504
505define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) {
506; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid(
507; CHECK-NEXT:    [[CMP_IDX_0:%.*]] = icmp ult i64 [[IDX_0:%.*]], 16
508; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_0]])
509; CHECK-NEXT:    [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64
510; CHECK-NEXT:    [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0]]
511; CHECK-NEXT:    [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]]
512; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
513; CHECK-NEXT:    ret i32 [[RES]]
514;
515  %cmp.idx.0 = icmp ult i64 %idx.0, 16
516  call void @llvm.assume(i1 %cmp.idx.0)
517
518  %lv = load <16 x i32>, <16 x i32>* %x
519  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0
520  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1
521  %res = add i32 %e.0, %e.1
522  ret i32 %res
523}
524
525define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_all_valid(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) {
526; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_all_valid(
527; CHECK-NEXT:    [[CMP_IDX_0:%.*]] = icmp ult i64 [[IDX_0:%.*]], 16
528; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_0]])
529; CHECK-NEXT:    [[CMP_IDX_1:%.*]] = icmp ult i64 [[IDX_1:%.*]], 16
530; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_1]])
531; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X:%.*]], i32 0, i64 [[IDX_0]]
532; CHECK-NEXT:    [[E_0:%.*]] = load i32, i32* [[TMP1]], align 4
533; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, <16 x i32>* [[X]], i32 0, i64 [[IDX_1]]
534; CHECK-NEXT:    [[E_1:%.*]] = load i32, i32* [[TMP2]], align 4
535; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
536; CHECK-NEXT:    ret i32 [[RES]]
537;
538  %cmp.idx.0 = icmp ult i64 %idx.0, 16
539  call void @llvm.assume(i1 %cmp.idx.0)
540  %cmp.idx.1 = icmp ult i64 %idx.1, 16
541  call void @llvm.assume(i1 %cmp.idx.1)
542
543  %lv = load <16 x i32>, <16 x i32>* %x
544  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0
545  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1
546  %res = add i32 %e.0, %e.1
547  ret i32 %res
548}
549
550define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid_by_and(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) {
551; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_only_first_valid_by_and(
552; CHECK-NEXT:    [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15
553; CHECK-NEXT:    [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64
554; CHECK-NEXT:    [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]]
555; CHECK-NEXT:    [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]]
556; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
557; CHECK-NEXT:    ret i32 [[RES]]
558;
559  %idx.0.clamped = and i64 %idx.0, 15
560
561  %lv = load <16 x i32>, <16 x i32>* %x
562  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped
563  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1
564  %res = add i32 %e.0, %e.1
565  ret i32 %res
566}
567
568define i32 @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) {
569; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and(
570; CHECK-NEXT:    [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15
571; CHECK-NEXT:    [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1:%.*]], 15
572; CHECK-NEXT:    [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64
573; CHECK-NEXT:    [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]]
574; CHECK-NEXT:    [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1_CLAMPED]]
575; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
576; CHECK-NEXT:    ret i32 [[RES]]
577;
578  %idx.0.clamped = and i64 %idx.0, 15
579  %idx.1.clamped = and i64 %idx.1, 15
580
581  %lv = load <16 x i32>, <16 x i32>* %x
582  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped
583  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1.clamped
584  %res = add i32 %e.0, %e.1
585  ret i32 %res
586}
587
588define 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) {
589; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector_all_valid_by_and_some_noundef(
590; CHECK-NEXT:    [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0:%.*]], 15
591; CHECK-NEXT:    [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1:%.*]], 15
592; CHECK-NEXT:    [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64
593; CHECK-NEXT:    [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0_CLAMPED]]
594; CHECK-NEXT:    [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1_CLAMPED]]
595; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
596; CHECK-NEXT:    ret i32 [[RES]]
597;
598  %idx.0.clamped = and i64 %idx.0, 15
599  %idx.1.clamped = and i64 %idx.1, 15
600
601  %lv = load <16 x i32>, <16 x i32>* %x
602  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0.clamped
603  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1.clamped
604  %res = add i32 %e.0, %e.1
605  ret i32 %res
606}
607