LLVM 22.0.0git
SPIRVPrepareGlobals.cpp
Go to the documentation of this file.
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#include "SPIRVUtils.h"
16
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/IR/Module.h"
19#include "llvm/Support/Debug.h"
20
21#define DEBUG_TYPE "spirv-prepare-globals"
22
23using namespace llvm;
24
25namespace {
26
27struct SPIRVPrepareGlobals : public ModulePass {
28 static char ID;
29 SPIRVPrepareGlobals() : ModulePass(ID) {}
30
31 StringRef getPassName() const override {
32 return "SPIRV prepare global variables";
33 }
34
35 bool runOnModule(Module &M) override;
36};
37
38bool tryExtendLLVMBitcodeMarker(GlobalVariable &Bitcode) {
39 assert(Bitcode.getName() == "llvm.embedded.module");
40
41 ArrayType *AT = cast<ArrayType>(Bitcode.getValueType());
42 if (AT->getNumElements() != 0)
43 return false;
44
45 ArrayType *AT1 = ArrayType::get(AT->getElementType(), 1);
46 Constant *OneEltInit = Constant::getNullValue(AT1);
47 Bitcode.replaceInitializer(OneEltInit);
48 return true;
49}
50
51// In HIP, dynamic LDS variables are represented using 0-element global arrays
52// in the __shared__ language address-space.
53//
54// extern __shared__ int LDS[];
55//
56// These are not representable in SPIRV directly.
57// To represent them, for AMD, we use an array with UINT32_MAX-elements.
58// These are reverse translated to 0-element arrays.
59bool tryExtendDynamicLDSGlobal(GlobalVariable &GV) {
60 constexpr unsigned WorkgroupAS =
61 storageClassToAddressSpace(SPIRV::StorageClass::Workgroup);
62 const bool IsWorkgroupExternal =
63 GV.hasExternalLinkage() && GV.getAddressSpace() == WorkgroupAS;
64 if (!IsWorkgroupExternal)
65 return false;
66
68 if (!AT || AT->getNumElements() != 0)
69 return false;
70
71 constexpr auto UInt32Max = std::numeric_limits<uint32_t>::max();
72 ArrayType *NewAT = ArrayType::get(AT->getElementType(), UInt32Max);
73 GlobalVariable *NewGV = new GlobalVariable(
74 *GV.getParent(), NewAT, GV.isConstant(), GV.getLinkage(), nullptr, "",
75 &GV, GV.getThreadLocalMode(), WorkgroupAS, GV.isExternallyInitialized());
76 NewGV->takeName(&GV);
77 GV.replaceAllUsesWith(NewGV);
78 GV.eraseFromParent();
79
80 return true;
81}
82
83// The backend does not support GlobalAlias. Replace aliases with their aliasees
84// when possible and remove them from the module.
85bool tryReplaceAliasWithAliasee(GlobalAlias &GA) {
86 // According to the lang ref, aliases cannot be replaced if either the alias
87 // or the aliasee are interposable. We only replace in the case that both
88 // are not interposable.
89 if (GA.isInterposable()) {
90 LLVM_DEBUG(dbgs() << "Skipping interposable alias: " << GA.getName()
91 << "\n");
92 return false;
93 }
94
95 auto *AO = dyn_cast<GlobalObject>(GA.getAliasee());
96 if (!AO) {
97 LLVM_DEBUG(dbgs() << "Skipping alias whose aliasee is not a GlobalObject: "
98 << GA.getName() << "\n");
99 return false;
100 }
101
102 if (AO->isInterposable()) {
103 LLVM_DEBUG(dbgs() << "Skipping interposable aliasee: " << AO->getName()
104 << "\n");
105 return false;
106 }
107
108 LLVM_DEBUG(dbgs() << "Replacing alias " << GA.getName()
109 << " with aliasee: " << AO->getName() << "\n");
110
111 GA.replaceAllUsesWith(AO);
112 if (GA.isDiscardableIfUnused()) {
113 GA.eraseFromParent();
114 }
115
116 return true;
117}
118
119bool SPIRVPrepareGlobals::runOnModule(Module &M) {
120 bool Changed = false;
121
122 for (GlobalAlias &GA : make_early_inc_range(M.aliases())) {
123 Changed |= tryReplaceAliasWithAliasee(GA);
124 }
125
126 const bool IsAMD = M.getTargetTriple().getVendor() == Triple::AMD;
127 if (!IsAMD)
128 return Changed;
129
130 if (GlobalVariable *Bitcode = M.getNamedGlobal("llvm.embedded.module"))
131 Changed |= tryExtendLLVMBitcodeMarker(*Bitcode);
132
133 for (GlobalVariable &GV : make_early_inc_range(M.globals()))
134 Changed |= tryExtendDynamicLDSGlobal(GV);
135
136 return Changed;
137}
138char SPIRVPrepareGlobals::ID = 0;
139
140} // namespace
141
142INITIALIZE_PASS(SPIRVPrepareGlobals, "prepare-globals",
143 "SPIRV prepare global variables", false, false)
144
145namespace llvm {
147 return new SPIRVPrepareGlobals();
148}
149} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
write Write Bitcode
Module.h This file contains the declarations for the Module class.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file contains some templates that are useful if you are working with the STL at all.
#define LLVM_DEBUG(...)
Definition Debug.h:114
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
This is an important base class in LLVM.
Definition Constant.h:43
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition Globals.cpp:628
const Constant * getAliasee() const
Definition GlobalAlias.h:87
bool hasExternalLinkage() const
LinkageTypes getLinkage() const
ThreadLocalMode getThreadLocalMode() const
unsigned getAddressSpace() const
Module * getParent()
Get the module that this global value is contained inside of...
LLVM_ABI bool isInterposable() const
Return true if this global's definition can be substituted with an arbitrary definition at link time ...
Definition Globals.cpp:107
static bool isDiscardableIfUnused(LinkageTypes Linkage)
Whether the definition of this global may be discarded if it is not used in its compilation unit.
Type * getValueType() const
bool isExternallyInitialized() const
bool isConstant() const
If the value is a global constant, its value is immutable throughout the runtime execution of the pro...
LLVM_ABI void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition Globals.cpp:520
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:322
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:403
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:632
constexpr unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
Definition SPIRVUtils.h:244
ModulePass * createSPIRVPrepareGlobalsPass()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559