27#include "llvm/IR/IntrinsicsSPIRV.h"
36class SPIRVLegalizeResourceBindingImpl {
38 bool runOnModule(
Module &M);
41 void collectBindingInfo(
Module &M);
42 uint32_t getAndReserveFirstUnusedBinding(uint32_t DescSet);
43 bool replaceImplicitBindingCalls(
Module &M);
44 bool replaceHeapBindingCalls(
Module &M);
47 std::vector<BitVector> UsedBindings;
52 bool MayHaveImplicitBindings =
false;
53 bool MayHaveHeapBindings =
false;
56class SPIRVLegalizeResourceBindingLegacy :
public ModulePass {
59 SPIRVLegalizeResourceBindingLegacy() : ModulePass(ID) {}
60 StringRef getPassName()
const override {
61 return "SPIRV Legalize Resource Binding";
63 bool runOnModule(
Module &M)
override {
64 return SPIRVLegalizeResourceBindingImpl().runOnModule(M);
71 case Intrinsic::spv_resource_handlefromimplicitbinding:
74 case Intrinsic::spv_resource_counterhandlefromimplicitbinding:
86void SPIRVLegalizeResourceBindingImpl::collectBindingInfo(
Module &M) {
88 auto addBinding = [&](uint32_t DescSet, uint32_t
Binding) {
89 if (UsedBindings.size() <= DescSet) {
90 UsedBindings.resize(DescSet + 1);
91 UsedBindings[DescSet].resize(64);
94 UsedBindings[DescSet].resize(2 *
Binding + 1);
96 UsedBindings[DescSet].set(
Binding);
99 auto collectBinding = [&](
Function &
F, uint32_t ArgDescSetIdx,
100 uint32_t ArgBindingIdx) {
101 for (User *U :
F.users()) {
103 const uint32_t DescSet =
113 if (!
F.isDeclaration())
116 switch (
F.getIntrinsicID()) {
117 case Intrinsic::spv_resource_handlefrombinding:
118 collectBinding(
F, 0, 1);
120 case Intrinsic::spv_resource_counterhandlefrombinding:
121 collectBinding(
F, 1, 2);
123 case Intrinsic::spv_resource_handlefromimplicitbinding:
124 case Intrinsic::spv_resource_counterhandlefromimplicitbinding:
125 MayHaveImplicitBindings =
true;
127 case Intrinsic::spv_resource_handlefromheap:
128 case Intrinsic::spv_resource_counterhandlefromheap:
129 MayHaveHeapBindings =
true;
137uint32_t SPIRVLegalizeResourceBindingImpl::getAndReserveFirstUnusedBinding(
139 if (UsedBindings.size() <= DescSet) {
140 UsedBindings.resize(DescSet + 1);
141 UsedBindings[DescSet].resize(64);
144 int NewBinding = UsedBindings[DescSet].find_first_unset();
145 if (NewBinding == -1) {
146 NewBinding = UsedBindings[DescSet].size();
147 UsedBindings[DescSet].resize(2 * NewBinding + 1);
150 UsedBindings[DescSet].set(NewBinding);
155static void replaceWithHandleFromBinding(
Module &M, CallInst *CI,
156 uint32_t DescSet, uint32_t
Binding,
160 Intrinsic::spv_resource_handlefromimplicitbinding ||
161 CI->
getIntrinsicID() == Intrinsic::spv_resource_handlefromheap) &&
162 "unexpected binding intrinsic");
164 Value *DescSetOp = Builder.getInt32(DescSet);
167 &M, Intrinsic::spv_resource_handlefrombinding, {CI->
getType()});
168 CallInst *NewCI = Builder.CreateCall(
169 NewFunc, {DescSetOp, BindingOp, RangeOp, IndexOp,
Name});
177static void replaceWithCounterHandleFromBinding(
Module &M, CallInst *CI,
182 Intrinsic::spv_resource_counterhandlefromimplicitbinding ||
183 CI->
getIntrinsicID() == Intrinsic::spv_resource_counterhandlefromheap) &&
184 "unexpected binding intrinsic");
186 Value *DescSetOp = Builder.getInt32(DescSet);
191 &M, Intrinsic::spv_resource_counterhandlefrombinding, OverloadTys);
193 Builder.CreateCall(NewFunc, {MainHandle, DescSetOp, BindingOp});
199bool SPIRVLegalizeResourceBindingImpl::replaceImplicitBindingCalls(
Module &M) {
204 if (!
F.isDeclaration())
208 if (
F.getIntrinsicID() == Intrinsic::spv_resource_handlefromimplicitbinding)
210 else if (
F.getIntrinsicID() ==
211 Intrinsic::spv_resource_counterhandlefromimplicitbinding)
216 for (User *U :
F.users()) {
233 uint32_t LastOrderId = -1;
234 uint32_t LastBinding = -1;
235 uint32_t LastDescSet = -1;
236 for (
auto &[OrderId, CI] : IBCalls) {
238 uint32_t DescSet = getDescSet(CI);
239 if (OrderId == LastOrderId) {
240 if (DescSet != LastDescSet)
242 "have the same descriptor set");
245 Binding = getAndReserveFirstUnusedBinding(DescSet);
250 Intrinsic::spv_resource_handlefromimplicitbinding)
251 replaceWithHandleFromBinding(M, CI, DescSet,
Binding,
255 replaceWithCounterHandleFromBinding(M, CI, DescSet,
Binding);
258 LastOrderId = OrderId;
260 LastDescSet = DescSet;
265bool moduleContainsConstantString(
Module &M, StringRef Str) {
266 for (GlobalVariable &GV :
M.globals()) {
267 if (!GV.hasInitializer())
269 if (ConstantDataArray *CDA =
271 if (CDA->isString() && CDA->getAsCString() == Str)
280GlobalVariable *createHeapNameString(
Module &M, StringRef Name) {
281 SmallString<32> GlobalStringName(Name);
282 uint32_t HeapNameLen =
Name.size();
284 for (
unsigned Suffix = 1;; ++Suffix) {
285 GlobalStringName.append(
".str");
286 if (!
M.getNamedValue(GlobalStringName)) {
289 HeapName = GlobalStringName.
substr(0, HeapNameLen);
290 if (!moduleContainsConstantString(M, HeapName))
293 GlobalStringName.resize(
Name.size());
294 raw_svector_ostream(GlobalStringName) <<
'.' << Suffix;
295 HeapNameLen = GlobalStringName.size();
298 GlobalVariable *HeapNameGV =
new GlobalVariable(
300 Init, GlobalStringName,
nullptr,
301 GlobalVariable::NotThreadLocal, 0);
327bool SPIRVLegalizeResourceBindingImpl::replaceHeapBindingCalls(
Module &M) {
336 if (!
F.isDeclaration() ||
F.user_empty())
339 if (
F.getIntrinsicID() == Intrinsic::spv_resource_handlefromheap) {
341 if (ResType->
getName() ==
"spirv.Sampler")
345 }
else if (
F.getIntrinsicID() ==
346 Intrinsic::spv_resource_counterhandlefromheap) {
357 constexpr uint32_t DescSet = 0;
361 if (!CbvSrvUavs.
empty()) {
365 uint32_t
Binding = getAndReserveFirstUnusedBinding(DescSet);
366 SmallDenseMap<TargetExtType *, GlobalVariable *> ResourceDescriptorHeaps;
369 GlobalVariable *HeapNameGV =
nullptr;
370 auto It = ResourceDescriptorHeaps.
find(ResType);
371 if (It == ResourceDescriptorHeaps.
end()) {
372 HeapNameGV = createHeapNameString(M,
"ResourceDescriptorHeap");
373 [[maybe_unused]]
auto [InsertedIt,
Inserted] =
374 ResourceDescriptorHeaps.
try_emplace(ResType, HeapNameGV);
375 assert(Inserted &&
"resource heap name already exists");
377 HeapNameGV = It->second;
383 replaceWithHandleFromBinding(M, CI, DescSet,
Binding, Zero, HeapIdx,
388 F->eraseFromParent();
392 if (!Samplers.
empty()) {
393 uint32_t
Binding = getAndReserveFirstUnusedBinding(DescSet);
396 [[maybe_unused]] TargetExtType *SamplerHandleType =
399 GlobalVariable *HeapNameGV =
400 createHeapNameString(M,
"SamplerDescriptorHeap");
402 assert(
F->getReturnType() == SamplerHandleType &&
403 "sampler handle type mismatch");
407 replaceWithHandleFromBinding(M, CI, DescSet,
Binding, Zero, HeapIdx,
412 F->eraseFromParent();
417 uint32_t
Binding = getAndReserveFirstUnusedBinding(DescSet);
418 [[maybe_unused]]
Type *CounterHandleTy =
Counters.front()->getReturnType();
422 assert(
F->getReturnType() == CounterHandleTy &&
423 "counter handle type mismatch");
426 replaceWithCounterHandleFromBinding(M, CI, DescSet,
Binding);
430 F->eraseFromParent();
437bool SPIRVLegalizeResourceBindingImpl::runOnModule(
Module &M) {
438 collectBindingInfo(M);
441 if (MayHaveImplicitBindings)
442 Changed |= replaceImplicitBindingCalls(M);
443 if (MayHaveHeapBindings)
444 Changed |= replaceHeapBindingCalls(M);
452 return SPIRVLegalizeResourceBindingImpl().runOnModule(M)
457char SPIRVLegalizeResourceBindingLegacy::ID = 0;
460 "legalize-spirv-resource-binding",
461 "Legalize SPIR-V resource bindings",
false,
false)
464 return new SPIRVLegalizeResourceBindingLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements the BitVector class.
DXIL Resource Implicit Binding
Module.h This file contains the declarations for the Module class.
Machine Check Debug Module
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file defines the SmallString class.
This file defines the SmallVector class.
void setCallingConv(CallingConv::ID CC)
CallingConv::ID getCallingConv() const
Value * getArgOperand(unsigned i) const
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI Constant * getString(LLVMContext &Context, StringRef Initializer, bool AddNull=true, bool ByteString=false)
This method constructs a CDS and initializes it with a text string.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
void setCallingConv(CallingConv::ID CC)
void setUnnamedAddr(UnnamedAddr Val)
@ PrivateLinkage
Like Internal, but omit from symbol table.
void setAlignment(Align Align)
Sets the alignment attribute of the GlobalVariable.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
reference emplace_back(ArgTypes &&... Args)
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
StringRef getName() const
Return the name for this target extension type.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
ModulePass * createSPIRVLegalizeResourceBindingPass()
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.