1; RUN: llc < %s -march=x86-64 -mcpu=corei7 -mattr=+ssse3 | FileCheck %s -check-prefix=CHECK -check-prefix=SSE
2; RUN: llc < %s -march=x86-64 -mcpu=corei7-avx | FileCheck %s -check-prefix=CHECK -check-prefix=AVX
3; RUN: llc < %s -march=x86-64 -mcpu=core-avx2 | FileCheck %s -check-prefix=CHECK -check-prefix=AVX2
4
5; Verify that we correctly fold horizontal binop even in the presence of UNDEFs.
6
7define <4 x float> @test1_undef(<4 x float> %a, <4 x float> %b) {
8  %vecext = extractelement <4 x float> %a, i32 0
9  %vecext1 = extractelement <4 x float> %a, i32 1
10  %add = fadd float %vecext, %vecext1
11  %vecinit = insertelement <4 x float> undef, float %add, i32 0
12  %vecext2 = extractelement <4 x float> %a, i32 2
13  %vecext3 = extractelement <4 x float> %a, i32 3
14  %add4 = fadd float %vecext2, %vecext3
15  %vecinit5 = insertelement <4 x float> %vecinit, float %add4, i32 1
16  %vecext10 = extractelement <4 x float> %b, i32 2
17  %vecext11 = extractelement <4 x float> %b, i32 3
18  %add12 = fadd float %vecext10, %vecext11
19  %vecinit13 = insertelement <4 x float> %vecinit5, float %add12, i32 3
20  ret <4 x float> %vecinit13
21}
22; CHECK-LABEL: test1_undef
23; SSE: haddps
24; AVX: vhaddps
25; AVX2: vhaddps
26; CHECK-NEXT: ret
27
28
29define <4 x float> @test2_undef(<4 x float> %a, <4 x float> %b) {
30  %vecext = extractelement <4 x float> %a, i32 0
31  %vecext1 = extractelement <4 x float> %a, i32 1
32  %add = fadd float %vecext, %vecext1
33  %vecinit = insertelement <4 x float> undef, float %add, i32 0
34  %vecext6 = extractelement <4 x float> %b, i32 0
35  %vecext7 = extractelement <4 x float> %b, i32 1
36  %add8 = fadd float %vecext6, %vecext7
37  %vecinit9 = insertelement <4 x float> %vecinit, float %add8, i32 2
38  %vecext10 = extractelement <4 x float> %b, i32 2
39  %vecext11 = extractelement <4 x float> %b, i32 3
40  %add12 = fadd float %vecext10, %vecext11
41  %vecinit13 = insertelement <4 x float> %vecinit9, float %add12, i32 3
42  ret <4 x float> %vecinit13
43}
44; CHECK-LABEL: test2_undef
45; SSE: haddps
46; AVX: vhaddps
47; AVX2: vhaddps
48; CHECK-NEXT: ret
49
50
51define <4 x float> @test3_undef(<4 x float> %a, <4 x float> %b) {
52  %vecext = extractelement <4 x float> %a, i32 0
53  %vecext1 = extractelement <4 x float> %a, i32 1
54  %add = fadd float %vecext, %vecext1
55  %vecinit = insertelement <4 x float> undef, float %add, i32 0
56  %vecext2 = extractelement <4 x float> %a, i32 2
57  %vecext3 = extractelement <4 x float> %a, i32 3
58  %add4 = fadd float %vecext2, %vecext3
59  %vecinit5 = insertelement <4 x float> %vecinit, float %add4, i32 1
60  %vecext6 = extractelement <4 x float> %b, i32 0
61  %vecext7 = extractelement <4 x float> %b, i32 1
62  %add8 = fadd float %vecext6, %vecext7
63  %vecinit9 = insertelement <4 x float> %vecinit5, float %add8, i32 2
64  ret <4 x float> %vecinit9
65}
66; CHECK-LABEL: test3_undef
67; SSE: haddps
68; AVX: vhaddps
69; AVX2: vhaddps
70; CHECK-NEXT: ret
71
72
73define <4 x float> @test4_undef(<4 x float> %a, <4 x float> %b) {
74  %vecext = extractelement <4 x float> %a, i32 0
75  %vecext1 = extractelement <4 x float> %a, i32 1
76  %add = fadd float %vecext, %vecext1
77  %vecinit = insertelement <4 x float> undef, float %add, i32 0
78  ret <4 x float> %vecinit
79}
80; CHECK-LABEL: test4_undef
81; CHECK-NOT: haddps
82; CHECK: ret
83
84
85define <2 x double> @test5_undef(<2 x double> %a, <2 x double> %b) {
86  %vecext = extractelement <2 x double> %a, i32 0
87  %vecext1 = extractelement <2 x double> %a, i32 1
88  %add = fadd double %vecext, %vecext1
89  %vecinit = insertelement <2 x double> undef, double %add, i32 0
90  ret <2 x double> %vecinit
91}
92; CHECK-LABEL: test5_undef
93; CHECK-NOT: haddpd
94; CHECK: ret
95
96
97define <4 x float> @test6_undef(<4 x float> %a, <4 x float> %b) {
98  %vecext = extractelement <4 x float> %a, i32 0
99  %vecext1 = extractelement <4 x float> %a, i32 1
100  %add = fadd float %vecext, %vecext1
101  %vecinit = insertelement <4 x float> undef, float %add, i32 0
102  %vecext2 = extractelement <4 x float> %a, i32 2
103  %vecext3 = extractelement <4 x float> %a, i32 3
104  %add4 = fadd float %vecext2, %vecext3
105  %vecinit5 = insertelement <4 x float> %vecinit, float %add4, i32 1
106  ret <4 x float> %vecinit5
107}
108; CHECK-LABEL: test6_undef
109; SSE: haddps
110; AVX: vhaddps
111; AVX2: vhaddps
112; CHECK-NEXT: ret
113
114
115define <4 x float> @test7_undef(<4 x float> %a, <4 x float> %b) {
116  %vecext = extractelement <4 x float> %b, i32 0
117  %vecext1 = extractelement <4 x float> %b, i32 1
118  %add = fadd float %vecext, %vecext1
119  %vecinit = insertelement <4 x float> undef, float %add, i32 2
120  %vecext2 = extractelement <4 x float> %b, i32 2
121  %vecext3 = extractelement <4 x float> %b, i32 3
122  %add4 = fadd float %vecext2, %vecext3
123  %vecinit5 = insertelement <4 x float> %vecinit, float %add4, i32 3
124  ret <4 x float> %vecinit5
125}
126; CHECK-LABEL: test7_undef
127; SSE: haddps
128; AVX: vhaddps
129; AVX2: vhaddps
130; CHECK-NEXT: ret
131
132
133define <4 x float> @test8_undef(<4 x float> %a, <4 x float> %b) {
134  %vecext = extractelement <4 x float> %a, i32 0
135  %vecext1 = extractelement <4 x float> %a, i32 1
136  %add = fadd float %vecext, %vecext1
137  %vecinit = insertelement <4 x float> undef, float %add, i32 0
138  %vecext2 = extractelement <4 x float> %a, i32 2
139  %vecext3 = extractelement <4 x float> %a, i32 3
140  %add4 = fadd float %vecext2, %vecext3
141  %vecinit5 = insertelement <4 x float> %vecinit, float %add4, i32 2
142  ret <4 x float> %vecinit5
143}
144; CHECK-LABEL: test8_undef
145; CHECK-NOT: haddps
146; CHECK: ret
147
148
149define <4 x float> @test9_undef(<4 x float> %a, <4 x float> %b) {
150  %vecext = extractelement <4 x float> %a, i32 0
151  %vecext1 = extractelement <4 x float> %a, i32 1
152  %add = fadd float %vecext, %vecext1
153  %vecinit = insertelement <4 x float> undef, float %add, i32 0
154  %vecext2 = extractelement <4 x float> %b, i32 2
155  %vecext3 = extractelement <4 x float> %b, i32 3
156  %add4 = fadd float %vecext2, %vecext3
157  %vecinit5 = insertelement <4 x float> %vecinit, float %add4, i32 3
158  ret <4 x float> %vecinit5
159}
160; CHECK-LABEL: test9_undef
161; CHECK: haddps
162; CHECK-NEXT: ret
163
164define <8 x float> @test10_undef(<8 x float> %a, <8 x float> %b) {
165  %vecext = extractelement <8 x float> %a, i32 0
166  %vecext1 = extractelement <8 x float> %a, i32 1
167  %add = fadd float %vecext, %vecext1
168  %vecinit = insertelement <8 x float> undef, float %add, i32 0
169  %vecext2 = extractelement <8 x float> %b, i32 2
170  %vecext3 = extractelement <8 x float> %b, i32 3
171  %add4 = fadd float %vecext2, %vecext3
172  %vecinit5 = insertelement <8 x float> %vecinit, float %add4, i32 3
173  ret <8 x float> %vecinit5
174}
175; CHECK-LABEL: test10_undef
176; SSE: haddps
177; AVX: vhaddps
178; AVX2: vhaddps
179; CHECK-NOT: haddps
180; CHECK: ret
181
182define <8 x float> @test11_undef(<8 x float> %a, <8 x float> %b) {
183  %vecext = extractelement <8 x float> %a, i32 0
184  %vecext1 = extractelement <8 x float> %a, i32 1
185  %add = fadd float %vecext, %vecext1
186  %vecinit = insertelement <8 x float> undef, float %add, i32 0
187  %vecext2 = extractelement <8 x float> %b, i32 4
188  %vecext3 = extractelement <8 x float> %b, i32 5
189  %add4 = fadd float %vecext2, %vecext3
190  %vecinit5 = insertelement <8 x float> %vecinit, float %add4, i32 6
191  ret <8 x float> %vecinit5
192}
193; CHECK-LABEL: test11_undef
194; SSE-NOT: haddps
195; AVX: vhaddps
196; AVX2: vhaddps
197; CHECK: ret
198
199define <8 x float> @test12_undef(<8 x float> %a, <8 x float> %b) {
200  %vecext = extractelement <8 x float> %a, i32 0
201  %vecext1 = extractelement <8 x float> %a, i32 1
202  %add = fadd float %vecext, %vecext1
203  %vecinit = insertelement <8 x float> undef, float %add, i32 0
204  %vecext2 = extractelement <8 x float> %a, i32 2
205  %vecext3 = extractelement <8 x float> %a, i32 3
206  %add4 = fadd float %vecext2, %vecext3
207  %vecinit5 = insertelement <8 x float> %vecinit, float %add4, i32 1
208  ret <8 x float> %vecinit5
209}
210; CHECK-LABEL: test12_undef
211; SSE: haddps
212; AVX: vhaddps
213; AVX2: vhaddps
214; CHECK-NOT: haddps
215; CHECK: ret
216
217define <8 x float> @test13_undef(<8 x float> %a, <8 x float> %b) {
218  %vecext = extractelement <8 x float> %a, i32 0
219  %vecext1 = extractelement <8 x float> %a, i32 1
220  %add1 = fadd float %vecext, %vecext1
221  %vecinit1 = insertelement <8 x float> undef, float %add1, i32 0
222  %vecext2 = extractelement <8 x float> %a, i32 2
223  %vecext3 = extractelement <8 x float> %a, i32 3
224  %add2 = fadd float %vecext2, %vecext3
225  %vecinit2 = insertelement <8 x float> %vecinit1, float %add2, i32 1
226  %vecext4 = extractelement <8 x float> %a, i32 4
227  %vecext5 = extractelement <8 x float> %a, i32 5
228  %add3 = fadd float %vecext4, %vecext5
229  %vecinit3 = insertelement <8 x float> %vecinit2, float %add3, i32 2
230  %vecext6 = extractelement <8 x float> %a, i32 6
231  %vecext7 = extractelement <8 x float> %a, i32 7
232  %add4 = fadd float %vecext6, %vecext7
233  %vecinit4 = insertelement <8 x float> %vecinit3, float %add4, i32 3
234  ret <8 x float> %vecinit4
235}
236; CHECK-LABEL: test13_undef
237; SSE: haddps
238; SSE-NOT: haddps
239; AVX: vhaddps
240; AVX2: vhaddps
241; CHECK-NOT: haddps
242; CHECK: ret
243
244define <8 x i32> @test14_undef(<8 x i32> %a, <8 x i32> %b) {
245  %vecext = extractelement <8 x i32> %a, i32 0
246  %vecext1 = extractelement <8 x i32> %a, i32 1
247  %add = add i32 %vecext, %vecext1
248  %vecinit = insertelement <8 x i32> undef, i32 %add, i32 0
249  %vecext2 = extractelement <8 x i32> %b, i32 2
250  %vecext3 = extractelement <8 x i32> %b, i32 3
251  %add4 = add i32 %vecext2, %vecext3
252  %vecinit5 = insertelement <8 x i32> %vecinit, i32 %add4, i32 3
253  ret <8 x i32> %vecinit5
254}
255; CHECK-LABEL: test14_undef
256; SSE: phaddd
257; AVX: vphaddd
258; AVX2: vphaddd
259; CHECK-NOT: phaddd
260; CHECK: ret
261
262; On AVX2, the following sequence can be folded into a single horizontal add.
263; If the Subtarget doesn't support AVX2, then we avoid emitting two packed
264; integer horizontal adds instead of two scalar adds followed by vector inserts.
265define <8 x i32> @test15_undef(<8 x i32> %a, <8 x i32> %b) {
266  %vecext = extractelement <8 x i32> %a, i32 0
267  %vecext1 = extractelement <8 x i32> %a, i32 1
268  %add = add i32 %vecext, %vecext1
269  %vecinit = insertelement <8 x i32> undef, i32 %add, i32 0
270  %vecext2 = extractelement <8 x i32> %b, i32 4
271  %vecext3 = extractelement <8 x i32> %b, i32 5
272  %add4 = add i32 %vecext2, %vecext3
273  %vecinit5 = insertelement <8 x i32> %vecinit, i32 %add4, i32 6
274  ret <8 x i32> %vecinit5
275}
276; CHECK-LABEL: test15_undef
277; SSE-NOT: phaddd
278; AVX-NOT: vphaddd
279; AVX2: vphaddd
280; CHECK: ret
281
282define <8 x i32> @test16_undef(<8 x i32> %a, <8 x i32> %b) {
283  %vecext = extractelement <8 x i32> %a, i32 0
284  %vecext1 = extractelement <8 x i32> %a, i32 1
285  %add = add i32 %vecext, %vecext1
286  %vecinit = insertelement <8 x i32> undef, i32 %add, i32 0
287  %vecext2 = extractelement <8 x i32> %a, i32 2
288  %vecext3 = extractelement <8 x i32> %a, i32 3
289  %add4 = add i32 %vecext2, %vecext3
290  %vecinit5 = insertelement <8 x i32> %vecinit, i32 %add4, i32 1
291  ret <8 x i32> %vecinit5
292}
293; CHECK-LABEL: test16_undef
294; SSE: phaddd
295; AVX: vphaddd
296; AVX2: vphaddd
297; CHECK-NOT: haddps
298; CHECK: ret
299
300define <8 x i32> @test17_undef(<8 x i32> %a, <8 x i32> %b) {
301  %vecext = extractelement <8 x i32> %a, i32 0
302  %vecext1 = extractelement <8 x i32> %a, i32 1
303  %add1 = add i32 %vecext, %vecext1
304  %vecinit1 = insertelement <8 x i32> undef, i32 %add1, i32 0
305  %vecext2 = extractelement <8 x i32> %a, i32 2
306  %vecext3 = extractelement <8 x i32> %a, i32 3
307  %add2 = add i32 %vecext2, %vecext3
308  %vecinit2 = insertelement <8 x i32> %vecinit1, i32 %add2, i32 1
309  %vecext4 = extractelement <8 x i32> %a, i32 4
310  %vecext5 = extractelement <8 x i32> %a, i32 5
311  %add3 = add i32 %vecext4, %vecext5
312  %vecinit3 = insertelement <8 x i32> %vecinit2, i32 %add3, i32 2
313  %vecext6 = extractelement <8 x i32> %a, i32 6
314  %vecext7 = extractelement <8 x i32> %a, i32 7
315  %add4 = add i32 %vecext6, %vecext7
316  %vecinit4 = insertelement <8 x i32> %vecinit3, i32 %add4, i32 3
317  ret <8 x i32> %vecinit4
318}
319; CHECK-LABEL: test17_undef
320; SSE: phaddd
321; AVX: vphaddd
322; AVX2: vphaddd
323; CHECK-NOT: haddps
324; CHECK: ret
325
326