1; RUN: opt < %s  -O3 -simplifycfg -keep-loops=false -mcpu=core-avx2 -mtriple=x86_64-unknown-linux-gnu -S | FileCheck --check-prefix AUTO_VEC %s
2
3; This test checks auto-vectorization with FP induction variable.
4; The FP operation is not "fast" and requires "fast-math" function attribute.
5
6;void fp_iv_loop1(float * __restrict__ A, int N) {
7;  float x = 1.0;
8;  for (int i=0; i < N; ++i) {
9;    A[i] = x;
10;    x += 0.5;
11;  }
12;}
13
14
15; AUTO_VEC-LABEL: @fp_iv_loop1(
16; AUTO_VEC: vector.body
17; AUTO_VEC: store <8 x float>
18
19define void @fp_iv_loop1(float* noalias nocapture %A, i32 %N) #0 {
20entry:
21  %cmp4 = icmp sgt i32 %N, 0
22  br i1 %cmp4, label %for.body.preheader, label %for.end
23
24for.body.preheader:                               ; preds = %entry
25  br label %for.body
26
27for.body:                                         ; preds = %for.body.preheader, %for.body
28  %indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %for.body.preheader ]
29  %x.06 = phi float [ %conv1, %for.body ], [ 1.000000e+00, %for.body.preheader ]
30  %arrayidx = getelementptr inbounds float, float* %A, i64 %indvars.iv
31  store float %x.06, float* %arrayidx, align 4
32  %conv1 = fadd float %x.06, 5.000000e-01
33  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
34  %lftr.wideiv = trunc i64 %indvars.iv.next to i32
35  %exitcond = icmp eq i32 %lftr.wideiv, %N
36  br i1 %exitcond, label %for.end.loopexit, label %for.body
37
38for.end.loopexit:                                 ; preds = %for.body
39  br label %for.end
40
41for.end:                                          ; preds = %for.end.loopexit, %entry
42  ret void
43}
44
45; The same as the previous, FP operation is not fast, different function attribute
46; Vectorization should be rejected.
47;void fp_iv_loop2(float * __restrict__ A, int N) {
48;  float x = 1.0;
49;  for (int i=0; i < N; ++i) {
50;    A[i] = x;
51;    x += 0.5;
52;  }
53;}
54
55; AUTO_VEC-LABEL: @fp_iv_loop2(
56; AUTO_VEC-NOT: vector.body
57; AUTO_VEC-NOT: store <{{.*}} x float>
58
59define void @fp_iv_loop2(float* noalias nocapture %A, i32 %N) #1 {
60entry:
61  %cmp4 = icmp sgt i32 %N, 0
62  br i1 %cmp4, label %for.body.preheader, label %for.end
63
64for.body.preheader:                               ; preds = %entry
65  br label %for.body
66
67for.body:                                         ; preds = %for.body.preheader, %for.body
68  %indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %for.body.preheader ]
69  %x.06 = phi float [ %conv1, %for.body ], [ 1.000000e+00, %for.body.preheader ]
70  %arrayidx = getelementptr inbounds float, float* %A, i64 %indvars.iv
71  store float %x.06, float* %arrayidx, align 4
72  %conv1 = fadd float %x.06, 5.000000e-01
73  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
74  %lftr.wideiv = trunc i64 %indvars.iv.next to i32
75  %exitcond = icmp eq i32 %lftr.wideiv, %N
76  br i1 %exitcond, label %for.end.loopexit, label %for.body
77
78for.end.loopexit:                                 ; preds = %for.body
79  br label %for.end
80
81for.end:                                          ; preds = %for.end.loopexit, %entry
82  ret void
83}
84
85; AUTO_VEC-LABEL: @external_use_with_fast_math(
86; AUTO_VEC-NEXT:  entry:
87; AUTO_VEC-NEXT:    [[TMP0:%.*]] = icmp sgt i64 %n, 1
88; AUTO_VEC-NEXT:    [[SMAX:%.*]] = select i1 [[TMP0]], i64 %n, i64 1
89; AUTO_VEC:         br i1 {{.*}}, label %for.body, label %vector.ph
90; AUTO_VEC:       vector.ph:
91; AUTO_VEC-NEXT:    [[N_VEC:%.*]] = and i64 [[SMAX]], 9223372036854775792
92; AUTO_VEC:         br label %vector.body
93; AUTO_VEC:       middle.block:
94; AUTO_VEC:         [[TMP11:%.*]] = add nsw i64 [[N_VEC]], -1
95; AUTO_VEC-NEXT:    [[CAST_CMO:%.*]] = sitofp i64 [[TMP11]] to double
96; AUTO_VEC-NEXT:    [[TMP12:%.*]] = fmul fast double [[CAST_CMO]], 3.000000e+00
97; AUTO_VEC-NEXT:    br i1 {{.*}}, label %for.end, label %for.body
98; AUTO_VEC:       for.end:
99; AUTO_VEC-NEXT:    [[J_LCSSA:%.*]] = phi double [ [[TMP12]], %middle.block ], [ %j, %for.body ]
100; AUTO_VEC-NEXT:    ret double [[J_LCSSA]]
101;
102define double @external_use_with_fast_math(double* %a, i64 %n) {
103entry:
104  br label %for.body
105
106for.body:
107  %i = phi i64 [ 0, %entry ], [%i.next, %for.body]
108  %j = phi double [ 0.0, %entry ], [ %j.next, %for.body ]
109  %tmp0 = getelementptr double, double* %a, i64 %i
110  store double %j, double* %tmp0
111  %i.next = add i64 %i, 1
112  %j.next = fadd fast double %j, 3.0
113  %cond = icmp slt i64 %i.next, %n
114  br i1 %cond, label %for.body, label %for.end
115
116for.end:
117  %tmp1 = phi double [ %j, %for.body ]
118  ret double %tmp1
119}
120
121; AUTO_VEC-LABEL: @external_use_without_fast_math(
122; AUTO_VEC:       for.body:
123; AUTO_VEC:         [[J:%.*]] = phi double [ 0.000000e+00, %entry ], [ [[J_NEXT:%.*]], %for.body ]
124; AUTO_VEC:         [[J_NEXT]] = fadd double [[J]], 3.000000e+00
125; AUTO_VEC:         br i1 {{.*}}, label %for.body, label %for.end
126; AUTO_VEC:       for.end:
127; AUTO_VEC-NEXT:    ret double [[J]]
128;
129define double @external_use_without_fast_math(double* %a, i64 %n) {
130entry:
131  br label %for.body
132
133for.body:
134  %i = phi i64 [ 0, %entry ], [%i.next, %for.body]
135  %j = phi double [ 0.0, %entry ], [ %j.next, %for.body ]
136  %tmp0 = getelementptr double, double* %a, i64 %i
137  store double %j, double* %tmp0
138  %i.next = add i64 %i, 1
139  %j.next = fadd double %j, 3.0
140  %cond = icmp slt i64 %i.next, %n
141  br i1 %cond, label %for.body, label %for.end
142
143for.end:
144  %tmp1 = phi double [ %j, %for.body ]
145  ret double %tmp1
146}
147
148attributes #0 = { "no-nans-fp-math"="true" }
149attributes #1 = { "no-nans-fp-math"="false" }
150