blob: 853a8a03ff82185633ef7847ab2a2f1960e82d0d [file]
; REQUIRES: asserts
; RUN: opt -passes=loop-vectorize -force-vector-width=4 \
; RUN: -force-vector-interleave=1 -tail-folding-policy=dont-fold-tail \
; RUN: -debug-only=loop-vectorize -disable-output %s 2>&1 | FileCheck %s --check-prefix=FIXED
; RUN: opt -passes=loop-vectorize -mattr=+sve -force-vector-width="vscale x 2" \
; RUN: -force-vector-interleave=1 -tail-folding-policy=dont-fold-tail \
; RUN: -debug-only=loop-vectorize -disable-output %s 2>&1 | FileCheck %s --check-prefix=SVE
target triple = "aarch64"
@a = common global [2048 x i32] zeroinitializer, align 16
@b = common global [2048 x i32] zeroinitializer, align 16
@c = common global [2048 x i32] zeroinitializer, align 16
@d = common global [2048 x i32] zeroinitializer, align 16
define void @uniform_load(ptr noalias %dst, ptr noalias readonly %src, i64 %n) {
; FIXED-LABEL: 'uniform_load'
; FIXED: LV: Memory widening: calculating best strategy for %val = load i32, ptr %src, align 4
; FIXED: LV: Memory widening: uniform memory op has GatherScatterCost = Invalid, ScalarizationCost = 3
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: %val = load i32, ptr %src, align 4
; FIXED: LV: Memory widening: calculating best strategy for store i32 %val, ptr %arrayidx, align 4
; FIXED: LV: Memory widening: can be widened normally with cost 1
; FIXED: LV: Setting widening decision to Widen for VF 4 and instruction: store i32 %val, ptr %arrayidx, align 4
;
; SVE-LABEL: 'uniform_load'
; SVE: LV: Memory widening: calculating best strategy for %val = load i32, ptr %src, align 4
; SVE: LV: Memory widening: uniform memory op has GatherScatterCost = 21, ScalarizationCost = 3
; SVE: LV: Setting widening decision to Scalarize for VF vscale x 2 and instruction: %val = load i32, ptr %src, align 4
; SVE: LV: Memory widening: calculating best strategy for store i32 %val, ptr %arrayidx, align 4
; SVE: LV: Memory widening: can be widened normally with cost 1
; SVE: LV: Setting widening decision to Widen for VF vscale x 2 and instruction: store i32 %val, ptr %arrayidx, align 4
;
entry:
br label %for.body
for.body:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
%val = load i32, ptr %src, align 4
%arrayidx = getelementptr inbounds i32, ptr %dst, i64 %iv
store i32 %val, ptr %arrayidx, align 4
%iv.next = add nuw nsw i64 %iv, 1
%exitcond.not = icmp eq i64 %iv.next, %n
br i1 %exitcond.not, label %for.end, label %for.body
for.end:
ret void
}
define void @interleaved_load(ptr noalias readonly %src, ptr noalias %dst, i64 %n) {
; FIXED-LABEL: 'interleaved_load'
; FIXED: LV: Memory widening: calculating best strategy for %load.0 = load i16, ptr %gep.0, align 2
; FIXED: LV: Memory widening: InterleaveCost = 2, GatherScatterCost = Invalid, ScalarizationCost = 32
; FIXED: LV: Setting widening decision to Interleave for VF 4 and instruction: %load.0 = load i16, ptr %gep.0, align 2
; FIXED: LV: Setting widening decision to Interleave for VF 4 and instruction: %load.1 = load i16, ptr %gep.1, align 2
; FIXED-NOT: LV: Memory widening: calculating best strategy for %load.1 = load i16, ptr %gep.1, align 2
; FIXED: LV: Memory widening: calculating best strategy for store i16 %add, ptr %dst.gep, align 2
; FIXED: LV: Memory widening: can be widened normally with cost 1
; FIXED: LV: Setting widening decision to Widen for VF 4 and instruction: store i16 %add, ptr %dst.gep, align 2
;
; SVE-LABEL: 'interleaved_load'
; SVE: LV: Memory widening: calculating best strategy for %load.0 = load i16, ptr %gep.0, align 2
; SVE: LV: Memory widening: InterleaveCost = 5, GatherScatterCost = 42, ScalarizationCost = Invalid
; SVE: LV: Setting widening decision to Interleave for VF vscale x 2 and instruction: %load.0 = load i16, ptr %gep.0, align 2
; SVE: LV: Setting widening decision to Interleave for VF vscale x 2 and instruction: %load.1 = load i16, ptr %gep.1, align 2
; SVE-NOT: LV: Memory widening: calculating best strategy for %load.1 = load i16, ptr %gep.1, align 2
; SVE: LV: Memory widening: calculating best strategy for store i16 %add, ptr %dst.gep, align 2
; SVE: LV: Memory widening: can be widened normally with cost 1
; SVE: LV: Setting widening decision to Widen for VF vscale x 2 and instruction: store i16 %add, ptr %dst.gep, align 2
;
entry:
br label %for.body
for.body:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
%iv2 = shl nuw nsw i64 %iv, 1
%gep.0 = getelementptr inbounds i16, ptr %src, i64 %iv2
%load.0 = load i16, ptr %gep.0, align 2
%idx.1 = or disjoint i64 %iv2, 1
%gep.1 = getelementptr inbounds i16, ptr %src, i64 %idx.1
%load.1 = load i16, ptr %gep.1, align 2
%add = add i16 %load.0, %load.1
%dst.gep = getelementptr inbounds i16, ptr %dst, i64 %iv
store i16 %add, ptr %dst.gep, align 2
%iv.next = add nuw nsw i64 %iv, 1
%exitcond.not = icmp eq i64 %iv.next, %n
br i1 %exitcond.not, label %for.end, label %for.body
for.end:
ret void
}
define void @interleave_member_update() {
; FIXED-LABEL: 'interleave_member_update'
; FIXED: LV: Memory widening: calculating best strategy for %idx = load i32, ptr %arrayidx, align 8
; FIXED: LV: Memory widening: InterleaveCost = 2, GatherScatterCost = Invalid, ScalarizationCost = 16
; FIXED: LV: Setting widening decision to Interleave for VF 4 and instruction: %idx = load i32, ptr %arrayidx, align 8
; FIXED: LV: Memory widening: calculating best strategy for %val = load i32, ptr %gather.ptr, align 4
; FIXED: LV: Memory widening: InterleaveCost = Invalid, GatherScatterCost = Invalid, ScalarizationCost = 52
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: %val = load i32, ptr %gather.ptr, align 4
; FIXED: LV: Memory widening: calculating best strategy for %addr.idx = load i32, ptr %addr.idx.ptr, align 4
; FIXED: LV: Memory widening: can be widened normally with cost 1
; FIXED: LV: Setting widening decision to Widen for VF 4 and instruction: %addr.idx = load i32, ptr %addr.idx.ptr, align 4
; FIXED: LV: Memory widening: calculating best strategy for store i32 %val, ptr %scatter.ptr, align 4
; FIXED: LV: Memory widening: InterleaveCost = Invalid, GatherScatterCost = Invalid, ScalarizationCost = 52
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: store i32 %val, ptr %scatter.ptr, align 4
; FIXED: LV: Memory widening: updating decision for load %addr.idx = load i32, ptr %addr.idx.ptr, align 4
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: %addr.idx = load i32, ptr %addr.idx.ptr, align 4
; FIXED: LV: Memory widening: updating decision for interleave member %idx = load i32, ptr %arrayidx, align 8
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: %idx = load i32, ptr %arrayidx, align 8
;
; SVE-LABEL: 'interleave_member_update'
; SVE: LV: Memory widening: calculating best strategy for %idx = load i32, ptr %arrayidx, align 8
; SVE: LV: Memory widening: InterleaveCost = 5, GatherScatterCost = 21, ScalarizationCost = Invalid
; SVE: LV: Setting widening decision to Interleave for VF vscale x 2 and instruction: %idx = load i32, ptr %arrayidx, align 8
; SVE: LV: Memory widening: calculating best strategy for %val = load i32, ptr %gather.ptr, align 4
; SVE: LV: Memory widening: InterleaveCost = Invalid, GatherScatterCost = 21, ScalarizationCost = Invalid
; SVE: LV: Setting widening decision to GatherScatter for VF vscale x 2 and instruction: %val = load i32, ptr %gather.ptr, align 4
; SVE: LV: Memory widening: calculating best strategy for %addr.idx = load i32, ptr %addr.idx.ptr, align 4
; SVE: LV: Memory widening: can be widened normally with cost 1
; SVE: LV: Setting widening decision to Widen for VF vscale x 2 and instruction: %addr.idx = load i32, ptr %addr.idx.ptr, align 4
; SVE: LV: Memory widening: calculating best strategy for store i32 %val, ptr %scatter.ptr, align 4
; SVE: LV: Memory widening: InterleaveCost = Invalid, GatherScatterCost = 21, ScalarizationCost = Invalid
; SVE: LV: Setting widening decision to GatherScatter for VF vscale x 2 and instruction: store i32 %val, ptr %scatter.ptr, align 4
;
entry:
br label %for.body
for.body:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
%iv2 = shl nsw i64 %iv, 1
%arrayidx = getelementptr inbounds [2048 x i32], ptr @c, i64 0, i64 %iv2
%idx = load i32, ptr %arrayidx, align 8
%idxprom = sext i32 %idx to i64
%gather.ptr = getelementptr inbounds [2048 x i32], ptr @b, i64 0, i64 %idxprom
%val = load i32, ptr %gather.ptr, align 4
%addr.idx.ptr = getelementptr inbounds [2048 x i32], ptr @d, i64 0, i64 %iv
%addr.idx = load i32, ptr %addr.idx.ptr, align 4
%scatter.idx = sext i32 %addr.idx to i64
%scatter.ptr = getelementptr inbounds [2048 x i32], ptr @a, i64 0, i64 %scatter.idx
store i32 %val, ptr %scatter.ptr, align 4
%iv.next = add i64 %iv, 1
%lftr.wideiv = trunc i64 %iv.next to i32
%exitcond = icmp eq i32 %lftr.wideiv, 256
br i1 %exitcond, label %for.end, label %for.body
for.end:
ret void
}
define void @reverse_load_scatter(ptr noalias %src, ptr noalias %dst, i64 %n) {
; FIXED-LABEL: 'reverse_load_scatter'
; FIXED: LV: Memory widening: calculating best strategy for %val = load i64, ptr %src.ptr, align 8
; FIXED: LV: Memory widening: can be widened normally with cost 4
; FIXED: LV: Setting widening decision to Widen_Reverse for VF 4 and instruction: %val = load i64, ptr %src.ptr, align 8
; FIXED: LV: Memory widening: calculating best strategy for store i64 %val, ptr %dst.ptr, align 8
; FIXED: LV: Memory widening: InterleaveCost = Invalid, GatherScatterCost = Invalid, ScalarizationCost = 60
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: store i64 %val, ptr %dst.ptr, align 8
; FIXED: LV: Memory widening: updating decision for load %val = load i64, ptr %src.ptr, align 8
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: %val = load i64, ptr %src.ptr, align 8
; FIXED: LV: Memory widening: updating decision for load user store i64 %val, ptr %dst.ptr, align 8
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: store i64 %val, ptr %dst.ptr, align 8
;
; SVE-LABEL: 'reverse_load_scatter'
; SVE: LV: Memory widening: calculating best strategy for %val = load i64, ptr %src.ptr, align 8
; SVE: LV: Memory widening: can be widened normally with cost 2
; SVE: LV: Setting widening decision to Widen_Reverse for VF vscale x 2 and instruction: %val = load i64, ptr %src.ptr, align 8
; SVE: LV: Memory widening: calculating best strategy for store i64 %val, ptr %dst.ptr, align 8
; SVE: LV: Memory widening: InterleaveCost = Invalid, GatherScatterCost = 21, ScalarizationCost = Invalid
; SVE: LV: Setting widening decision to GatherScatter for VF vscale x 2 and instruction: store i64 %val, ptr %dst.ptr, align 8
;
entry:
br label %loop
loop:
%iv.dec = phi i64 [ %n, %entry ], [ %iv.dec.next, %loop ]
%src.ptr = getelementptr inbounds i64, ptr %src, i64 %iv.dec
%val = load i64, ptr %src.ptr, align 8
%dst.ptr = getelementptr inbounds i64, ptr %dst, i64 %val
store i64 %val, ptr %dst.ptr, align 8
%iv.dec.next = add i64 %iv.dec, -1
%done = icmp eq i64 %iv.dec.next, 0
br i1 %done, label %exit, label %loop
exit:
ret void
}
define double @gather_load(ptr noalias readonly %data, ptr noalias readonly %offset, i64 %n) {
; FIXED-LABEL: 'gather_load'
; FIXED: LV: Memory widening: calculating best strategy for %idx = load i32, ptr %idx.ptr, align 4
; FIXED: LV: Memory widening: can be widened normally with cost 1
; FIXED: LV: Setting widening decision to Widen for VF 4 and instruction: %idx = load i32, ptr %idx.ptr, align 4
; FIXED: LV: Memory widening: calculating best strategy for %val = load double, ptr %gather.ptr, align 8
; FIXED: LV: Memory widening: InterleaveCost = Invalid, GatherScatterCost = Invalid, ScalarizationCost = 48
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: %val = load double, ptr %gather.ptr, align 8
; FIXED: LV: Memory widening: updating decision for load %idx = load i32, ptr %idx.ptr, align 4
; FIXED: LV: Setting widening decision to Scalarize for VF 4 and instruction: %idx = load i32, ptr %idx.ptr, align 4
;
; SVE-LABEL: 'gather_load'
; SVE: LV: Memory widening: calculating best strategy for %idx = load i32, ptr %idx.ptr, align 4
; SVE: LV: Memory widening: can be widened normally with cost 1
; SVE: LV: Setting widening decision to Widen for VF vscale x 2 and instruction: %idx = load i32, ptr %idx.ptr, align 4
; SVE: LV: Memory widening: calculating best strategy for %val = load double, ptr %gather.ptr, align 8
; SVE: LV: Memory widening: InterleaveCost = Invalid, GatherScatterCost = 21, ScalarizationCost = Invalid
; SVE: LV: Setting widening decision to GatherScatter for VF vscale x 2 and instruction: %val = load double, ptr %gather.ptr, align 8
;
entry:
br label %for.body
for.body:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
%sum = phi double [ 0.000000e+00, %entry ], [ %add, %for.body ]
%idx.ptr = getelementptr inbounds i32, ptr %offset, i64 %iv
%idx = load i32, ptr %idx.ptr, align 4
%idxprom = sext i32 %idx to i64
%gather.ptr = getelementptr inbounds double, ptr %data, i64 %idxprom
%val = load double, ptr %gather.ptr, align 8
%add = fadd double %sum, %val
%iv.next = add nuw nsw i64 %iv, 1
%exitcond.not = icmp eq i64 %iv.next, %n
br i1 %exitcond.not, label %for.end, label %for.body
for.end:
%res = phi double [ %add, %for.body ]
ret double %res
}