[llvm] [SPIR-V] Fix getArg() assert on pointer constants in variadic call arguments (PR #214136)

Paulius Velesko via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 4 22:51:52 PDT 2026


https://github.com/pvelesko created https://github.com/llvm/llvm-project/pull/214136

`insertPtrCastOrAssignTypeInstr` bounds its loop by the call's operand count but indexes the callee's declared formal parameters, so a variadic callee passed a pointer constant in a variadic position trips `getArg() out of range!`. This is long standing: it reproduces on LLVM 22 too, and needs only `llc`.

```llvm
@.fmt = private unnamed_addr addrspace(2) constant [3 x i8] c"%s\00"
@.arg = private unnamed_addr addrspace(2) constant [2 x i8] c"a\00"

define spir_kernel void @foo() {
entry:
  %r = call spir_func i32 (ptr addrspace(2), ...) @_Z18__spirv_ocl_printfPU3AS2Kcz(ptr addrspace(2) @.fmt, ptr addrspace(2) @.arg)
  ret void
}

declare dso_local spir_func i32 @_Z18__spirv_ocl_printfPU3AS2Kcz(ptr addrspace(2), ...)
```

`llc -mtriple=spirv64-unknown-unknown t.ll -o /dev/null` asserts in `SPIRV emit intrinsics`. OpenCL `printf("%s", ...)` hits this in practice.

Fix: skip operands that have no matching formal parameter.


>From 4af542a9ac38d5fc0c7b60e75cfbc1bf18d90ec3 Mon Sep 17 00:00:00 2001
From: Paulius Velesko <pvelesko at gmail.com>
Date: Wed, 5 Aug 2026 08:47:50 +0300
Subject: [PATCH 1/2] [SPIR-V] Add reproducer for getArg() assert on variadic
 pointer argument

---
 llvm/test/CodeGen/SPIRV/printf-vararg-ptr.ll | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 llvm/test/CodeGen/SPIRV/printf-vararg-ptr.ll

diff --git a/llvm/test/CodeGen/SPIRV/printf-vararg-ptr.ll b/llvm/test/CodeGen/SPIRV/printf-vararg-ptr.ll
new file mode 100644
index 0000000000000..90b438bd40a8b
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/printf-vararg-ptr.ll
@@ -0,0 +1,19 @@
+; Check that a pointer constant passed in a variadic argument position does not
+; crash when the callee declares fewer formal parameters than the call site.
+
+; RUN: llc -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: %[[#ExtImport:]] = OpExtInstImport "OpenCL.std"
+; CHECK: OpExtInst %[[#]] %[[#ExtImport]] printf
+
+ at .fmt = private unnamed_addr addrspace(2) constant [3 x i8] c"%s\00"
+ at .arg = private unnamed_addr addrspace(2) constant [2 x i8] c"a\00"
+
+define spir_kernel void @foo() {
+entry:
+  %r = call spir_func i32 (ptr addrspace(2), ...) @_Z18__spirv_ocl_printfPU3AS2Kcz(ptr addrspace(2) @.fmt, ptr addrspace(2) @.arg)
+  ret void
+}
+
+declare dso_local spir_func i32 @_Z18__spirv_ocl_printfPU3AS2Kcz(ptr addrspace(2), ...)

>From 0c8dfaec22c0c80279e3e71fc138507d46c6ade8 Mon Sep 17 00:00:00 2001
From: Paulius Velesko <pvelesko at gmail.com>
Date: Wed, 5 Aug 2026 08:50:38 +0300
Subject: [PATCH 2/2] [SPIR-V] Skip variadic operands without a matching formal
 parameter

---
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 513b3149dd28f..6400959d8ba1b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -2369,6 +2369,8 @@ void SPIRVEmitIntrinsicsImpl::insertPtrCastOrAssignTypeInstr(Instruction *I,
       // However, we may have assumptions about the formal argument's type and
       // may have a need to insert a ptr cast for the actual parameter of this
       // call.
+      if (OpIdx >= CalledF->arg_size())
+        continue;
       Argument *CalledArg = CalledF->getArg(OpIdx);
       if (!GR->findDeducedElementType(CalledArg))
         continue;



More information about the llvm-commits mailing list