[llvm] [SPIR-V] Handle undef aggregate initializers for global variables (PR #186785)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 16 10:48:13 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/186785
>From 90770b298cd2a8a99c05627a3430d8b5edf2fb10 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 16 Mar 2026 13:08:09 +0100
Subject: [PATCH 1/5] [SPIR-V] Handle undef aggregate initializers for global
variables
Expand undef aggregate global initializers into per-element spv_undef intrinsics
---
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 32 ++++++++++++-
llvm/lib/Target/SPIRV/SPIRVUtils.h | 6 ++-
.../undef-global-aggregate-initializer.ll | 48 +++++++++++++++++++
3 files changed, 83 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 87bb871dda80c..eb97269898115 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -255,6 +255,7 @@ class SPIRVEmitIntrinsics
bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);
void insertConstantsForFPFastMathDefault(Module &M);
+ Value *buildSpvUndefComposite(Type *AggrTy, IRBuilder<> &B);
void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
void processParamTypes(Function *F, IRBuilder<> &B);
void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
@@ -424,7 +425,9 @@ static bool isMemInstrToReplace(Instruction *I) {
static bool isAggrConstForceInt32(const Value *V) {
return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||
isa<ConstantDataArray>(V) ||
- (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
+ (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy()) ||
+ (isa<UndefValue>(V) && !isa<PoisonValue>(V) &&
+ V->getType()->isAggregateType());
}
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {
@@ -2269,6 +2272,28 @@ shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers,
return F == &FirstDefinition;
}
+Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(Type *AggrTy,
+ IRBuilder<> &B) {
+ unsigned NumElems = isa<StructType>(AggrTy)
+ ? cast<StructType>(AggrTy)->getNumElements()
+ : cast<ArrayType>(AggrTy)->getNumElements();
+ SmallVector<Value *, 4> Elems(NumElems);
+ for (unsigned I = 0; I < NumElems; ++I) {
+ Type *ElemTy = isa<StructType>(AggrTy)
+ ? AggrTy->getContainedType(I)
+ : cast<ArrayType>(AggrTy)->getElementType();
+ auto *UI = B.CreateIntrinsic(Intrinsic::spv_undef, {});
+ AggrConsts[UI] = UndefValue::get(ElemTy);
+ AggrConstTypes[UI] = ElemTy;
+ Elems[I] = UI;
+ }
+ auto *Composite = B.CreateIntrinsic(Intrinsic::spv_const_composite,
+ {B.getInt32Ty()}, Elems);
+ AggrConsts[Composite] = UndefValue::get(AggrTy);
+ AggrConstTypes[Composite] = AggrTy;
+ return Composite;
+}
+
void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
IRBuilder<> &B) {
@@ -2282,11 +2307,14 @@ void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
// by llvm IR general logic.
deduceElementTypeHelper(&GV, false);
Init = GV.getInitializer();
+ Value *InitOp = Init;
+ if (isa<UndefValue>(Init) && Init->getType()->isAggregateType())
+ InitOp = buildSpvUndefComposite(Init->getType(), B);
Type *Ty = isAggrConstForceInt32(Init) ? B.getInt32Ty() : Init->getType();
Constant *Const = isAggrConstForceInt32(Init) ? B.getInt32(1) : Init;
auto *InitInst = B.CreateIntrinsic(Intrinsic::spv_init_global,
{GV.getType(), Ty}, {&GV, Const});
- InitInst->setArgOperand(1, Init);
+ InitInst->setArgOperand(1, InitOp);
}
if (!Init && GV.use_empty())
B.CreateIntrinsic(Intrinsic::spv_unref_global, GV.getType(), &GV);
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 8a152cd58d517..3b5d908928c35 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -347,7 +347,11 @@ bool matchPeeledArrayPattern(const StructType *Ty, Type *&OriginalElementType,
Type *reconstitutePeeledArrayType(Type *Ty);
inline bool hasInitializer(const GlobalVariable *GV) {
- return GV->hasInitializer() && !isa<UndefValue>(GV->getInitializer());
+ if (!GV->hasInitializer())
+ return false;
+ if (const auto *Init = GV->getInitializer(); isa<UndefValue>(Init))
+ return !isa<PoisonValue>(Init) && Init->getType()->isAggregateType();
+ return true;
}
// True if this is an instance of TypedPointerType.
diff --git a/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll b/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
new file mode 100644
index 0000000000000..15d005215f7aa
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
@@ -0,0 +1,48 @@
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
+target triple = "spir"
+
+%struct.simple = type { i8 }
+ at g_simple = private unnamed_addr addrspace(2) constant %struct.simple undef, align 1
+
+%struct.multi = type { i32, float, i8 }
+ at g_multi = private addrspace(2) constant %struct.multi undef, align 4
+
+ at g_arr = private addrspace(2) constant [3 x i32] undef, align 4
+
+%struct.inner = type { i32 }
+%struct.outer = type { %struct.inner, float }
+ at g_nested = private addrspace(2) constant %struct.outer undef, align 4
+
+define spir_kernel void @k() #0 !kernel_arg_addr_space !0 !kernel_arg_access_qual !0 !kernel_arg_type !0 !kernel_arg_base_type !0 !kernel_arg_type_qual !0 {
+entry:
+ ret void
+}
+
+; CHECK-DAG: %[[#I32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#F32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#I8:]] = OpTypeInt 8 0
+
+; CHECK-DAG: %[[#INNER:]] = OpTypeStruct %[[#I32]]
+; CHECK-DAG: %[[#OUTER:]] = OpTypeStruct %[[#INNER]] %[[#F32]]
+; CHECK-DAG: %[[#MULTI:]] = OpTypeStruct %[[#I32]] %[[#F32]] %[[#I8]]
+; CHECK-DAG: %[[#SIMPLE:]] = OpTypeStruct %[[#I8]]
+; CHECK-DAG: %[[#ARR:]] = OpTypeArray %[[#I32]] %[[#]]
+
+; CHECK-DAG: %[[#OUTER_PTR:]] = OpTypePointer UniformConstant %[[#OUTER]]
+; CHECK-DAG: %[[#ARR_PTR:]] = OpTypePointer UniformConstant %[[#ARR]]
+; CHECK-DAG: %[[#MULTI_PTR:]] = OpTypePointer UniformConstant %[[#MULTI]]
+; CHECK-DAG: %[[#SIMPLE_PTR:]] = OpTypePointer UniformConstant %[[#SIMPLE]]
+
+; CHECK: OpConstantComposite %[[#SIMPLE]]
+; CHECK: OpVariable %[[#SIMPLE_PTR]] UniformConstant
+; CHECK: OpConstantComposite %[[#MULTI]]
+; CHECK: OpVariable %[[#MULTI_PTR]] UniformConstant
+; CHECK: OpConstantComposite %[[#ARR]]
+; CHECK: OpVariable %[[#ARR_PTR]] UniformConstant
+; CHECK: OpConstantComposite %[[#OUTER]]
+; CHECK: OpVariable %[[#OUTER_PTR]] UniformConstant
+
+!0 = !{}
>From a6a94e6125d3592cbbd189f8c49addf71e9abc70 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 16 Mar 2026 13:29:03 +0100
Subject: [PATCH 2/5] Address deprecator concerns
---
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 7 +++----
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 5 +++--
llvm/lib/Target/SPIRV/SPIRVUtils.h | 2 +-
.../CodeGen/SPIRV/undef-global-aggregate-initializer.ll | 8 ++++----
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index eb97269898115..307e01071093b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -426,8 +426,7 @@ static bool isAggrConstForceInt32(const Value *V) {
return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||
isa<ConstantDataArray>(V) ||
(isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy()) ||
- (isa<UndefValue>(V) && !isa<PoisonValue>(V) &&
- V->getType()->isAggregateType());
+ (isa<UndefValue>(V) && V->getType()->isAggregateType());
}
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {
@@ -2283,13 +2282,13 @@ Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(Type *AggrTy,
? AggrTy->getContainedType(I)
: cast<ArrayType>(AggrTy)->getElementType();
auto *UI = B.CreateIntrinsic(Intrinsic::spv_undef, {});
- AggrConsts[UI] = UndefValue::get(ElemTy);
+ AggrConsts[UI] = PoisonValue::get(ElemTy);
AggrConstTypes[UI] = ElemTy;
Elems[I] = UI;
}
auto *Composite = B.CreateIntrinsic(Intrinsic::spv_const_composite,
{B.getInt32Ty()}, Elems);
- AggrConsts[Composite] = UndefValue::get(AggrTy);
+ AggrConsts[Composite] = PoisonValue::get(AggrTy);
AggrConstTypes[Composite] = AggrTy;
return Composite;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 7cf039e03430a..879c3322ad0f3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -554,8 +554,9 @@ static bool isConstReg(MachineRegisterInfo *MRI, MachineInstr *OpDef) {
case TargetOpcode::G_INTRINSIC:
case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
- if (cast<GIntrinsic>(*OpDef).getIntrinsicID() !=
- Intrinsic::spv_const_composite)
+ if (cast<GIntrinsic>(*MI).getIntrinsicID() !=
+ Intrinsic::spv_const_composite &&
+ cast<GIntrinsic>(*MI).getIntrinsicID() != Intrinsic::spv_undef)
return false;
continue;
case TargetOpcode::G_BUILD_VECTOR:
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 3b5d908928c35..d541ead5ac22c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -350,7 +350,7 @@ inline bool hasInitializer(const GlobalVariable *GV) {
if (!GV->hasInitializer())
return false;
if (const auto *Init = GV->getInitializer(); isa<UndefValue>(Init))
- return !isa<PoisonValue>(Init) && Init->getType()->isAggregateType();
+ return GV->isConstant() && Init->getType()->isAggregateType();
return true;
}
diff --git a/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll b/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
index 15d005215f7aa..6bd4a0dfced6a 100644
--- a/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
+++ b/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
@@ -5,16 +5,16 @@ target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:2
target triple = "spir"
%struct.simple = type { i8 }
- at g_simple = private unnamed_addr addrspace(2) constant %struct.simple undef, align 1
+ at g_simple = private unnamed_addr addrspace(2) constant %struct.simple poison, align 1
%struct.multi = type { i32, float, i8 }
- at g_multi = private addrspace(2) constant %struct.multi undef, align 4
+ at g_multi = private addrspace(2) constant %struct.multi poison, align 4
- at g_arr = private addrspace(2) constant [3 x i32] undef, align 4
+ at g_arr = private addrspace(2) constant [3 x i32] poison, align 4
%struct.inner = type { i32 }
%struct.outer = type { %struct.inner, float }
- at g_nested = private addrspace(2) constant %struct.outer undef, align 4
+ at g_nested = private addrspace(2) constant %struct.outer poison, align 4
define spir_kernel void @k() #0 !kernel_arg_addr_space !0 !kernel_arg_access_qual !0 !kernel_arg_type !0 !kernel_arg_base_type !0 !kernel_arg_type_qual !0 {
entry:
>From 14c15d6de142414ee8481de504e0a64f4643156d Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 16 Mar 2026 17:03:48 +0100
Subject: [PATCH 3/5] Address review comments
---
.../undef-global-aggregate-initializer.ll | 44 +++++++++++--------
1 file changed, 26 insertions(+), 18 deletions(-)
diff --git a/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll b/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
index 6bd4a0dfced6a..2cb2f57da010c 100644
--- a/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
+++ b/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
@@ -1,9 +1,6 @@
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir"
-
%struct.simple = type { i8 }
@g_simple = private unnamed_addr addrspace(2) constant %struct.simple poison, align 1
@@ -16,7 +13,10 @@ target triple = "spir"
%struct.outer = type { %struct.inner, float }
@g_nested = private addrspace(2) constant %struct.outer poison, align 4
-define spir_kernel void @k() #0 !kernel_arg_addr_space !0 !kernel_arg_access_qual !0 !kernel_arg_type !0 !kernel_arg_base_type !0 !kernel_arg_type_qual !0 {
+%struct.mixed = type { i32, float }
+ at g_mixed = private addrspace(2) constant %struct.mixed { i32 poison, float 1.0 }, align 4
+
+define spir_kernel void @k() {
entry:
ret void
}
@@ -24,25 +24,33 @@ entry:
; CHECK-DAG: %[[#I32:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#F32:]] = OpTypeFloat 32
; CHECK-DAG: %[[#I8:]] = OpTypeInt 8 0
-
-; CHECK-DAG: %[[#INNER:]] = OpTypeStruct %[[#I32]]
-; CHECK-DAG: %[[#OUTER:]] = OpTypeStruct %[[#INNER]] %[[#F32]]
; CHECK-DAG: %[[#MULTI:]] = OpTypeStruct %[[#I32]] %[[#F32]] %[[#I8]]
-; CHECK-DAG: %[[#SIMPLE:]] = OpTypeStruct %[[#I8]]
+; CHECK-DAG: %[[#SIMPLE:]] = OpTypeStruct %[[#I8]]{{$}}
; CHECK-DAG: %[[#ARR:]] = OpTypeArray %[[#I32]] %[[#]]
+; CHECK-DAG: %[[#INNER:]] = OpTypeStruct %[[#I32]]{{$}}
+; CHECK-DAG: %[[#OUTER:]] = OpTypeStruct %[[#INNER]] %[[#F32]]
+; CHECK-DAG: %[[#MIXED:]] = OpTypeStruct %[[#I32]] %[[#F32]]{{$}}
+
+; CHECK-DAG: %[[#MIXED_PTR:]] = OpTypePointer UniformConstant %[[#MIXED]]
; CHECK-DAG: %[[#OUTER_PTR:]] = OpTypePointer UniformConstant %[[#OUTER]]
; CHECK-DAG: %[[#ARR_PTR:]] = OpTypePointer UniformConstant %[[#ARR]]
; CHECK-DAG: %[[#MULTI_PTR:]] = OpTypePointer UniformConstant %[[#MULTI]]
; CHECK-DAG: %[[#SIMPLE_PTR:]] = OpTypePointer UniformConstant %[[#SIMPLE]]
-; CHECK: OpConstantComposite %[[#SIMPLE]]
-; CHECK: OpVariable %[[#SIMPLE_PTR]] UniformConstant
-; CHECK: OpConstantComposite %[[#MULTI]]
-; CHECK: OpVariable %[[#MULTI_PTR]] UniformConstant
-; CHECK: OpConstantComposite %[[#ARR]]
-; CHECK: OpVariable %[[#ARR_PTR]] UniformConstant
-; CHECK: OpConstantComposite %[[#OUTER]]
-; CHECK: OpVariable %[[#OUTER_PTR]] UniformConstant
-
-!0 = !{}
+; CHECK-DAG: %[[#CONST_F32:]] = OpConstant %[[#F32]] 1
+; CHECK-DAG: %[[#UNDEF_I8:]] = OpUndef %[[#I8]]
+; CHECK-DAG: %[[#UNDEF_I32:]] = OpUndef %[[#I32]]
+; CHECK-DAG: %[[#UNDEF_F32:]] = OpUndef %[[#F32]]
+; CHECK-DAG: %[[#UNDEF_INNER:]] = OpUndef %[[#INNER]]
+
+; CHECK-DAG: OpConstantComposite %[[#SIMPLE]] %[[#UNDEF_I8]]
+; CHECK-DAG: OpVariable %[[#SIMPLE_PTR]] UniformConstant
+; CHECK-DAG: OpConstantComposite %[[#MULTI]] %[[#UNDEF_I32]] %[[#UNDEF_F32]] %[[#UNDEF_I8]]
+; CHECK-DAG: OpVariable %[[#MULTI_PTR]] UniformConstant
+; CHECK-DAG: OpConstantComposite %[[#ARR]] %[[#UNDEF_I32]] %[[#UNDEF_I32]] %[[#UNDEF_I32]]
+; CHECK-DAG: OpVariable %[[#ARR_PTR]] UniformConstant
+; CHECK-DAG: OpConstantComposite %[[#OUTER]] %[[#UNDEF_INNER]] %[[#UNDEF_F32]]
+; CHECK-DAG: OpVariable %[[#OUTER_PTR]] UniformConstant
+; CHECK-DAG: OpConstantComposite %[[#MIXED]] %[[#UNDEF_I32]] %[[#CONST_F32]]
+; CHECK-DAG: OpVariable %[[#MIXED_PTR]] UniformConstant
>From 224e9ef151ed68815ce1f3846d82592fb2932b1b Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 16 Mar 2026 18:29:08 +0100
Subject: [PATCH 4/5] Address review comments
---
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 29 ++++++++++++-------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 307e01071093b..88c9653ab6472 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -423,10 +423,11 @@ static bool isMemInstrToReplace(Instruction *I) {
}
static bool isAggrConstForceInt32(const Value *V) {
+ bool IsUndefAggregate = isa<UndefValue>(V) && V->getType()->isAggregateType();
return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||
isa<ConstantDataArray>(V) ||
(isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy()) ||
- (isa<UndefValue>(V) && V->getType()->isAggregateType());
+ IsUndefAggregate;
}
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {
@@ -2273,18 +2274,26 @@ shouldEmitIntrinsicsForGlobalValue(const GlobalVariableUsers &GVUsers,
Value *SPIRVEmitIntrinsics::buildSpvUndefComposite(Type *AggrTy,
IRBuilder<> &B) {
- unsigned NumElems = isa<StructType>(AggrTy)
- ? cast<StructType>(AggrTy)->getNumElements()
- : cast<ArrayType>(AggrTy)->getNumElements();
- SmallVector<Value *, 4> Elems(NumElems);
- for (unsigned I = 0; I < NumElems; ++I) {
- Type *ElemTy = isa<StructType>(AggrTy)
- ? AggrTy->getContainedType(I)
- : cast<ArrayType>(AggrTy)->getElementType();
+ SmallVector<Value *, 4> Elems;
+ if (auto *ArrTy = dyn_cast<ArrayType>(AggrTy)) {
+ Type *ElemTy = ArrTy->getElementType();
auto *UI = B.CreateIntrinsic(Intrinsic::spv_undef, {});
AggrConsts[UI] = PoisonValue::get(ElemTy);
AggrConstTypes[UI] = ElemTy;
- Elems[I] = UI;
+ Elems.assign(ArrTy->getNumElements(), UI);
+ } else {
+ auto *StructTy = cast<StructType>(AggrTy);
+ DenseMap<Type *, Instruction *> UndefByType;
+ for (unsigned I = 0; I < StructTy->getNumElements(); ++I) {
+ Type *ElemTy = StructTy->getContainedType(I);
+ auto &Entry = UndefByType[ElemTy];
+ if (!Entry) {
+ Entry = B.CreateIntrinsic(Intrinsic::spv_undef, {});
+ AggrConsts[Entry] = PoisonValue::get(ElemTy);
+ AggrConstTypes[Entry] = ElemTy;
+ }
+ Elems.push_back(Entry);
+ }
}
auto *Composite = B.CreateIntrinsic(Intrinsic::spv_const_composite,
{B.getInt32Ty()}, Elems);
>From 12256535b829f514c1989df0bbc88c3f9f24a3f3 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 16 Mar 2026 18:47:57 +0100
Subject: [PATCH 5/5] Add test: struct nested in an array
---
.../SPIRV/undef-global-aggregate-initializer.ll | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll b/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
index 2cb2f57da010c..ce247a11e37f4 100644
--- a/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
+++ b/llvm/test/CodeGen/SPIRV/undef-global-aggregate-initializer.ll
@@ -16,6 +16,11 @@
%struct.mixed = type { i32, float }
@g_mixed = private addrspace(2) constant %struct.mixed { i32 poison, float 1.0 }, align 4
+%struct.with_arr = type { [2 x i32], float }
+ at g_struct_with_arr = private addrspace(2) constant %struct.with_arr poison, align 4
+
+ at g_arr_of_struct = private addrspace(2) constant [2 x %struct.with_arr] poison, align 4
+
define spir_kernel void @k() {
entry:
ret void
@@ -24,14 +29,19 @@ entry:
; CHECK-DAG: %[[#I32:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#F32:]] = OpTypeFloat 32
; CHECK-DAG: %[[#I8:]] = OpTypeInt 8 0
+; CHECK-DAG: %[[#I32_ARR2:]] = OpTypeArray %[[#I32]] %[[#]]
; CHECK-DAG: %[[#MULTI:]] = OpTypeStruct %[[#I32]] %[[#F32]] %[[#I8]]
; CHECK-DAG: %[[#SIMPLE:]] = OpTypeStruct %[[#I8]]{{$}}
; CHECK-DAG: %[[#ARR:]] = OpTypeArray %[[#I32]] %[[#]]
; CHECK-DAG: %[[#INNER:]] = OpTypeStruct %[[#I32]]{{$}}
+; CHECK-DAG: %[[#WITH_ARR:]] = OpTypeStruct %[[#I32_ARR2]] %[[#F32]]
; CHECK-DAG: %[[#OUTER:]] = OpTypeStruct %[[#INNER]] %[[#F32]]
; CHECK-DAG: %[[#MIXED:]] = OpTypeStruct %[[#I32]] %[[#F32]]{{$}}
+; CHECK-DAG: %[[#ARR_OF_STRUCT:]] = OpTypeArray %[[#WITH_ARR]] %[[#]]
+; CHECK-DAG: %[[#ARR_OF_STRUCT_PTR:]] = OpTypePointer UniformConstant %[[#ARR_OF_STRUCT]]
+; CHECK-DAG: %[[#WITH_ARR_PTR:]] = OpTypePointer UniformConstant %[[#WITH_ARR]]
; CHECK-DAG: %[[#MIXED_PTR:]] = OpTypePointer UniformConstant %[[#MIXED]]
; CHECK-DAG: %[[#OUTER_PTR:]] = OpTypePointer UniformConstant %[[#OUTER]]
; CHECK-DAG: %[[#ARR_PTR:]] = OpTypePointer UniformConstant %[[#ARR]]
@@ -43,6 +53,8 @@ entry:
; CHECK-DAG: %[[#UNDEF_I32:]] = OpUndef %[[#I32]]
; CHECK-DAG: %[[#UNDEF_F32:]] = OpUndef %[[#F32]]
; CHECK-DAG: %[[#UNDEF_INNER:]] = OpUndef %[[#INNER]]
+; CHECK-DAG: %[[#UNDEF_I32_ARR2:]] = OpUndef %[[#I32_ARR2]]
+; CHECK-DAG: %[[#UNDEF_WITH_ARR:]] = OpUndef %[[#WITH_ARR]]
; CHECK-DAG: OpConstantComposite %[[#SIMPLE]] %[[#UNDEF_I8]]
; CHECK-DAG: OpVariable %[[#SIMPLE_PTR]] UniformConstant
@@ -54,3 +66,7 @@ entry:
; CHECK-DAG: OpVariable %[[#OUTER_PTR]] UniformConstant
; CHECK-DAG: OpConstantComposite %[[#MIXED]] %[[#UNDEF_I32]] %[[#CONST_F32]]
; CHECK-DAG: OpVariable %[[#MIXED_PTR]] UniformConstant
+; CHECK-DAG: OpConstantComposite %[[#WITH_ARR]] %[[#UNDEF_I32_ARR2]] %[[#UNDEF_F32]]
+; CHECK-DAG: OpVariable %[[#WITH_ARR_PTR]] UniformConstant
+; CHECK-DAG: OpConstantComposite %[[#ARR_OF_STRUCT]] %[[#UNDEF_WITH_ARR]] %[[#UNDEF_WITH_ARR]]
+; CHECK-DAG: OpVariable %[[#ARR_OF_STRUCT_PTR]] UniformConstant
More information about the llvm-commits
mailing list