1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -vector-combine -mtriple=arm64-apple-darwinos -S %s | FileCheck %s
3
4define i32 @load_extract_idx_0(<4 x i32>* %x) {
5; CHECK-LABEL: @load_extract_idx_0(
6; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
7; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 3
8; CHECK-NEXT:    ret i32 [[R]]
9;
10  %lv = load <4 x i32>, <4 x i32>* %x
11  %r = extractelement <4 x i32> %lv, i32 3
12  ret i32 %r
13}
14
15define i32 @load_extract_idx_1(<4 x i32>* %x) {
16; CHECK-LABEL: @load_extract_idx_1(
17; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
18; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 1
19; CHECK-NEXT:    ret i32 [[R]]
20;
21  %lv = load <4 x i32>, <4 x i32>* %x
22  %r = extractelement <4 x i32> %lv, i32 1
23  ret i32 %r
24}
25
26define i32 @load_extract_idx_2(<4 x i32>* %x) {
27; CHECK-LABEL: @load_extract_idx_2(
28; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
29; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
30; CHECK-NEXT:    ret i32 [[R]]
31;
32  %lv = load <4 x i32>, <4 x i32>* %x
33  %r = extractelement <4 x i32> %lv, i32 2
34  ret i32 %r
35}
36
37define i32 @load_extract_idx_3(<4 x i32>* %x) {
38; CHECK-LABEL: @load_extract_idx_3(
39; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
40; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 3
41; CHECK-NEXT:    ret i32 [[R]]
42;
43  %lv = load <4 x i32>, <4 x i32>* %x
44  %r = extractelement <4 x i32> %lv, i32 3
45  ret i32 %r
46}
47
48define i32 @load_extract_idx_var_i64(<4 x i32>* %x, i64 %idx) {
49; CHECK-LABEL: @load_extract_idx_var_i64(
50; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
51; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX:%.*]]
52; CHECK-NEXT:    ret i32 [[R]]
53;
54  %lv = load <4 x i32>, <4 x i32>* %x
55  %r = extractelement <4 x i32> %lv, i64 %idx
56  ret i32 %r
57}
58
59declare void @maythrow() readnone
60
61define i32 @load_extract_idx_var_i64_known_valid_by_assume(<4 x i32>* %x, i64 %idx) {
62; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_assume(
63; CHECK-NEXT:  entry:
64; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4
65; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
66; CHECK-NEXT:    call void @maythrow()
67; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
68; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]]
69; CHECK-NEXT:    ret i32 [[R]]
70;
71entry:
72  %cmp = icmp ult i64 %idx, 4
73  %lv = load <4 x i32>, <4 x i32>* %x
74  call void @maythrow()
75  call void @llvm.assume(i1 %cmp)
76  %r = extractelement <4 x i32> %lv, i64 %idx
77  ret i32 %r
78}
79
80define i32 @load_extract_idx_var_i64_not_known_valid_by_assume_after_load(<4 x i32>* %x, i64 %idx) {
81; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume_after_load(
82; CHECK-NEXT:  entry:
83; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4
84; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
85; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
86; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]]
87; CHECK-NEXT:    ret i32 [[R]]
88;
89entry:
90  %cmp = icmp ult i64 %idx, 4
91  call void @llvm.assume(i1 %cmp)
92  %lv = load <4 x i32>, <4 x i32>* %x
93  %r = extractelement <4 x i32> %lv, i64 %idx
94  ret i32 %r
95}
96
97define i32 @load_extract_idx_var_i64_not_known_valid_by_assume(<4 x i32>* %x, i64 %idx) {
98; CHECK-LABEL: @load_extract_idx_var_i64_not_known_valid_by_assume(
99; CHECK-NEXT:  entry:
100; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 5
101; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
102; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
103; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX]]
104; CHECK-NEXT:    ret i32 [[R]]
105;
106entry:
107  %cmp = icmp ult i64 %idx, 5
108  call void @llvm.assume(i1 %cmp)
109  %lv = load <4 x i32>, <4 x i32>* %x
110  %r = extractelement <4 x i32> %lv, i64 %idx
111  ret i32 %r
112}
113
114declare void @llvm.assume(i1)
115
116define i32 @load_extract_idx_var_i32(<4 x i32>* %x, i32 %idx) {
117; CHECK-LABEL: @load_extract_idx_var_i32(
118; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
119; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 [[IDX:%.*]]
120; CHECK-NEXT:    ret i32 [[R]]
121;
122  %lv = load <4 x i32>, <4 x i32>* %x
123  %r = extractelement <4 x i32> %lv, i32 %idx
124  ret i32 %r
125}
126
127declare void @clobber()
128
129define i32 @load_extract_clobber_call_before(<4 x i32>* %x) {
130; CHECK-LABEL: @load_extract_clobber_call_before(
131; CHECK-NEXT:    call void @clobber()
132; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
133; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
134; CHECK-NEXT:    ret i32 [[R]]
135;
136  call void @clobber()
137  %lv = load <4 x i32>, <4 x i32>* %x
138  %r = extractelement <4 x i32> %lv, i32 2
139  ret i32 %r
140}
141
142define i32 @load_extract_clobber_call_between(<4 x i32>* %x) {
143; CHECK-LABEL: @load_extract_clobber_call_between(
144; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
145; CHECK-NEXT:    call void @clobber()
146; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
147; CHECK-NEXT:    ret i32 [[R]]
148;
149  %lv = load <4 x i32>, <4 x i32>* %x
150  call void @clobber()
151  %r = extractelement <4 x i32> %lv, i32 2
152  ret i32 %r
153}
154
155define i32 @load_extract_clobber_call_after(<4 x i32>* %x) {
156; CHECK-LABEL: @load_extract_clobber_call_after(
157; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
158; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
159; CHECK-NEXT:    call void @clobber()
160; CHECK-NEXT:    ret i32 [[R]]
161;
162  %lv = load <4 x i32>, <4 x i32>* %x
163  %r = extractelement <4 x i32> %lv, i32 2
164  call void @clobber()
165  ret i32 %r
166}
167
168define i32 @load_extract_clobber_store_before(<4 x i32>* %x, i8* %y) {
169; CHECK-LABEL: @load_extract_clobber_store_before(
170; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
171; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
172; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
173; CHECK-NEXT:    ret i32 [[R]]
174;
175  store i8 0, i8* %y
176  %lv = load <4 x i32>, <4 x i32>* %x
177  %r = extractelement <4 x i32> %lv, i32 2
178  ret i32 %r
179}
180
181define i32 @load_extract_clobber_store_between(<4 x i32>* %x, i8* %y) {
182; CHECK-LABEL: @load_extract_clobber_store_between(
183; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
184; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
185; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
186; CHECK-NEXT:    ret i32 [[R]]
187;
188  %lv = load <4 x i32>, <4 x i32>* %x
189  store i8 0, i8* %y
190  %r = extractelement <4 x i32> %lv, i32 2
191  ret i32 %r
192}
193
194define i32 @load_extract_clobber_store_between_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) {
195; CHECK-LABEL: @load_extract_clobber_store_between_limit(
196; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
197; CHECK-NEXT:    [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0
198; CHECK-NEXT:    [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1
199; CHECK-NEXT:    [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]]
200; CHECK-NEXT:    [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2
201; CHECK-NEXT:    [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]]
202; CHECK-NEXT:    [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3
203; CHECK-NEXT:    [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]]
204; CHECK-NEXT:    [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4
205; CHECK-NEXT:    [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]]
206; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
207; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
208; CHECK-NEXT:    [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]]
209; CHECK-NEXT:    ret i32 [[ADD_4]]
210;
211  %lv = load <4 x i32>, <4 x i32>* %x
212  %z.0 = extractelement <8 x i32> %z, i32 0
213  %z.1 = extractelement <8 x i32> %z, i32 1
214  %add.0 = add i32 %z.0, %z.1
215  %z.2 = extractelement <8 x i32> %z, i32 2
216  %add.1 = add i32 %add.0, %z.2
217  %z.3 = extractelement <8 x i32> %z, i32 3
218  %add.2 = add i32 %add.1, %z.3
219  %z.4 = extractelement <8 x i32> %z, i32 4
220  %add.3 = add i32 %add.2, %z.4
221  store i8 0, i8* %y
222  %r = extractelement <4 x i32> %lv, i32 2
223  %add.4 = add i32 %add.3, %r
224  ret i32 %add.4
225}
226
227define i32 @load_extract_clobber_store_after_limit(<4 x i32>* %x, i8* %y, <8 x i32> %z) {
228; CHECK-LABEL: @load_extract_clobber_store_after_limit(
229; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
230; CHECK-NEXT:    [[Z_0:%.*]] = extractelement <8 x i32> [[Z:%.*]], i32 0
231; CHECK-NEXT:    [[Z_1:%.*]] = extractelement <8 x i32> [[Z]], i32 1
232; CHECK-NEXT:    [[ADD_0:%.*]] = add i32 [[Z_0]], [[Z_1]]
233; CHECK-NEXT:    [[Z_2:%.*]] = extractelement <8 x i32> [[Z]], i32 2
234; CHECK-NEXT:    [[ADD_1:%.*]] = add i32 [[ADD_0]], [[Z_2]]
235; CHECK-NEXT:    [[Z_3:%.*]] = extractelement <8 x i32> [[Z]], i32 3
236; CHECK-NEXT:    [[ADD_2:%.*]] = add i32 [[ADD_1]], [[Z_3]]
237; CHECK-NEXT:    [[Z_4:%.*]] = extractelement <8 x i32> [[Z]], i32 4
238; CHECK-NEXT:    [[ADD_3:%.*]] = add i32 [[ADD_2]], [[Z_4]]
239; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 2
240; CHECK-NEXT:    store i8 0, i8* [[Y:%.*]], align 1
241; CHECK-NEXT:    [[ADD_4:%.*]] = add i32 [[ADD_3]], [[R]]
242; CHECK-NEXT:    ret i32 [[ADD_4]]
243;
244  %lv = load <4 x i32>, <4 x i32>* %x
245  %z.0 = extractelement <8 x i32> %z, i32 0
246  %z.1 = extractelement <8 x i32> %z, i32 1
247  %add.0 = add i32 %z.0, %z.1
248  %z.2 = extractelement <8 x i32> %z, i32 2
249  %add.1 = add i32 %add.0, %z.2
250  %z.3 = extractelement <8 x i32> %z, i32 3
251  %add.2 = add i32 %add.1, %z.3
252  %z.4 = extractelement <8 x i32> %z, i32 4
253  %add.3 = add i32 %add.2, %z.4
254  %r = extractelement <4 x i32> %lv, i32 2
255  store i8 0, i8* %y
256  %add.4 = add i32 %add.3, %r
257  ret i32 %add.4
258}
259
260declare void @use.v4i32(<4 x i32>)
261
262define i32 @load_extract_idx_different_bbs(<4 x i32>* %x, i1 %c) {
263; CHECK-LABEL: @load_extract_idx_different_bbs(
264; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
265; CHECK-NEXT:    br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
266; CHECK:       then:
267; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[LV]], i32 1
268; CHECK-NEXT:    ret i32 [[R]]
269; CHECK:       else:
270; CHECK-NEXT:    call void @use.v4i32(<4 x i32> [[LV]])
271; CHECK-NEXT:    ret i32 20
272;
273  %lv = load <4 x i32>, <4 x i32>* %x
274  br i1 %c, label %then, label %else
275
276then:
277  %r = extractelement <4 x i32> %lv, i32 1
278  ret i32 %r
279
280else:
281  call void @use.v4i32(<4 x i32> %lv)
282  ret i32 20
283}
284
285define i31 @load_with_non_power_of_2_element_type(<4 x i31>* %x) {
286; CHECK-LABEL: @load_with_non_power_of_2_element_type(
287; CHECK-NEXT:    [[LV:%.*]] = load <4 x i31>, <4 x i31>* [[X:%.*]], align 16
288; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i31> [[LV]], i32 1
289; CHECK-NEXT:    ret i31 [[R]]
290;
291  %lv = load <4 x i31>, <4 x i31>* %x
292  %r = extractelement <4 x i31> %lv, i32 1
293  ret i31 %r
294}
295
296; Scalarizing the load for multiple constant indices may not be profitable.
297define i32 @load_multiple_extracts_with_constant_idx(<4 x i32>* %x) {
298; CHECK-LABEL: @load_multiple_extracts_with_constant_idx(
299; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
300; CHECK-NEXT:    [[SHIFT:%.*]] = shufflevector <4 x i32> [[LV]], <4 x i32> poison, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef>
301; CHECK-NEXT:    [[TMP1:%.*]] = add <4 x i32> [[LV]], [[SHIFT]]
302; CHECK-NEXT:    [[RES:%.*]] = extractelement <4 x i32> [[TMP1]], i32 0
303; CHECK-NEXT:    ret i32 [[RES]]
304;
305  %lv = load <4 x i32>, <4 x i32>* %x
306  %e.0 = extractelement <4 x i32> %lv, i32 0
307  %e.1 = extractelement <4 x i32> %lv, i32 1
308  %res = add i32 %e.0, %e.1
309  ret i32 %res
310}
311
312; Scalarizing may or may not be profitable, depending on the target.
313define i32 @load_multiple_2_with_variable_indices(<4 x i32>* %x, i64 %idx.0, i64 %idx.1) {
314; CHECK-LABEL: @load_multiple_2_with_variable_indices(
315; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
316; CHECK-NEXT:    [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]]
317; CHECK-NEXT:    [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]]
318; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
319; CHECK-NEXT:    ret i32 [[RES]]
320;
321  %lv = load <4 x i32>, <4 x i32>* %x
322  %e.0 = extractelement <4 x i32> %lv, i64 %idx.0
323  %e.1 = extractelement <4 x i32> %lv, i64 %idx.1
324  %res = add i32 %e.0, %e.1
325  ret i32 %res
326}
327
328define 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) {
329; CHECK-LABEL: @load_4_extracts_with_variable_indices_short_vector(
330; CHECK-NEXT:    [[LV:%.*]] = load <4 x i32>, <4 x i32>* [[X:%.*]], align 16
331; CHECK-NEXT:    [[E_0:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_0:%.*]]
332; CHECK-NEXT:    [[E_1:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_1:%.*]]
333; CHECK-NEXT:    [[E_2:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_2:%.*]]
334; CHECK-NEXT:    [[E_3:%.*]] = extractelement <4 x i32> [[LV]], i64 [[IDX_3:%.*]]
335; CHECK-NEXT:    [[RES_0:%.*]] = add i32 [[E_0]], [[E_1]]
336; CHECK-NEXT:    [[RES_1:%.*]] = add i32 [[RES_0]], [[E_2]]
337; CHECK-NEXT:    [[RES_2:%.*]] = add i32 [[RES_1]], [[E_3]]
338; CHECK-NEXT:    ret i32 [[RES_2]]
339;
340  %lv = load <4 x i32>, <4 x i32>* %x
341  %e.0 = extractelement <4 x i32> %lv, i64 %idx.0
342  %e.1 = extractelement <4 x i32> %lv, i64 %idx.1
343  %e.2 = extractelement <4 x i32> %lv, i64 %idx.2
344  %e.3 = extractelement <4 x i32> %lv, i64 %idx.3
345  %res.0 = add i32 %e.0, %e.1
346  %res.1 = add i32 %res.0, %e.2
347  %res.2 = add i32 %res.1, %e.3
348  ret i32 %res.2
349}
350
351define i32 @load_multiple_extracts_with_variable_indices_large_vector(<16 x i32>* %x, i64 %idx.0, i64 %idx.1) {
352; CHECK-LABEL: @load_multiple_extracts_with_variable_indices_large_vector(
353; CHECK-NEXT:    [[LV:%.*]] = load <16 x i32>, <16 x i32>* [[X:%.*]], align 64
354; CHECK-NEXT:    [[E_0:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_0:%.*]]
355; CHECK-NEXT:    [[E_1:%.*]] = extractelement <16 x i32> [[LV]], i64 [[IDX_1:%.*]]
356; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
357; CHECK-NEXT:    ret i32 [[RES]]
358;
359  %lv = load <16 x i32>, <16 x i32>* %x
360  %e.0 = extractelement <16 x i32> %lv, i64 %idx.0
361  %e.1 = extractelement <16 x i32> %lv, i64 %idx.1
362  %res = add i32 %e.0, %e.1
363  ret i32 %res
364}
365