[llvm] [SPIRV] Support -fembed-bitcode=marker for non-shader modules (PR #162082)

Juan Manuel Martinez CaamaƱo via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 6 05:54:51 PDT 2025


https://github.com/jmmartinez created https://github.com/llvm/llvm-project/pull/162082

-fembed-bitcode=marker gets lowered as a [0 x i8] zeroinitialized global
variable. This is interpreted as a runtime-array and is not supported in
non-shaders.

To work around this, we replace the [0 x i8] by a zeroinitialized
single-element array.

I'm not sure this is the way we want to support this, neither for shaders (using runtime arrays) nor for kernels (using the 1-sized zeroinitialized array).
A part of me would like to just delete the variable since we do not really need the delimiter.

Depends on https://github.com/llvm/llvm-project/pull/162081

>From ea5bc3baad44e5f7c536af23712ea0abc62cd99d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Mon, 6 Oct 2025 14:20:17 +0200
Subject: [PATCH 1/2] Pre-Commit tests: [SPIRV] Support -fembed-bitcode=marker
 for non-shader modules

---
 .../SPIRV/fembed-bitcode-marker-shader.ll     | 21 ++++++++++++++++
 .../CodeGen/SPIRV/fembed-bitcode-marker.ll    | 11 ++++++++
 llvm/test/CodeGen/SPIRV/fembed-bitcode.ll     | 25 +++++++++++++++++++
 3 files changed, 57 insertions(+)
 create mode 100644 llvm/test/CodeGen/SPIRV/fembed-bitcode-marker-shader.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/fembed-bitcode.ll

diff --git a/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker-shader.ll b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker-shader.ll
new file mode 100644
index 0000000000000..20ac543486766
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker-shader.ll
@@ -0,0 +1,21 @@
+; RUN: llc -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
+
+ at llvm.embedded.module = private constant [0 x i8] zeroinitializer, section ".llvmbc", align 1
+ at llvm.cmdline = private constant [5 x i8] c"-cc1\00", section ".llvmcmd", align 1
+ at llvm.compiler.used = appending global [2 x ptr] [ptr @llvm.embedded.module, ptr @llvm.cmdline], section "llvm.metadata"
+
+; CHECK-DAG: OpName [[FOO:%[0-9]+]] "foo"
+; CHECK-DAG: OpName [[MODULE:%[0-9]+]] "llvm.embedded.module"
+; CHECK-DAG: [[INT8:%[0-9]+]] = OpTypeInt 8 0
+; CHECK-DAG: [[RUNTIME_ARRAY_INT8x1:%[0-9]+]] = OpTypeRuntimeArray [[INT8]]
+; CHECK-DAG: [[POINTER:%[0-9]+]] = OpTypePointer Function [[RUNTIME_ARRAY_INT8x1]]
+; CHECK-DAG: [[EMBEDDED_MODULE_INIT:%[0-9]+]] = OpConstantNull [[RUNTIME_ARRAY_INT8x1]]
+; CHECK: [[FOO]] = OpFunction {{.*}} None {{.*}} 
+; CHECK-DAG: {{%[0-9]+}} = OpVariable [[POINTER]] Function [[EMBEDDED_MODULE_INIT]]
+
+define void @foo() #1 {
+entry:
+  ret void
+}
+
+attributes #1 = { "hlsl.numthreads"="4,8,16" "hlsl.shader"="compute" }
diff --git a/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll
new file mode 100644
index 0000000000000..6bc9beec1e9e3
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll
@@ -0,0 +1,11 @@
+; XFAIL: *
+; RUN: llc -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+
+ at llvm.embedded.module = private constant [0 x i8] zeroinitializer, section ".llvmbc", align 1
+ at llvm.cmdline = private constant [5 x i8] c"-cc1\00", section ".llvmcmd", align 1
+ at llvm.compiler.used = appending global [2 x ptr] [ptr @llvm.embedded.module, ptr @llvm.cmdline], section "llvm.metadata"
+
+define spir_kernel void @foo() {
+entry:
+  ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/fembed-bitcode.ll b/llvm/test/CodeGen/SPIRV/fembed-bitcode.ll
new file mode 100644
index 0000000000000..0044e09aceaab
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/fembed-bitcode.ll
@@ -0,0 +1,25 @@
+; RUN: llc -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+
+ at llvm.embedded.module = private constant [4 x i8] c"BC\C0\DE", section ".llvmbc", align 1
+ at llvm.cmdline = private constant [5 x i8] c"-cc1\00", section ".llvmcmd", align 1
+ at llvm.compiler.used = appending global [2 x ptr] [ptr @llvm.embedded.module, ptr @llvm.cmdline], section "llvm.metadata"
+
+; CHECK-DAG: OpName [[FOO:%[0-9]+]] "foo"
+; CHECK-DAG: OpName [[MODULE:%[0-9]+]] "llvm.embedded.module"
+; CHECK-DAG: [[INT8:%[0-9]+]] = OpTypeInt 8 0
+; CHECK-DAG: [[INT32:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[CONST_4_32:%[0-9]+]] = OpConstant [[INT32]] 4
+; CHECK-DAG: [[ARRAY_INT8x4:%[0-9]+]] = OpTypeArray [[INT8]] [[CONST_4_32]]
+; CHECK-DAG: [[POINTER:%[0-9]+]] = OpTypePointer Function [[ARRAY_INT8x4]]
+; CHECK-DAG: [[CONST_B_8:%[0-9]+]] = OpConstant [[INT8]] 66
+; CHECK-DAG: [[CONST_C_8:%[0-9]+]] = OpConstant [[INT8]] 67
+; CHECK-DAG: [[CONST_0xC0_8:%[0-9]+]] = OpConstant [[INT8]] 192
+; CHECK-DAG: [[CONST_0xDE_8:%[0-9]+]] = OpConstant [[INT8]] 222
+; CHECK-DAG: [[EMBEDDED_MODULE_INIT:%[0-9]+]] = OpConstantComposite [[ARRAY_INT8x4]] [[CONST_B_8]] [[CONST_C_8]] [[CONST_0xC0_8]] [[CONST_0xDE_8]]
+; CHECK: [[FOO]] = OpFunction {{.*}} None {{.*}} 
+; CHECK-DAG: {{%[0-9]+}} = OpVariable [[POINTER]] Function [[EMBEDDED_MODULE_INIT]]
+
+define spir_kernel void @foo() {
+entry:
+  ret void
+}

>From 39d7fbf9155c2def69c0bba87a05e115ccedba7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Mon, 6 Oct 2025 13:48:36 +0200
Subject: [PATCH 2/2] [SPIRV] Support -fembed-bitcode=marker for non-shader
 modules

-fembed-bitcode=marker gets lowered as a [0 x i8] zeroinitialized global
variable. This is interpreted as a runtime-array and is not supported in
non-shaders.

To work around this, we replace the [0 x i8] by a zeroinitialized
single-element array.
---
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 36 +++++++++++++++++++
 .../CodeGen/SPIRV/fembed-bitcode-marker.ll    | 12 ++++++-
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 9f2e07508a36a..447fbb9d1ac0a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -236,6 +236,8 @@ class SPIRVEmitIntrinsics
 
   Instruction *buildLogicalAccessChainFromGEP(GetElementPtrInst &GEP);
 
+  bool promoteEmbddedBitcodeMarker(Module &M) const;
+
 public:
   static char ID;
   SPIRVEmitIntrinsics(SPIRVTargetMachine *TM = nullptr)
@@ -3007,9 +3009,43 @@ void SPIRVEmitIntrinsics::parseFunDeclarations(Module &M) {
   }
 }
 
+bool SPIRVEmitIntrinsics::promoteEmbddedBitcodeMarker(Module &M) const {
+  const SPIRVSubtarget *STI = TM->getSubtargetImpl();
+  if (STI->isShader())
+    return false;
+
+  GlobalVariable *EmbeddedBitcode = M.getNamedGlobal("llvm.embedded.module");
+  if (!EmbeddedBitcode)
+    return false;
+
+  ArrayType *AT = cast<ArrayType>(EmbeddedBitcode->getValueType());
+  if (AT->getNumElements() != 0)
+    return false;
+
+  // When compiling with -fembed-bitcode=marker, LLVM generates a [0 x i8]
+  // zeroinitialized global variable containing the bitcode. This results in an
+  // assert outside of shaders. As a workaround, we replace this global with a
+  // zeroinitialized [1 x i8].
+  ArrayType *AT1 = ArrayType::get(AT->getElementType(), 1);
+  Constant *ZeroInit = Constant::getNullValue(AT1);
+  GlobalVariable *NewEmbeddedBitcode = new GlobalVariable(
+      AT1, EmbeddedBitcode->isConstant(), EmbeddedBitcode->getLinkage(),
+      ZeroInit, "", EmbeddedBitcode->getThreadLocalMode(),
+      EmbeddedBitcode->getAddressSpace(),
+      EmbeddedBitcode->isExternallyInitialized());
+  NewEmbeddedBitcode->setSection(NewEmbeddedBitcode->getSection());
+  NewEmbeddedBitcode->takeName(EmbeddedBitcode);
+
+  M.insertGlobalVariable(NewEmbeddedBitcode);
+  EmbeddedBitcode->replaceAllUsesWith(NewEmbeddedBitcode);
+  EmbeddedBitcode->eraseFromParent();
+  return true;
+}
+
 bool SPIRVEmitIntrinsics::runOnModule(Module &M) {
   bool Changed = false;
 
+  Changed |= promoteEmbddedBitcodeMarker(M);
   parseFunDeclarations(M);
   insertConstantsForFPFastMathDefault(M);
 
diff --git a/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll
index 6bc9beec1e9e3..e3d21fcdc8084 100644
--- a/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll
+++ b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll
@@ -1,10 +1,20 @@
-; XFAIL: *
 ; RUN: llc -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
 
 @llvm.embedded.module = private constant [0 x i8] zeroinitializer, section ".llvmbc", align 1
 @llvm.cmdline = private constant [5 x i8] c"-cc1\00", section ".llvmcmd", align 1
 @llvm.compiler.used = appending global [2 x ptr] [ptr @llvm.embedded.module, ptr @llvm.cmdline], section "llvm.metadata"
 
+; CHECK-DAG: OpName [[FOO:%[0-9]+]] "foo"
+; CHECK-DAG: OpName [[MODULE:%[0-9]+]] "llvm.embedded.module"
+; CHECK-DAG: [[INT8:%[0-9]+]] = OpTypeInt 8 0
+; CHECK-DAG: [[INT32:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[CONST_1_32:%[0-9]+]] = OpConstant [[INT32]] 1
+; CHECK-DAG: [[ARRAY_INT8x1:%[0-9]+]] = OpTypeArray [[INT8]] [[CONST_1_32]]
+; CHECK-DAG: [[POINTER:%[0-9]+]] = OpTypePointer Function [[ARRAY_INT8x1]]
+; CHECK-DAG: [[EMBEDDED_MODULE_INIT:%[0-9]+]] = OpConstantNull [[ARRAY_INT8x1]]
+; CHECK: [[FOO]] = OpFunction {{.*}} None {{.*}}
+; CHECK-DAG: {{%[0-9]+}} = OpVariable [[POINTER]] Function [[EMBEDDED_MODULE_INIT]]
+
 define spir_kernel void @foo() {
 entry:
   ret void



More information about the llvm-commits mailing list