| ; RUN: opt -mtriple armv7-linux-gnueabihf -passes=loop-vectorize -S %s -debug-only=loop-vectorize --disable-output -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=LINUX | |
| ; RUN: opt -mtriple armv8-linux-gnu -passes=loop-vectorize -S %s -debug-only=loop-vectorize --disable-output -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=LINUX | |
| ; RUN: opt -mtriple armv8.1.m-none-eabi -mattr=+mve.fp -passes=loop-vectorize -S %s -debug-only=loop-vectorize --disable-output -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MVE | |
| ; RUN: opt -mtriple armv7-unknwon-darwin -passes=loop-vectorize -S %s -debug-only=loop-vectorize --disable-output -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=DARWIN | |
| ; REQUIRES: asserts | |
| target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" | |
| ; Testing the ability of the loop vectorizer to tell when SIMD is safe or not | |
| ; regarding IEEE 754 standard. | |
| ; On Linux, we only want the vectorizer to work when -ffast-math flag is set, | |
| ; because NEON is not IEEE compliant. | |
| ; Darwin, on the other hand, doesn't support subnormals, and all optimizations | |
| ; are allowed, even without -ffast-math. | |
| ; Integer loops are always vectorizeable | |
| ; CHECK: Checking a loop in 'sumi' | |
| ; CHECK: Loop passed LoopVectorizationLegality checks! | |
| define void @sumi(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) { | |
| entry: | |
| %cmp5 = icmp eq i32 %N, 0 | |
| br i1 %cmp5, label %for.end, label %for.body.preheader | |
| for.body.preheader: | |
| br label %for.body | |
| for.body: | |
| %i.06 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] | |
| %arrayidx = getelementptr inbounds i32, ptr %A, i32 %i.06 | |
| %0 = load i32, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds i32, ptr %B, i32 %i.06 | |
| %1 = load i32, ptr %arrayidx1, align 4 | |
| %mul = mul nsw i32 %1, %0 | |
| %arrayidx2 = getelementptr inbounds i32, ptr %C, i32 %i.06 | |
| store i32 %mul, ptr %arrayidx2, align 4 | |
| %inc = add nuw nsw i32 %i.06, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end.loopexit, label %for.body | |
| for.end.loopexit: | |
| br label %for.end | |
| for.end: | |
| ret void | |
| } | |
| ; Floating-point loops need fast-math to be vectorizeable | |
| ; LINUX: Checking a loop in 'sumf' | |
| ; LINUX: Potentially unsafe FP op prevents vectorization | |
| ; MVE: Checking a loop in 'sumf' | |
| ; MVE: Loop passed LoopVectorizationLegality checks! | |
| ; DARWIN: Checking a loop in 'sumf' | |
| ; DARWIN: Loop passed LoopVectorizationLegality checks! | |
| define void @sumf(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) { | |
| entry: | |
| %cmp5 = icmp eq i32 %N, 0 | |
| br i1 %cmp5, label %for.end, label %for.body.preheader | |
| for.body.preheader: | |
| br label %for.body | |
| for.body: | |
| %i.06 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] | |
| %arrayidx = getelementptr inbounds float, ptr %A, i32 %i.06 | |
| %0 = load float, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds float, ptr %B, i32 %i.06 | |
| %1 = load float, ptr %arrayidx1, align 4 | |
| %mul = fmul float %0, %1 | |
| %arrayidx2 = getelementptr inbounds float, ptr %C, i32 %i.06 | |
| store float %mul, ptr %arrayidx2, align 4 | |
| %inc = add nuw nsw i32 %i.06, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end.loopexit, label %for.body | |
| for.end.loopexit: | |
| br label %for.end | |
| for.end: | |
| ret void | |
| } | |
| ; Integer loops are always vectorizeable | |
| ; CHECK: Checking a loop in 'redi' | |
| ; CHECK: Loop passed LoopVectorizationLegality checks! | |
| define i32 @redi(ptr noalias nocapture readonly %a, ptr noalias nocapture readonly %b, i32 %N) { | |
| entry: | |
| br label %for.body.preheader | |
| for.body.preheader: | |
| br label %for.body | |
| for.body: | |
| %i.07 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] | |
| %Red.06 = phi i32 [ %add, %for.body ], [ 0, %for.body.preheader ] | |
| %arrayidx = getelementptr inbounds i32, ptr %a, i32 %i.07 | |
| %0 = load i32, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds i32, ptr %b, i32 %i.07 | |
| %1 = load i32, ptr %arrayidx1, align 4 | |
| %mul = mul nsw i32 %1, %0 | |
| %add = add nsw i32 %mul, %Red.06 | |
| %inc = add nuw nsw i32 %i.07, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end.loopexit, label %for.body | |
| for.end.loopexit: | |
| %add.lcssa = phi i32 [ %add, %for.body ] | |
| br label %for.end | |
| for.end: | |
| ret i32 %add.lcssa | |
| } | |
| ; Floating-point loops need fast-math to be vectorizeable | |
| ; LINUX: Checking a loop in 'redf' | |
| ; LINUX: Potentially unsafe FP op prevents vectorization | |
| ; MVE: Checking a loop in 'redf' | |
| ; MVE: Loop passed LoopVectorizationLegality checks! | |
| ; DARWIN: Checking a loop in 'redf' | |
| ; DARWIN: Loop passed LoopVectorizationLegality checks! | |
| define float @redf(ptr noalias nocapture readonly %a, ptr noalias nocapture readonly %b, i32 %N) { | |
| entry: | |
| br label %for.body.preheader | |
| for.body.preheader: | |
| br label %for.body | |
| for.body: | |
| %i.07 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] | |
| %Red.06 = phi float [ %add, %for.body ], [ 0.0e+00, %for.body.preheader ] | |
| %arrayidx = getelementptr inbounds float, ptr %a, i32 %i.07 | |
| %0 = load float, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds float, ptr %b, i32 %i.07 | |
| %1 = load float, ptr %arrayidx1, align 4 | |
| %mul = fmul float %0, %1 | |
| %add = fadd float %Red.06, %mul | |
| %inc = add nuw nsw i32 %i.07, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end.loopexit, label %for.body | |
| for.end.loopexit: | |
| %add.lcssa = phi float [ %add, %for.body ] | |
| br label %for.end | |
| for.end: | |
| ret float %add.lcssa | |
| } | |
| ; Make sure calls that turn into builtins are also covered | |
| ; LINUX: Checking a loop in 'fabs' | |
| ; LINUX: Potentially unsafe FP op prevents vectorization | |
| ; DARWIN: Checking a loop in 'fabs' | |
| ; DARWIN: Loop passed LoopVectorizationLegality checks! | |
| define void @fabs(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) { | |
| entry: | |
| %cmp10 = icmp eq i32 %N, 0 | |
| br i1 %cmp10, label %for.end, label %for.body | |
| for.body: | |
| %i.011 = phi i32 [ %inc, %for.body ], [ 0, %entry ] | |
| %arrayidx = getelementptr inbounds float, ptr %A, i32 %i.011 | |
| %0 = load float, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds float, ptr %B, i32 %i.011 | |
| %1 = load float, ptr %arrayidx1, align 4 | |
| %fabsf = tail call float @fabsf(float %1) #1 | |
| %conv3 = fmul float %0, %fabsf | |
| %arrayidx4 = getelementptr inbounds float, ptr %C, i32 %i.011 | |
| store float %conv3, ptr %arrayidx4, align 4 | |
| %inc = add nuw nsw i32 %i.011, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end, label %for.body | |
| for.end: | |
| ret void | |
| } | |
| ; Integer loops are always vectorizeable | |
| ; CHECK: Checking a loop in 'sumi_fast' | |
| ; CHECK: Loop passed LoopVectorizationLegality checks! | |
| define void @sumi_fast(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) { | |
| entry: | |
| %cmp5 = icmp eq i32 %N, 0 | |
| br i1 %cmp5, label %for.end, label %for.body.preheader | |
| for.body.preheader: | |
| br label %for.body | |
| for.body: | |
| %i.06 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] | |
| %arrayidx = getelementptr inbounds i32, ptr %A, i32 %i.06 | |
| %0 = load i32, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds i32, ptr %B, i32 %i.06 | |
| %1 = load i32, ptr %arrayidx1, align 4 | |
| %mul = mul nsw i32 %1, %0 | |
| %arrayidx2 = getelementptr inbounds i32, ptr %C, i32 %i.06 | |
| store i32 %mul, ptr %arrayidx2, align 4 | |
| %inc = add nuw nsw i32 %i.06, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end.loopexit, label %for.body | |
| for.end.loopexit: | |
| br label %for.end | |
| for.end: | |
| ret void | |
| } | |
| ; Floating-point loops can be vectorizeable with fast-math | |
| ; CHECK: Checking a loop in 'sumf_fast' | |
| ; CHECK: Loop passed LoopVectorizationLegality checks! | |
| define void @sumf_fast(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) { | |
| entry: | |
| %cmp5 = icmp eq i32 %N, 0 | |
| br i1 %cmp5, label %for.end, label %for.body.preheader | |
| for.body.preheader: | |
| br label %for.body | |
| for.body: | |
| %i.06 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] | |
| %arrayidx = getelementptr inbounds float, ptr %A, i32 %i.06 | |
| %0 = load float, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds float, ptr %B, i32 %i.06 | |
| %1 = load float, ptr %arrayidx1, align 4 | |
| %mul = fmul fast float %1, %0 | |
| %arrayidx2 = getelementptr inbounds float, ptr %C, i32 %i.06 | |
| store float %mul, ptr %arrayidx2, align 4 | |
| %inc = add nuw nsw i32 %i.06, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end.loopexit, label %for.body | |
| for.end.loopexit: | |
| br label %for.end | |
| for.end: | |
| ret void | |
| } | |
| ; Integer loops are always vectorizeable | |
| ; CHECK: Checking a loop in 'redi_fast' | |
| ; CHECK: Loop passed LoopVectorizationLegality checks! | |
| define i32 @redi_fast(ptr noalias nocapture readonly %a, ptr noalias nocapture readonly %b, i32 %N) { | |
| entry: | |
| %cmp5 = icmp eq i32 %N, 0 | |
| br i1 %cmp5, label %for.end, label %for.body.preheader | |
| for.body.preheader: | |
| br label %for.body | |
| for.body: | |
| %i.07 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] | |
| %Red.06 = phi i32 [ %add, %for.body ], [ 0, %for.body.preheader ] | |
| %arrayidx = getelementptr inbounds i32, ptr %a, i32 %i.07 | |
| %0 = load i32, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds i32, ptr %b, i32 %i.07 | |
| %1 = load i32, ptr %arrayidx1, align 4 | |
| %mul = mul nsw i32 %1, %0 | |
| %add = add nsw i32 %mul, %Red.06 | |
| %inc = add nuw nsw i32 %i.07, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end.loopexit, label %for.body | |
| for.end.loopexit: | |
| %add.lcssa = phi i32 [ %add, %for.body ] | |
| br label %for.end | |
| for.end: | |
| %Red.0.lcssa = phi i32 [ 0, %entry ], [ %add.lcssa, %for.end.loopexit ] | |
| ret i32 %Red.0.lcssa | |
| } | |
| ; Floating-point loops can be vectorizeable with fast-math | |
| ; CHECK: Checking a loop in 'redf_fast' | |
| ; CHECK: Loop passed LoopVectorizationLegality checks! | |
| define float @redf_fast(ptr noalias nocapture readonly %a, ptr noalias nocapture readonly %b, i32 %N) { | |
| entry: | |
| br label %for.body.preheader | |
| for.body.preheader: | |
| br label %for.body | |
| for.body: | |
| %i.07 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] | |
| %Red.06 = phi float [ %add, %for.body ], [ 0.0e+00, %for.body.preheader ] | |
| %arrayidx = getelementptr inbounds float, ptr %a, i32 %i.07 | |
| %0 = load float, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds float, ptr %b, i32 %i.07 | |
| %1 = load float, ptr %arrayidx1, align 4 | |
| %mul = fmul fast float %1, %0 | |
| %add = fadd fast float %mul, %Red.06 | |
| %inc = add nuw nsw i32 %i.07, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end.loopexit, label %for.body | |
| for.end.loopexit: | |
| %add.lcssa = phi float [ %add, %for.body ] | |
| br label %for.end | |
| for.end: | |
| ret float %add.lcssa | |
| } | |
| ; Make sure calls that turn into builtins are also covered | |
| ; CHECK: Checking a loop in 'fabs_fast' | |
| ; CHECK: Loop passed LoopVectorizationLegality checks! | |
| define void @fabs_fast(ptr noalias nocapture readonly %A, ptr noalias nocapture readonly %B, ptr noalias nocapture %C, i32 %N) { | |
| entry: | |
| %cmp10 = icmp eq i32 %N, 0 | |
| br i1 %cmp10, label %for.end, label %for.body | |
| for.body: | |
| %i.011 = phi i32 [ %inc, %for.body ], [ 0, %entry ] | |
| %arrayidx = getelementptr inbounds float, ptr %A, i32 %i.011 | |
| %0 = load float, ptr %arrayidx, align 4 | |
| %arrayidx1 = getelementptr inbounds float, ptr %B, i32 %i.011 | |
| %1 = load float, ptr %arrayidx1, align 4 | |
| %fabsf = tail call fast float @fabsf(float %1) #1 | |
| %conv3 = fmul fast float %fabsf, %0 | |
| %arrayidx4 = getelementptr inbounds float, ptr %C, i32 %i.011 | |
| store float %conv3, ptr %arrayidx4, align 4 | |
| %inc = add nuw nsw i32 %i.011, 1 | |
| %exitcond = icmp eq i32 %inc, %N | |
| br i1 %exitcond, label %for.end, label %for.body | |
| for.end: | |
| ret void | |
| } | |
| declare float @fabsf(float) | |
| attributes #1 = { readnone } |