From e43cefcf8641d0fbb6fd33948e1cd2f7748d95de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Thu, 6 Nov 2025 15:48:22 +0100 Subject: [PATCH 1/5] [SPIRV][SPIRVPrepareGlobals] Add pass skeleton Add a pass where we can do IR->IR preprocessing of global-variables. --- llvm/lib/Target/SPIRV/CMakeLists.txt | 1 + llvm/lib/Target/SPIRV/SPIRV.h | 2 + llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp | 43 +++++++++++++++++++ llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp | 2 + llvm/test/CodeGen/SPIRV/llc-pipeline.ll | 2 + 5 files changed, 50 insertions(+) create mode 100644 llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp diff --git a/llvm/lib/Target/SPIRV/CMakeLists.txt b/llvm/lib/Target/SPIRV/CMakeLists.txt index eab7b213756b3..79b76165cd57a 100644 --- a/llvm/lib/Target/SPIRV/CMakeLists.txt +++ b/llvm/lib/Target/SPIRV/CMakeLists.txt @@ -41,6 +41,7 @@ add_llvm_target(SPIRVCodeGen SPIRVPreLegalizerCombiner.cpp SPIRVPostLegalizer.cpp SPIRVPrepareFunctions.cpp + SPIRVPrepareGlobals.cpp SPIRVRegisterBankInfo.cpp SPIRVRegisterInfo.cpp SPIRVRegularizer.cpp diff --git a/llvm/lib/Target/SPIRV/SPIRV.h b/llvm/lib/Target/SPIRV/SPIRV.h index efd49b930aa34..fa85ee781c249 100644 --- a/llvm/lib/Target/SPIRV/SPIRV.h +++ b/llvm/lib/Target/SPIRV/SPIRV.h @@ -31,6 +31,7 @@ FunctionPass *createSPIRVPreLegalizerCombiner(); FunctionPass *createSPIRVPreLegalizerPass(); FunctionPass *createSPIRVPostLegalizerPass(); ModulePass *createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM); +ModulePass *createSPIRVPrepareGlobalsPass(); MachineFunctionPass *createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM); InstructionSelector * createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, @@ -51,6 +52,7 @@ void initializeSPIRVLegalizePointerCastPass(PassRegistry &); void initializeSPIRVRegularizerPass(PassRegistry &); void initializeSPIRVMergeRegionExitTargetsPass(PassRegistry &); void initializeSPIRVPrepareFunctionsPass(PassRegistry &); +void initializeSPIRVPrepareGlobalsPass(PassRegistry &); void initializeSPIRVStripConvergentIntrinsicsPass(PassRegistry &); void initializeSPIRVLegalizeImplicitBindingPass(PassRegistry &); } // namespace llvm diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp new file mode 100644 index 0000000000000..46c8a6f2c3a54 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp @@ -0,0 +1,43 @@ +//===-- SPIRVPrepareGlobals.cpp - Prepare IR SPIRV globals ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// The pass transforms IR globals that cannot be trivially mapped to SPIRV +// into something that is trival to lower. +// +//===----------------------------------------------------------------------===// + +#include "SPIRV.h" + +using namespace llvm; + +namespace { + +struct SPIRVPrepareGlobals : public ModulePass { + static char ID; + SPIRVPrepareGlobals() : ModulePass(ID) {} + + StringRef getPassName() const override { + return "SPIRV prepare global variables"; + } + + bool runOnModule(Module &M) override; +}; + +bool SPIRVPrepareGlobals::runOnModule(Module &M) { return false; } +char SPIRVPrepareGlobals::ID = 0; + +} // namespace + +INITIALIZE_PASS(SPIRVPrepareGlobals, "prepare-globals", + "SPIRV prepare global variables", false, false) + +namespace llvm { +ModulePass *createSPIRVPrepareGlobalsPass() { + return new SPIRVPrepareGlobals(); +} +} // namespace llvm diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp index 2951a4bc695e2..10bbca225b20a 100644 --- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp @@ -59,6 +59,7 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() { initializeSPIRVEmitIntrinsicsPass(PR); initializeSPIRVEmitNonSemanticDIPass(PR); initializeSPIRVPrepareFunctionsPass(PR); + initializeSPIRVPrepareGlobalsPass(PR); initializeSPIRVStripConvergentIntrinsicsPass(PR); } @@ -172,6 +173,7 @@ void SPIRVPassConfig::addIRPasses() { addPass(createSPIRVRegularizerPass()); addPass(createSPIRVPrepareFunctionsPass(TM)); + addPass(createSPIRVPrepareGlobalsPass()); } void SPIRVPassConfig::addISelPrepare() { diff --git a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll index 3fff2a8a24a73..6db375445e4a3 100644 --- a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll +++ b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll @@ -31,6 +31,7 @@ ; SPIRV-O0-NEXT: Expand reduction intrinsics ; SPIRV-O0-NEXT: SPIR-V Regularizer ; SPIRV-O0-NEXT: SPIRV prepare functions +; SPIRV-O0-NEXT: SPIRV prepare global variables ; SPIRV-O0-NEXT: FunctionPass Manager ; SPIRV-O0-NEXT: Lower invoke and unwind, for unwindless code generators ; SPIRV-O0-NEXT: Remove unreachable blocks from the CFG @@ -130,6 +131,7 @@ ; SPIRV-Opt-NEXT: Expand reduction intrinsics ; SPIRV-Opt-NEXT: SPIR-V Regularizer ; SPIRV-Opt-NEXT: SPIRV prepare functions +; SPIRV-Opt-NEXT: SPIRV prepare global variables ; SPIRV-Opt-NEXT: FunctionPass Manager ; SPIRV-Opt-NEXT: Dominator Tree Construction ; SPIRV-Opt-NEXT: Natural Loop Information From eb7f3404fa31441460e97833e12014508be9d936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Fri, 7 Nov 2025 13:55:31 +0100 Subject: [PATCH 2/5] Pre-commit test: [SPIRV][SPIRVPrepareGlobals] tryExtendLLVMBitcodeMarker --- .../CodeGen/SPIRV/fembed-bitcode-marker.ll | 22 +++++++++++++ llvm/test/CodeGen/SPIRV/fembed-bitcode.ll | 32 +++++++++++++++++++ 2 files changed, 54 insertions(+) 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.ll b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll new file mode 100644 index 0000000000000..863736ef84d87 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll @@ -0,0 +1,22 @@ +; RUN: not llc -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - +; RUN: not llc -verify-machineinstrs -mtriple=spirv64-amd-amdhsa %s -o - +; +; Verify that we lower the embedded bitcode + +@llvm.embedded.module = private addrspace(1) constant [0 x i8] zeroinitializer, section ".llvmbc", align 1 +@llvm.compiler.used = appending addrspace(1) global [1 x ptr addrspace(4)] [ptr addrspace(4) addrspacecast (ptr addrspace(1) @llvm.embedded.module to ptr addrspace(4))], section "llvm.metadata" + +; CHECK: OpName %[[#LLVM_EMBEDDED_MODULE:]] "llvm.embedded.module" +; CHECK: OpDecorate %[[#LLVM_EMBEDDED_MODULE]] Constant +; CHECK: %[[#UCHAR:]] = OpTypeInt 8 0 +; CHECK: %[[#UINT:]] = OpTypeInt 32 0 +; CHECK: %[[#ONE:]] = OpConstant %[[#UINT]] 1 +; CHECK: %[[#UCHAR_ARR_1:]] = OpTypeArray %[[#UCHAR]] %[[#ONE]] +; CHECK: %[[#UCHAR_ARR_1_PTR:]] = OpTypePointer CrossWorkgroup %[[#UCHAR_ARR_1]] +; CHECK: %[[#CONST_UCHAR_ARR_1:]] = OpConstantNull %[[#UCHAR_ARR_1]] +; CHECK: %[[#LLVM_EMBEDDED_MODULE]] = OpVariable %[[#UCHAR_ARR_1_PTR]] CrossWorkgroup %[[#CONST_UCHAR_ARR_1]] + +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..1e7106e0674c5 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/fembed-bitcode.ll @@ -0,0 +1,32 @@ +; RUN: llc -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %} +; RUN: llc -verify-machineinstrs -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %} +; +; Verify that we can lower the embeded module and cmdline + +@llvm.embedded.module = private addrspace(1) constant [4 x i8] c"BC\C0\DE", section ".llvmbc", align 1 +@llvm.cmdline = private addrspace(1) constant [5 x i8] c"-cc1\00", section ".llvmcmd", align 1 +@llvm.compiler.used = appending addrspace(1) global [2 x ptr addrspace(4)] [ptr addrspace(4) addrspacecast (ptr addrspace(1) @llvm.embedded.module to ptr addrspace(4)), ptr addrspace(4) addrspacecast (ptr addrspace(1) @llvm.cmdline to ptr addrspace(4))], section "llvm.metadata" + +; CHECK: OpName %[[#LLVM_EMBEDDED_MODULE:]] "llvm.embedded.module" +; CHECK: OpName %[[#LLVM_CMDLINE:]] "llvm.cmdline" +; CHECK: OpDecorate %[[#LLVM_EMBEDDED_MODULE]] Constant +; CHECK: OpDecorate %[[#LLVM_CMDLINE]] Constant +; CHECK: %[[#UCHAR:]] = OpTypeInt 8 0 +; CHECK: %[[#UINT:]] = OpTypeInt 32 0 +; CHECK: %[[#FIVE:]] = OpConstant %[[#UINT]] 5 +; CHECK: %[[#UCHAR_ARR_5:]] = OpTypeArray %[[#UCHAR]] %[[#FIVE]] +; CHECK: %[[#FOUR:]] = OpConstant %[[#UINT]] 4 +; CHECK: %[[#UCHAR_ARR_4:]] = OpTypeArray %[[#UCHAR]] %[[#FOUR]] +; CHECK: %[[#UCHAR_ARR_5_PTR:]] = OpTypePointer CrossWorkgroup %[[#UCHAR_ARR_5]] +; CHECK: %[[#UCHAR_ARR_4_PTR:]] = OpTypePointer CrossWorkgroup %[[#UCHAR_ARR_4]] +; CHECK: %[[#CONST_UCHAR_ARR_4:]] = OpConstantComposite %[[#UCHAR_ARR_4]] +; CHECK: %[[#LLVM_EMBEDDED_MODULE]] = OpVariable %[[#UCHAR_ARR_4_PTR]] CrossWorkgroup %[[#CONST_UCHAR_ARR_4]] +; CHECK: %[[#CONST_UCHAR_ARR_5:]] = OpConstantComposite %[[#UCHAR_ARR_5]] +; CHECK: %[[#LLVM_CMDLINE]] = OpVariable %[[#UCHAR_ARR_5_PTR]] CrossWorkgroup %[[#CONST_UCHAR_ARR_5]] + +define spir_kernel void @foo() { +entry: + ret void +} From 5815524bd328eab02e806712ebbc8fdd087c2063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Thu, 6 Nov 2025 17:14:10 +0100 Subject: [PATCH 3/5] [SPIRV][SPIRVPrepareGlobals] Convert llvm.embedded.module from a 0-element array to a 1-element array When compiling with -fembed-bitcode-marker, Clang inserts a placeholder for the bitcode. This placeholder is a [0 x i8] array, which we cannot represent in SPIRV. For AMD flavoured SPIRV, we extend the llvm.embedded.module global to a zeroinitialized 1-element array. --- llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp | 27 ++++++++++++++++++- .../CodeGen/SPIRV/fembed-bitcode-marker.ll | 4 ++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp index 46c8a6f2c3a54..c44c53129f1e0 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPrepareGlobals.cpp @@ -13,6 +13,8 @@ #include "SPIRV.h" +#include "llvm/IR/Module.h" + using namespace llvm; namespace { @@ -28,7 +30,30 @@ struct SPIRVPrepareGlobals : public ModulePass { bool runOnModule(Module &M) override; }; -bool SPIRVPrepareGlobals::runOnModule(Module &M) { return false; } +bool tryExtendLLVMBitcodeMarker(GlobalVariable &Bitcode) { + assert(Bitcode.getName() == "llvm.embedded.module"); + + ArrayType *AT = cast(Bitcode.getValueType()); + if (AT->getNumElements() != 0) + return false; + + ArrayType *AT1 = ArrayType::get(AT->getElementType(), 1); + Constant *OneEltInit = Constant::getNullValue(AT1); + Bitcode.replaceInitializer(OneEltInit); + return true; +} + +bool SPIRVPrepareGlobals::runOnModule(Module &M) { + const bool IsAMD = M.getTargetTriple().getVendor() == Triple::AMD; + if (!IsAMD) + return false; + + bool Changed = false; + if (GlobalVariable *Bitcode = M.getNamedGlobal("llvm.embedded.module")) + Changed |= tryExtendLLVMBitcodeMarker(*Bitcode); + + return Changed; +} char SPIRVPrepareGlobals::ID = 0; } // namespace diff --git a/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll index 863736ef84d87..72caa68b52930 100644 --- a/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll +++ b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll @@ -1,5 +1,7 @@ +; Expanding the bitcode marker works only for AMD at the moment ; RUN: not llc -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - -; RUN: not llc -verify-machineinstrs -mtriple=spirv64-amd-amdhsa %s -o - +; RUN: llc -verify-machineinstrs -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %} ; ; Verify that we lower the embedded bitcode From 4d9159adfbc0b3b4ab3f96809063fc6686f4b665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Wed, 12 Nov 2025 09:16:50 +0100 Subject: [PATCH 4/5] Add missing . to comment Co-authored-by: Marcos Maronas --- llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll index 72caa68b52930..4ffdb9b7f3c7a 100644 --- a/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll +++ b/llvm/test/CodeGen/SPIRV/fembed-bitcode-marker.ll @@ -1,4 +1,4 @@ -; Expanding the bitcode marker works only for AMD at the moment +; Expanding the bitcode marker works only for AMD at the moment. ; RUN: not llc -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - ; RUN: llc -verify-machineinstrs -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s ; RUN: %if spirv-tools %{ llc -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %} From 7cb1fc5836201a43c37290ef25472de01c8ab349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= Date: Wed, 12 Nov 2025 09:17:28 +0100 Subject: [PATCH 5/5] Add missing . to comment and embeded->embedded Thanks ! Co-authored-by: Marcos Maronas --- llvm/test/CodeGen/SPIRV/fembed-bitcode.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/CodeGen/SPIRV/fembed-bitcode.ll b/llvm/test/CodeGen/SPIRV/fembed-bitcode.ll index 1e7106e0674c5..a75b44925a1ea 100644 --- a/llvm/test/CodeGen/SPIRV/fembed-bitcode.ll +++ b/llvm/test/CodeGen/SPIRV/fembed-bitcode.ll @@ -3,7 +3,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s ; RUN: %if spirv-tools %{ llc -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %} ; -; Verify that we can lower the embeded module and cmdline +; Verify that we can lower the embedded module and cmdline. @llvm.embedded.module = private addrspace(1) constant [4 x i8] c"BC\C0\DE", section ".llvmbc", align 1 @llvm.cmdline = private addrspace(1) constant [5 x i8] c"-cc1\00", section ".llvmcmd", align 1