[llvm] [SPIR-V] Fix direct return of aggregate extractvalue (PR #209762)

Tim Besard via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 15 06:08:15 PDT 2026


https://github.com/maleadt created https://github.com/llvm/llvm-project/pull/209762

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.

>From 585e1bb01fa677a53b80a4aa9e3f62d184fda0a5 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] [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 19e1e71488ee3..2fe8f3f831634 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -2455,11 +2455,19 @@ Instruction *SPIRVEmitIntrinsics::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
+}



More information about the llvm-commits mailing list