1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -slp-vectorizer -S %s | FileCheck %s
3
4target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
5target triple = "arm64-apple-darwin"
6
7declare void @use(double)
8
9; The extracts %v1.lane.0 and %v1.lane.1 should be considered free during SLP,
10; because they will be directly in a vector register on AArch64.
11define void @noop_extracts_first_2_lanes(<2 x double>* %ptr.1, <4 x double>* %ptr.2) {
12; CHECK-LABEL: @noop_extracts_first_2_lanes(
13; CHECK-NEXT:  bb:
14; CHECK-NEXT:    [[V_1:%.*]] = load <2 x double>, <2 x double>* [[PTR_1:%.*]], align 8
15; CHECK-NEXT:    [[V1_LANE_0:%.*]] = extractelement <2 x double> [[V_1]], i32 0
16; CHECK-NEXT:    [[V1_LANE_1:%.*]] = extractelement <2 x double> [[V_1]], i32 1
17; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
18; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
19; CHECK-NEXT:    [[V2_LANE_3:%.*]] = extractelement <4 x double> [[V_2]], i32 3
20; CHECK-NEXT:    [[A_LANE_0:%.*]] = fmul double [[V1_LANE_0]], [[V2_LANE_2]]
21; CHECK-NEXT:    [[A_LANE_1:%.*]] = fmul double [[V1_LANE_1]], [[V2_LANE_3]]
22; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <2 x double> undef, double [[A_LANE_0]], i32 0
23; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <2 x double> [[A_INS_0]], double [[A_LANE_1]], i32 1
24; CHECK-NEXT:    call void @use(double [[V1_LANE_0]])
25; CHECK-NEXT:    call void @use(double [[V1_LANE_1]])
26; CHECK-NEXT:    store <2 x double> [[A_INS_1]], <2 x double>* [[PTR_1]], align 8
27; CHECK-NEXT:    ret void
28;
29bb:
30  %v.1 = load <2 x double>, <2 x double>* %ptr.1, align 8
31  %v1.lane.0 = extractelement <2 x double> %v.1, i32 0
32  %v1.lane.1 = extractelement <2 x double> %v.1, i32 1
33
34  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
35  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
36  %v2.lane.3 = extractelement <4 x double> %v.2, i32 3
37
38  %a.lane.0 = fmul double %v1.lane.0, %v2.lane.2
39  %a.lane.1 = fmul double %v1.lane.1, %v2.lane.3
40
41  %a.ins.0 = insertelement <2 x double> undef, double %a.lane.0, i32 0
42  %a.ins.1 = insertelement <2 x double> %a.ins.0, double %a.lane.1, i32 1
43
44  call void @use(double %v1.lane.0)
45  call void @use(double %v1.lane.1)
46
47  store <2 x double> %a.ins.1, <2 x double>* %ptr.1, align 8
48  ret void
49}
50
51; Extracts of consecutive indices, but different vector operand.
52define void @extracts_first_2_lanes_different_vectors(<2 x double>* %ptr.1, <4 x double>* %ptr.2, <2 x double>* %ptr.3) {
53; CHECK-LABEL: @extracts_first_2_lanes_different_vectors(
54; CHECK-NEXT:  bb:
55; CHECK-NEXT:    [[V_1:%.*]] = load <2 x double>, <2 x double>* [[PTR_1:%.*]], align 8
56; CHECK-NEXT:    [[V1_LANE_0:%.*]] = extractelement <2 x double> [[V_1]], i32 0
57; CHECK-NEXT:    [[V_3:%.*]] = load <2 x double>, <2 x double>* [[PTR_3:%.*]], align 8
58; CHECK-NEXT:    [[V3_LANE_1:%.*]] = extractelement <2 x double> [[V_3]], i32 1
59; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
60; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
61; CHECK-NEXT:    [[A_LANE_0:%.*]] = fmul double [[V1_LANE_0]], [[V2_LANE_2]]
62; CHECK-NEXT:    [[A_LANE_1:%.*]] = fmul double [[V3_LANE_1]], [[V2_LANE_2]]
63; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <2 x double> undef, double [[A_LANE_0]], i32 0
64; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <2 x double> [[A_INS_0]], double [[A_LANE_1]], i32 1
65; CHECK-NEXT:    call void @use(double [[V1_LANE_0]])
66; CHECK-NEXT:    call void @use(double [[V3_LANE_1]])
67; CHECK-NEXT:    store <2 x double> [[A_INS_1]], <2 x double>* [[PTR_1]], align 8
68; CHECK-NEXT:    ret void
69;
70bb:
71  %v.1 = load <2 x double>, <2 x double>* %ptr.1, align 8
72  %v1.lane.0 = extractelement <2 x double> %v.1, i32 0
73  %v.3 = load <2 x double>, <2 x double>* %ptr.3, align 8
74  %v3.lane.1 = extractelement <2 x double> %v.3, i32 1
75
76  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
77  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
78
79  %a.lane.0 = fmul double %v1.lane.0, %v2.lane.2
80  %a.lane.1 = fmul double %v3.lane.1, %v2.lane.2
81
82  %a.ins.0 = insertelement <2 x double> undef, double %a.lane.0, i32 0
83  %a.ins.1 = insertelement <2 x double> %a.ins.0, double %a.lane.1, i32 1
84
85  call void @use(double %v1.lane.0)
86  call void @use(double %v3.lane.1)
87
88  store <2 x double> %a.ins.1, <2 x double>* %ptr.1, align 8
89  ret void
90}
91
92; The extracts %v1.lane.2 and %v1.lane.3 should be considered free during SLP,
93; because they will be directly in a vector register on AArch64.
94define void @noop_extract_second_2_lanes(<4 x double>* %ptr.1, <4 x double>* %ptr.2) {
95; CHECK-LABEL: @noop_extract_second_2_lanes(
96; CHECK-NEXT:  bb:
97; CHECK-NEXT:    [[V_1:%.*]] = load <4 x double>, <4 x double>* [[PTR_1:%.*]], align 8
98; CHECK-NEXT:    [[V1_LANE_2:%.*]] = extractelement <4 x double> [[V_1]], i32 2
99; CHECK-NEXT:    [[V1_LANE_3:%.*]] = extractelement <4 x double> [[V_1]], i32 3
100; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
101; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
102; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <2 x double> poison, double [[V1_LANE_2]], i32 0
103; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x double> [[TMP0]], double [[V1_LANE_3]], i32 1
104; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <2 x double> poison, double [[V2_LANE_2]], i32 0
105; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <2 x double> [[TMP2]], double [[V2_LANE_2]], i32 1
106; CHECK-NEXT:    [[TMP4:%.*]] = fmul <2 x double> [[TMP1]], [[TMP3]]
107; CHECK-NEXT:    [[TMP5:%.*]] = extractelement <2 x double> [[TMP4]], i32 0
108; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <4 x double> undef, double [[TMP5]], i32 0
109; CHECK-NEXT:    [[TMP6:%.*]] = extractelement <2 x double> [[TMP4]], i32 1
110; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <4 x double> [[A_INS_0]], double [[TMP6]], i32 1
111; CHECK-NEXT:    call void @use(double [[V1_LANE_2]])
112; CHECK-NEXT:    call void @use(double [[V1_LANE_3]])
113; CHECK-NEXT:    store <4 x double> [[A_INS_1]], <4 x double>* [[PTR_1]], align 8
114; CHECK-NEXT:    ret void
115;
116bb:
117  %v.1 = load <4 x double>, <4 x double>* %ptr.1, align 8
118  %v1.lane.2 = extractelement <4 x double> %v.1, i32 2
119  %v1.lane.3 = extractelement <4 x double> %v.1, i32 3
120
121  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
122  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
123
124  %a.lane.0 = fmul double %v1.lane.2, %v2.lane.2
125  %a.lane.1 = fmul double %v1.lane.3, %v2.lane.2
126
127  %a.ins.0 = insertelement <4 x double> undef, double %a.lane.0, i32 0
128  %a.ins.1 = insertelement <4 x double> %a.ins.0, double %a.lane.1, i32 1
129
130  call void @use(double %v1.lane.2)
131  call void @use(double %v1.lane.3)
132  store <4 x double> %a.ins.1, <4 x double>* %ptr.1, align 8
133  ret void
134}
135
136; %v1.lane.0 and %v1.lane.1 are used in reverse-order, so they won't be
137; directly in a vector register on AArch64.
138define void @extract_reverse_order(<2 x double>* %ptr.1, <4 x double>* %ptr.2) {
139; CHECK-LABEL: @extract_reverse_order(
140; CHECK-NEXT:  bb:
141; CHECK-NEXT:    [[V_1:%.*]] = load <2 x double>, <2 x double>* [[PTR_1:%.*]], align 8
142; CHECK-NEXT:    [[V1_LANE_0:%.*]] = extractelement <2 x double> [[V_1]], i32 0
143; CHECK-NEXT:    [[V1_LANE_1:%.*]] = extractelement <2 x double> [[V_1]], i32 1
144; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
145; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
146; CHECK-NEXT:    [[A_LANE_0:%.*]] = fmul double [[V1_LANE_1]], [[V2_LANE_2]]
147; CHECK-NEXT:    [[A_LANE_1:%.*]] = fmul double [[V1_LANE_0]], [[V2_LANE_2]]
148; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <2 x double> undef, double [[A_LANE_0]], i32 0
149; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <2 x double> [[A_INS_0]], double [[A_LANE_1]], i32 1
150; CHECK-NEXT:    call void @use(double [[V1_LANE_0]])
151; CHECK-NEXT:    call void @use(double [[V1_LANE_1]])
152; CHECK-NEXT:    store <2 x double> [[A_INS_1]], <2 x double>* [[PTR_1]], align 8
153; CHECK-NEXT:    ret void
154;
155bb:
156  %v.1 = load <2 x double>, <2 x double>* %ptr.1, align 8
157  %v1.lane.0 = extractelement <2 x double> %v.1, i32 0
158  %v1.lane.1 = extractelement <2 x double> %v.1, i32 1
159
160  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
161  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
162
163  %a.lane.0 = fmul double %v1.lane.1, %v2.lane.2
164  %a.lane.1 = fmul double %v1.lane.0, %v2.lane.2
165
166  %a.ins.0 = insertelement <2 x double> undef, double %a.lane.0, i32 0
167  %a.ins.1 = insertelement <2 x double> %a.ins.0, double %a.lane.1, i32 1
168
169  call void @use(double %v1.lane.0)
170  call void @use(double %v1.lane.1)
171
172  store <2 x double> %a.ins.1, <2 x double>* %ptr.1, align 8
173  ret void
174}
175
176; %v1.lane.1 and %v1.lane.2 are extracted from different vector registers on AArch64.
177define void @extract_lanes_1_and_2(<4 x double>* %ptr.1, <4 x double>* %ptr.2) {
178; CHECK-LABEL: @extract_lanes_1_and_2(
179; CHECK-NEXT:  bb:
180; CHECK-NEXT:    [[V_1:%.*]] = load <4 x double>, <4 x double>* [[PTR_1:%.*]], align 8
181; CHECK-NEXT:    [[V1_LANE_1:%.*]] = extractelement <4 x double> [[V_1]], i32 1
182; CHECK-NEXT:    [[V1_LANE_2:%.*]] = extractelement <4 x double> [[V_1]], i32 2
183; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
184; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
185; CHECK-NEXT:    [[A_LANE_0:%.*]] = fmul double [[V1_LANE_1]], [[V2_LANE_2]]
186; CHECK-NEXT:    [[A_LANE_1:%.*]] = fmul double [[V1_LANE_2]], [[V2_LANE_2]]
187; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <4 x double> undef, double [[A_LANE_0]], i32 0
188; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <4 x double> [[A_INS_0]], double [[A_LANE_1]], i32 1
189; CHECK-NEXT:    call void @use(double [[V1_LANE_1]])
190; CHECK-NEXT:    call void @use(double [[V1_LANE_2]])
191; CHECK-NEXT:    store <4 x double> [[A_INS_1]], <4 x double>* [[PTR_1]], align 8
192; CHECK-NEXT:    ret void
193;
194bb:
195  %v.1 = load <4 x double>, <4 x double>* %ptr.1, align 8
196  %v1.lane.1 = extractelement <4 x double> %v.1, i32 1
197  %v1.lane.2 = extractelement <4 x double> %v.1, i32 2
198
199  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
200  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
201
202  %a.lane.0 = fmul double %v1.lane.1, %v2.lane.2
203  %a.lane.1 = fmul double %v1.lane.2, %v2.lane.2
204
205  %a.ins.0 = insertelement <4 x double> undef, double %a.lane.0, i32 0
206  %a.ins.1 = insertelement <4 x double> %a.ins.0, double %a.lane.1, i32 1
207
208  call void @use(double %v1.lane.1)
209  call void @use(double %v1.lane.2)
210
211  store <4 x double> %a.ins.1, <4 x double>* %ptr.1, align 8
212  ret void
213}
214
215; More complex case where the extracted lanes are directly from a vector
216; register on AArch64 and should be considered free, because we can
217; directly use the source vector register.
218define void @noop_extracts_existing_vector_4_lanes(<9 x double>* %ptr.1, <4 x double>* %ptr.2) {
219; CHECK-LABEL: @noop_extracts_existing_vector_4_lanes(
220; CHECK-NEXT:  bb:
221; CHECK-NEXT:    [[V_1:%.*]] = load <9 x double>, <9 x double>* [[PTR_1:%.*]], align 8
222; CHECK-NEXT:    [[V1_LANE_0:%.*]] = extractelement <9 x double> [[V_1]], i32 0
223; CHECK-NEXT:    [[V1_LANE_1:%.*]] = extractelement <9 x double> [[V_1]], i32 1
224; CHECK-NEXT:    [[V1_LANE_2:%.*]] = extractelement <9 x double> [[V_1]], i32 2
225; CHECK-NEXT:    [[V1_LANE_3:%.*]] = extractelement <9 x double> [[V_1]], i32 3
226; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
227; CHECK-NEXT:    [[V2_LANE_0:%.*]] = extractelement <4 x double> [[V_2]], i32 0
228; CHECK-NEXT:    [[V2_LANE_1:%.*]] = extractelement <4 x double> [[V_2]], i32 1
229; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
230; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <2 x double> poison, double [[V1_LANE_2]], i32 0
231; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x double> [[TMP0]], double [[V1_LANE_3]], i32 1
232; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <2 x double> poison, double [[V2_LANE_2]], i32 0
233; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <2 x double> [[TMP2]], double [[V2_LANE_2]], i32 1
234; CHECK-NEXT:    [[TMP4:%.*]] = fmul <2 x double> [[TMP1]], [[TMP3]]
235; CHECK-NEXT:    [[A_LANE_2:%.*]] = fmul double [[V1_LANE_0]], [[V2_LANE_2]]
236; CHECK-NEXT:    [[A_LANE_3:%.*]] = fmul double [[V1_LANE_1]], [[V2_LANE_0]]
237; CHECK-NEXT:    [[TMP5:%.*]] = extractelement <2 x double> [[TMP4]], i32 0
238; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <9 x double> undef, double [[TMP5]], i32 0
239; CHECK-NEXT:    [[TMP6:%.*]] = extractelement <2 x double> [[TMP4]], i32 1
240; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <9 x double> [[A_INS_0]], double [[TMP6]], i32 1
241; CHECK-NEXT:    [[A_INS_2:%.*]] = insertelement <9 x double> [[A_INS_1]], double [[A_LANE_2]], i32 2
242; CHECK-NEXT:    [[A_INS_3:%.*]] = insertelement <9 x double> [[A_INS_2]], double [[A_LANE_3]], i32 3
243; CHECK-NEXT:    call void @use(double [[V1_LANE_0]])
244; CHECK-NEXT:    call void @use(double [[V1_LANE_1]])
245; CHECK-NEXT:    call void @use(double [[V1_LANE_2]])
246; CHECK-NEXT:    call void @use(double [[V1_LANE_3]])
247; CHECK-NEXT:    store <9 x double> [[A_INS_3]], <9 x double>* [[PTR_1]], align 8
248; CHECK-NEXT:    ret void
249;
250bb:
251  %v.1 = load <9 x double>, <9 x double>* %ptr.1, align 8
252  %v1.lane.0 = extractelement <9 x double> %v.1, i32 0
253  %v1.lane.1 = extractelement <9 x double> %v.1, i32 1
254  %v1.lane.2 = extractelement <9 x double> %v.1, i32 2
255  %v1.lane.3 = extractelement <9 x double> %v.1, i32 3
256  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
257  %v2.lane.0 = extractelement <4 x double> %v.2, i32 0
258  %v2.lane.1 = extractelement <4 x double> %v.2, i32 1
259  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
260  %a.lane.0 = fmul double %v1.lane.2, %v2.lane.2
261  %a.lane.1 = fmul double %v1.lane.3, %v2.lane.2
262  %a.lane.2 = fmul double %v1.lane.0, %v2.lane.2
263  %a.lane.3 = fmul double %v1.lane.1, %v2.lane.0
264  %a.ins.0 = insertelement <9 x double> undef, double %a.lane.0, i32 0
265  %a.ins.1 = insertelement <9 x double> %a.ins.0, double %a.lane.1, i32 1
266  %a.ins.2 = insertelement <9 x double> %a.ins.1, double %a.lane.2, i32 2
267  %a.ins.3 = insertelement <9 x double> %a.ins.2, double %a.lane.3, i32 3
268  call void @use(double %v1.lane.0)
269  call void @use(double %v1.lane.1)
270  call void @use(double %v1.lane.2)
271  call void @use(double %v1.lane.3)
272  store <9 x double> %a.ins.3, <9 x double>* %ptr.1, align 8
273  ret void
274}
275
276; Extracted lanes are not used in the right order, so we cannot reuse the
277; source vector registers directly.
278define void @extracts_jumbled_4_lanes(<9 x double>* %ptr.1, <4 x double>* %ptr.2) {
279; CHECK-LABEL: @extracts_jumbled_4_lanes(
280; CHECK-NEXT:  bb:
281; CHECK-NEXT:    [[V_1:%.*]] = load <9 x double>, <9 x double>* [[PTR_1:%.*]], align 8
282; CHECK-NEXT:    [[V1_LANE_0:%.*]] = extractelement <9 x double> [[V_1]], i32 0
283; CHECK-NEXT:    [[V1_LANE_1:%.*]] = extractelement <9 x double> [[V_1]], i32 1
284; CHECK-NEXT:    [[V1_LANE_2:%.*]] = extractelement <9 x double> [[V_1]], i32 2
285; CHECK-NEXT:    [[V1_LANE_3:%.*]] = extractelement <9 x double> [[V_1]], i32 3
286; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
287; CHECK-NEXT:    [[V2_LANE_0:%.*]] = extractelement <4 x double> [[V_2]], i32 0
288; CHECK-NEXT:    [[V2_LANE_1:%.*]] = extractelement <4 x double> [[V_2]], i32 1
289; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
290; CHECK-NEXT:    [[A_LANE_0:%.*]] = fmul double [[V1_LANE_0]], [[V2_LANE_2]]
291; CHECK-NEXT:    [[A_LANE_1:%.*]] = fmul double [[V1_LANE_2]], [[V2_LANE_1]]
292; CHECK-NEXT:    [[A_LANE_2:%.*]] = fmul double [[V1_LANE_1]], [[V2_LANE_2]]
293; CHECK-NEXT:    [[A_LANE_3:%.*]] = fmul double [[V1_LANE_3]], [[V2_LANE_0]]
294; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <9 x double> undef, double [[A_LANE_0]], i32 0
295; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <9 x double> [[A_INS_0]], double [[A_LANE_1]], i32 1
296; CHECK-NEXT:    [[A_INS_2:%.*]] = insertelement <9 x double> [[A_INS_1]], double [[A_LANE_2]], i32 2
297; CHECK-NEXT:    [[A_INS_3:%.*]] = insertelement <9 x double> [[A_INS_2]], double [[A_LANE_3]], i32 3
298; CHECK-NEXT:    call void @use(double [[V1_LANE_0]])
299; CHECK-NEXT:    call void @use(double [[V1_LANE_1]])
300; CHECK-NEXT:    call void @use(double [[V1_LANE_2]])
301; CHECK-NEXT:    call void @use(double [[V1_LANE_3]])
302; CHECK-NEXT:    store <9 x double> [[A_INS_3]], <9 x double>* [[PTR_1]], align 8
303; CHECK-NEXT:    ret void
304;
305bb:
306  %v.1 = load <9 x double>, <9 x double>* %ptr.1, align 8
307  %v1.lane.0 = extractelement <9 x double> %v.1, i32 0
308  %v1.lane.1 = extractelement <9 x double> %v.1, i32 1
309  %v1.lane.2 = extractelement <9 x double> %v.1, i32 2
310  %v1.lane.3 = extractelement <9 x double> %v.1, i32 3
311  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
312  %v2.lane.0 = extractelement <4 x double> %v.2, i32 0
313  %v2.lane.1 = extractelement <4 x double> %v.2, i32 1
314  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
315  %a.lane.0 = fmul double %v1.lane.0, %v2.lane.2
316  %a.lane.1 = fmul double %v1.lane.2, %v2.lane.1
317  %a.lane.2 = fmul double %v1.lane.1, %v2.lane.2
318  %a.lane.3 = fmul double %v1.lane.3, %v2.lane.0
319  %a.ins.0 = insertelement <9 x double> undef, double %a.lane.0, i32 0
320  %a.ins.1 = insertelement <9 x double> %a.ins.0, double %a.lane.1, i32 1
321  %a.ins.2 = insertelement <9 x double> %a.ins.1, double %a.lane.2, i32 2
322  %a.ins.3 = insertelement <9 x double> %a.ins.2, double %a.lane.3, i32 3
323  call void @use(double %v1.lane.0)
324  call void @use(double %v1.lane.1)
325  call void @use(double %v1.lane.2)
326  call void @use(double %v1.lane.3)
327  store <9 x double> %a.ins.3, <9 x double>* %ptr.1, align 8
328  ret void
329}
330
331
332; Even more complex case where the extracted lanes are directly from a vector
333; register on AArch64 and should be considered free, because we can
334; directly use the source vector register.
335define void @noop_extracts_9_lanes(<9 x double>* %ptr.1, <4 x double>* %ptr.2) {
336; CHECK-LABEL: @noop_extracts_9_lanes(
337; CHECK-NEXT:  bb:
338; CHECK-NEXT:    [[V_1:%.*]] = load <9 x double>, <9 x double>* [[PTR_1:%.*]], align 8
339; CHECK-NEXT:    [[V1_LANE_0:%.*]] = extractelement <9 x double> [[V_1]], i32 0
340; CHECK-NEXT:    [[V1_LANE_1:%.*]] = extractelement <9 x double> [[V_1]], i32 1
341; CHECK-NEXT:    [[V1_LANE_2:%.*]] = extractelement <9 x double> [[V_1]], i32 2
342; CHECK-NEXT:    [[V1_LANE_3:%.*]] = extractelement <9 x double> [[V_1]], i32 3
343; CHECK-NEXT:    [[V1_LANE_4:%.*]] = extractelement <9 x double> [[V_1]], i32 4
344; CHECK-NEXT:    [[V1_LANE_5:%.*]] = extractelement <9 x double> [[V_1]], i32 5
345; CHECK-NEXT:    [[V1_LANE_6:%.*]] = extractelement <9 x double> [[V_1]], i32 6
346; CHECK-NEXT:    [[V1_LANE_7:%.*]] = extractelement <9 x double> [[V_1]], i32 7
347; CHECK-NEXT:    [[V1_LANE_8:%.*]] = extractelement <9 x double> [[V_1]], i32 8
348; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
349; CHECK-NEXT:    [[V2_LANE_0:%.*]] = extractelement <4 x double> [[V_2]], i32 0
350; CHECK-NEXT:    [[V2_LANE_1:%.*]] = extractelement <4 x double> [[V_2]], i32 1
351; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
352; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <8 x double> poison, double [[V1_LANE_3]], i32 0
353; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x double> [[TMP0]], double [[V1_LANE_4]], i32 1
354; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <8 x double> [[TMP1]], double [[V1_LANE_5]], i32 2
355; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <8 x double> [[TMP2]], double [[V1_LANE_6]], i32 3
356; CHECK-NEXT:    [[TMP4:%.*]] = insertelement <8 x double> [[TMP3]], double [[V1_LANE_7]], i32 4
357; CHECK-NEXT:    [[TMP5:%.*]] = insertelement <8 x double> [[TMP4]], double [[V1_LANE_8]], i32 5
358; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <8 x double> [[TMP5]], double [[V1_LANE_0]], i32 6
359; CHECK-NEXT:    [[TMP7:%.*]] = insertelement <8 x double> [[TMP6]], double [[V1_LANE_1]], i32 7
360; CHECK-NEXT:    [[TMP8:%.*]] = insertelement <8 x double> poison, double [[V2_LANE_0]], i32 0
361; CHECK-NEXT:    [[TMP9:%.*]] = insertelement <8 x double> [[TMP8]], double [[V2_LANE_2]], i32 1
362; CHECK-NEXT:    [[TMP10:%.*]] = insertelement <8 x double> [[TMP9]], double [[V2_LANE_1]], i32 2
363; CHECK-NEXT:    [[TMP11:%.*]] = insertelement <8 x double> [[TMP10]], double [[V2_LANE_0]], i32 3
364; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <8 x double> [[TMP11]], double [[V2_LANE_2]], i32 4
365; CHECK-NEXT:    [[TMP13:%.*]] = insertelement <8 x double> [[TMP12]], double [[V2_LANE_0]], i32 5
366; CHECK-NEXT:    [[TMP14:%.*]] = insertelement <8 x double> [[TMP13]], double [[V2_LANE_2]], i32 6
367; CHECK-NEXT:    [[TMP15:%.*]] = insertelement <8 x double> [[TMP14]], double [[V2_LANE_1]], i32 7
368; CHECK-NEXT:    [[TMP16:%.*]] = fmul <8 x double> [[TMP7]], [[TMP15]]
369; CHECK-NEXT:    [[A_LANE_8:%.*]] = fmul double [[V1_LANE_2]], [[V2_LANE_0]]
370; CHECK-NEXT:    [[TMP17:%.*]] = extractelement <8 x double> [[TMP16]], i32 0
371; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <9 x double> undef, double [[TMP17]], i32 0
372; CHECK-NEXT:    [[TMP18:%.*]] = extractelement <8 x double> [[TMP16]], i32 1
373; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <9 x double> [[A_INS_0]], double [[TMP18]], i32 1
374; CHECK-NEXT:    [[TMP19:%.*]] = extractelement <8 x double> [[TMP16]], i32 2
375; CHECK-NEXT:    [[A_INS_2:%.*]] = insertelement <9 x double> [[A_INS_1]], double [[TMP19]], i32 2
376; CHECK-NEXT:    [[TMP20:%.*]] = extractelement <8 x double> [[TMP16]], i32 3
377; CHECK-NEXT:    [[A_INS_3:%.*]] = insertelement <9 x double> [[A_INS_2]], double [[TMP20]], i32 3
378; CHECK-NEXT:    [[TMP21:%.*]] = extractelement <8 x double> [[TMP16]], i32 4
379; CHECK-NEXT:    [[A_INS_4:%.*]] = insertelement <9 x double> [[A_INS_3]], double [[TMP21]], i32 4
380; CHECK-NEXT:    [[TMP22:%.*]] = extractelement <8 x double> [[TMP16]], i32 5
381; CHECK-NEXT:    [[A_INS_5:%.*]] = insertelement <9 x double> [[A_INS_4]], double [[TMP22]], i32 5
382; CHECK-NEXT:    [[TMP23:%.*]] = extractelement <8 x double> [[TMP16]], i32 6
383; CHECK-NEXT:    [[A_INS_6:%.*]] = insertelement <9 x double> [[A_INS_5]], double [[TMP23]], i32 6
384; CHECK-NEXT:    [[TMP24:%.*]] = extractelement <8 x double> [[TMP16]], i32 7
385; CHECK-NEXT:    [[A_INS_7:%.*]] = insertelement <9 x double> [[A_INS_6]], double [[TMP24]], i32 7
386; CHECK-NEXT:    [[A_INS_8:%.*]] = insertelement <9 x double> [[A_INS_7]], double [[A_LANE_8]], i32 8
387; CHECK-NEXT:    [[TMP25:%.*]] = insertelement <8 x double> poison, double [[V1_LANE_6]], i32 0
388; CHECK-NEXT:    [[TMP26:%.*]] = insertelement <8 x double> [[TMP25]], double [[V1_LANE_7]], i32 1
389; CHECK-NEXT:    [[TMP27:%.*]] = insertelement <8 x double> [[TMP26]], double [[V1_LANE_8]], i32 2
390; CHECK-NEXT:    [[TMP28:%.*]] = insertelement <8 x double> [[TMP27]], double [[V1_LANE_0]], i32 3
391; CHECK-NEXT:    [[TMP29:%.*]] = insertelement <8 x double> [[TMP28]], double [[V1_LANE_1]], i32 4
392; CHECK-NEXT:    [[TMP30:%.*]] = insertelement <8 x double> [[TMP29]], double [[V1_LANE_2]], i32 5
393; CHECK-NEXT:    [[TMP31:%.*]] = insertelement <8 x double> [[TMP30]], double [[V1_LANE_3]], i32 6
394; CHECK-NEXT:    [[TMP32:%.*]] = insertelement <8 x double> [[TMP31]], double [[V1_LANE_4]], i32 7
395; CHECK-NEXT:    [[TMP33:%.*]] = insertelement <8 x double> poison, double [[V2_LANE_2]], i32 0
396; CHECK-NEXT:    [[TMP34:%.*]] = insertelement <8 x double> [[TMP33]], double [[V2_LANE_1]], i32 1
397; CHECK-NEXT:    [[TMP35:%.*]] = insertelement <8 x double> [[TMP34]], double [[V2_LANE_0]], i32 2
398; CHECK-NEXT:    [[TMP36:%.*]] = insertelement <8 x double> [[TMP35]], double [[V2_LANE_2]], i32 3
399; CHECK-NEXT:    [[TMP37:%.*]] = insertelement <8 x double> [[TMP36]], double [[V2_LANE_1]], i32 4
400; CHECK-NEXT:    [[TMP38:%.*]] = insertelement <8 x double> [[TMP37]], double [[V2_LANE_0]], i32 5
401; CHECK-NEXT:    [[TMP39:%.*]] = insertelement <8 x double> [[TMP38]], double [[V2_LANE_2]], i32 6
402; CHECK-NEXT:    [[TMP40:%.*]] = insertelement <8 x double> [[TMP39]], double [[V2_LANE_1]], i32 7
403; CHECK-NEXT:    [[TMP41:%.*]] = fmul <8 x double> [[TMP32]], [[TMP40]]
404; CHECK-NEXT:    [[B_LANE_8:%.*]] = fmul double [[V1_LANE_5]], [[V2_LANE_0]]
405; CHECK-NEXT:    [[TMP42:%.*]] = extractelement <8 x double> [[TMP41]], i32 0
406; CHECK-NEXT:    [[B_INS_0:%.*]] = insertelement <9 x double> undef, double [[TMP42]], i32 0
407; CHECK-NEXT:    [[TMP43:%.*]] = extractelement <8 x double> [[TMP41]], i32 1
408; CHECK-NEXT:    [[B_INS_1:%.*]] = insertelement <9 x double> [[B_INS_0]], double [[TMP43]], i32 1
409; CHECK-NEXT:    [[TMP44:%.*]] = extractelement <8 x double> [[TMP41]], i32 2
410; CHECK-NEXT:    [[B_INS_2:%.*]] = insertelement <9 x double> [[B_INS_1]], double [[TMP44]], i32 2
411; CHECK-NEXT:    [[TMP45:%.*]] = extractelement <8 x double> [[TMP41]], i32 3
412; CHECK-NEXT:    [[B_INS_3:%.*]] = insertelement <9 x double> [[B_INS_2]], double [[TMP45]], i32 3
413; CHECK-NEXT:    [[TMP46:%.*]] = extractelement <8 x double> [[TMP41]], i32 4
414; CHECK-NEXT:    [[B_INS_4:%.*]] = insertelement <9 x double> [[B_INS_3]], double [[TMP46]], i32 4
415; CHECK-NEXT:    [[TMP47:%.*]] = extractelement <8 x double> [[TMP41]], i32 5
416; CHECK-NEXT:    [[B_INS_5:%.*]] = insertelement <9 x double> [[B_INS_4]], double [[TMP47]], i32 5
417; CHECK-NEXT:    [[TMP48:%.*]] = extractelement <8 x double> [[TMP41]], i32 6
418; CHECK-NEXT:    [[B_INS_6:%.*]] = insertelement <9 x double> [[B_INS_5]], double [[TMP48]], i32 6
419; CHECK-NEXT:    [[TMP49:%.*]] = extractelement <8 x double> [[TMP41]], i32 7
420; CHECK-NEXT:    [[B_INS_7:%.*]] = insertelement <9 x double> [[B_INS_6]], double [[TMP49]], i32 7
421; CHECK-NEXT:    [[B_INS_8:%.*]] = insertelement <9 x double> [[B_INS_7]], double [[B_LANE_8]], i32 8
422; CHECK-NEXT:    [[RES:%.*]] = fsub <9 x double> [[A_INS_8]], [[B_INS_8]]
423; CHECK-NEXT:    store <9 x double> [[RES]], <9 x double>* [[PTR_1]], align 8
424; CHECK-NEXT:    ret void
425;
426bb:
427  %v.1 = load <9 x double>, <9 x double>* %ptr.1, align 8
428  %v1.lane.0 = extractelement <9 x double> %v.1, i32 0
429  %v1.lane.1 = extractelement <9 x double> %v.1, i32 1
430  %v1.lane.2 = extractelement <9 x double> %v.1, i32 2
431  %v1.lane.3 = extractelement <9 x double> %v.1, i32 3
432  %v1.lane.4 = extractelement <9 x double> %v.1, i32 4
433  %v1.lane.5 = extractelement <9 x double> %v.1, i32 5
434  %v1.lane.6 = extractelement <9 x double> %v.1, i32 6
435  %v1.lane.7 = extractelement <9 x double> %v.1, i32 7
436  %v1.lane.8 = extractelement <9 x double> %v.1, i32 8
437
438  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
439  %v2.lane.0 = extractelement <4 x double> %v.2, i32 0
440  %v2.lane.1 = extractelement <4 x double> %v.2, i32 1
441  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
442
443  %a.lane.0 = fmul double %v1.lane.3, %v2.lane.0
444  %a.lane.1 = fmul double %v1.lane.4, %v2.lane.2
445  %a.lane.2 = fmul double %v1.lane.5, %v2.lane.1
446  %a.lane.3 = fmul double %v1.lane.6, %v2.lane.0
447  %a.lane.4 = fmul double %v1.lane.7, %v2.lane.2
448  %a.lane.5 = fmul double %v1.lane.8, %v2.lane.0
449  %a.lane.6 = fmul double %v1.lane.0, %v2.lane.2
450  %a.lane.7 = fmul double %v1.lane.1, %v2.lane.1
451  %a.lane.8 = fmul double %v1.lane.2, %v2.lane.0
452
453  %a.ins.0 = insertelement <9 x double> undef, double %a.lane.0, i32 0
454  %a.ins.1 = insertelement <9 x double> %a.ins.0, double %a.lane.1, i32 1
455  %a.ins.2 = insertelement <9 x double> %a.ins.1, double %a.lane.2, i32 2
456  %a.ins.3 = insertelement <9 x double> %a.ins.2, double %a.lane.3, i32 3
457  %a.ins.4 = insertelement <9 x double> %a.ins.3, double %a.lane.4, i32 4
458  %a.ins.5 = insertelement <9 x double> %a.ins.4, double %a.lane.5, i32 5
459  %a.ins.6 = insertelement <9 x double> %a.ins.5, double %a.lane.6, i32 6
460  %a.ins.7 = insertelement <9 x double> %a.ins.6, double %a.lane.7, i32 7
461  %a.ins.8 = insertelement <9 x double> %a.ins.7, double %a.lane.8, i32 8
462
463  %b.lane.0 = fmul double %v1.lane.6, %v2.lane.2
464  %b.lane.1 = fmul double %v1.lane.7, %v2.lane.1
465  %b.lane.2 = fmul double %v1.lane.8, %v2.lane.0
466  %b.lane.3 = fmul double %v1.lane.0, %v2.lane.2
467  %b.lane.4 = fmul double %v1.lane.1, %v2.lane.1
468  %b.lane.5 = fmul double %v1.lane.2, %v2.lane.0
469  %b.lane.6 = fmul double %v1.lane.3, %v2.lane.2
470  %b.lane.7 = fmul double %v1.lane.4, %v2.lane.1
471  %b.lane.8 = fmul double %v1.lane.5, %v2.lane.0
472
473  %b.ins.0 = insertelement <9 x double> undef, double %b.lane.0, i32 0
474  %b.ins.1 = insertelement <9 x double> %b.ins.0, double %b.lane.1, i32 1
475  %b.ins.2 = insertelement <9 x double> %b.ins.1, double %b.lane.2, i32 2
476  %b.ins.3 = insertelement <9 x double> %b.ins.2, double %b.lane.3, i32 3
477  %b.ins.4 = insertelement <9 x double> %b.ins.3, double %b.lane.4, i32 4
478  %b.ins.5 = insertelement <9 x double> %b.ins.4, double %b.lane.5, i32 5
479  %b.ins.6 = insertelement <9 x double> %b.ins.5, double %b.lane.6, i32 6
480  %b.ins.7 = insertelement <9 x double> %b.ins.6, double %b.lane.7, i32 7
481  %b.ins.8 = insertelement <9 x double> %b.ins.7, double %b.lane.8, i32 8
482
483  %res = fsub <9 x double> %a.ins.8, %b.ins.8
484  store <9 x double> %res, <9 x double>* %ptr.1, align 8
485  ret void
486}
487
488; Extracted lanes used in first fmul chain are not used in the right order, so
489; we cannot reuse the source vector registers directly.
490define void @first_mul_chain_jumbled(<9 x double>* %ptr.1, <4 x double>* %ptr.2) {
491; CHECK-LABEL: @first_mul_chain_jumbled(
492; CHECK-NEXT:  bb:
493; CHECK-NEXT:    [[V_1:%.*]] = load <9 x double>, <9 x double>* [[PTR_1:%.*]], align 8
494; CHECK-NEXT:    [[V1_LANE_0:%.*]] = extractelement <9 x double> [[V_1]], i32 0
495; CHECK-NEXT:    [[V1_LANE_1:%.*]] = extractelement <9 x double> [[V_1]], i32 1
496; CHECK-NEXT:    [[V1_LANE_2:%.*]] = extractelement <9 x double> [[V_1]], i32 2
497; CHECK-NEXT:    [[V1_LANE_3:%.*]] = extractelement <9 x double> [[V_1]], i32 3
498; CHECK-NEXT:    [[V1_LANE_4:%.*]] = extractelement <9 x double> [[V_1]], i32 4
499; CHECK-NEXT:    [[V1_LANE_5:%.*]] = extractelement <9 x double> [[V_1]], i32 5
500; CHECK-NEXT:    [[V1_LANE_6:%.*]] = extractelement <9 x double> [[V_1]], i32 6
501; CHECK-NEXT:    [[V1_LANE_7:%.*]] = extractelement <9 x double> [[V_1]], i32 7
502; CHECK-NEXT:    [[V1_LANE_8:%.*]] = extractelement <9 x double> [[V_1]], i32 8
503; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
504; CHECK-NEXT:    [[V2_LANE_0:%.*]] = extractelement <4 x double> [[V_2]], i32 0
505; CHECK-NEXT:    [[V2_LANE_1:%.*]] = extractelement <4 x double> [[V_2]], i32 1
506; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
507; CHECK-NEXT:    [[A_LANE_0:%.*]] = fmul double [[V1_LANE_4]], [[V2_LANE_1]]
508; CHECK-NEXT:    [[A_LANE_1:%.*]] = fmul double [[V1_LANE_3]], [[V2_LANE_0]]
509; CHECK-NEXT:    [[A_LANE_2:%.*]] = fmul double [[V1_LANE_6]], [[V2_LANE_2]]
510; CHECK-NEXT:    [[A_LANE_3:%.*]] = fmul double [[V1_LANE_5]], [[V2_LANE_0]]
511; CHECK-NEXT:    [[A_LANE_4:%.*]] = fmul double [[V1_LANE_8]], [[V2_LANE_2]]
512; CHECK-NEXT:    [[A_LANE_5:%.*]] = fmul double [[V1_LANE_7]], [[V2_LANE_1]]
513; CHECK-NEXT:    [[A_LANE_6:%.*]] = fmul double [[V1_LANE_1]], [[V2_LANE_0]]
514; CHECK-NEXT:    [[A_LANE_7:%.*]] = fmul double [[V1_LANE_0]], [[V2_LANE_2]]
515; CHECK-NEXT:    [[A_LANE_8:%.*]] = fmul double [[V1_LANE_2]], [[V2_LANE_1]]
516; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <9 x double> undef, double [[A_LANE_0]], i32 0
517; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <9 x double> [[A_INS_0]], double [[A_LANE_1]], i32 1
518; CHECK-NEXT:    [[A_INS_2:%.*]] = insertelement <9 x double> [[A_INS_1]], double [[A_LANE_2]], i32 2
519; CHECK-NEXT:    [[A_INS_3:%.*]] = insertelement <9 x double> [[A_INS_2]], double [[A_LANE_3]], i32 3
520; CHECK-NEXT:    [[A_INS_4:%.*]] = insertelement <9 x double> [[A_INS_3]], double [[A_LANE_4]], i32 4
521; CHECK-NEXT:    [[A_INS_5:%.*]] = insertelement <9 x double> [[A_INS_4]], double [[A_LANE_5]], i32 5
522; CHECK-NEXT:    [[A_INS_6:%.*]] = insertelement <9 x double> [[A_INS_5]], double [[A_LANE_6]], i32 6
523; CHECK-NEXT:    [[A_INS_7:%.*]] = insertelement <9 x double> [[A_INS_6]], double [[A_LANE_7]], i32 7
524; CHECK-NEXT:    [[A_INS_8:%.*]] = insertelement <9 x double> [[A_INS_7]], double [[A_LANE_8]], i32 8
525; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <8 x double> poison, double [[V1_LANE_6]], i32 0
526; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <8 x double> [[TMP0]], double [[V1_LANE_7]], i32 1
527; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <8 x double> [[TMP1]], double [[V1_LANE_8]], i32 2
528; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <8 x double> [[TMP2]], double [[V1_LANE_0]], i32 3
529; CHECK-NEXT:    [[TMP4:%.*]] = insertelement <8 x double> [[TMP3]], double [[V1_LANE_1]], i32 4
530; CHECK-NEXT:    [[TMP5:%.*]] = insertelement <8 x double> [[TMP4]], double [[V1_LANE_2]], i32 5
531; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <8 x double> [[TMP5]], double [[V1_LANE_3]], i32 6
532; CHECK-NEXT:    [[TMP7:%.*]] = insertelement <8 x double> [[TMP6]], double [[V1_LANE_4]], i32 7
533; CHECK-NEXT:    [[TMP8:%.*]] = insertelement <8 x double> poison, double [[V2_LANE_1]], i32 0
534; CHECK-NEXT:    [[TMP9:%.*]] = insertelement <8 x double> [[TMP8]], double [[V2_LANE_0]], i32 1
535; CHECK-NEXT:    [[TMP10:%.*]] = insertelement <8 x double> [[TMP9]], double [[V2_LANE_2]], i32 2
536; CHECK-NEXT:    [[TMP11:%.*]] = insertelement <8 x double> [[TMP10]], double [[V2_LANE_0]], i32 3
537; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <8 x double> [[TMP11]], double [[V2_LANE_2]], i32 4
538; CHECK-NEXT:    [[TMP13:%.*]] = insertelement <8 x double> [[TMP12]], double [[V2_LANE_1]], i32 5
539; CHECK-NEXT:    [[TMP14:%.*]] = insertelement <8 x double> [[TMP13]], double [[V2_LANE_0]], i32 6
540; CHECK-NEXT:    [[TMP15:%.*]] = insertelement <8 x double> [[TMP14]], double [[V2_LANE_2]], i32 7
541; CHECK-NEXT:    [[TMP16:%.*]] = fmul <8 x double> [[TMP7]], [[TMP15]]
542; CHECK-NEXT:    [[B_LANE_8:%.*]] = fmul double [[V1_LANE_5]], [[V2_LANE_0]]
543; CHECK-NEXT:    [[TMP17:%.*]] = extractelement <8 x double> [[TMP16]], i32 0
544; CHECK-NEXT:    [[B_INS_0:%.*]] = insertelement <9 x double> undef, double [[TMP17]], i32 0
545; CHECK-NEXT:    [[TMP18:%.*]] = extractelement <8 x double> [[TMP16]], i32 1
546; CHECK-NEXT:    [[B_INS_1:%.*]] = insertelement <9 x double> [[B_INS_0]], double [[TMP18]], i32 1
547; CHECK-NEXT:    [[TMP19:%.*]] = extractelement <8 x double> [[TMP16]], i32 2
548; CHECK-NEXT:    [[B_INS_2:%.*]] = insertelement <9 x double> [[B_INS_1]], double [[TMP19]], i32 2
549; CHECK-NEXT:    [[TMP20:%.*]] = extractelement <8 x double> [[TMP16]], i32 3
550; CHECK-NEXT:    [[B_INS_3:%.*]] = insertelement <9 x double> [[B_INS_2]], double [[TMP20]], i32 3
551; CHECK-NEXT:    [[TMP21:%.*]] = extractelement <8 x double> [[TMP16]], i32 4
552; CHECK-NEXT:    [[B_INS_4:%.*]] = insertelement <9 x double> [[B_INS_3]], double [[TMP21]], i32 4
553; CHECK-NEXT:    [[TMP22:%.*]] = extractelement <8 x double> [[TMP16]], i32 5
554; CHECK-NEXT:    [[B_INS_5:%.*]] = insertelement <9 x double> [[B_INS_4]], double [[TMP22]], i32 5
555; CHECK-NEXT:    [[TMP23:%.*]] = extractelement <8 x double> [[TMP16]], i32 6
556; CHECK-NEXT:    [[B_INS_6:%.*]] = insertelement <9 x double> [[B_INS_5]], double [[TMP23]], i32 6
557; CHECK-NEXT:    [[TMP24:%.*]] = extractelement <8 x double> [[TMP16]], i32 7
558; CHECK-NEXT:    [[B_INS_7:%.*]] = insertelement <9 x double> [[B_INS_6]], double [[TMP24]], i32 7
559; CHECK-NEXT:    [[B_INS_8:%.*]] = insertelement <9 x double> [[B_INS_7]], double [[B_LANE_8]], i32 8
560; CHECK-NEXT:    [[RES:%.*]] = fsub <9 x double> [[A_INS_8]], [[B_INS_8]]
561; CHECK-NEXT:    store <9 x double> [[RES]], <9 x double>* [[PTR_1]], align 8
562; CHECK-NEXT:    ret void
563;
564bb:
565  %v.1 = load <9 x double>, <9 x double>* %ptr.1, align 8
566  %v1.lane.0 = extractelement <9 x double> %v.1, i32 0
567  %v1.lane.1 = extractelement <9 x double> %v.1, i32 1
568  %v1.lane.2 = extractelement <9 x double> %v.1, i32 2
569  %v1.lane.3 = extractelement <9 x double> %v.1, i32 3
570  %v1.lane.4 = extractelement <9 x double> %v.1, i32 4
571  %v1.lane.5 = extractelement <9 x double> %v.1, i32 5
572  %v1.lane.6 = extractelement <9 x double> %v.1, i32 6
573  %v1.lane.7 = extractelement <9 x double> %v.1, i32 7
574  %v1.lane.8 = extractelement <9 x double> %v.1, i32 8
575
576  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
577  %v2.lane.0 = extractelement <4 x double> %v.2, i32 0
578  %v2.lane.1 = extractelement <4 x double> %v.2, i32 1
579  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
580
581  %a.lane.0 = fmul double %v1.lane.4, %v2.lane.1
582  %a.lane.1 = fmul double %v1.lane.3, %v2.lane.0
583  %a.lane.2 = fmul double %v1.lane.6, %v2.lane.2
584  %a.lane.3 = fmul double %v1.lane.5, %v2.lane.0
585  %a.lane.4 = fmul double %v1.lane.8, %v2.lane.2
586  %a.lane.5 = fmul double %v1.lane.7, %v2.lane.1
587  %a.lane.6 = fmul double %v1.lane.1, %v2.lane.0
588  %a.lane.7 = fmul double %v1.lane.0, %v2.lane.2
589  %a.lane.8 = fmul double %v1.lane.2, %v2.lane.1
590
591  %a.ins.0 = insertelement <9 x double> undef, double %a.lane.0, i32 0
592  %a.ins.1 = insertelement <9 x double> %a.ins.0, double %a.lane.1, i32 1
593  %a.ins.2 = insertelement <9 x double> %a.ins.1, double %a.lane.2, i32 2
594  %a.ins.3 = insertelement <9 x double> %a.ins.2, double %a.lane.3, i32 3
595  %a.ins.4 = insertelement <9 x double> %a.ins.3, double %a.lane.4, i32 4
596  %a.ins.5 = insertelement <9 x double> %a.ins.4, double %a.lane.5, i32 5
597  %a.ins.6 = insertelement <9 x double> %a.ins.5, double %a.lane.6, i32 6
598  %a.ins.7 = insertelement <9 x double> %a.ins.6, double %a.lane.7, i32 7
599  %a.ins.8 = insertelement <9 x double> %a.ins.7, double %a.lane.8, i32 8
600
601  %b.lane.0 = fmul double %v1.lane.6, %v2.lane.1
602  %b.lane.1 = fmul double %v1.lane.7, %v2.lane.0
603  %b.lane.2 = fmul double %v1.lane.8, %v2.lane.2
604  %b.lane.3 = fmul double %v1.lane.0, %v2.lane.0
605  %b.lane.4 = fmul double %v1.lane.1, %v2.lane.2
606  %b.lane.5 = fmul double %v1.lane.2, %v2.lane.1
607  %b.lane.6 = fmul double %v1.lane.3, %v2.lane.0
608  %b.lane.7 = fmul double %v1.lane.4, %v2.lane.2
609  %b.lane.8 = fmul double %v1.lane.5, %v2.lane.0
610
611  %b.ins.0 = insertelement <9 x double> undef, double %b.lane.0, i32 0
612  %b.ins.1 = insertelement <9 x double> %b.ins.0, double %b.lane.1, i32 1
613  %b.ins.2 = insertelement <9 x double> %b.ins.1, double %b.lane.2, i32 2
614  %b.ins.3 = insertelement <9 x double> %b.ins.2, double %b.lane.3, i32 3
615  %b.ins.4 = insertelement <9 x double> %b.ins.3, double %b.lane.4, i32 4
616  %b.ins.5 = insertelement <9 x double> %b.ins.4, double %b.lane.5, i32 5
617  %b.ins.6 = insertelement <9 x double> %b.ins.5, double %b.lane.6, i32 6
618  %b.ins.7 = insertelement <9 x double> %b.ins.6, double %b.lane.7, i32 7
619  %b.ins.8 = insertelement <9 x double> %b.ins.7, double %b.lane.8, i32 8
620
621  %res = fsub <9 x double> %a.ins.8, %b.ins.8
622  store <9 x double> %res, <9 x double>* %ptr.1, align 8
623  ret void
624}
625
626; Extracted lanes used in both fmul chain are not used in the right order, so
627; we cannot reuse the source vector registers directly.
628define void @first_and_second_mul_chain_jumbled(<9 x double>* %ptr.1, <4 x double>* %ptr.2) {
629; CHECK-LABEL: @first_and_second_mul_chain_jumbled(
630; CHECK-NEXT:  bb:
631; CHECK-NEXT:    [[V_1:%.*]] = load <9 x double>, <9 x double>* [[PTR_1:%.*]], align 8
632; CHECK-NEXT:    [[V1_LANE_0:%.*]] = extractelement <9 x double> [[V_1]], i32 0
633; CHECK-NEXT:    [[V1_LANE_1:%.*]] = extractelement <9 x double> [[V_1]], i32 1
634; CHECK-NEXT:    [[V1_LANE_2:%.*]] = extractelement <9 x double> [[V_1]], i32 2
635; CHECK-NEXT:    [[V1_LANE_3:%.*]] = extractelement <9 x double> [[V_1]], i32 3
636; CHECK-NEXT:    [[V1_LANE_4:%.*]] = extractelement <9 x double> [[V_1]], i32 4
637; CHECK-NEXT:    [[V1_LANE_5:%.*]] = extractelement <9 x double> [[V_1]], i32 5
638; CHECK-NEXT:    [[V1_LANE_6:%.*]] = extractelement <9 x double> [[V_1]], i32 6
639; CHECK-NEXT:    [[V1_LANE_7:%.*]] = extractelement <9 x double> [[V_1]], i32 7
640; CHECK-NEXT:    [[V1_LANE_8:%.*]] = extractelement <9 x double> [[V_1]], i32 8
641; CHECK-NEXT:    [[V_2:%.*]] = load <4 x double>, <4 x double>* [[PTR_2:%.*]], align 16
642; CHECK-NEXT:    [[V2_LANE_0:%.*]] = extractelement <4 x double> [[V_2]], i32 0
643; CHECK-NEXT:    [[V2_LANE_1:%.*]] = extractelement <4 x double> [[V_2]], i32 1
644; CHECK-NEXT:    [[V2_LANE_2:%.*]] = extractelement <4 x double> [[V_2]], i32 2
645; CHECK-NEXT:    [[A_LANE_0:%.*]] = fmul double [[V1_LANE_4]], [[V2_LANE_0]]
646; CHECK-NEXT:    [[A_LANE_1:%.*]] = fmul double [[V1_LANE_3]], [[V2_LANE_2]]
647; CHECK-NEXT:    [[A_LANE_2:%.*]] = fmul double [[V1_LANE_5]], [[V2_LANE_1]]
648; CHECK-NEXT:    [[A_LANE_3:%.*]] = fmul double [[V1_LANE_6]], [[V2_LANE_2]]
649; CHECK-NEXT:    [[A_LANE_4:%.*]] = fmul double [[V1_LANE_8]], [[V2_LANE_1]]
650; CHECK-NEXT:    [[A_LANE_5:%.*]] = fmul double [[V1_LANE_7]], [[V2_LANE_0]]
651; CHECK-NEXT:    [[A_LANE_6:%.*]] = fmul double [[V1_LANE_1]], [[V2_LANE_2]]
652; CHECK-NEXT:    [[A_LANE_7:%.*]] = fmul double [[V1_LANE_0]], [[V2_LANE_1]]
653; CHECK-NEXT:    [[A_LANE_8:%.*]] = fmul double [[V1_LANE_2]], [[V2_LANE_0]]
654; CHECK-NEXT:    [[A_INS_0:%.*]] = insertelement <9 x double> undef, double [[A_LANE_0]], i32 0
655; CHECK-NEXT:    [[A_INS_1:%.*]] = insertelement <9 x double> [[A_INS_0]], double [[A_LANE_1]], i32 1
656; CHECK-NEXT:    [[A_INS_2:%.*]] = insertelement <9 x double> [[A_INS_1]], double [[A_LANE_2]], i32 2
657; CHECK-NEXT:    [[A_INS_3:%.*]] = insertelement <9 x double> [[A_INS_2]], double [[A_LANE_3]], i32 3
658; CHECK-NEXT:    [[A_INS_4:%.*]] = insertelement <9 x double> [[A_INS_3]], double [[A_LANE_4]], i32 4
659; CHECK-NEXT:    [[A_INS_5:%.*]] = insertelement <9 x double> [[A_INS_4]], double [[A_LANE_5]], i32 5
660; CHECK-NEXT:    [[A_INS_6:%.*]] = insertelement <9 x double> [[A_INS_5]], double [[A_LANE_6]], i32 6
661; CHECK-NEXT:    [[A_INS_7:%.*]] = insertelement <9 x double> [[A_INS_6]], double [[A_LANE_7]], i32 7
662; CHECK-NEXT:    [[A_INS_8:%.*]] = insertelement <9 x double> [[A_INS_7]], double [[A_LANE_8]], i32 8
663; CHECK-NEXT:    [[B_LANE_0:%.*]] = fmul double [[V1_LANE_7]], [[V2_LANE_2]]
664; CHECK-NEXT:    [[B_LANE_1:%.*]] = fmul double [[V1_LANE_6]], [[V2_LANE_1]]
665; CHECK-NEXT:    [[B_LANE_2:%.*]] = fmul double [[V1_LANE_8]], [[V2_LANE_0]]
666; CHECK-NEXT:    [[B_LANE_3:%.*]] = fmul double [[V1_LANE_1]], [[V2_LANE_2]]
667; CHECK-NEXT:    [[B_LANE_4:%.*]] = fmul double [[V1_LANE_0]], [[V2_LANE_0]]
668; CHECK-NEXT:    [[B_LANE_5:%.*]] = fmul double [[V1_LANE_3]], [[V2_LANE_2]]
669; CHECK-NEXT:    [[B_LANE_6:%.*]] = fmul double [[V1_LANE_2]], [[V2_LANE_1]]
670; CHECK-NEXT:    [[B_LANE_7:%.*]] = fmul double [[V1_LANE_5]], [[V2_LANE_0]]
671; CHECK-NEXT:    [[B_LANE_8:%.*]] = fmul double [[V1_LANE_4]], [[V2_LANE_2]]
672; CHECK-NEXT:    [[B_INS_0:%.*]] = insertelement <9 x double> undef, double [[B_LANE_0]], i32 0
673; CHECK-NEXT:    [[B_INS_1:%.*]] = insertelement <9 x double> [[B_INS_0]], double [[B_LANE_1]], i32 1
674; CHECK-NEXT:    [[B_INS_2:%.*]] = insertelement <9 x double> [[B_INS_1]], double [[B_LANE_2]], i32 2
675; CHECK-NEXT:    [[B_INS_3:%.*]] = insertelement <9 x double> [[B_INS_2]], double [[B_LANE_3]], i32 3
676; CHECK-NEXT:    [[B_INS_4:%.*]] = insertelement <9 x double> [[B_INS_3]], double [[B_LANE_4]], i32 4
677; CHECK-NEXT:    [[B_INS_5:%.*]] = insertelement <9 x double> [[B_INS_4]], double [[B_LANE_5]], i32 5
678; CHECK-NEXT:    [[B_INS_6:%.*]] = insertelement <9 x double> [[B_INS_5]], double [[B_LANE_6]], i32 6
679; CHECK-NEXT:    [[B_INS_7:%.*]] = insertelement <9 x double> [[B_INS_6]], double [[B_LANE_7]], i32 7
680; CHECK-NEXT:    [[B_INS_8:%.*]] = insertelement <9 x double> [[B_INS_7]], double [[B_LANE_8]], i32 8
681; CHECK-NEXT:    [[RES:%.*]] = fsub <9 x double> [[A_INS_8]], [[B_INS_8]]
682; CHECK-NEXT:    store <9 x double> [[RES]], <9 x double>* [[PTR_1]], align 8
683; CHECK-NEXT:    ret void
684;
685bb:
686  %v.1 = load <9 x double>, <9 x double>* %ptr.1, align 8
687  %v1.lane.0 = extractelement <9 x double> %v.1, i32 0
688  %v1.lane.1 = extractelement <9 x double> %v.1, i32 1
689  %v1.lane.2 = extractelement <9 x double> %v.1, i32 2
690  %v1.lane.3 = extractelement <9 x double> %v.1, i32 3
691  %v1.lane.4 = extractelement <9 x double> %v.1, i32 4
692  %v1.lane.5 = extractelement <9 x double> %v.1, i32 5
693  %v1.lane.6 = extractelement <9 x double> %v.1, i32 6
694  %v1.lane.7 = extractelement <9 x double> %v.1, i32 7
695  %v1.lane.8 = extractelement <9 x double> %v.1, i32 8
696
697  %v.2 = load <4 x double>, <4 x double>* %ptr.2, align 16
698  %v2.lane.0 = extractelement <4 x double> %v.2, i32 0
699  %v2.lane.1 = extractelement <4 x double> %v.2, i32 1
700  %v2.lane.2 = extractelement <4 x double> %v.2, i32 2
701
702  %a.lane.0 = fmul double %v1.lane.4, %v2.lane.0
703  %a.lane.1 = fmul double %v1.lane.3, %v2.lane.2
704  %a.lane.2 = fmul double %v1.lane.5, %v2.lane.1
705  %a.lane.3 = fmul double %v1.lane.6, %v2.lane.2
706  %a.lane.4 = fmul double %v1.lane.8, %v2.lane.1
707  %a.lane.5 = fmul double %v1.lane.7, %v2.lane.0
708  %a.lane.6 = fmul double %v1.lane.1, %v2.lane.2
709  %a.lane.7 = fmul double %v1.lane.0, %v2.lane.1
710  %a.lane.8 = fmul double %v1.lane.2, %v2.lane.0
711
712  %a.ins.0 = insertelement <9 x double> undef, double %a.lane.0, i32 0
713  %a.ins.1 = insertelement <9 x double> %a.ins.0, double %a.lane.1, i32 1
714  %a.ins.2 = insertelement <9 x double> %a.ins.1, double %a.lane.2, i32 2
715  %a.ins.3 = insertelement <9 x double> %a.ins.2, double %a.lane.3, i32 3
716  %a.ins.4 = insertelement <9 x double> %a.ins.3, double %a.lane.4, i32 4
717  %a.ins.5 = insertelement <9 x double> %a.ins.4, double %a.lane.5, i32 5
718  %a.ins.6 = insertelement <9 x double> %a.ins.5, double %a.lane.6, i32 6
719  %a.ins.7 = insertelement <9 x double> %a.ins.6, double %a.lane.7, i32 7
720  %a.ins.8 = insertelement <9 x double> %a.ins.7, double %a.lane.8, i32 8
721
722  %b.lane.0 = fmul double %v1.lane.7, %v2.lane.2
723  %b.lane.1 = fmul double %v1.lane.6, %v2.lane.1
724  %b.lane.2 = fmul double %v1.lane.8, %v2.lane.0
725  %b.lane.3 = fmul double %v1.lane.1, %v2.lane.2
726  %b.lane.4 = fmul double %v1.lane.0, %v2.lane.0
727  %b.lane.5 = fmul double %v1.lane.3, %v2.lane.2
728  %b.lane.6 = fmul double %v1.lane.2, %v2.lane.1
729  %b.lane.7 = fmul double %v1.lane.5, %v2.lane.0
730  %b.lane.8 = fmul double %v1.lane.4, %v2.lane.2
731
732  %b.ins.0 = insertelement <9 x double> undef, double %b.lane.0, i32 0
733  %b.ins.1 = insertelement <9 x double> %b.ins.0, double %b.lane.1, i32 1
734  %b.ins.2 = insertelement <9 x double> %b.ins.1, double %b.lane.2, i32 2
735  %b.ins.3 = insertelement <9 x double> %b.ins.2, double %b.lane.3, i32 3
736  %b.ins.4 = insertelement <9 x double> %b.ins.3, double %b.lane.4, i32 4
737  %b.ins.5 = insertelement <9 x double> %b.ins.4, double %b.lane.5, i32 5
738  %b.ins.6 = insertelement <9 x double> %b.ins.5, double %b.lane.6, i32 6
739  %b.ins.7 = insertelement <9 x double> %b.ins.6, double %b.lane.7, i32 7
740  %b.ins.8 = insertelement <9 x double> %b.ins.7, double %b.lane.8, i32 8
741
742  %res = fsub <9 x double> %a.ins.8, %b.ins.8
743  store <9 x double> %res, <9 x double>* %ptr.1, align 8
744  ret void
745}
746