[llvm] [SPIR-V] Fix verifier crash on aggregate extract into a mutated callsite (PR #203729)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 13 15:01:52 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-spir-v
Author: Dmitry Sidorov (MrSidims)
<details>
<summary>Changes</summary>
SPIRVPrepareFunctions rewrites indirect/inline-asm callsite signatures so aggregate params become i32 value-ids, but leaves the operands for SPIRVEmitIntrinsics to tokenize. An aggregate-returning spv_extractv result passed to such a call was never tokenized, so it no longer matched the mutated callee signature, tripping the IR verifier ("Call parameter type does not match function signature!").
Mutate the spv_extractv result to i32 when it feeds a callsite param that was rewritten to a value-id. Real SPIR-V type is recovered from the value attributes later during selection.
---
Full diff: https://github.com/llvm/llvm-project/pull/203729.diff
3 Files Affected:
- (modified) llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp (+16)
- (added) llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/extractvalue-aggregate-mutated-callsite-indirect.ll (+21)
- (added) llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_inline_assembly/extractvalue-aggregate-mutated-callsite-asm.ll (+21)
``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 89b6dad3d5239..ff78983ac05f8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -2409,6 +2409,22 @@ Instruction *SPIRVEmitIntrinsics::visitExtractValueInst(ExtractValueInst &I) {
auto *NewI =
B.CreateIntrinsic(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 (NewI->getType()->isAggregateType()) {
+ for (Use &U : NewI->uses()) {
+ auto *CB = dyn_cast<CallBase>(U.getUser());
+ if (!CB || !CB->isArgOperand(&U))
+ continue;
+ unsigned ArgNo = CB->getArgOperandNo(&U);
+ FunctionType *FT = CB->getFunctionType();
+ if (ArgNo < FT->getNumParams() &&
+ !FT->getParamType(ArgNo)->isAggregateType()) {
+ NewI->mutateType(B.getInt32Ty());
+ break;
+ }
+ }
+ }
return NewI;
}
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/extractvalue-aggregate-mutated-callsite-indirect.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/extractvalue-aggregate-mutated-callsite-indirect.ll
new file mode 100644
index 0000000000000..df533da7592be
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/extractvalue-aggregate-mutated-callsite-indirect.ll
@@ -0,0 +1,21 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s
+; TODO: add spirv-val
+
+; An aggregate extractvalue feeding an indirect call used to crash the verifier.
+
+%struct.Inner = type { float, float }
+%struct.Outer = type { %struct.Inner, %struct.Inner }
+
+; CHECK: %[[#Inner:]] = OpTypeStruct
+; CHECK: %[[#Outer:]] = OpTypeStruct %[[#Inner]] %[[#Inner]]
+; CHECK: %[[#Null:]] = OpConstantNull %[[#Outer]]
+
+; CHECK: OpFunction
+; CHECK: %[[#Field:]] = OpCompositeExtract %[[#Inner]] %[[#Null]] 1
+; CHECK: %[[#]] = OpFunctionPointerCallINTEL %[[#]] %[[#]] %[[#Field]]
+define spir_func i32 @f(ptr %fp) {
+entry:
+ %a = extractvalue %struct.Outer zeroinitializer, 1
+ %r = call spir_func i32 %fp(%struct.Inner %a)
+ ret i32 %r
+}
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_inline_assembly/extractvalue-aggregate-mutated-callsite-asm.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_inline_assembly/extractvalue-aggregate-mutated-callsite-asm.ll
new file mode 100644
index 0000000000000..9b282eb022e07
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_inline_assembly/extractvalue-aggregate-mutated-callsite-asm.ll
@@ -0,0 +1,21 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_inline_assembly %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_inline_assembly %s -o - -filetype=obj | spirv-val %}
+
+; An aggregate extractvalue feeding an inline-asm call used to crash the verifier.
+
+%struct.Inner = type { float, float }
+%struct.Outer = type { %struct.Inner, %struct.Inner }
+
+; CHECK: %[[#Inner:]] = OpTypeStruct
+; CHECK: %[[#Outer:]] = OpTypeStruct %[[#Inner]] %[[#Inner]]
+; CHECK: %[[#Null:]] = OpConstantNull %[[#Outer]]
+
+; CHECK: OpFunction
+; CHECK: %[[#Field:]] = OpCompositeExtract %[[#Inner]] %[[#Null]] 1
+; CHECK: %[[#]] = OpAsmCallINTEL %[[#]] %[[#]] %[[#Field]]
+define i32 @f() {
+entry:
+ %a = extractvalue %struct.Outer zeroinitializer, 1
+ %r = call i32 asm sideeffect "", "=r,r"(%struct.Inner %a)
+ ret i32 %r
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/203729
More information about the llvm-commits
mailing list