[llvm-branch-commits] [llvm] release/23.x: [ExpandVariadics] Don't lower unmangled C printf on SPIR-V (#206998) (PR #213893)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Aug 4 02:56:36 PDT 2026


https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/213893

Backport b1d21c6d3121898dc13c0df8cf9e4410bee75cfb

Requested by: @pvelesko

>From 140b0f7564b0c68c946b32c225b622bd43d6bee3 Mon Sep 17 00:00:00 2001
From: Paulius Velesko <pvelesko at pglc.io>
Date: Tue, 21 Jul 2026 15:39:14 +0300
Subject: [PATCH] [ExpandVariadics] Don't lower unmangled C printf on SPIR-V
 (#206998)

An unmangled C `printf` declaration demangles to bare `printf` (no
argument list), so `SPIRV::ignoreFunction`'s `printf(` prefix check
missed it and ExpandVariadics packed its arguments into a vararg buffer;
the SPIR-V backend then passed the buffer pointer as printf's first
variadic operand, so device printf printed pointer values instead of the
actual arguments. Match the bare name too so OpenCL/HIP printf (emitted
unmangled) is left as a variadic call for the backend's OpenCL.std
printf lowering.

(cherry picked from commit b1d21c6d3121898dc13c0df8cf9e4410bee75cfb)
---
 llvm/lib/Transforms/IPO/ExpandVariadics.cpp   |  7 +++-
 .../ExpandVariadics/spirv-printf.ll           | 35 +++++++++++++++++++
 2 files changed, 41 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/Transforms/ExpandVariadics/spirv-printf.ll

diff --git a/llvm/lib/Transforms/IPO/ExpandVariadics.cpp b/llvm/lib/Transforms/IPO/ExpandVariadics.cpp
index 4a45e8d5137a4..948752718fde6 100644
--- a/llvm/lib/Transforms/IPO/ExpandVariadics.cpp
+++ b/llvm/lib/Transforms/IPO/ExpandVariadics.cpp
@@ -1067,8 +1067,13 @@ struct SPIRV final : public VariadicABIInfo {
     StringRef DemangledName(Demangled);
 
     // Skip any SPIR-V builtins.
+    // Note: an unmangled C `printf` declaration demangles to "printf" with no
+    // argument list, so the "printf(" prefix check below misses it. Match the
+    // bare name as well so OpenCL/HIP printf (emitted unmangled) is left as a
+    // variadic call for the backend's OpenCL.std printf lowering to expand
+    // inline, rather than being packed into a vararg buffer here.
     if (DemangledName.starts_with("__spirv_") ||
-        DemangledName.starts_with("printf("))
+        DemangledName.starts_with("printf(") || F->getName() == "printf")
       return true;
 
     return false;
diff --git a/llvm/test/Transforms/ExpandVariadics/spirv-printf.ll b/llvm/test/Transforms/ExpandVariadics/spirv-printf.ll
new file mode 100644
index 0000000000000..c9be77a405243
--- /dev/null
+++ b/llvm/test/Transforms/ExpandVariadics/spirv-printf.ll
@@ -0,0 +1,35 @@
+; RUN: opt -mtriple=spirv64-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=lowering %s | FileCheck %s
+;
+; An unmangled C `printf` declaration demangles to bare "printf" (no argument
+; list). On SPIR-V it must be left as a variadic call so the backend can lower
+; it to the OpenCL.std printf ExtInst with inline operands, instead of having
+; its arguments packed into a vararg buffer here. A user-defined variadic
+; function with a body is still expanded as usual.
+
+ at .str = private unnamed_addr addrspace(2) constant [4 x i8] c"%d\0A\00"
+
+declare spir_func i32 @printf(ptr addrspace(2), ...)
+
+; printf is left untouched: the call stays variadic and nothing is packed
+; (CHECK-NEXT pins that ret immediately follows the call).
+; CHECK-LABEL: define spir_kernel void @uses_printf(
+; CHECK-NEXT:    {{%.*}} = call spir_func i32 (ptr addrspace(2), ...) @printf(ptr addrspace(2) @.str, i32 42)
+; CHECK-NEXT:    ret void
+define spir_kernel void @uses_printf() {
+  %r = call spir_func i32 (ptr addrspace(2), ...) @printf(ptr addrspace(2) @.str, i32 42)
+  ret void
+}
+
+; Control: an ordinary variadic function with a body is still expanded, i.e.
+; its caller packs the arguments into a vararg buffer.
+define spir_func i32 @my_variadic(...) {
+  ret i32 0
+}
+
+; CHECK-LABEL: define spir_kernel void @uses_my_variadic(
+; CHECK:    %vararg_buffer = alloca %uses_my_variadic.vararg
+; CHECK:    call spir_func i32 @my_variadic(ptr %vararg_buffer)
+define spir_kernel void @uses_my_variadic() {
+  %r = call spir_func i32 (...) @my_variadic(i32 7)
+  ret void
+}



More information about the llvm-branch-commits mailing list