1 ; RUN: opt -S -passes=loop-vectorize,instcombine -force-vector-interleave=1 -mattr=+sve -mtriple aarch64-unknown-linux-gnu \
2 ; RUN: -prefer-predicate-over-epilogue=scalar-epilogue -pass-remarks-missed=loop-vectorize < %s 2>%t | FileCheck %s
3 ; RUN: cat %t | FileCheck %s --check-prefix=CHECK-REMARKS
4 ; RUN: opt -S -passes=loop-vectorize,instcombine -force-vector-interleave=1 -force-target-instruction-cost=1 -mattr=+sve -mtriple aarch64-unknown-linux-gnu \
5 ; RUN: -prefer-predicate-over-epilogue=scalar-epilogue -pass-remarks-missed=loop-vectorize < %s 2>%t | FileCheck %s
6 ; RUN: cat %t | FileCheck %s --check-prefix=CHECK-REMARKS
8 define void @vec_load(i64 %N, ptr nocapture %a, ptr nocapture readonly %b) {
9 ; CHECK-LABEL: @vec_load
11 ; CHECK: %[[LOAD:.*]] = load <vscale x 2 x double>, ptr
12 ; CHECK: call <vscale x 2 x double> @foo_vec(<vscale x 2 x double> %[[LOAD]])
14 %cmp7 = icmp sgt i64 %N, 0
15 br i1 %cmp7, label %for.body, label %for.end
17 for.body: ; preds = %for.body.preheader, %for.body
18 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
19 %arrayidx = getelementptr inbounds double, ptr %b, i64 %iv
20 %0 = load double, ptr %arrayidx, align 8
21 %1 = call double @foo(double %0) #0
22 %add = fadd double %1, 1.000000e+00
23 %arrayidx2 = getelementptr inbounds double, ptr %a, i64 %iv
24 store double %add, ptr %arrayidx2, align 8
25 %iv.next = add nuw nsw i64 %iv, 1
26 %exitcond.not = icmp eq i64 %iv.next, %N
27 br i1 %exitcond.not, label %for.end, label %for.body, !llvm.loop !1
29 for.end: ; preds = %for.body, %entry
33 define void @vec_scalar(i64 %N, ptr nocapture %a) {
34 ; CHECK-LABEL: @vec_scalar
36 ; CHECK: call <vscale x 2 x double> @foo_vec(<vscale x 2 x double> shufflevector (<vscale x 2 x double> insertelement (<vscale x 2 x double> poison, double 1.000000e+01, i64 0), <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer))
38 %cmp7 = icmp sgt i64 %N, 0
39 br i1 %cmp7, label %for.body, label %for.end
41 for.body: ; preds = %for.body.preheader, %for.body
42 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
43 %0 = call double @foo(double 10.0) #0
44 %sub = fsub double %0, 1.000000e+00
45 %arrayidx = getelementptr inbounds double, ptr %a, i64 %iv
46 store double %sub, ptr %arrayidx, align 8
47 %iv.next = add nuw nsw i64 %iv, 1
48 %exitcond.not = icmp eq i64 %iv.next, %N
49 br i1 %exitcond.not, label %for.end, label %for.body, !llvm.loop !1
51 for.end: ; preds = %for.body, %entry
55 define void @vec_ptr(i64 %N, ptr noalias %a, ptr readnone %b) {
56 ; CHECK-LABEL: @vec_ptr
58 ; CHECK: %[[LOAD:.*]] = load <vscale x 2 x ptr>, ptr
59 ; CHECK: call <vscale x 2 x i64> @bar_vec(<vscale x 2 x ptr> %[[LOAD]])
61 %cmp7 = icmp sgt i64 %N, 0
62 br i1 %cmp7, label %for.body, label %for.end
65 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
66 %gep = getelementptr ptr, ptr %b, i64 %iv
67 %load = load ptr, ptr %gep
68 %call = call i64 @bar(ptr %load) #1
69 %arrayidx = getelementptr inbounds i64, ptr %a, i64 %iv
70 store i64 %call, ptr %arrayidx
71 %iv.next = add nuw nsw i64 %iv, 1
72 %exitcond = icmp eq i64 %iv.next, 1024
73 br i1 %exitcond, label %for.end, label %for.body, !llvm.loop !1
79 define void @vec_intrinsic(i64 %N, ptr nocapture readonly %a) {
80 ; CHECK-LABEL: @vec_intrinsic
82 ; CHECK: %[[LOAD:.*]] = load <vscale x 2 x double>, ptr
83 ; CHECK: call fast <vscale x 2 x double> @sin_vec_nxv2f64(<vscale x 2 x double> %[[LOAD]])
85 %cmp7 = icmp sgt i64 %N, 0
86 br i1 %cmp7, label %for.body, label %for.end
89 %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
90 %arrayidx = getelementptr inbounds double, ptr %a, i64 %iv
91 %0 = load double, ptr %arrayidx, align 8
92 %1 = call fast double @llvm.sin.f64(double %0) #2
93 %add = fadd fast double %1, 1.000000e+00
94 store double %add, ptr %arrayidx, align 8
95 %iv.next = add nuw nsw i64 %iv, 1
96 %exitcond = icmp eq i64 %iv.next, %N
97 br i1 %exitcond, label %for.end, label %for.body, !llvm.loop !1
103 ; CHECK-REMARKS: UserVF ignored because of invalid costs.
104 ; CHECK-REMARKS-NEXT: t.c:3:10: Instruction with invalid costs prevented vectorization at VF=(vscale x 1): load
105 ; CHECK-REMARKS-NEXT: t.c:3:20: Instruction with invalid costs prevented vectorization at VF=(vscale x 1, vscale x 2): call to llvm.sin.f32
106 ; CHECK-REMARKS-NEXT: t.c:3:30: Instruction with invalid costs prevented vectorization at VF=(vscale x 1): store
107 define void @vec_sin_no_mapping(ptr noalias nocapture %dst, ptr noalias nocapture readonly %src, i64 %n) {
108 ; CHECK: @vec_sin_no_mapping
109 ; CHECK: call fast <2 x float> @llvm.sin.v2f32
110 ; CHECK-NOT: <vscale x
114 for.body: ; preds = %entry, %for.body
115 %i.07 = phi i64 [ %inc, %for.body ], [ 0, %entry ]
116 %arrayidx = getelementptr inbounds float, ptr %src, i64 %i.07
117 %0 = load float, ptr %arrayidx, align 4, !dbg !11
118 %1 = tail call fast float @llvm.sin.f32(float %0), !dbg !12
119 %arrayidx1 = getelementptr inbounds float, ptr %dst, i64 %i.07
120 store float %1, ptr %arrayidx1, align 4, !dbg !13
121 %inc = add nuw nsw i64 %i.07, 1
122 %exitcond.not = icmp eq i64 %inc, %n
123 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body, !llvm.loop !1
125 for.cond.cleanup: ; preds = %for.body
129 ; CHECK-REMARKS: UserVF ignored because of invalid costs.
130 ; CHECK-REMARKS-NEXT: t.c:3:10: Instruction with invalid costs prevented vectorization at VF=(vscale x 1): load
131 ; CHECK-REMARKS-NEXT: t.c:3:30: Instruction with invalid costs prevented vectorization at VF=(vscale x 1, vscale x 2): call to llvm.sin.f32
132 ; CHECK-REMARKS-NEXT: t.c:3:20: Instruction with invalid costs prevented vectorization at VF=(vscale x 1, vscale x 2): call to llvm.sin.f32
133 ; CHECK-REMARKS-NEXT: t.c:3:40: Instruction with invalid costs prevented vectorization at VF=(vscale x 1): store
134 define void @vec_sin_no_mapping_ite(ptr noalias nocapture %dst, ptr noalias nocapture readonly %src, i64 %n) {
135 ; CHECK: @vec_sin_no_mapping_ite
136 ; CHECK-NOT: <vscale x
141 for.body: ; preds = %entry, %if.end
142 %i.07 = phi i64 [ %inc, %if.end ], [ 0, %entry ]
143 %arrayidx = getelementptr inbounds float, ptr %src, i64 %i.07
144 %0 = load float, ptr %arrayidx, align 4, !dbg !11
145 %cmp = fcmp ugt float %0, 0.0000
146 br i1 %cmp, label %if.then, label %if.else
148 %1 = tail call fast float @llvm.sin.f32(float %0), !dbg !12
151 %2 = tail call fast float @llvm.sin.f32(float 0.0), !dbg !13
154 %3 = phi float [%1, %if.then], [%2, %if.else]
155 %arrayidx1 = getelementptr inbounds float, ptr %dst, i64 %i.07
156 store float %3, ptr %arrayidx1, align 4, !dbg !14
157 %inc = add nuw nsw i64 %i.07, 1
158 %exitcond.not = icmp eq i64 %inc, %n
159 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body, !llvm.loop !1
161 for.cond.cleanup: ; preds = %for.body
165 ; CHECK-REMARKS: UserVF ignored because of invalid costs.
166 ; CHECK-REMARKS-NEXT: t.c:3:10: Instruction with invalid costs prevented vectorization at VF=(vscale x 1): load
167 ; CHECK-REMARKS-NEXT: t.c:3:20: Instruction with invalid costs prevented vectorization at VF=(vscale x 1, vscale x 2): call to llvm.sin.f32
168 ; CHECK-REMARKS-NEXT: t.c:3:30: Instruction with invalid costs prevented vectorization at VF=(vscale x 1): store
169 define void @vec_sin_fixed_mapping(ptr noalias nocapture %dst, ptr noalias nocapture readonly %src, i64 %n) {
170 ; CHECK: @vec_sin_fixed_mapping
171 ; CHECK: call fast <2 x float> @llvm.sin.v2f32
172 ; CHECK-NOT: <vscale x
176 for.body: ; preds = %entry, %for.body
177 %i.07 = phi i64 [ %inc, %for.body ], [ 0, %entry ]
178 %arrayidx = getelementptr inbounds float, ptr %src, i64 %i.07
179 %0 = load float, ptr %arrayidx, align 4, !dbg !11
180 %1 = tail call fast float @llvm.sin.f32(float %0) #3, !dbg !12
181 %arrayidx1 = getelementptr inbounds float, ptr %dst, i64 %i.07
182 store float %1, ptr %arrayidx1, align 4, !dbg !13
183 %inc = add nuw nsw i64 %i.07, 1
184 %exitcond.not = icmp eq i64 %inc, %n
185 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body, !llvm.loop !1
187 for.cond.cleanup: ; preds = %for.body
191 ; Even though there are no function mappings attached to the call
192 ; in the loop below we can still vectorize the loop because SVE has
193 ; hardware support in the form of the 'fqsrt' instruction.
194 define void @vec_sqrt_no_mapping(ptr noalias nocapture %dst, ptr noalias nocapture readonly %src, i64 %n) {
195 ; CHECK: @vec_sqrt_no_mapping
196 ; CHECK: call fast <vscale x 2 x float> @llvm.sqrt.nxv2f32
200 for.body: ; preds = %entry, %for.body
201 %i.07 = phi i64 [ %inc, %for.body ], [ 0, %entry ]
202 %arrayidx = getelementptr inbounds float, ptr %src, i64 %i.07
203 %0 = load float, ptr %arrayidx, align 4
204 %1 = tail call fast float @llvm.sqrt.f32(float %0)
205 %arrayidx1 = getelementptr inbounds float, ptr %dst, i64 %i.07
206 store float %1, ptr %arrayidx1, align 4
207 %inc = add nuw nsw i64 %i.07, 1
208 %exitcond.not = icmp eq i64 %inc, %n
209 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body, !llvm.loop !1
211 for.cond.cleanup: ; preds = %for.body
216 declare double @foo(double)
217 declare i64 @bar(ptr)
218 declare double @llvm.sin.f64(double)
219 declare float @llvm.sin.f32(float)
220 declare float @llvm.sqrt.f32(float)
222 declare <vscale x 2 x double> @foo_vec(<vscale x 2 x double>)
223 declare <vscale x 2 x i64> @bar_vec(<vscale x 2 x ptr>)
224 declare <vscale x 2 x double> @sin_vec_nxv2f64(<vscale x 2 x double>)
225 declare <2 x double> @sin_vec_v2f64(<2 x double>)
227 attributes #0 = { "vector-function-abi-variant"="_ZGVsNxv_foo(foo_vec)" }
228 attributes #1 = { "vector-function-abi-variant"="_ZGVsNxv_bar(bar_vec)" }
229 attributes #2 = { "vector-function-abi-variant"="_ZGVsNxv_llvm.sin.f64(sin_vec_nxv2f64)" }
230 attributes #3 = { "vector-function-abi-variant"="_ZGV_LLVM_N2v_llvm.sin.f64(sin_vec_v2f64)" }
232 !1 = distinct !{!1, !2, !3}
233 !2 = !{!"llvm.loop.vectorize.width", i32 2}
234 !3 = !{!"llvm.loop.vectorize.scalable.enable", i1 true}
237 !llvm.module.flags = !{!7}
240 !4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !5, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: NoDebug, enums: !6, splitDebugInlining: false, nameTableKind: None)
241 !5 = !DIFile(filename: "t.c", directory: "somedir")
243 !7 = !{i32 2, !"Debug Info Version", i32 3}
245 !9 = distinct !DISubprogram(name: "foo", scope: !5, file: !5, line: 2, type: !10, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !4, retainedNodes: !6)
246 !10 = !DISubroutineType(types: !6)
247 !11 = !DILocation(line: 3, column: 10, scope: !9)
248 !12 = !DILocation(line: 3, column: 20, scope: !9)
249 !13 = !DILocation(line: 3, column: 30, scope: !9)
250 !14 = !DILocation(line: 3, column: 40, scope: !9)