[llvm] [SPIRV] Scalarize single-element vectors in type creation (PR #180735)

Dmitry Sidorov via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 10 05:25:52 PST 2026


https://github.com/MrSidims updated https://github.com/llvm/llvm-project/pull/180735

>From cd82ea34ae200595d0ca64f0e23c0ad25f26ff1b Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Fri, 6 Feb 2026 00:21:41 +0100
Subject: [PATCH 1/3] [SPIRV] Scalarize single-element vectors in type creation

SPIR-V requires vectors to have at least 2 components. So treat <1 x T>
as T.
---
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 12 +++++
 .../CodeGen/SPIRV/single-element-vector.ll    | 52 +++++++++++++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 llvm/test/CodeGen/SPIRV/single-element-vector.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 14f1c97741ccc..dae85278f199f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -311,6 +311,7 @@ SPIRVType *SPIRVGlobalRegistry::getOpTypeVector(uint32_t NumElems,
                                                 MachineIRBuilder &MIRBuilder) {
   auto EleOpc = ElemType->getOpcode();
   (void)EleOpc;
+  assert(NumElems >= 2 && "SPIR-V OpTypeVector requires at least 2 components");
   assert((EleOpc == SPIRV::OpTypeInt || EleOpc == SPIRV::OpTypeFloat ||
           EleOpc == SPIRV::OpTypeBool) &&
          "Invalid vector element type");
@@ -1278,6 +1279,11 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVType(
     const Type *Ty, MachineIRBuilder &MIRBuilder,
     SPIRV::AccessQualifier::AccessQualifier AccessQual,
     bool ExplicitLayoutRequired, bool EmitIR) {
+  // SPIR-V doesn't support single-element vectors. Treat <1 x T> as T.
+  if (auto *FVT = dyn_cast<FixedVectorType>(Ty);
+      FVT && FVT->getNumElements() == 1)
+    return getOrCreateSPIRVType(FVT->getElementType(), MIRBuilder, AccessQual,
+                                ExplicitLayoutRequired, EmitIR);
   const MachineFunction *MF = &MIRBuilder.getMF();
   Register Reg;
   if (auto *ExtTy = dyn_cast<TargetExtType>(Ty);
@@ -1896,6 +1902,9 @@ SPIRVGlobalRegistry::getOrCreateSPIRVBoolType(MachineInstr &I,
 SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVVectorType(
     SPIRVType *BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder,
     bool EmitIR) {
+  // SPIR-V doesn't support single-element vectors.
+  if (NumElements == 1)
+    return BaseType;
   return getOrCreateSPIRVType(
       FixedVectorType::get(const_cast<Type *>(getTypeForSPIRVType(BaseType)),
                            NumElements),
@@ -1905,6 +1914,9 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVVectorType(
 SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVVectorType(
     SPIRVType *BaseType, unsigned NumElements, MachineInstr &I,
     const SPIRVInstrInfo &TII) {
+  // SPIR-V doesn't support single-element vectors.
+  if (NumElements == 1)
+    return BaseType;
   Type *Ty = FixedVectorType::get(
       const_cast<Type *>(getTypeForSPIRVType(BaseType)), NumElements);
   if (const MachineInstr *MI = findMI(Ty, false, CurMF))
diff --git a/llvm/test/CodeGen/SPIRV/single-element-vector.ll b/llvm/test/CodeGen/SPIRV/single-element-vector.ll
new file mode 100644
index 0000000000000..4cc14489b0df0
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/single-element-vector.ll
@@ -0,0 +1,52 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+
+; Verify that <1 x T> types are scalarized to T since SPIR-V doesn't support
+; single-element vectors.
+
+; CHECK-DAG: %[[#INT16:]] = OpTypeInt 16 0
+; CHECK-DAG: %[[#FLOAT64:]] = OpTypeFloat 64
+; CHECK-DAG: %[[#VEC4:]] = OpTypeVector %[[#FLOAT64]] 4
+; CHECK-DAG: %[[#FNTY:]] = OpTypeFunction %[[#VEC4]] %[[#INT16]]
+; CHECK-DAG: %[[#ZERO:]] = OpConstantNull %[[#INT16]]
+
+; CHECK: OpFunctionCall %[[#VEC4]] %[[#]] %[[#ZERO]]
+define spir_func <4 x double> @caller() {
+entry:
+  %C = call <4 x double> @callee(<1 x i16> zeroinitializer)
+  ret <4 x double> %C
+}
+declare <4 x double> @callee(<1 x i16>)
+
+; CHECK: %[[#EXTRACT_RES:]] = OpFunctionParameter %[[#INT16]]
+; CHECK: OpReturnValue %[[#EXTRACT_RES]]
+define spir_func i16 @test_extractelement(<1 x i16> %v) {
+entry:
+  %e = extractelement <1 x i16> %v, i32 0
+  ret i16 %e
+}
+
+; CHECK: %[[#INSERT_VAL:]] = OpFunctionParameter %[[#INT16]]
+; CHECK: OpReturnValue %[[#INSERT_VAL]]
+define spir_func <1 x i16> @test_insertelement(i16 %val) {
+entry:
+  %v = insertelement <1 x i16> undef, i16 %val, i32 0
+  ret <1 x i16> %v
+}
+
+; CHECK: %[[#SHUF_PARAM:]] = OpFunctionParameter %[[#INT16]]
+; CHECK: OpReturnValue %[[#SHUF_PARAM]]
+define spir_func <1 x i16> @test_shufflevector(<1 x i16> %v) {
+entry:
+  %s = shufflevector <1 x i16> %v, <1 x i16> undef, <1 x i32> zeroinitializer
+  ret <1 x i16> %s
+}
+
+; CHECK: %[[#LHS_PARAM:]] = OpFunctionParameter %[[#INT16]]
+; CHECK: %[[#RHS_PARAM:]] = OpFunctionParameter %[[#INT16]]
+; CHECK: %[[#RET:]] = OpIAdd %[[#INT16]] %[[#LHS_PARAM]] %[[#RHS_PARAM]]
+; CHECK: OpReturnValue %[[#RET]]
+define spir_func <1 x i16> @test_arithm(<1 x i16> %v1, <1 x i16> %v2) {
+entry:
+  %s = add <1 x i16> %v1, %v2
+  ret <1 x i16> %s
+}

>From 4d8fc05431c15df2abd11e0a426db80b6a3fea20 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Tue, 10 Feb 2026 07:24:26 -0600
Subject: [PATCH 2/3] remove some unneeded checksY

---
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index dae85278f199f..df4d01c22ea85 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -1902,9 +1902,6 @@ SPIRVGlobalRegistry::getOrCreateSPIRVBoolType(MachineInstr &I,
 SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVVectorType(
     SPIRVType *BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder,
     bool EmitIR) {
-  // SPIR-V doesn't support single-element vectors.
-  if (NumElements == 1)
-    return BaseType;
   return getOrCreateSPIRVType(
       FixedVectorType::get(const_cast<Type *>(getTypeForSPIRVType(BaseType)),
                            NumElements),
@@ -1914,9 +1911,6 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVVectorType(
 SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVVectorType(
     SPIRVType *BaseType, unsigned NumElements, MachineInstr &I,
     const SPIRVInstrInfo &TII) {
-  // SPIR-V doesn't support single-element vectors.
-  if (NumElements == 1)
-    return BaseType;
   Type *Ty = FixedVectorType::get(
       const_cast<Type *>(getTypeForSPIRVType(BaseType)), NumElements);
   if (const MachineInstr *MI = findMI(Ty, false, CurMF))

>From 8fdc4f5bb65c51bb55a896c16544367cb833ad44 Mon Sep 17 00:00:00 2001
From: Dmitry Sidorov <Dmitry.Sidorov at amd.com>
Date: Tue, 10 Feb 2026 07:25:33 -0600
Subject: [PATCH 3/3] undef -> poison

---
 llvm/test/CodeGen/SPIRV/single-element-vector.ll | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/single-element-vector.ll b/llvm/test/CodeGen/SPIRV/single-element-vector.ll
index 4cc14489b0df0..c4f176027d70c 100644
--- a/llvm/test/CodeGen/SPIRV/single-element-vector.ll
+++ b/llvm/test/CodeGen/SPIRV/single-element-vector.ll
@@ -29,7 +29,7 @@ entry:
 ; CHECK: OpReturnValue %[[#INSERT_VAL]]
 define spir_func <1 x i16> @test_insertelement(i16 %val) {
 entry:
-  %v = insertelement <1 x i16> undef, i16 %val, i32 0
+  %v = insertelement <1 x i16> poison, i16 %val, i32 0
   ret <1 x i16> %v
 }
 
@@ -37,7 +37,7 @@ entry:
 ; CHECK: OpReturnValue %[[#SHUF_PARAM]]
 define spir_func <1 x i16> @test_shufflevector(<1 x i16> %v) {
 entry:
-  %s = shufflevector <1 x i16> %v, <1 x i16> undef, <1 x i32> zeroinitializer
+  %s = shufflevector <1 x i16> %v, <1 x i16> poison, <1 x i32> zeroinitializer
   ret <1 x i16> %s
 }
 



More information about the llvm-commits mailing list