[llvm] c28d907 - [llubi] Implement vector reduction/manipulation intrinsics (#194345)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 28 05:40:05 PDT 2026
Author: Zhige Chen
Date: 2026-04-28T14:39:58+02:00
New Revision: c28d9076ec8b2d36e0ce897c08ca62963f96b975
URL: https://github.com/llvm/llvm-project/commit/c28d9076ec8b2d36e0ce897c08ca62963f96b975
DIFF: https://github.com/llvm/llvm-project/commit/c28d9076ec8b2d36e0ce897c08ca62963f96b975.diff
LOG: [llubi] Implement vector reduction/manipulation intrinsics (#194345)
This PR implements vector reduction and manipulation intrinsics.
Note that floating-point vector reduction intrinsics are not covered by
this change; they will be added in a follow-up PR after #188453 is
merged.
Added:
llvm/test/tools/llubi/intr_vector_interleave.ll
llvm/test/tools/llubi/intr_vector_manip.ll
llvm/test/tools/llubi/intr_vector_reduce.ll
llvm/test/tools/llubi/intr_vector_stepvector.ll
Modified:
llvm/tools/llubi/lib/Interpreter.cpp
Removed:
################################################################################
diff --git a/llvm/test/tools/llubi/intr_vector_interleave.ll b/llvm/test/tools/llubi/intr_vector_interleave.ll
new file mode 100644
index 0000000000000..d6eea81c330e4
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_vector_interleave.ll
@@ -0,0 +1,61 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose --vscale=4 < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %i2 = call <4 x i32> @llvm.vector.interleave2.v4i32.v2i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>)
+ %i3 = call <6 x i32> @llvm.vector.interleave3.v6i32.v2i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>)
+ %i4 = call <8 x i32> @llvm.vector.interleave4.v8i32.v2i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>)
+ %i5 = call <10 x i32> @llvm.vector.interleave5.v10i32.v2i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>, <2 x i32> <i32 40, i32 41>)
+ %i6 = call <12 x i32> @llvm.vector.interleave6.v12i32.v2i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>, <2 x i32> <i32 40, i32 41>, <2 x i32> <i32 50, i32 51>)
+ %i7 = call <14 x i32> @llvm.vector.interleave7.v14i32.v2i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>, <2 x i32> <i32 40, i32 41>, <2 x i32> <i32 50, i32 51>, <2 x i32> <i32 60, i32 61>)
+ %i8 = call <16 x i32> @llvm.vector.interleave8.v16i32.v2i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>, <2 x i32> <i32 40, i32 41>, <2 x i32> <i32 50, i32 51>, <2 x i32> <i32 60, i32 61>, <2 x i32> <i32 70, i32 71>)
+
+ %d2 = call { <2 x i32>, <2 x i32> } @llvm.vector.deinterleave2.v4i32(<4 x i32> <i32 0, i32 10, i32 1, i32 11>)
+ %d3 = call { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave3.v6i32(<6 x i32> <i32 0, i32 10, i32 20, i32 1, i32 11, i32 21>)
+ %d4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave4.v8i32(<8 x i32> <i32 0, i32 10, i32 20, i32 30, i32 1, i32 11, i32 21, i32 31>)
+ %d5 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave5.v10i32(<10 x i32> <i32 0, i32 10, i32 20, i32 30, i32 40, i32 1, i32 11, i32 21, i32 31, i32 41>)
+ %d6 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave6.v12i32(<12 x i32> <i32 0, i32 10, i32 20, i32 30, i32 40, i32 50, i32 1, i32 11, i32 21, i32 31, i32 41, i32 51>)
+ %d7 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave7.v14i32(<14 x i32> <i32 0, i32 10, i32 20, i32 30, i32 40, i32 50, i32 60, i32 1, i32 11, i32 21, i32 31, i32 41, i32 51, i32 61>)
+ %d8 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave8.v16i32(<16 x i32> <i32 0, i32 10, i32 20, i32 30, i32 40, i32 50, i32 60, i32 70, i32 1, i32 11, i32 21, i32 31, i32 41, i32 51, i32 61, i32 71>)
+
+ %base = call <vscale x 1 x i32> @llvm.stepvector.nxv1i32()
+ %insert10 = insertelement <vscale x 1 x i32> poison, i32 10, i32 0
+ %splat10 = shufflevector <vscale x 1 x i32> %insert10, <vscale x 1 x i32> poison, <vscale x 1 x i32> zeroinitializer
+ %insert20 = insertelement <vscale x 1 x i32> poison, i32 20, i32 0
+ %splat20 = shufflevector <vscale x 1 x i32> %insert20, <vscale x 1 x i32> poison, <vscale x 1 x i32> zeroinitializer
+ %sv1 = add <vscale x 1 x i32> %base, %splat10
+ %sv2 = add <vscale x 1 x i32> %base, %splat20
+
+ %s3 = call <vscale x 3 x i32> @llvm.vector.interleave3.nxv3i32.nxv1i32(<vscale x 1 x i32> %base, <vscale x 1 x i32> %sv1, <vscale x 1 x i32> %sv2)
+
+ %sd3 = call { <vscale x 1 x i32>, <vscale x 1 x i32>, <vscale x 1 x i32> } @llvm.vector.deinterleave3.nxv3i32(<vscale x 3 x i32> %s3)
+
+ ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT: %i2 = call <4 x i32> @llvm.vector.interleave2.v4i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>) => { i32 0, i32 10, i32 1, i32 11 }
+; CHECK-NEXT: %i3 = call <6 x i32> @llvm.vector.interleave3.v6i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>) => { i32 0, i32 10, i32 20, i32 1, i32 11, i32 21 }
+; CHECK-NEXT: %i4 = call <8 x i32> @llvm.vector.interleave4.v8i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>) => { i32 0, i32 10, i32 20, i32 30, i32 1, i32 11, i32 21, i32 31 }
+; CHECK-NEXT: %i5 = call <10 x i32> @llvm.vector.interleave5.v10i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>, <2 x i32> <i32 40, i32 41>) => { i32 0, i32 10, i32 20, i32 30, i32 40, i32 1, i32 11, i32 21, i32 31, i32 41 }
+; CHECK-NEXT: %i6 = call <12 x i32> @llvm.vector.interleave6.v12i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>, <2 x i32> <i32 40, i32 41>, <2 x i32> <i32 50, i32 51>) => { i32 0, i32 10, i32 20, i32 30, i32 40, i32 50, i32 1, i32 11, i32 21, i32 31, i32 41, i32 51 }
+; CHECK-NEXT: %i7 = call <14 x i32> @llvm.vector.interleave7.v14i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>, <2 x i32> <i32 40, i32 41>, <2 x i32> <i32 50, i32 51>, <2 x i32> <i32 60, i32 61>) => { i32 0, i32 10, i32 20, i32 30, i32 40, i32 50, i32 60, i32 1, i32 11, i32 21, i32 31, i32 41, i32 51, i32 61 }
+; CHECK-NEXT: %i8 = call <16 x i32> @llvm.vector.interleave8.v16i32(<2 x i32> <i32 0, i32 1>, <2 x i32> <i32 10, i32 11>, <2 x i32> <i32 20, i32 21>, <2 x i32> <i32 30, i32 31>, <2 x i32> <i32 40, i32 41>, <2 x i32> <i32 50, i32 51>, <2 x i32> <i32 60, i32 61>, <2 x i32> <i32 70, i32 71>) => { i32 0, i32 10, i32 20, i32 30, i32 40, i32 50, i32 60, i32 70, i32 1, i32 11, i32 21, i32 31, i32 41, i32 51, i32 61, i32 71 }
+; CHECK-NEXT: %d2 = call { <2 x i32>, <2 x i32> } @llvm.vector.deinterleave2.v4i32(<4 x i32> <i32 0, i32 10, i32 1, i32 11>) => { { i32 0, i32 1 }, { i32 10, i32 11 } }
+; CHECK-NEXT: %d3 = call { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave3.v6i32(<6 x i32> <i32 0, i32 10, i32 20, i32 1, i32 11, i32 21>) => { { i32 0, i32 1 }, { i32 10, i32 11 }, { i32 20, i32 21 } }
+; CHECK-NEXT: %d4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave4.v8i32(<8 x i32> <i32 0, i32 10, i32 20, i32 30, i32 1, i32 11, i32 21, i32 31>) => { { i32 0, i32 1 }, { i32 10, i32 11 }, { i32 20, i32 21 }, { i32 30, i32 31 } }
+; CHECK-NEXT: %d5 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave5.v10i32(<10 x i32> <i32 0, i32 10, i32 20, i32 30, i32 40, i32 1, i32 11, i32 21, i32 31, i32 41>) => { { i32 0, i32 1 }, { i32 10, i32 11 }, { i32 20, i32 21 }, { i32 30, i32 31 }, { i32 40, i32 41 } }
+; CHECK-NEXT: %d6 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave6.v12i32(<12 x i32> <i32 0, i32 10, i32 20, i32 30, i32 40, i32 50, i32 1, i32 11, i32 21, i32 31, i32 41, i32 51>) => { { i32 0, i32 1 }, { i32 10, i32 11 }, { i32 20, i32 21 }, { i32 30, i32 31 }, { i32 40, i32 41 }, { i32 50, i32 51 } }
+; CHECK-NEXT: %d7 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave7.v14i32(<14 x i32> <i32 0, i32 10, i32 20, i32 30, i32 40, i32 50, i32 60, i32 1, i32 11, i32 21, i32 31, i32 41, i32 51, i32 61>) => { { i32 0, i32 1 }, { i32 10, i32 11 }, { i32 20, i32 21 }, { i32 30, i32 31 }, { i32 40, i32 41 }, { i32 50, i32 51 }, { i32 60, i32 61 } }
+; CHECK-NEXT: %d8 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave8.v16i32(<16 x i32> <i32 0, i32 10, i32 20, i32 30, i32 40, i32 50, i32 60, i32 70, i32 1, i32 11, i32 21, i32 31, i32 41, i32 51, i32 61, i32 71>) => { { i32 0, i32 1 }, { i32 10, i32 11 }, { i32 20, i32 21 }, { i32 30, i32 31 }, { i32 40, i32 41 }, { i32 50, i32 51 }, { i32 60, i32 61 }, { i32 70, i32 71 } }
+; CHECK-NEXT: %base = call <vscale x 1 x i32> @llvm.stepvector.nxv1i32() => { i32 0, i32 1, i32 2, i32 3 }
+; CHECK-NEXT: %insert10 = insertelement <vscale x 1 x i32> poison, i32 10, i32 0 => { i32 10, poison, poison, poison }
+; CHECK-NEXT: %splat10 = shufflevector <vscale x 1 x i32> %insert10, <vscale x 1 x i32> poison, <vscale x 1 x i32> zeroinitializer => { i32 10, i32 10, i32 10, i32 10 }
+; CHECK-NEXT: %insert20 = insertelement <vscale x 1 x i32> poison, i32 20, i32 0 => { i32 20, poison, poison, poison }
+; CHECK-NEXT: %splat20 = shufflevector <vscale x 1 x i32> %insert20, <vscale x 1 x i32> poison, <vscale x 1 x i32> zeroinitializer => { i32 20, i32 20, i32 20, i32 20 }
+; CHECK-NEXT: %sv1 = add <vscale x 1 x i32> %base, %splat10 => { i32 10, i32 11, i32 12, i32 13 }
+; CHECK-NEXT: %sv2 = add <vscale x 1 x i32> %base, %splat20 => { i32 20, i32 21, i32 22, i32 23 }
+; CHECK-NEXT: %s3 = call <vscale x 3 x i32> @llvm.vector.interleave3.nxv3i32(<vscale x 1 x i32> %base, <vscale x 1 x i32> %sv1, <vscale x 1 x i32> %sv2) => { i32 0, i32 10, i32 20, i32 1, i32 11, i32 21, i32 2, i32 12, i32 22, i32 3, i32 13, i32 23 }
+; CHECK-NEXT: %sd3 = call { <vscale x 1 x i32>, <vscale x 1 x i32>, <vscale x 1 x i32> } @llvm.vector.deinterleave3.nxv3i32(<vscale x 3 x i32> %s3) => { { i32 0, i32 1, i32 2, i32 3 }, { i32 10, i32 11, i32 12, i32 13 }, { i32 20, i32 21, i32 22, i32 23 } }
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_vector_manip.ll b/llvm/test/tools/llubi/intr_vector_manip.ll
new file mode 100644
index 0000000000000..bcccb9de93d8a
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_vector_manip.ll
@@ -0,0 +1,56 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %insert_mid = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, <2 x i32> <i32 10, i32 11>, i64 2)
+ %insert_poison_lane = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, <2 x i32> <i32 poison, i32 11>, i64 2)
+ %insert_tail = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> <i32 9, i32 10>, i64 4)
+ %insert_poison = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> <i32 9, i32 10>, i64 5)
+
+ %extract_mid = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, i64 2)
+ %extract_poison_lane = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> <i32 0, i32 poison, i32 2, i32 3, i32 4, i32 5>, i64 0)
+ %extract_tail = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, i64 4)
+ %extract_poison = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, i64 5)
+
+ %reverse = call <4 x i32> @llvm.vector.reverse.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>)
+ %reverse_poison = call <4 x i32> @llvm.vector.reverse.v4i32(<4 x i32> <i32 0, i32 poison, i32 2, i32 3>)
+
+ %splice_left = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 2)
+ %splice_left_poison_lane = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> <i32 0, i32 poison, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 1)
+ %splice_left_poison = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> <i32 0, i32 poison, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 5)
+
+ %splice_right = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 1)
+ %splice_right_full_rhs = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 0)
+ %splice_right_poison = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 5)
+
+ %extract_poison_idx = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> zeroinitializer, i64 poison)
+ %insert_poison_idx = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> <i32 1, i32 2>, i64 poison)
+ %splice_left_poison_idx = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> zeroinitializer, <4 x i32> zeroinitializer, i32 poison)
+ %splice_right_poison_idx = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> zeroinitializer, <4 x i32> zeroinitializer, i32 poison)
+
+ ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT: %insert_mid = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, <2 x i32> <i32 10, i32 11>, i64 2) => { i32 0, i32 1, i32 10, i32 11, i32 4, i32 5 }
+; CHECK-NEXT: %insert_poison_lane = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, <2 x i32> <i32 poison, i32 11>, i64 2) => { i32 0, i32 1, poison, i32 11, i32 4, i32 5 }
+; CHECK-NEXT: %insert_tail = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> <i32 9, i32 10>, i64 4) => { i32 0, i32 0, i32 0, i32 0, i32 9, i32 10 }
+; CHECK-NEXT: %insert_poison = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> <i32 9, i32 10>, i64 5) => poison
+; CHECK-NEXT: %extract_mid = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, i64 2) => { i32 2, i32 3 }
+; CHECK-NEXT: %extract_poison_lane = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> <i32 0, i32 poison, i32 2, i32 3, i32 4, i32 5>, i64 0) => { i32 0, poison }
+; CHECK-NEXT: %extract_tail = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, i64 4) => { i32 4, i32 5 }
+; CHECK-NEXT: %extract_poison = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5>, i64 5) => poison
+; CHECK-NEXT: %reverse = call <4 x i32> @llvm.vector.reverse.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>) => { i32 3, i32 2, i32 1, i32 0 }
+; CHECK-NEXT: %reverse_poison = call <4 x i32> @llvm.vector.reverse.v4i32(<4 x i32> <i32 0, i32 poison, i32 2, i32 3>) => { i32 3, i32 2, poison, i32 0 }
+; CHECK-NEXT: %splice_left = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 2) => { i32 2, i32 3, i32 10, i32 11 }
+; CHECK-NEXT: %splice_left_poison_lane = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> <i32 0, i32 poison, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 1) => { poison, i32 2, i32 3, i32 10 }
+; CHECK-NEXT: %splice_left_poison = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> <i32 0, i32 poison, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 5) => poison
+; CHECK-NEXT: %splice_right = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 1) => { i32 3, i32 10, i32 11, i32 12 }
+; CHECK-NEXT: %splice_right_full_rhs = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 0) => { i32 10, i32 11, i32 12, i32 13 }
+; CHECK-NEXT: %splice_right_poison = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32> <i32 10, i32 11, i32 12, i32 13>, i32 5) => poison
+; CHECK-NEXT: %extract_poison_idx = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> zeroinitializer, i64 poison) => poison
+; CHECK-NEXT: %insert_poison_idx = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> <i32 1, i32 2>, i64 poison) => poison
+; CHECK-NEXT: %splice_left_poison_idx = call <4 x i32> @llvm.vector.splice.left.v4i32(<4 x i32> zeroinitializer, <4 x i32> zeroinitializer, i32 poison) => poison
+; CHECK-NEXT: %splice_right_poison_idx = call <4 x i32> @llvm.vector.splice.right.v4i32(<4 x i32> zeroinitializer, <4 x i32> zeroinitializer, i32 poison) => poison
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_vector_reduce.ll b/llvm/test/tools/llubi/intr_vector_reduce.ll
new file mode 100644
index 0000000000000..9508419a96829
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_vector_reduce.ll
@@ -0,0 +1,55 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %reduce_add = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> <i32 1, i32 2, i32 3, i32 4>)
+ %reduce_add_poison = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> <i32 1, i32 poison, i32 3, i32 4>)
+
+ %reduce_mul = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 2, i32 3, i32 4, i32 5>)
+ %reduce_mul_poison = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 2, i32 poison, i32 4, i32 5>)
+
+ %reduce_and = call i32 @llvm.vector.reduce.and.v4i32(<4 x i32> <i32 15, i32 14, i32 13, i32 12>)
+ %reduce_and_poison = call i32 @llvm.vector.reduce.and.v4i32(<4 x i32> <i32 15, i32 poison, i32 13, i32 12>)
+
+ %reduce_or = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> <i32 1, i32 2, i32 4, i32 8>)
+ %reduce_or_poison = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> <i32 1, i32 poison, i32 4, i32 8>)
+
+ %reduce_xor = call i32 @llvm.vector.reduce.xor.v4i32(<4 x i32> <i32 1, i32 3, i32 7, i32 15>)
+ %reduce_xor_poison = call i32 @llvm.vector.reduce.xor.v4i32(<4 x i32> <i32 1, i32 poison, i32 7, i32 15>)
+
+ %reduce_smax = call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> <i32 -4, i32 -2, i32 7, i32 3>)
+ %reduce_smax_poison = call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> <i32 -4, i32 poison, i32 7, i32 3>)
+
+ %reduce_smin = call i32 @llvm.vector.reduce.smin.v4i32(<4 x i32> <i32 -4, i32 -2, i32 7, i32 3>)
+ %reduce_smin_poison = call i32 @llvm.vector.reduce.smin.v4i32(<4 x i32> <i32 -4, i32 poison, i32 7, i32 3>)
+
+ %reduce_umax = call i32 @llvm.vector.reduce.umax.v4i32(<4 x i32> <i32 -1, i32 5, i32 9, i32 2>)
+ %reduce_umax_poison = call i32 @llvm.vector.reduce.umax.v4i32(<4 x i32> <i32 -1, i32 poison, i32 9, i32 2>)
+
+ %reduce_umin = call i32 @llvm.vector.reduce.umin.v4i32(<4 x i32> <i32 -1, i32 5, i32 9, i32 2>)
+ %reduce_umin_poison = call i32 @llvm.vector.reduce.umin.v4i32(<4 x i32> <i32 -1, i32 poison, i32 9, i32 2>)
+
+ ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT: %reduce_add = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> <i32 1, i32 2, i32 3, i32 4>) => i32 10
+; CHECK-NEXT: %reduce_add_poison = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> <i32 1, i32 poison, i32 3, i32 4>) => poison
+; CHECK-NEXT: %reduce_mul = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 2, i32 3, i32 4, i32 5>) => i32 120
+; CHECK-NEXT: %reduce_mul_poison = call i32 @llvm.vector.reduce.mul.v4i32(<4 x i32> <i32 2, i32 poison, i32 4, i32 5>) => poison
+; CHECK-NEXT: %reduce_and = call i32 @llvm.vector.reduce.and.v4i32(<4 x i32> <i32 15, i32 14, i32 13, i32 12>) => i32 12
+; CHECK-NEXT: %reduce_and_poison = call i32 @llvm.vector.reduce.and.v4i32(<4 x i32> <i32 15, i32 poison, i32 13, i32 12>) => poison
+; CHECK-NEXT: %reduce_or = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> <i32 1, i32 2, i32 4, i32 8>) => i32 15
+; CHECK-NEXT: %reduce_or_poison = call i32 @llvm.vector.reduce.or.v4i32(<4 x i32> <i32 1, i32 poison, i32 4, i32 8>) => poison
+; CHECK-NEXT: %reduce_xor = call i32 @llvm.vector.reduce.xor.v4i32(<4 x i32> <i32 1, i32 3, i32 7, i32 15>) => i32 10
+; CHECK-NEXT: %reduce_xor_poison = call i32 @llvm.vector.reduce.xor.v4i32(<4 x i32> <i32 1, i32 poison, i32 7, i32 15>) => poison
+; CHECK-NEXT: %reduce_smax = call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> <i32 -4, i32 -2, i32 7, i32 3>) => i32 7
+; CHECK-NEXT: %reduce_smax_poison = call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> <i32 -4, i32 poison, i32 7, i32 3>) => poison
+; CHECK-NEXT: %reduce_smin = call i32 @llvm.vector.reduce.smin.v4i32(<4 x i32> <i32 -4, i32 -2, i32 7, i32 3>) => i32 -4
+; CHECK-NEXT: %reduce_smin_poison = call i32 @llvm.vector.reduce.smin.v4i32(<4 x i32> <i32 -4, i32 poison, i32 7, i32 3>) => poison
+; CHECK-NEXT: %reduce_umax = call i32 @llvm.vector.reduce.umax.v4i32(<4 x i32> <i32 -1, i32 5, i32 9, i32 2>) => i32 -1
+; CHECK-NEXT: %reduce_umax_poison = call i32 @llvm.vector.reduce.umax.v4i32(<4 x i32> <i32 -1, i32 poison, i32 9, i32 2>) => poison
+; CHECK-NEXT: %reduce_umin = call i32 @llvm.vector.reduce.umin.v4i32(<4 x i32> <i32 -1, i32 5, i32 9, i32 2>) => i32 2
+; CHECK-NEXT: %reduce_umin_poison = call i32 @llvm.vector.reduce.umin.v4i32(<4 x i32> <i32 -1, i32 poison, i32 9, i32 2>) => poison
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_vector_stepvector.ll b/llvm/test/tools/llubi/intr_vector_stepvector.ll
new file mode 100644
index 0000000000000..3846ef897b8aa
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_vector_stepvector.ll
@@ -0,0 +1,17 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose --vscale=4 < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %1 = call <vscale x 4 x i32> @llvm.stepvector.nxv4i32()
+ %2 = call <vscale x 8 x i16> @llvm.stepvector.nxv8i16()
+ %3 = call <4 x i32> @llvm.stepvector.v4i32()
+ %4 = call <8 x i16> @llvm.stepvector.v8i16()
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %1 = call <vscale x 4 x i32> @llvm.stepvector.nxv4i32() => { i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15 }
+; CHECK-NEXT: %2 = call <vscale x 8 x i16> @llvm.stepvector.nxv8i16() => { i16 0, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7, i16 8, i16 9, i16 10, i16 11, i16 12, i16 13, i16 14, i16 15, i16 16, i16 17, i16 18, i16 19, i16 20, i16 21, i16 22, i16 23, i16 24, i16 25, i16 26, i16 27, i16 28, i16 29, i16 30, i16 31 }
+; CHECK-NEXT: %3 = call <4 x i32> @llvm.stepvector.v4i32() => { i32 0, i32 1, i32 2, i32 3 }
+; CHECK-NEXT: %4 = call <8 x i16> @llvm.stepvector.v8i16() => { i16 0, i16 1, i16 2, i16 3, i16 4, i16 5, i16 6, i16 7 }
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 704416ce6d737..26e01c0e4bd70 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -14,6 +14,7 @@
#include "ExecutorBase.h"
#include "Library.h"
#include "Value.h"
+#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/InstVisitor.h"
@@ -683,6 +684,186 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
});
}
+ case Intrinsic::vector_reduce_add:
+ case Intrinsic::vector_reduce_mul:
+ case Intrinsic::vector_reduce_and:
+ case Intrinsic::vector_reduce_or:
+ case Intrinsic::vector_reduce_xor:
+ case Intrinsic::vector_reduce_smax:
+ case Intrinsic::vector_reduce_smin:
+ case Intrinsic::vector_reduce_umax:
+ case Intrinsic::vector_reduce_umin: {
+ std::optional<APInt> Res;
+ for (const auto &V : Args[0].asAggregate()) {
+ if (V.isPoison()) {
+ Res.reset();
+ break;
+ }
+ const auto &IntV = V.asInteger();
+ if (!Res) {
+ Res = IntV;
+ continue;
+ }
+ switch (IID) {
+ case Intrinsic::vector_reduce_add:
+ *Res += IntV;
+ break;
+ case Intrinsic::vector_reduce_mul:
+ *Res *= IntV;
+ break;
+ case Intrinsic::vector_reduce_and:
+ *Res &= IntV;
+ break;
+ case Intrinsic::vector_reduce_or:
+ *Res |= IntV;
+ break;
+ case Intrinsic::vector_reduce_xor:
+ *Res ^= IntV;
+ break;
+ case Intrinsic::vector_reduce_smax:
+ *Res = APIntOps::smax(*Res, IntV);
+ break;
+ case Intrinsic::vector_reduce_smin:
+ *Res = APIntOps::smin(*Res, IntV);
+ break;
+ case Intrinsic::vector_reduce_umax:
+ *Res = APIntOps::umax(*Res, IntV);
+ break;
+ case Intrinsic::vector_reduce_umin:
+ *Res = APIntOps::umin(*Res, IntV);
+ break;
+ default:
+ llvm_unreachable("Unexpected intrinsic ID");
+ }
+ }
+ return Res ? *Res : AnyValue::poison();
+ }
+ case Intrinsic::vector_insert: {
+ if (Args[2].isPoison())
+ return AnyValue::poison();
+ const auto &Vec = Args[0].asAggregate();
+ const auto &SubVec = Args[1].asAggregate();
+ const auto &Idx = Args[2].asInteger();
+ const uint64_t Offset = Idx.getZExtValue();
+ if (Offset + SubVec.size() > Vec.size())
+ return AnyValue::poison();
+ std::vector<AnyValue> Res;
+ Res.reserve(Vec.size());
+ for (size_t I = 0; I != Vec.size(); ++I) {
+ if (I >= Offset && I < Offset + SubVec.size())
+ Res.push_back(SubVec[I - Offset]);
+ else
+ Res.push_back(Vec[I]);
+ }
+ return std::move(Res);
+ }
+ case Intrinsic::vector_extract: {
+ if (Args[1].isPoison())
+ return AnyValue::poison();
+ const auto &Vec = Args[0].asAggregate();
+ const auto &Idx = Args[1].asInteger();
+ const uint64_t Offset = Idx.getZExtValue();
+ const uint64_t DstSize =
+ Ctx.getEVL(cast<VectorType>(RetTy)->getElementCount());
+ if (Offset + DstSize > Vec.size())
+ return AnyValue::poison();
+ return std::vector(Vec.begin() + Offset, Vec.begin() + Offset + DstSize);
+ }
+ case Intrinsic::vector_reverse: {
+ auto Vec = Args[0].asAggregate();
+ std::reverse(Vec.begin(), Vec.end());
+ return std::move(Vec);
+ }
+ case Intrinsic::vector_deinterleave2:
+ case Intrinsic::vector_deinterleave3:
+ case Intrinsic::vector_deinterleave4:
+ case Intrinsic::vector_deinterleave5:
+ case Intrinsic::vector_deinterleave6:
+ case Intrinsic::vector_deinterleave7:
+ case Intrinsic::vector_deinterleave8: {
+ const unsigned Factor = getDeinterleaveIntrinsicFactor(IID);
+ if (Factor == 0)
+ llvm_unreachable("Unexpected intrinsic ID");
+ const auto &Vec = Args[0].asAggregate();
+ std::vector<std::vector<AnyValue>> Res(Factor);
+ for (auto &SubVec : Res)
+ SubVec.reserve(Vec.size() / Factor);
+ for (size_t I = 0, E = Vec.size(); I != E; ++I)
+ Res[I % Factor].push_back(Vec[I]);
+
+ std::vector<AnyValue> AggRes;
+ AggRes.reserve(Factor);
+ for (auto &SubVec : Res)
+ AggRes.emplace_back(std::move(SubVec));
+ return AnyValue(std::move(AggRes));
+ }
+ case Intrinsic::vector_interleave2:
+ case Intrinsic::vector_interleave3:
+ case Intrinsic::vector_interleave4:
+ case Intrinsic::vector_interleave5:
+ case Intrinsic::vector_interleave6:
+ case Intrinsic::vector_interleave7:
+ case Intrinsic::vector_interleave8: {
+ const unsigned Factor = getInterleaveIntrinsicFactor(IID);
+ if (Factor == 0)
+ llvm_unreachable("Unexpected intrinsic ID");
+ const auto &Vec = Args[0].asAggregate();
+ std::vector<AnyValue> Res;
+ Res.reserve(Vec.size() * Factor);
+ for (size_t I = 0, E = Vec.size(); I != E; ++I) {
+ for (unsigned J = 0; J != Factor; ++J)
+ Res.push_back(Args[J].asAggregate()[I]);
+ }
+ return std::move(Res);
+ }
+ case Intrinsic::vector_splice_left: {
+ if (Args[2].isPoison())
+ return AnyValue::poison();
+ const auto &LHS = Args[0].asAggregate();
+ const auto &RHS = Args[1].asAggregate();
+ const auto &Off = Args[2].asInteger();
+ const size_t Len = LHS.size();
+ if (Off.ugt(Len))
+ return AnyValue::poison();
+ uint64_t Offset = Off.getZExtValue();
+ std::vector<AnyValue> Res;
+ Res.reserve(Len);
+ for (size_t I = 0; I != Len; ++I) {
+ size_t Pos = I + Offset;
+ Res.push_back(Pos < Len ? LHS[Pos] : RHS[Pos - Len]);
+ }
+ return std::move(Res);
+ }
+ case Intrinsic::vector_splice_right: {
+ if (Args[2].isPoison())
+ return AnyValue::poison();
+ const auto &LHS = Args[0].asAggregate();
+ const auto &RHS = Args[1].asAggregate();
+ const auto &Off = Args[2].asInteger();
+ const size_t Len = LHS.size();
+ if (Off.ugt(Len))
+ return AnyValue::poison();
+ uint64_t Offset = Len - Off.getZExtValue();
+ std::vector<AnyValue> Res;
+ Res.reserve(Len);
+ for (size_t I = 0; I != Len; ++I) {
+ size_t Pos = I + Offset;
+ Res.push_back(Pos < Len ? LHS[Pos] : RHS[Pos - Len]);
+ }
+ return std::move(Res);
+ }
+ case Intrinsic::stepvector: {
+ std::vector<AnyValue> Res;
+ const uint32_t Len =
+ Ctx.getEVL(cast<VectorType>(RetTy)->getElementCount());
+ const unsigned BitWidth = RetTy->getScalarSizeInBits();
+ Res.reserve(Len);
+ for (uint64_t I = 0; I != Len; ++I) {
+ Res.push_back(
+ APInt(BitWidth, I, /*IsSigned=*/false, /*ImplicitTrunc=*/true));
+ }
+ return std::move(Res);
+ }
default:
Handler.onUnrecognizedInstruction(CB);
setFailed();
More information about the llvm-commits
mailing list