[llvm] [SPIR-V] Preserve constexpr vectors as OpSpecConstantComposite (PR #215794)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 25 07:36:02 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/215794

>From f4beea153861d4c4302f1e7cf5c198eb72a22bc5 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 12 Aug 2026 14:58:37 +0200
Subject: [PATCH 1/2] [SPIR-V] Preserve constexpr vectors as
 OpSpecConstantComposite

Let SPIRVEmitIntrinsics handle these the same as structs/arrays, instead of eagerly expanding them to runtime insertelement chains
---
 llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp    | 45 ++-----------------
 .../CodeGen/SPIRV/pointers/global-ptrtoint.ll | 20 ++++++++-
 2 files changed, 23 insertions(+), 42 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp b/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
index d5e393470eae9..f8f549928d059 100644
--- a/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVRegularizer.cpp
@@ -93,56 +93,19 @@ static void runLowerConstExpr(Function &F) {
     };
 
     WorkList.pop_front();
-    auto LowerConstantVec = [&II, &LowerOp, &WorkList,
-                             &Ctx](ConstantVector *Vec,
-                                   unsigned NumOfOp) -> Value * {
-      if (llvm::all_of(Vec->operands(), [](Value *V) {
-            return isa<ConstantExpr>(V) || isa<Function>(V);
-          })) {
-        // Expand a vector of constexprs and construct it back with
-        // series of insertelement instructions.
-        std::list<Value *> OpList;
-        llvm::transform(Vec->operands(), std::back_inserter(OpList),
-                        [LowerOp](Value *V) { return LowerOp(V); });
-        Value *Repl = nullptr;
-        unsigned Idx = 0;
-        auto *PhiII = dyn_cast<PHINode>(II);
-        Instruction *InsPoint =
-            PhiII ? &PhiII->getIncomingBlock(NumOfOp)->back() : II;
-        std::list<Instruction *> ReplList;
-        for (auto V : OpList) {
-          if (auto *Inst = dyn_cast<Instruction>(V))
-            ReplList.push_back(Inst);
-          Repl = InsertElementInst::Create(
-              (Repl ? Repl : PoisonValue::get(Vec->getType())), V,
-              ConstantInt::get(Type::getInt32Ty(Ctx), Idx++), "",
-              InsPoint->getIterator());
-        }
-        WorkList.splice(WorkList.begin(), ReplList);
-        return Repl;
-      }
-      return nullptr;
-    };
     for (unsigned OI = 0, OE = II->getNumOperands(); OI != OE; ++OI) {
       auto *Op = II->getOperand(OI);
-      if (auto *Vec = dyn_cast<ConstantVector>(Op)) {
-        Value *ReplInst = LowerConstantVec(Vec, OI);
-        if (ReplInst)
-          II->replaceUsesOfWith(Op, ReplInst);
-      } else if (auto CE = dyn_cast<ConstantExpr>(Op)) {
+      if (auto CE = dyn_cast<ConstantExpr>(Op)) {
         WorkList.push_front(cast<Instruction>(LowerOp(CE)));
       } else if (auto MDAsVal = dyn_cast<MetadataAsValue>(Op)) {
         auto ConstMD = dyn_cast<ConstantAsMetadata>(MDAsVal->getMetadata());
         if (!ConstMD)
           continue;
         Constant *C = ConstMD->getValue();
-        Value *ReplInst = nullptr;
-        if (auto *Vec = dyn_cast<ConstantVector>(C))
-          ReplInst = LowerConstantVec(Vec, OI);
-        if (auto *CE = dyn_cast<ConstantExpr>(C))
-          ReplInst = LowerOp(CE);
-        if (!ReplInst)
+        auto *CE = dyn_cast<ConstantExpr>(C);
+        if (!CE)
           continue;
+        Value *ReplInst = LowerOp(CE);
         Metadata *RepMD = ValueAsMetadata::get(ReplInst);
         Value *RepMDVal = MetadataAsValue::get(Ctx, RepMD);
         II->setOperand(OI, RepMDVal);
diff --git a/llvm/test/CodeGen/SPIRV/pointers/global-ptrtoint.ll b/llvm/test/CodeGen/SPIRV/pointers/global-ptrtoint.ll
index aa6d714e2e767..0044d15b20576 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/global-ptrtoint.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/global-ptrtoint.ll
@@ -16,13 +16,31 @@
 ; CHECK-DAG: %[[UseGlobalValue:.*]] = OpSpecConstantOp %[[TyI64]] Bitcast %[[PtrToInt]]
 ; CHECK-DAG: %[[ConstComposite:.*]] = OpSpecConstantComposite %[[TyStruct]] %[[Const128]] %[[UseGlobalValue]]
 ; CHECK-DAG: %[[TyPtrStruct:.*]] = OpTypePointer CrossWorkgroup %[[TyStruct]]
-; CHECK: OpVariable %[[TyPtrStruct]] CrossWorkgroup %[[ConstComposite]]
+; CHECK-DAG: OpVariable %[[TyPtrStruct]] CrossWorkgroup %[[ConstComposite]]
+
+; CHECK-DAG: OpName %[[VecGlobal1:.*]] "vec_global1"
+; CHECK-DAG: OpName %[[VecGlobal2:.*]] "vec_global2"
+; CHECK-DAG: %[[TyVec:.*]] = OpTypeVector %[[TyI64]] 2
+; CHECK-DAG: %[[PtrToInt1:.*]] = OpSpecConstantOp %[[TyI64]] ConvertPtrToU %[[VecGlobal1]]
+; CHECK-DAG: %[[PtrToInt2:.*]] = OpSpecConstantOp %[[TyI64]] ConvertPtrToU %[[VecGlobal2]]
+; CHECK-DAG: %[[VecElt1:.*]] = OpSpecConstantOp %[[TyI64]] Bitcast %[[PtrToInt1]]
+; CHECK-DAG: %[[VecElt2:.*]] = OpSpecConstantOp %[[TyI64]] Bitcast %[[PtrToInt2]]
+; CHECK-DAG: OpSpecConstantComposite %[[TyVec]] %[[VecElt1]] %[[VecElt2]]
 ; CHECK: OpFunction
 
 @dev_global = addrspace(1) global [2 x i32] zeroinitializer
+ at vec_global1 = addrspace(1) global [2 x i32] zeroinitializer
+ at vec_global2 = addrspace(1) global [2 x i32] zeroinitializer
 @__AsanDeviceGlobalMetadata = addrspace(1) global { i64, i64 } { i64 128, i64 ptrtoint (ptr addrspace(1) @dev_global to i64) }
 
 define void @foo() {
 entry:
   ret void
 }
+
+define <2 x i64> @bar() {
+entry:
+  ret <2 x i64> <i64 ptrtoint (ptr addrspace(1) @vec_global1 to i64), i64 ptrtoint (ptr addrspace(1) @vec_global2 to i64)>
+}
+
+; CHECK-NOT: OpCompositeInsert

>From 5d430aba7e9a59e1a4015a690797a35881bd7fb9 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Tue, 25 Aug 2026 16:35:27 +0200
Subject: [PATCH 2/2] Add test

---
 .../SPIRVRegularizer-constexpr-metadata.ll       | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 llvm/test/CodeGen/SPIRV/passes/SPIRVRegularizer-constexpr-metadata.ll

diff --git a/llvm/test/CodeGen/SPIRV/passes/SPIRVRegularizer-constexpr-metadata.ll b/llvm/test/CodeGen/SPIRV/passes/SPIRVRegularizer-constexpr-metadata.ll
new file mode 100644
index 0000000000000..0caa509b4fa6a
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/passes/SPIRVRegularizer-constexpr-metadata.ll
@@ -0,0 +1,16 @@
+; RUN: opt -S -passes=spirv-regularizer -mtriple=spirv64-unknown-unknown < %s | FileCheck %s
+
+; Verify that a ConstantExpr wrapped in metadata (a call operand) is lowered
+; to an instruction, matching the legacy pass behavior in runLowerConstExpr.
+
+ at g = addrspace(1) global i32 0
+
+declare void @llvm.use_md(metadata)
+
+define void @constexpr_in_metadata() {
+; CHECK-LABEL: define void @constexpr_in_metadata(
+; CHECK:    [[V:%.*]] = ptrtoint ptr addrspace(1) @g to i64
+; CHECK:    call void @llvm.use_md(metadata i64 [[V]])
+  call void @llvm.use_md(metadata i64 ptrtoint (ptr addrspace(1) @g to i64))
+  ret void
+}



More information about the llvm-commits mailing list