Skip to content

Commit d23d8ab

Browse files
authored
[SPIRV][SPIRVPrepareGlobals] Convert llvm.embedded.module from a 0-element array to a 1-element array (#166950)
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 flavored SPIRV, we extend the `llvm.embedded.module` global to a `zeroinitializer [1 x i8]` array. To achieve this, this patch adds a new pass, `SPIRVPrepareGlobals`, that we can use to write global variable's _non-trivial-to-lower-IR_ -> _trivial-to-lower-IR_ mappings. This is a second attempt at #162082, but cleaner. In the translator something similar is done for every 0-element array since KhronosGroup/SPIRV-LLVM-Translator#2743 . But I don't think we want to do this mapping for all cases.
1 parent fe8865c commit d23d8ab

File tree

7 files changed

+131
-0
lines changed

7 files changed

+131
-0
lines changed

llvm/lib/Target/SPIRV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ add_llvm_target(SPIRVCodeGen
4141
SPIRVPreLegalizerCombiner.cpp
4242
SPIRVPostLegalizer.cpp
4343
SPIRVPrepareFunctions.cpp
44+
SPIRVPrepareGlobals.cpp
4445
SPIRVRegisterBankInfo.cpp
4546
SPIRVRegisterInfo.cpp
4647
SPIRVRegularizer.cpp

llvm/lib/Target/SPIRV/SPIRV.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ FunctionPass *createSPIRVPreLegalizerCombiner();
3131
FunctionPass *createSPIRVPreLegalizerPass();
3232
FunctionPass *createSPIRVPostLegalizerPass();
3333
ModulePass *createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM);
34+
ModulePass *createSPIRVPrepareGlobalsPass();
3435
MachineFunctionPass *createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM);
3536
InstructionSelector *
3637
createSPIRVInstructionSelector(const SPIRVTargetMachine &TM,
@@ -51,6 +52,7 @@ void initializeSPIRVLegalizePointerCastPass(PassRegistry &);
5152
void initializeSPIRVRegularizerPass(PassRegistry &);
5253
void initializeSPIRVMergeRegionExitTargetsPass(PassRegistry &);
5354
void initializeSPIRVPrepareFunctionsPass(PassRegistry &);
55+
void initializeSPIRVPrepareGlobalsPass(PassRegistry &);
5456
void initializeSPIRVStripConvergentIntrinsicsPass(PassRegistry &);
5557
void initializeSPIRVLegalizeImplicitBindingPass(PassRegistry &);
5658
} // namespace llvm
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===-- SPIRVPrepareGlobals.cpp - Prepare IR SPIRV globals ------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// The pass transforms IR globals that cannot be trivially mapped to SPIRV
10+
// into something that is trival to lower.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "SPIRV.h"
15+
16+
#include "llvm/IR/Module.h"
17+
18+
using namespace llvm;
19+
20+
namespace {
21+
22+
struct SPIRVPrepareGlobals : public ModulePass {
23+
static char ID;
24+
SPIRVPrepareGlobals() : ModulePass(ID) {}
25+
26+
StringRef getPassName() const override {
27+
return "SPIRV prepare global variables";
28+
}
29+
30+
bool runOnModule(Module &M) override;
31+
};
32+
33+
bool tryExtendLLVMBitcodeMarker(GlobalVariable &Bitcode) {
34+
assert(Bitcode.getName() == "llvm.embedded.module");
35+
36+
ArrayType *AT = cast<ArrayType>(Bitcode.getValueType());
37+
if (AT->getNumElements() != 0)
38+
return false;
39+
40+
ArrayType *AT1 = ArrayType::get(AT->getElementType(), 1);
41+
Constant *OneEltInit = Constant::getNullValue(AT1);
42+
Bitcode.replaceInitializer(OneEltInit);
43+
return true;
44+
}
45+
46+
bool SPIRVPrepareGlobals::runOnModule(Module &M) {
47+
const bool IsAMD = M.getTargetTriple().getVendor() == Triple::AMD;
48+
if (!IsAMD)
49+
return false;
50+
51+
bool Changed = false;
52+
if (GlobalVariable *Bitcode = M.getNamedGlobal("llvm.embedded.module"))
53+
Changed |= tryExtendLLVMBitcodeMarker(*Bitcode);
54+
55+
return Changed;
56+
}
57+
char SPIRVPrepareGlobals::ID = 0;
58+
59+
} // namespace
60+
61+
INITIALIZE_PASS(SPIRVPrepareGlobals, "prepare-globals",
62+
"SPIRV prepare global variables", false, false)
63+
64+
namespace llvm {
65+
ModulePass *createSPIRVPrepareGlobalsPass() {
66+
return new SPIRVPrepareGlobals();
67+
}
68+
} // namespace llvm

llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {
5959
initializeSPIRVEmitIntrinsicsPass(PR);
6060
initializeSPIRVEmitNonSemanticDIPass(PR);
6161
initializeSPIRVPrepareFunctionsPass(PR);
62+
initializeSPIRVPrepareGlobalsPass(PR);
6263
initializeSPIRVStripConvergentIntrinsicsPass(PR);
6364
}
6465

@@ -172,6 +173,7 @@ void SPIRVPassConfig::addIRPasses() {
172173

173174
addPass(createSPIRVRegularizerPass());
174175
addPass(createSPIRVPrepareFunctionsPass(TM));
176+
addPass(createSPIRVPrepareGlobalsPass());
175177
}
176178

177179
void SPIRVPassConfig::addISelPrepare() {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
; Expanding the bitcode marker works only for AMD at the moment.
2+
; RUN: not llc -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o -
3+
; RUN: llc -verify-machineinstrs -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s
4+
; RUN: %if spirv-tools %{ llc -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %}
5+
;
6+
; Verify that we lower the embedded bitcode
7+
8+
@llvm.embedded.module = private addrspace(1) constant [0 x i8] zeroinitializer, section ".llvmbc", align 1
9+
@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"
10+
11+
; CHECK: OpName %[[#LLVM_EMBEDDED_MODULE:]] "llvm.embedded.module"
12+
; CHECK: OpDecorate %[[#LLVM_EMBEDDED_MODULE]] Constant
13+
; CHECK: %[[#UCHAR:]] = OpTypeInt 8 0
14+
; CHECK: %[[#UINT:]] = OpTypeInt 32 0
15+
; CHECK: %[[#ONE:]] = OpConstant %[[#UINT]] 1
16+
; CHECK: %[[#UCHAR_ARR_1:]] = OpTypeArray %[[#UCHAR]] %[[#ONE]]
17+
; CHECK: %[[#UCHAR_ARR_1_PTR:]] = OpTypePointer CrossWorkgroup %[[#UCHAR_ARR_1]]
18+
; CHECK: %[[#CONST_UCHAR_ARR_1:]] = OpConstantNull %[[#UCHAR_ARR_1]]
19+
; CHECK: %[[#LLVM_EMBEDDED_MODULE]] = OpVariable %[[#UCHAR_ARR_1_PTR]] CrossWorkgroup %[[#CONST_UCHAR_ARR_1]]
20+
21+
define spir_kernel void @foo() {
22+
entry:
23+
ret void
24+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
; RUN: llc -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
3+
; RUN: llc -verify-machineinstrs -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s
4+
; RUN: %if spirv-tools %{ llc -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %}
5+
;
6+
; Verify that we can lower the embedded module and cmdline.
7+
8+
@llvm.embedded.module = private addrspace(1) constant [4 x i8] c"BC\C0\DE", section ".llvmbc", align 1
9+
@llvm.cmdline = private addrspace(1) constant [5 x i8] c"-cc1\00", section ".llvmcmd", align 1
10+
@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"
11+
12+
; CHECK: OpName %[[#LLVM_EMBEDDED_MODULE:]] "llvm.embedded.module"
13+
; CHECK: OpName %[[#LLVM_CMDLINE:]] "llvm.cmdline"
14+
; CHECK: OpDecorate %[[#LLVM_EMBEDDED_MODULE]] Constant
15+
; CHECK: OpDecorate %[[#LLVM_CMDLINE]] Constant
16+
; CHECK: %[[#UCHAR:]] = OpTypeInt 8 0
17+
; CHECK: %[[#UINT:]] = OpTypeInt 32 0
18+
; CHECK: %[[#FIVE:]] = OpConstant %[[#UINT]] 5
19+
; CHECK: %[[#UCHAR_ARR_5:]] = OpTypeArray %[[#UCHAR]] %[[#FIVE]]
20+
; CHECK: %[[#FOUR:]] = OpConstant %[[#UINT]] 4
21+
; CHECK: %[[#UCHAR_ARR_4:]] = OpTypeArray %[[#UCHAR]] %[[#FOUR]]
22+
; CHECK: %[[#UCHAR_ARR_5_PTR:]] = OpTypePointer CrossWorkgroup %[[#UCHAR_ARR_5]]
23+
; CHECK: %[[#UCHAR_ARR_4_PTR:]] = OpTypePointer CrossWorkgroup %[[#UCHAR_ARR_4]]
24+
; CHECK: %[[#CONST_UCHAR_ARR_4:]] = OpConstantComposite %[[#UCHAR_ARR_4]]
25+
; CHECK: %[[#LLVM_EMBEDDED_MODULE]] = OpVariable %[[#UCHAR_ARR_4_PTR]] CrossWorkgroup %[[#CONST_UCHAR_ARR_4]]
26+
; CHECK: %[[#CONST_UCHAR_ARR_5:]] = OpConstantComposite %[[#UCHAR_ARR_5]]
27+
; CHECK: %[[#LLVM_CMDLINE]] = OpVariable %[[#UCHAR_ARR_5_PTR]] CrossWorkgroup %[[#CONST_UCHAR_ARR_5]]
28+
29+
define spir_kernel void @foo() {
30+
entry:
31+
ret void
32+
}

llvm/test/CodeGen/SPIRV/llc-pipeline.ll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
; SPIRV-O0-NEXT: Expand reduction intrinsics
3232
; SPIRV-O0-NEXT: SPIR-V Regularizer
3333
; SPIRV-O0-NEXT: SPIRV prepare functions
34+
; SPIRV-O0-NEXT: SPIRV prepare global variables
3435
; SPIRV-O0-NEXT: FunctionPass Manager
3536
; SPIRV-O0-NEXT: Lower invoke and unwind, for unwindless code generators
3637
; SPIRV-O0-NEXT: Remove unreachable blocks from the CFG
@@ -130,6 +131,7 @@
130131
; SPIRV-Opt-NEXT: Expand reduction intrinsics
131132
; SPIRV-Opt-NEXT: SPIR-V Regularizer
132133
; SPIRV-Opt-NEXT: SPIRV prepare functions
134+
; SPIRV-Opt-NEXT: SPIRV prepare global variables
133135
; SPIRV-Opt-NEXT: FunctionPass Manager
134136
; SPIRV-Opt-NEXT: Dominator Tree Construction
135137
; SPIRV-Opt-NEXT: Natural Loop Information

0 commit comments

Comments
 (0)