[llvm] [llubi] Vector manipulation intrinsics cleanup (PR #195004)
Zhige Chen via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 30 05:03:26 PDT 2026
https://github.com/nofe1248 updated https://github.com/llvm/llvm-project/pull/195004
>From 55154647e66668e5a9b4ce6a0217bfa14c787459 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Thu, 30 Apr 2026 13:18:50 +0800
Subject: [PATCH 1/5] [llubi] Vector manipulation intrinsics cleanup
---
.../llubi/intr_vector_extract_bad_idx.ll | 11 ++++++
...tr_vector_extract_scalable_idx_overflow.ll | 12 ++++++
.../tools/llubi/intr_vector_insert_bad_idx.ll | 11 ++++++
...ntr_vector_insert_scalable_idx_overflow.ll | 12 ++++++
llvm/test/tools/llubi/intr_vector_manip.ll | 8 ++--
llvm/tools/llubi/lib/Interpreter.cpp | 38 ++++++++++++++++---
6 files changed, 82 insertions(+), 10 deletions(-)
create mode 100644 llvm/test/tools/llubi/intr_vector_extract_bad_idx.ll
create mode 100644 llvm/test/tools/llubi/intr_vector_extract_scalable_idx_overflow.ll
create mode 100644 llvm/test/tools/llubi/intr_vector_insert_bad_idx.ll
create mode 100644 llvm/test/tools/llubi/intr_vector_insert_scalable_idx_overflow.ll
diff --git a/llvm/test/tools/llubi/intr_vector_extract_bad_idx.ll b/llvm/test/tools/llubi/intr_vector_extract_bad_idx.ll
new file mode 100644
index 0000000000000..e4c8462e87ff7
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_vector_extract_bad_idx.ll
@@ -0,0 +1,11 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %extract_bad_idx = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> zeroinitializer, i64 1)
+ ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT: Immediate UB detected: llvm.vector.extract index is not a multiple of the result's known minimum vector length.
+; CHECK-NEXT: error: Execution of function 'main' failed.
diff --git a/llvm/test/tools/llubi/intr_vector_extract_scalable_idx_overflow.ll b/llvm/test/tools/llubi/intr_vector_extract_scalable_idx_overflow.ll
new file mode 100644
index 0000000000000..a1a40eb1574e5
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_vector_extract_scalable_idx_overflow.ll
@@ -0,0 +1,12 @@
+; 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() {
+ %extract_idx_overflow = call <vscale x 2 x i32> @llvm.vector.extract.nxv2i32.nxv4i32(<vscale x 4 x i32> zeroinitializer, i64 9223372036854775808)
+ ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT: %extract_idx_overflow = call <vscale x 2 x i32> @llvm.vector.extract.nxv2i32.nxv4i32(<vscale x 4 x i32> zeroinitializer, i64 -9223372036854775808) => poison
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_vector_insert_bad_idx.ll b/llvm/test/tools/llubi/intr_vector_insert_bad_idx.ll
new file mode 100644
index 0000000000000..0158e3e1642e1
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_vector_insert_bad_idx.ll
@@ -0,0 +1,11 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %insert_bad_idx = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> zeroinitializer, i64 1)
+ ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT: Immediate UB detected: llvm.vector.insert index is not a multiple of the subvector's known minimum vector length.
+; CHECK-NEXT: error: Execution of function 'main' failed.
diff --git a/llvm/test/tools/llubi/intr_vector_insert_scalable_idx_overflow.ll b/llvm/test/tools/llubi/intr_vector_insert_scalable_idx_overflow.ll
new file mode 100644
index 0000000000000..0b087d998b95c
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_vector_insert_scalable_idx_overflow.ll
@@ -0,0 +1,12 @@
+; 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() {
+ %insert_idx_overflow = call <vscale x 4 x i32> @llvm.vector.insert.nxv4i32.nxv2i32(<vscale x 4 x i32> zeroinitializer, <vscale x 2 x i32> zeroinitializer, i64 9223372036854775808)
+ ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT: %insert_idx_overflow = call <vscale x 4 x i32> @llvm.vector.insert.nxv4i32.nxv2i32(<vscale x 4 x i32> zeroinitializer, <vscale x 2 x i32> zeroinitializer, i64 -9223372036854775808) => poison
+; 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
index bcccb9de93d8a..3dcbbd226c4ad 100644
--- a/llvm/test/tools/llubi/intr_vector_manip.ll
+++ b/llvm/test/tools/llubi/intr_vector_manip.ll
@@ -5,12 +5,12 @@ 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)
+ %insert_poison = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> <i32 9, i32 10>, i64 6)
%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)
+ %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 6)
%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>)
@@ -35,11 +35,11 @@ define void @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: %insert_poison = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> <i32 9, i32 10>, i64 6) => 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: %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 6) => 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 }
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 26e01c0e4bd70..e87ebfabc5db9 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -22,6 +22,8 @@
#include "llvm/IR/PatternMatch.h"
#include "llvm/Support/Allocator.h"
+#include <limits>
+
namespace llvm::ubi {
using namespace PatternMatch;
@@ -744,8 +746,21 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
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())
+ auto EC = cast<VectorType>(CB.getArgOperand(1)->getType())
+ ->getElementCount();
+ const uint64_t RawOffset = Idx.getZExtValue();
+ if (RawOffset % EC.getKnownMinValue() != 0) {
+ reportImmediateUB("llvm.vector.insert index is not a multiple of the "
+ "subvector's known minimum vector length.");
+ return AnyValue::poison();
+ }
+ const uint32_t VScale = Ctx.getVScale();
+ if (EC.isScalable() && VScale != 0 &&
+ RawOffset > std::numeric_limits<uint64_t>::max() / VScale)
+ return AnyValue::poison();
+ const uint64_t Offset =
+ EC.isScalable() ? RawOffset * VScale : RawOffset;
+ if (Offset > Vec.size() || SubVec.size() > Vec.size() - Offset)
return AnyValue::poison();
std::vector<AnyValue> Res;
Res.reserve(Vec.size());
@@ -762,10 +777,21 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
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())
+ auto EC = cast<VectorType>(RetTy)->getElementCount();
+ const uint64_t RawOffset = Idx.getZExtValue();
+ if (RawOffset % EC.getKnownMinValue() != 0) {
+ reportImmediateUB("llvm.vector.extract index is not a multiple of the "
+ "result's known minimum vector length.");
+ return AnyValue::poison();
+ }
+ const uint32_t VScale = Ctx.getVScale();
+ if (EC.isScalable() && VScale != 0 &&
+ RawOffset > std::numeric_limits<uint64_t>::max() / VScale)
+ return AnyValue::poison();
+ const uint64_t Offset =
+ EC.isScalable() ? RawOffset * VScale : RawOffset;
+ const uint64_t DstSize = Ctx.getEVL(EC);
+ if (Offset > Vec.size() || DstSize > Vec.size() - Offset)
return AnyValue::poison();
return std::vector(Vec.begin() + Offset, Vec.begin() + Offset + DstSize);
}
>From 515628b9f51c0bad208f19e6f95b5572c2328a84 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Thu, 30 Apr 2026 13:23:15 +0800
Subject: [PATCH 2/5] [llubi] Format code
---
llvm/tools/llubi/lib/Interpreter.cpp | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index e87ebfabc5db9..453fc3a3dc3bd 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -746,8 +746,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
const auto &Vec = Args[0].asAggregate();
const auto &SubVec = Args[1].asAggregate();
const auto &Idx = Args[2].asInteger();
- auto EC = cast<VectorType>(CB.getArgOperand(1)->getType())
- ->getElementCount();
+ auto EC =
+ cast<VectorType>(CB.getArgOperand(1)->getType())->getElementCount();
const uint64_t RawOffset = Idx.getZExtValue();
if (RawOffset % EC.getKnownMinValue() != 0) {
reportImmediateUB("llvm.vector.insert index is not a multiple of the "
@@ -758,8 +758,7 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
if (EC.isScalable() && VScale != 0 &&
RawOffset > std::numeric_limits<uint64_t>::max() / VScale)
return AnyValue::poison();
- const uint64_t Offset =
- EC.isScalable() ? RawOffset * VScale : RawOffset;
+ const uint64_t Offset = EC.isScalable() ? RawOffset * VScale : RawOffset;
if (Offset > Vec.size() || SubVec.size() > Vec.size() - Offset)
return AnyValue::poison();
std::vector<AnyValue> Res;
@@ -788,8 +787,7 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
if (EC.isScalable() && VScale != 0 &&
RawOffset > std::numeric_limits<uint64_t>::max() / VScale)
return AnyValue::poison();
- const uint64_t Offset =
- EC.isScalable() ? RawOffset * VScale : RawOffset;
+ const uint64_t Offset = EC.isScalable() ? RawOffset * VScale : RawOffset;
const uint64_t DstSize = Ctx.getEVL(EC);
if (Offset > Vec.size() || DstSize > Vec.size() - Offset)
return AnyValue::poison();
>From 085f7d8a237d22dc67c7ade888d39be5513299c2 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Thu, 30 Apr 2026 18:37:57 +0800
Subject: [PATCH 3/5] [llubi] Small fix
---
.../tools/llubi/intr_vector_extract_bad_idx.ll | 11 -----------
.../intr_vector_extract_scalable_idx_overflow.ll | 12 ------------
.../test/tools/llubi/intr_vector_insert_bad_idx.ll | 11 -----------
.../intr_vector_insert_scalable_idx_overflow.ll | 12 ------------
llvm/test/tools/llubi/intr_vector_manip.ll | 10 ++++++++++
llvm/test/tools/llubi/intr_vscale_poison.ll | 4 ++--
llvm/tools/llubi/lib/Interpreter.cpp | 14 ++++----------
llvm/tools/llubi/llubi.cpp | 11 +++++++++++
8 files changed, 27 insertions(+), 58 deletions(-)
delete mode 100644 llvm/test/tools/llubi/intr_vector_extract_bad_idx.ll
delete mode 100644 llvm/test/tools/llubi/intr_vector_extract_scalable_idx_overflow.ll
delete mode 100644 llvm/test/tools/llubi/intr_vector_insert_bad_idx.ll
delete mode 100644 llvm/test/tools/llubi/intr_vector_insert_scalable_idx_overflow.ll
diff --git a/llvm/test/tools/llubi/intr_vector_extract_bad_idx.ll b/llvm/test/tools/llubi/intr_vector_extract_bad_idx.ll
deleted file mode 100644
index e4c8462e87ff7..0000000000000
--- a/llvm/test/tools/llubi/intr_vector_extract_bad_idx.ll
+++ /dev/null
@@ -1,11 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
-; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
-
-define void @main() {
- %extract_bad_idx = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> zeroinitializer, i64 1)
- ret void
-}
-
-; CHECK: Entering function: main
-; CHECK-NEXT: Immediate UB detected: llvm.vector.extract index is not a multiple of the result's known minimum vector length.
-; CHECK-NEXT: error: Execution of function 'main' failed.
diff --git a/llvm/test/tools/llubi/intr_vector_extract_scalable_idx_overflow.ll b/llvm/test/tools/llubi/intr_vector_extract_scalable_idx_overflow.ll
deleted file mode 100644
index a1a40eb1574e5..0000000000000
--- a/llvm/test/tools/llubi/intr_vector_extract_scalable_idx_overflow.ll
+++ /dev/null
@@ -1,12 +0,0 @@
-; 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() {
- %extract_idx_overflow = call <vscale x 2 x i32> @llvm.vector.extract.nxv2i32.nxv4i32(<vscale x 4 x i32> zeroinitializer, i64 9223372036854775808)
- ret void
-}
-
-; CHECK: Entering function: main
-; CHECK-NEXT: %extract_idx_overflow = call <vscale x 2 x i32> @llvm.vector.extract.nxv2i32.nxv4i32(<vscale x 4 x i32> zeroinitializer, i64 -9223372036854775808) => poison
-; CHECK-NEXT: ret void
-; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_vector_insert_bad_idx.ll b/llvm/test/tools/llubi/intr_vector_insert_bad_idx.ll
deleted file mode 100644
index 0158e3e1642e1..0000000000000
--- a/llvm/test/tools/llubi/intr_vector_insert_bad_idx.ll
+++ /dev/null
@@ -1,11 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
-; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
-
-define void @main() {
- %insert_bad_idx = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> zeroinitializer, i64 1)
- ret void
-}
-
-; CHECK: Entering function: main
-; CHECK-NEXT: Immediate UB detected: llvm.vector.insert index is not a multiple of the subvector's known minimum vector length.
-; CHECK-NEXT: error: Execution of function 'main' failed.
diff --git a/llvm/test/tools/llubi/intr_vector_insert_scalable_idx_overflow.ll b/llvm/test/tools/llubi/intr_vector_insert_scalable_idx_overflow.ll
deleted file mode 100644
index 0b087d998b95c..0000000000000
--- a/llvm/test/tools/llubi/intr_vector_insert_scalable_idx_overflow.ll
+++ /dev/null
@@ -1,12 +0,0 @@
-; 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() {
- %insert_idx_overflow = call <vscale x 4 x i32> @llvm.vector.insert.nxv4i32.nxv2i32(<vscale x 4 x i32> zeroinitializer, <vscale x 2 x i32> zeroinitializer, i64 9223372036854775808)
- ret void
-}
-
-; CHECK: Entering function: main
-; CHECK-NEXT: %insert_idx_overflow = call <vscale x 4 x i32> @llvm.vector.insert.nxv4i32.nxv2i32(<vscale x 4 x i32> zeroinitializer, <vscale x 2 x i32> zeroinitializer, i64 -9223372036854775808) => poison
-; 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
index 3dcbbd226c4ad..20895550565d9 100644
--- a/llvm/test/tools/llubi/intr_vector_manip.ll
+++ b/llvm/test/tools/llubi/intr_vector_manip.ll
@@ -28,6 +28,12 @@ define void @main() {
%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)
+ %insert_bad_idx = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> zeroinitializer, i64 1)
+ %extract_bad_idx = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> zeroinitializer, i64 1)
+
+ %insert_idx_overflow = call <vscale x 4 x i32> @llvm.vector.insert.nxv4i32.nxv2i32(<vscale x 4 x i32> zeroinitializer, <vscale x 2 x i32> zeroinitializer, i64 9223372036854775808)
+ %extract_idx_overflow = call <vscale x 2 x i32> @llvm.vector.extract.nxv2i32.nxv4i32(<vscale x 4 x i32> zeroinitializer, i64 9223372036854775808)
+
ret void
}
@@ -52,5 +58,9 @@ define void @main() {
; 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: %insert_bad_idx = call <6 x i32> @llvm.vector.insert.v6i32.v2i32(<6 x i32> zeroinitializer, <2 x i32> zeroinitializer, i64 1) => poison
+; CHECK-NEXT: %extract_bad_idx = call <2 x i32> @llvm.vector.extract.v2i32.v6i32(<6 x i32> zeroinitializer, i64 1) => poison
+; CHECK-NEXT: %insert_idx_overflow = call <vscale x 4 x i32> @llvm.vector.insert.nxv4i32.nxv2i32(<vscale x 4 x i32> zeroinitializer, <vscale x 2 x i32> zeroinitializer, i64 -9223372036854775808) => poison
+; CHECK-NEXT: %extract_idx_overflow = call <vscale x 2 x i32> @llvm.vector.extract.nxv2i32.nxv4i32(<vscale x 4 x i32> zeroinitializer, i64 -9223372036854775808) => poison
; CHECK-NEXT: ret void
; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_vscale_poison.ll b/llvm/test/tools/llubi/intr_vscale_poison.ll
index 2fe406d532254..f6314abb3c2bc 100644
--- a/llvm/test/tools/llubi/intr_vscale_poison.ll
+++ b/llvm/test/tools/llubi/intr_vscale_poison.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
-; RUN: llubi --vscale=257 --verbose < %s 2>&1 | FileCheck %s
+; RUN: llubi --vscale=512 --verbose < %s 2>&1 | FileCheck %s
define void @main() {
call i8 @llvm.vscale.i8()
@@ -8,6 +8,6 @@ define void @main() {
}
; CHECK: Entering function: main
; CHECK-NEXT: %1 = call i8 @llvm.vscale.i8() => poison
-; CHECK-NEXT: %2 = call i16 @llvm.vscale.i16() => i16 257
+; CHECK-NEXT: %2 = call i16 @llvm.vscale.i16() => i16 512
; 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 453fc3a3dc3bd..592a0b527575c 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -749,13 +749,10 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
auto EC =
cast<VectorType>(CB.getArgOperand(1)->getType())->getElementCount();
const uint64_t RawOffset = Idx.getZExtValue();
- if (RawOffset % EC.getKnownMinValue() != 0) {
- reportImmediateUB("llvm.vector.insert index is not a multiple of the "
- "subvector's known minimum vector length.");
+ if (RawOffset % EC.getKnownMinValue() != 0)
return AnyValue::poison();
- }
const uint32_t VScale = Ctx.getVScale();
- if (EC.isScalable() && VScale != 0 &&
+ if (EC.isScalable() &&
RawOffset > std::numeric_limits<uint64_t>::max() / VScale)
return AnyValue::poison();
const uint64_t Offset = EC.isScalable() ? RawOffset * VScale : RawOffset;
@@ -778,13 +775,10 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
const auto &Idx = Args[1].asInteger();
auto EC = cast<VectorType>(RetTy)->getElementCount();
const uint64_t RawOffset = Idx.getZExtValue();
- if (RawOffset % EC.getKnownMinValue() != 0) {
- reportImmediateUB("llvm.vector.extract index is not a multiple of the "
- "result's known minimum vector length.");
+ if (RawOffset % EC.getKnownMinValue() != 0)
return AnyValue::poison();
- }
const uint32_t VScale = Ctx.getVScale();
- if (EC.isScalable() && VScale != 0 &&
+ if (EC.isScalable() &&
RawOffset > std::numeric_limits<uint64_t>::max() / VScale)
return AnyValue::poison();
const uint64_t Offset = EC.isScalable() ? RawOffset * VScale : RawOffset;
diff --git a/llvm/tools/llubi/llubi.cpp b/llvm/tools/llubi/llubi.cpp
index 0ec2e236049dd..9e8a55cee9e43 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -166,6 +166,17 @@ int main(int argc, char **argv) {
return 1;
}
+ if (VScale == 0) {
+ WithColor::error() << "--vscale value must be positive\n";
+ return 1;
+ }
+
+ if (std::pow(2, static_cast<unsigned>(std::log2(VScale.getValue()))) !=
+ VScale.getValue()) {
+ WithColor::error() << "--vscale value must be a power of 2\n";
+ return 1;
+ }
+
LLVMContext Context;
// Load the bitcode...
>From 4bc320a091257051d6a7f9d528d6b90221d043c3 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Thu, 30 Apr 2026 18:51:39 +0800
Subject: [PATCH 4/5] [llubi] Use isPowerOf2_32 instead
---
llvm/tools/llubi/llubi.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/tools/llubi/llubi.cpp b/llvm/tools/llubi/llubi.cpp
index 9e8a55cee9e43..a17c9f4f01f7c 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -171,8 +171,7 @@ int main(int argc, char **argv) {
return 1;
}
- if (std::pow(2, static_cast<unsigned>(std::log2(VScale.getValue()))) !=
- VScale.getValue()) {
+ if (isPowerOf2_32(VScale)) {
WithColor::error() << "--vscale value must be a power of 2\n";
return 1;
}
>From 57df8db92ff9a76676e3dc3281b26e5b05ddcb13 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Thu, 30 Apr 2026 20:03:08 +0800
Subject: [PATCH 5/5] [llubi] Use getEVL and fix the reversed power of 2 check
---
llvm/tools/llubi/lib/Interpreter.cpp | 27 ++++++++++++++-------------
llvm/tools/llubi/llubi.cpp | 2 +-
2 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 592a0b527575c..1f68051c617a0 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -749,13 +749,14 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
auto EC =
cast<VectorType>(CB.getArgOperand(1)->getType())->getElementCount();
const uint64_t RawOffset = Idx.getZExtValue();
- if (RawOffset % EC.getKnownMinValue() != 0)
+ const uint32_t MinSize = EC.getKnownMinValue();
+ if (RawOffset % MinSize != 0)
return AnyValue::poison();
- const uint32_t VScale = Ctx.getVScale();
- if (EC.isScalable() &&
- RawOffset > std::numeric_limits<uint64_t>::max() / VScale)
+ const uint64_t Chunk = RawOffset / MinSize;
+ const uint64_t EVL = Ctx.getEVL(EC);
+ if (Chunk > std::numeric_limits<uint64_t>::max() / EVL)
return AnyValue::poison();
- const uint64_t Offset = EC.isScalable() ? RawOffset * VScale : RawOffset;
+ const uint64_t Offset = Chunk * EVL;
if (Offset > Vec.size() || SubVec.size() > Vec.size() - Offset)
return AnyValue::poison();
std::vector<AnyValue> Res;
@@ -775,17 +776,17 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
const auto &Idx = Args[1].asInteger();
auto EC = cast<VectorType>(RetTy)->getElementCount();
const uint64_t RawOffset = Idx.getZExtValue();
- if (RawOffset % EC.getKnownMinValue() != 0)
+ const uint32_t MinSize = EC.getKnownMinValue();
+ if (RawOffset % MinSize != 0)
return AnyValue::poison();
- const uint32_t VScale = Ctx.getVScale();
- if (EC.isScalable() &&
- RawOffset > std::numeric_limits<uint64_t>::max() / VScale)
+ const uint64_t Chunk = RawOffset / MinSize;
+ const uint64_t EVL = Ctx.getEVL(EC);
+ if (Chunk > std::numeric_limits<uint64_t>::max() / EVL)
return AnyValue::poison();
- const uint64_t Offset = EC.isScalable() ? RawOffset * VScale : RawOffset;
- const uint64_t DstSize = Ctx.getEVL(EC);
- if (Offset > Vec.size() || DstSize > Vec.size() - Offset)
+ const uint64_t Offset = Chunk * EVL;
+ if (Offset > Vec.size() || EVL > Vec.size() - Offset)
return AnyValue::poison();
- return std::vector(Vec.begin() + Offset, Vec.begin() + Offset + DstSize);
+ return std::vector(Vec.begin() + Offset, Vec.begin() + Offset + EVL);
}
case Intrinsic::vector_reverse: {
auto Vec = Args[0].asAggregate();
diff --git a/llvm/tools/llubi/llubi.cpp b/llvm/tools/llubi/llubi.cpp
index a17c9f4f01f7c..6e0616405b703 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -171,7 +171,7 @@ int main(int argc, char **argv) {
return 1;
}
- if (isPowerOf2_32(VScale)) {
+ if (!isPowerOf2_32(VScale)) {
WithColor::error() << "--vscale value must be a power of 2\n";
return 1;
}
More information about the llvm-commits
mailing list