[llvm] [LV] Linear argument tests for vectorization of function calls (PR #73936)

via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 30 05:37:17 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Graham Hunter (huntergr-arm)

<details>
<summary>Changes</summary>

Tests to exercise vectorization of function calls where a vector variant takes a linear parameter.

---
Full diff: https://github.com/llvm/llvm-project/pull/73936.diff


1 Files Affected:

- (added) llvm/test/Transforms/LoopVectorize/AArch64/vector-call-linear-args.ll (+275) 


``````````diff
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/vector-call-linear-args.ll b/llvm/test/Transforms/LoopVectorize/AArch64/vector-call-linear-args.ll
new file mode 100644
index 000000000000000..ef6b8e1d83f3811
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/vector-call-linear-args.ll
@@ -0,0 +1,275 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=loop-vectorize,instsimplify -force-vector-interleave=1 -S | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+; A call whose argument can remain a scalar because it's sequential and only the
+; starting value is required.
+define void @test_linear(ptr noalias %a, ptr readnone %b, i64 %n) #0 {
+; CHECK-LABEL: define void @test_linear
+; CHECK-SAME: (ptr noalias [[A:%.*]], ptr readnone [[B:%.*]], i64 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[GEPB:%.*]] = getelementptr i64, ptr [[B]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    [[CALL:%.*]] = call i64 @foo(ptr [[GEPB]]) #[[ATTR1:[0-9]+]]
+; CHECK-NEXT:    [[GEPA:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    store i64 [[CALL]], ptr [[GEPA]], align 8
+; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
+; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
+; CHECK:       for.cond.cleanup:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %gepb = getelementptr i64, ptr %b, i64 %indvars.iv
+  %call = call i64 @foo(ptr %gepb) #1
+  %gepa = getelementptr inbounds i64, ptr %a, i64 %indvars.iv
+  store i64 %call, ptr %gepa
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, %n
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @test_linear_with_mask(ptr noalias %a, ptr readnone %b, i64 %n) #0 {
+; CHECK-LABEL: define void @test_linear_with_mask
+; CHECK-SAME: (ptr noalias [[A:%.*]], ptr readnone [[B:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[GEPB:%.*]] = getelementptr i64, ptr [[B]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    [[CALL:%.*]] = call i64 @foo(ptr [[GEPB]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT:    [[GEPA:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    store i64 [[CALL]], ptr [[GEPA]], align 8
+; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
+; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
+; CHECK:       for.cond.cleanup:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %gepb = getelementptr i64, ptr %b, i64 %indvars.iv
+  %call = call i64 @foo(ptr %gepb) #2
+  %gepa = getelementptr inbounds i64, ptr %a, i64 %indvars.iv
+  store i64 %call, ptr %gepa
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, %n
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @test_linear_with_vector(ptr noalias %a, ptr readnone %b, ptr readonly %c, i64 %n) #0 {
+; CHECK-LABEL: define void @test_linear_with_vector
+; CHECK-SAME: (ptr noalias [[A:%.*]], ptr readnone [[B:%.*]], ptr readonly [[C:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[GEPC:%.*]] = getelementptr i32, ptr [[C]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    [[DATA:%.*]] = load i32, ptr [[GEPC]], align 8
+; CHECK-NEXT:    [[GEPB:%.*]] = getelementptr i32, ptr [[B]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @baz(i32 [[DATA]], ptr [[GEPB]]) #[[ATTR3:[0-9]+]]
+; CHECK-NEXT:    [[GEPA:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    store i32 [[CALL]], ptr [[GEPA]], align 8
+; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
+; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
+; CHECK:       for.cond.cleanup:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %gepc = getelementptr i32, ptr %c, i64 %indvars.iv
+  %data = load i32, ptr %gepc, align 8
+  %gepb = getelementptr i32, ptr %b, i64 %indvars.iv
+  %call = call i32 @baz(i32 %data, ptr %gepb) #3
+  %gepa = getelementptr inbounds i32, ptr %a, i64 %indvars.iv
+  store i32 %call, ptr %gepa, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, %n
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @test_linear_bad_stride(ptr noalias %a, ptr readnone %b, i64 %n) #0 {
+; CHECK-LABEL: define void @test_linear_bad_stride
+; CHECK-SAME: (ptr noalias [[A:%.*]], ptr readnone [[B:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[GEPB:%.*]] = getelementptr i64, ptr [[B]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    [[CALL:%.*]] = call i64 @foo(ptr [[GEPB]]) #[[ATTR4:[0-9]+]]
+; CHECK-NEXT:    [[GEPA:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    store i64 [[CALL]], ptr [[GEPA]], align 8
+; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
+; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
+; CHECK:       for.cond.cleanup:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %gepb = getelementptr i64, ptr %b, i64 %indvars.iv
+  %call = call i64 @foo(ptr %gepb) #4
+  %gepa = getelementptr inbounds i64, ptr %a, i64 %indvars.iv
+  store i64 %call, ptr %gepa
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, %n
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @test_linear_wide_stride(ptr noalias %a, ptr readnone %b, i64 %n) #0 {
+; CHECK-LABEL: define void @test_linear_wide_stride
+; CHECK-SAME: (ptr noalias [[A:%.*]], ptr readnone [[B:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[DOUBLE:%.*]] = mul i64 [[INDVARS_IV]], 2
+; CHECK-NEXT:    [[GEPB:%.*]] = getelementptr i64, ptr [[B]], i64 [[DOUBLE]]
+; CHECK-NEXT:    [[CALL:%.*]] = call i64 @foo(ptr [[GEPB]]) #[[ATTR4]]
+; CHECK-NEXT:    [[GEPA:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    store i64 [[CALL]], ptr [[GEPA]], align 8
+; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
+; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
+; CHECK:       for.cond.cleanup:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %double = mul i64 %indvars.iv, 2
+  %gepb = getelementptr i64, ptr %b, i64 %double
+  %call = call i64 @foo(ptr %gepb) #4
+  %gepa = getelementptr inbounds i64, ptr %a, i64 %indvars.iv
+  store i64 %call, ptr %gepa
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, %n
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @test_linear_mixed_types(ptr noalias %a, ptr readnone %b, ptr readonly %c, i64 %n) #0 {
+; CHECK-LABEL: define void @test_linear_mixed_types
+; CHECK-SAME: (ptr noalias [[A:%.*]], ptr readnone [[B:%.*]], ptr readonly [[C:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[GEPC:%.*]] = getelementptr i32, ptr [[C]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    [[GEPB:%.*]] = getelementptr i64, ptr [[B]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @quux(ptr [[GEPC]], ptr [[GEPB]]) #[[ATTR5:[0-9]+]]
+; CHECK-NEXT:    [[GEPA:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    store i32 [[CALL]], ptr [[GEPA]], align 8
+; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
+; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
+; CHECK:       for.cond.cleanup:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %gepc = getelementptr i32, ptr %c, i64 %indvars.iv
+  %gepb = getelementptr i64, ptr %b, i64 %indvars.iv
+  %call = call i32 @quux(ptr %gepc, ptr %gepb) #5
+  %gepa = getelementptr inbounds i32, ptr %a, i64 %indvars.iv
+  store i32 %call, ptr %gepa, align 8
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, %n
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+
+for.cond.cleanup:
+  ret void
+}
+
+define void @test_linear_non_ptr(ptr noalias %a, i64 %n) #0 {
+; CHECK-LABEL: define void @test_linear_non_ptr
+; CHECK-SAME: (ptr noalias [[A:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[LITTLE_IV:%.*]] = trunc i64 [[INDVARS_IV]] to i32
+; CHECK-NEXT:    [[TREBLED:%.*]] = mul i32 [[LITTLE_IV]], 3
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @bar(i32 [[TREBLED]]) #[[ATTR6:[0-9]+]]
+; CHECK-NEXT:    [[GEPA:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[INDVARS_IV]]
+; CHECK-NEXT:    store i32 [[CALL]], ptr [[GEPA]], align 4
+; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
+; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
+; CHECK:       for.cond.cleanup:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.body
+
+for.body:
+  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
+  %little.iv = trunc i64 %indvars.iv to i32
+  %trebled = mul i32 %little.iv, 3
+  %call = call i32 @bar(i32 %trebled) #6
+  %gepa = getelementptr inbounds i32, ptr %a, i64 %indvars.iv
+  store i32 %call, ptr %gepa
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %exitcond = icmp eq i64 %indvars.iv.next, %n
+  br i1 %exitcond, label %for.cond.cleanup, label %for.body
+
+for.cond.cleanup:
+  ret void
+}
+
+declare i64 @foo(ptr)
+declare i32 @baz(i32, ptr)
+declare i32 @quux(ptr, ptr)
+declare i32 @bar(i32)
+
+; vector variants of foo
+declare <vscale x 2 x i64> @foo_linear(ptr, <vscale x 2 x i1>)
+declare <vscale x 2 x i64> @foo_linear_nomask(ptr)
+declare <vscale x 2 x i64> @foo_linear_nomask_2x(ptr)
+declare <vscale x 4 x i32> @baz_vector_and_linear(<vscale x 4 x i32>, ptr)
+declare <vscale x 4 x i32> @quux_linear_mask(ptr, ptr, <vscale x 4 x i1>)
+declare <vscale x 4 x i32> @bar_linear(i32)
+
+attributes #0 = { "target-features"="+sve" }
+attributes #1 = { nounwind "vector-function-abi-variant"="_ZGVsNxl8_foo(foo_linear_nomask)" }
+attributes #2 = { nounwind "vector-function-abi-variant"="_ZGVsMxl8_foo(foo_linear)" }
+attributes #3 = { nounwind "vector-function-abi-variant"="_ZGVsNxvl4_baz(baz_vector_and_linear)" }
+attributes #4 = { nounwind "vector-function-abi-variant"="_ZGVsNxl16_foo(foo_linear_nomask_2x)" }
+attributes #5 = { nounwind "vector-function-abi-variant"="_ZGVsMxl4l8_quux(quux_linear_mask)" }
+attributes #6 = { nounwind "vector-function-abi-variant"="_ZGVsNxl3_bar(bar_linear)" }

``````````

</details>


https://github.com/llvm/llvm-project/pull/73936


More information about the llvm-commits mailing list