1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -loop-vectorize -mtriple=x86_64-apple-darwin %s | FileCheck %s --check-prefixes=CHECK,SSE
3; RUN: opt -S -loop-vectorize -mtriple=x86_64-apple-darwin -mattr=+avx %s | FileCheck %s --check-prefixes=CHECK,AVX
4
5; Two mostly identical functions. The only difference is the presence of
6; fast-math flags on the second. The loop is a pretty simple reduction:
7
8; for (int i = 0; i < 32; ++i)
9;   if (arr[i] != 42)
10;     tot += arr[i];
11
12define double @sumIfScalar(double* nocapture readonly %arr) {
13; CHECK-LABEL: @sumIfScalar(
14; CHECK-NEXT:  entry:
15; CHECK-NEXT:    br label [[LOOP:%.*]]
16; CHECK:       loop:
17; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[NEXT_ITER:%.*]] ]
18; CHECK-NEXT:    [[TOT:%.*]] = phi double [ 0.000000e+00, [[ENTRY]] ], [ [[TOT_NEXT:%.*]], [[NEXT_ITER]] ]
19; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr double, double* [[ARR:%.*]], i32 [[I]]
20; CHECK-NEXT:    [[NEXTVAL:%.*]] = load double, double* [[ADDR]]
21; CHECK-NEXT:    [[TST:%.*]] = fcmp une double [[NEXTVAL]], 4.200000e+01
22; CHECK-NEXT:    br i1 [[TST]], label [[DO_ADD:%.*]], label [[NO_ADD:%.*]]
23; CHECK:       do.add:
24; CHECK-NEXT:    [[TOT_NEW:%.*]] = fadd double [[TOT]], [[NEXTVAL]]
25; CHECK-NEXT:    br label [[NEXT_ITER]]
26; CHECK:       no.add:
27; CHECK-NEXT:    br label [[NEXT_ITER]]
28; CHECK:       next.iter:
29; CHECK-NEXT:    [[TOT_NEXT]] = phi double [ [[TOT]], [[NO_ADD]] ], [ [[TOT_NEW]], [[DO_ADD]] ]
30; CHECK-NEXT:    [[I_NEXT]] = add i32 [[I]], 1
31; CHECK-NEXT:    [[AGAIN:%.*]] = icmp ult i32 [[I_NEXT]], 32
32; CHECK-NEXT:    br i1 [[AGAIN]], label [[LOOP]], label [[DONE:%.*]]
33; CHECK:       done:
34; CHECK-NEXT:    [[TOT_NEXT_LCSSA:%.*]] = phi double [ [[TOT_NEXT]], [[NEXT_ITER]] ]
35; CHECK-NEXT:    ret double [[TOT_NEXT_LCSSA]]
36;
37entry:
38  br label %loop
39
40loop:
41  %i = phi i32 [0, %entry], [%i.next, %next.iter]
42  %tot = phi double [0.0, %entry], [%tot.next, %next.iter]
43
44  %addr = getelementptr double, double* %arr, i32 %i
45  %nextval = load double, double* %addr
46
47  %tst = fcmp une double %nextval, 42.0
48  br i1 %tst, label %do.add, label %no.add
49
50do.add:
51  %tot.new = fadd double %tot, %nextval
52  br label %next.iter
53
54no.add:
55  br label %next.iter
56
57next.iter:
58  %tot.next = phi double [%tot, %no.add], [%tot.new, %do.add]
59  %i.next = add i32 %i, 1
60  %again = icmp ult i32 %i.next, 32
61  br i1 %again, label %loop, label %done
62
63done:
64  ret double %tot.next
65}
66
67define double @sumIfVector(double* nocapture readonly %arr) {
68; SSE-LABEL: @sumIfVector(
69; SSE-NEXT:  entry:
70; SSE-NEXT:    br label [[LOOP:%.*]]
71; SSE:       loop:
72; SSE-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[NEXT_ITER:%.*]] ]
73; SSE-NEXT:    [[TOT:%.*]] = phi double [ 0.000000e+00, [[ENTRY]] ], [ [[TOT_NEXT:%.*]], [[NEXT_ITER]] ]
74; SSE-NEXT:    [[ADDR:%.*]] = getelementptr double, double* [[ARR:%.*]], i32 [[I]]
75; SSE-NEXT:    [[NEXTVAL:%.*]] = load double, double* [[ADDR]]
76; SSE-NEXT:    [[TST:%.*]] = fcmp fast une double [[NEXTVAL]], 4.200000e+01
77; SSE-NEXT:    br i1 [[TST]], label [[DO_ADD:%.*]], label [[NO_ADD:%.*]]
78; SSE:       do.add:
79; SSE-NEXT:    [[TOT_NEW:%.*]] = fadd fast double [[TOT]], [[NEXTVAL]]
80; SSE-NEXT:    br label [[NEXT_ITER]]
81; SSE:       no.add:
82; SSE-NEXT:    br label [[NEXT_ITER]]
83; SSE:       next.iter:
84; SSE-NEXT:    [[TOT_NEXT]] = phi double [ [[TOT]], [[NO_ADD]] ], [ [[TOT_NEW]], [[DO_ADD]] ]
85; SSE-NEXT:    [[I_NEXT]] = add i32 [[I]], 1
86; SSE-NEXT:    [[AGAIN:%.*]] = icmp ult i32 [[I_NEXT]], 32
87; SSE-NEXT:    br i1 [[AGAIN]], label [[LOOP]], label [[DONE:%.*]]
88; SSE:       done:
89; SSE-NEXT:    [[TOT_NEXT_LCSSA:%.*]] = phi double [ [[TOT_NEXT]], [[NEXT_ITER]] ]
90; SSE-NEXT:    ret double [[TOT_NEXT_LCSSA]]
91;
92; AVX-LABEL: @sumIfVector(
93; AVX-NEXT:  entry:
94; AVX-NEXT:    br i1 false, label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]]
95; AVX:       vector.ph:
96; AVX-NEXT:    br label [[VECTOR_BODY:%.*]]
97; AVX:       vector.body:
98; AVX-NEXT:    [[INDEX:%.*]] = phi i32 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
99; AVX-NEXT:    [[VEC_PHI:%.*]] = phi <4 x double> [ zeroinitializer, [[VECTOR_PH]] ], [ [[PREDPHI:%.*]], [[VECTOR_BODY]] ]
100; AVX-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i32> undef, i32 [[INDEX]], i32 0
101; AVX-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i32> [[BROADCAST_SPLATINSERT]], <4 x i32> undef, <4 x i32> zeroinitializer
102; AVX-NEXT:    [[INDUCTION:%.*]] = add <4 x i32> [[BROADCAST_SPLAT]], <i32 0, i32 1, i32 2, i32 3>
103; AVX-NEXT:    [[TMP0:%.*]] = add i32 [[INDEX]], 0
104; AVX-NEXT:    [[TMP1:%.*]] = getelementptr double, double* [[ARR:%.*]], i32 [[TMP0]]
105; AVX-NEXT:    [[TMP2:%.*]] = getelementptr double, double* [[TMP1]], i32 0
106; AVX-NEXT:    [[TMP3:%.*]] = bitcast double* [[TMP2]] to <4 x double>*
107; AVX-NEXT:    [[WIDE_LOAD:%.*]] = load <4 x double>, <4 x double>* [[TMP3]], align 8
108; AVX-NEXT:    [[TMP4:%.*]] = fcmp fast une <4 x double> [[WIDE_LOAD]], <double 4.200000e+01, double 4.200000e+01, double 4.200000e+01, double 4.200000e+01>
109; AVX-NEXT:    [[TMP5:%.*]] = fadd fast <4 x double> [[VEC_PHI]], [[WIDE_LOAD]]
110; AVX-NEXT:    [[TMP6:%.*]] = xor <4 x i1> [[TMP4]], <i1 true, i1 true, i1 true, i1 true>
111; AVX-NEXT:    [[PREDPHI]] = select <4 x i1> [[TMP4]], <4 x double> [[TMP5]], <4 x double> [[VEC_PHI]]
112; AVX-NEXT:    [[INDEX_NEXT]] = add i32 [[INDEX]], 4
113; AVX-NEXT:    [[TMP7:%.*]] = icmp eq i32 [[INDEX_NEXT]], 32
114; AVX-NEXT:    br i1 [[TMP7]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop !0
115; AVX:       middle.block:
116; AVX-NEXT:    [[RDX_SHUF:%.*]] = shufflevector <4 x double> [[PREDPHI]], <4 x double> undef, <4 x i32> <i32 2, i32 3, i32 undef, i32 undef>
117; AVX-NEXT:    [[BIN_RDX:%.*]] = fadd fast <4 x double> [[PREDPHI]], [[RDX_SHUF]]
118; AVX-NEXT:    [[RDX_SHUF1:%.*]] = shufflevector <4 x double> [[BIN_RDX]], <4 x double> undef, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef>
119; AVX-NEXT:    [[BIN_RDX2:%.*]] = fadd fast <4 x double> [[BIN_RDX]], [[RDX_SHUF1]]
120; AVX-NEXT:    [[TMP8:%.*]] = extractelement <4 x double> [[BIN_RDX2]], i32 0
121; AVX-NEXT:    [[CMP_N:%.*]] = icmp eq i32 32, 32
122; AVX-NEXT:    br i1 [[CMP_N]], label [[DONE:%.*]], label [[SCALAR_PH]]
123; AVX:       scalar.ph:
124; AVX-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i32 [ 32, [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY:%.*]] ]
125; AVX-NEXT:    [[BC_MERGE_RDX:%.*]] = phi double [ 0.000000e+00, [[ENTRY]] ], [ [[TMP8]], [[MIDDLE_BLOCK]] ]
126; AVX-NEXT:    br label [[LOOP:%.*]]
127; AVX:       loop:
128; AVX-NEXT:    [[I:%.*]] = phi i32 [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ], [ [[I_NEXT:%.*]], [[NEXT_ITER:%.*]] ]
129; AVX-NEXT:    [[TOT:%.*]] = phi double [ [[BC_MERGE_RDX]], [[SCALAR_PH]] ], [ [[TOT_NEXT:%.*]], [[NEXT_ITER]] ]
130; AVX-NEXT:    [[ADDR:%.*]] = getelementptr double, double* [[ARR]], i32 [[I]]
131; AVX-NEXT:    [[NEXTVAL:%.*]] = load double, double* [[ADDR]]
132; AVX-NEXT:    [[TST:%.*]] = fcmp fast une double [[NEXTVAL]], 4.200000e+01
133; AVX-NEXT:    br i1 [[TST]], label [[DO_ADD:%.*]], label [[NO_ADD:%.*]]
134; AVX:       do.add:
135; AVX-NEXT:    [[TOT_NEW:%.*]] = fadd fast double [[TOT]], [[NEXTVAL]]
136; AVX-NEXT:    br label [[NEXT_ITER]]
137; AVX:       no.add:
138; AVX-NEXT:    br label [[NEXT_ITER]]
139; AVX:       next.iter:
140; AVX-NEXT:    [[TOT_NEXT]] = phi double [ [[TOT]], [[NO_ADD]] ], [ [[TOT_NEW]], [[DO_ADD]] ]
141; AVX-NEXT:    [[I_NEXT]] = add i32 [[I]], 1
142; AVX-NEXT:    [[AGAIN:%.*]] = icmp ult i32 [[I_NEXT]], 32
143; AVX-NEXT:    br i1 [[AGAIN]], label [[LOOP]], label [[DONE]], !llvm.loop !2
144; AVX:       done:
145; AVX-NEXT:    [[TOT_NEXT_LCSSA:%.*]] = phi double [ [[TOT_NEXT]], [[NEXT_ITER]] ], [ [[TMP8]], [[MIDDLE_BLOCK]] ]
146; AVX-NEXT:    ret double [[TOT_NEXT_LCSSA]]
147;
148entry:
149  br label %loop
150
151loop:
152  %i = phi i32 [0, %entry], [%i.next, %next.iter]
153  %tot = phi double [0.0, %entry], [%tot.next, %next.iter]
154
155  %addr = getelementptr double, double* %arr, i32 %i
156  %nextval = load double, double* %addr
157
158  %tst = fcmp fast une double %nextval, 42.0
159  br i1 %tst, label %do.add, label %no.add
160
161do.add:
162  %tot.new = fadd fast double %tot, %nextval
163  br label %next.iter
164
165no.add:
166  br label %next.iter
167
168next.iter:
169  %tot.next = phi double [%tot, %no.add], [%tot.new, %do.add]
170  %i.next = add i32 %i, 1
171  %again = icmp ult i32 %i.next, 32
172  br i1 %again, label %loop, label %done
173
174done:
175  ret double %tot.next
176}
177
178