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