[llvm] [SPIR-V] Fix direct return of aggregate extractvalue (PR #209762)
Tim Besard via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 24 03:03:18 PDT 2026
https://github.com/maleadt updated https://github.com/llvm/llvm-project/pull/209762
>From 3fbde74b60504669230882c8fb91418be48b2bcb Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Wed, 15 Jul 2026 14:53:13 +0200
Subject: [PATCH 1/2] [SPIR-V] Fix direct return of aggregate extractvalue
SPIRVPrepareFunctions rewrites aggregate function returns to i32 value IDs, but an aggregate extractvalue used directly by ret kept its original type, leaving invalid IR for the verifier. Mutate the lowered spv_extractv result when it feeds a rewritten return so the LLVM type matches while the registry preserves the aggregate SPIR-V type.
---
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 14 +++++++++++---
.../instructions/ret-single-element-array.ll | 18 ++++++++++++++++++
2 files changed, 29 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/instructions/ret-single-element-array.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index e5afaa5c63e4b..705994117b0ec 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -2466,11 +2466,19 @@ SPIRVEmitIntrinsicsImpl::visitExtractValueInst(ExtractValueInst &I) {
Instruction *NewI = B.CreateIntrinsicWithoutFolding(Intrinsic::spv_extractv,
{I.getType()}, {Args});
replaceAllUsesWithAndErase(B, &I, NewI);
- // If the aggregate result feeds a callsite whose aggregate params were
- // rewritten to i32 value-ids by SPIRVPrepareFunctions, mutate it to match.
+ // If the aggregate result feeds a return or callsite whose type was rewritten
+ // to an i32 value-id by SPIRVPrepareFunctions, mutate it to match.
if (NewI->getType()->isAggregateType()) {
for (const Use &U : NewI->uses()) {
- auto *CB = dyn_cast<CallBase>(U.getUser());
+ User *Usr = U.getUser();
+ if (auto *RI = dyn_cast<ReturnInst>(Usr)) {
+ if (RI->getFunction()->getReturnType() != NewI->getType()) {
+ NewI->mutateType(B.getInt32Ty());
+ break;
+ }
+ continue;
+ }
+ auto *CB = dyn_cast<CallBase>(Usr);
if (!CB || !CB->isArgOperand(&U))
continue;
unsigned ArgNo = CB->getArgOperandNo(&U);
diff --git a/llvm/test/CodeGen/SPIRV/instructions/ret-single-element-array.ll b/llvm/test/CodeGen/SPIRV/instructions/ret-single-element-array.ll
new file mode 100644
index 0000000000000..fc1b7a74402d1
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/instructions/ret-single-element-array.ll
@@ -0,0 +1,18 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: %[[#Float:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#One:]] = OpConstant %[[#]] 1
+; CHECK-DAG: %[[#Array:]] = OpTypeArray %[[#Float]] %[[#One]]
+; CHECK-DAG: %[[#Nested:]] = OpTypeArray %[[#Array]] %[[#One]]
+; CHECK: OpFunction
+; CHECK: %[[#X:]] = OpFunctionParameter %[[#Float]]
+; CHECK: %[[#NestedVal:]] = OpCompositeInsert %[[#Nested]] %[[#X]] %[[#]] 0 0
+; CHECK: %[[#Ret:]] = OpCompositeExtract %[[#Array]] %[[#NestedVal]] 0
+; CHECK: OpReturnValue %[[#Ret]]
+
+define spir_func [1 x float] @single_element_array(float %x) {
+entry:
+ %nested = insertvalue [1 x [1 x float]] zeroinitializer, float %x, 0, 0
+ %ret = extractvalue [1 x [1 x float]] %nested, 0
+ ret [1 x float] %ret
+}
>From a011c83d53a1aa6edfe49b5550fb130e2b80230e Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Fri, 24 Jul 2026 12:02:08 +0200
Subject: [PATCH 2/2] Address review: add spirv-val/-verify-machineinstrs run
lines and struct test coverage
Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
---
.../instructions/ret-single-element-array.ll | 55 ++++++++++++++++---
1 file changed, 48 insertions(+), 7 deletions(-)
diff --git a/llvm/test/CodeGen/SPIRV/instructions/ret-single-element-array.ll b/llvm/test/CodeGen/SPIRV/instructions/ret-single-element-array.ll
index fc1b7a74402d1..6f6855f1673f7 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/ret-single-element-array.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/ret-single-element-array.ll
@@ -1,18 +1,59 @@
-; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#Float:]] = OpTypeFloat 32
; CHECK-DAG: %[[#One:]] = OpConstant %[[#]] 1
; CHECK-DAG: %[[#Array:]] = OpTypeArray %[[#Float]] %[[#One]]
-; CHECK-DAG: %[[#Nested:]] = OpTypeArray %[[#Array]] %[[#One]]
-; CHECK: OpFunction
-; CHECK: %[[#X:]] = OpFunctionParameter %[[#Float]]
-; CHECK: %[[#NestedVal:]] = OpCompositeInsert %[[#Nested]] %[[#X]] %[[#]] 0 0
-; CHECK: %[[#Ret:]] = OpCompositeExtract %[[#Array]] %[[#NestedVal]] 0
-; CHECK: OpReturnValue %[[#Ret]]
+; CHECK-DAG: %[[#ArrayInArray:]] = OpTypeArray %[[#Array]] %[[#One]]
+; CHECK-DAG: %[[#Struct:]] = OpTypeStruct %[[#Float]]
+; CHECK-DAG: %[[#StructInStruct:]] = OpTypeStruct %[[#Struct]]
+; CHECK-DAG: %[[#StructInArray:]] = OpTypeArray %[[#Struct]] %[[#One]]
+; CHECK-DAG: %[[#ArrayInStruct:]] = OpTypeStruct %[[#Array]]
+; CHECK: OpFunction
+; CHECK: %[[#X1:]] = OpFunctionParameter %[[#Float]]
+; CHECK: %[[#Agg1:]] = OpCompositeInsert %[[#ArrayInArray]] %[[#X1]] %[[#]] 0 0
+; CHECK: %[[#Ret1:]] = OpCompositeExtract %[[#Array]] %[[#Agg1]] 0
+; CHECK: OpReturnValue %[[#Ret1]]
define spir_func [1 x float] @single_element_array(float %x) {
entry:
%nested = insertvalue [1 x [1 x float]] zeroinitializer, float %x, 0, 0
%ret = extractvalue [1 x [1 x float]] %nested, 0
ret [1 x float] %ret
}
+
+; CHECK: OpFunction
+; CHECK: %[[#X2:]] = OpFunctionParameter %[[#Float]]
+; CHECK: %[[#Agg2:]] = OpCompositeInsert %[[#StructInStruct]] %[[#X2]] %[[#]] 0 0
+; CHECK: %[[#Ret2:]] = OpCompositeExtract %[[#Struct]] %[[#Agg2]] 0
+; CHECK: OpReturnValue %[[#Ret2]]
+define spir_func { float } @single_element_struct(float %x) {
+entry:
+ %nested = insertvalue { { float } } zeroinitializer, float %x, 0, 0
+ %ret = extractvalue { { float } } %nested, 0
+ ret { float } %ret
+}
+
+; CHECK: OpFunction
+; CHECK: %[[#X3:]] = OpFunctionParameter %[[#Float]]
+; CHECK: %[[#Agg3:]] = OpCompositeInsert %[[#StructInArray]] %[[#X3]] %[[#]] 0 0
+; CHECK: %[[#Ret3:]] = OpCompositeExtract %[[#Struct]] %[[#Agg3]] 0
+; CHECK: OpReturnValue %[[#Ret3]]
+define spir_func { float } @struct_in_array(float %x) {
+entry:
+ %nested = insertvalue [1 x { float }] zeroinitializer, float %x, 0, 0
+ %ret = extractvalue [1 x { float }] %nested, 0
+ ret { float } %ret
+}
+
+; CHECK: OpFunction
+; CHECK: %[[#X4:]] = OpFunctionParameter %[[#Float]]
+; CHECK: %[[#Agg4:]] = OpCompositeInsert %[[#ArrayInStruct]] %[[#X4]] %[[#]] 0 0
+; CHECK: %[[#Ret4:]] = OpCompositeExtract %[[#Array]] %[[#Agg4]] 0
+; CHECK: OpReturnValue %[[#Ret4]]
+define spir_func [1 x float] @array_in_struct(float %x) {
+entry:
+ %nested = insertvalue { [1 x float] } zeroinitializer, float %x, 0, 0
+ %ret = extractvalue { [1 x float] } %nested, 0
+ ret [1 x float] %ret
+}
More information about the llvm-commits
mailing list