23#include "llvm/IR/IntrinsicsSPIRV.h"
31class SPIRVLegalizeImplicitBindingImpl {
33 bool runOnModule(
Module &M);
36 void collectBindingInfo(
Module &M);
37 uint32_t getAndReserveFirstUnusedBinding(uint32_t DescSet);
38 bool replaceImplicitBindingCalls(
Module &M);
41 std::vector<BitVector> UsedBindings;
45 bool MayHaveImplicitBindings =
false;
48class SPIRVLegalizeImplicitBindingLegacy :
public ModulePass {
51 SPIRVLegalizeImplicitBindingLegacy() : ModulePass(ID) {}
52 StringRef getPassName()
const override {
53 return "SPIRV Legalize Implicit Binding";
55 bool runOnModule(
Module &M)
override {
56 return SPIRVLegalizeImplicitBindingImpl().runOnModule(M);
63 case Intrinsic::spv_resource_handlefromimplicitbinding:
66 case Intrinsic::spv_resource_counterhandlefromimplicitbinding:
78void SPIRVLegalizeImplicitBindingImpl::collectBindingInfo(
Module &M) {
80 auto addBinding = [&](uint32_t DescSet, uint32_t
Binding) {
81 if (UsedBindings.size() <= DescSet) {
82 UsedBindings.resize(DescSet + 1);
83 UsedBindings[DescSet].resize(64);
86 UsedBindings[DescSet].resize(2 *
Binding + 1);
88 UsedBindings[DescSet].set(
Binding);
91 auto collectBinding = [&](
Function &
F, uint32_t ArgDescSetIdx,
92 uint32_t ArgBindingIdx) {
93 for (User *U :
F.users()) {
95 const uint32_t DescSet =
105 if (!
F.isDeclaration())
108 switch (
F.getIntrinsicID()) {
109 case Intrinsic::spv_resource_handlefrombinding:
110 collectBinding(
F, 0, 1);
112 case Intrinsic::spv_resource_counterhandlefrombinding:
113 collectBinding(
F, 1, 2);
115 case Intrinsic::spv_resource_handlefromimplicitbinding:
116 case Intrinsic::spv_resource_counterhandlefromimplicitbinding:
117 MayHaveImplicitBindings =
true;
125uint32_t SPIRVLegalizeImplicitBindingImpl::getAndReserveFirstUnusedBinding(
127 if (UsedBindings.size() <= DescSet) {
128 UsedBindings.resize(DescSet + 1);
129 UsedBindings[DescSet].resize(64);
132 int NewBinding = UsedBindings[DescSet].find_first_unset();
133 if (NewBinding == -1) {
134 NewBinding = UsedBindings[DescSet].size();
135 UsedBindings[DescSet].resize(2 * NewBinding + 1);
138 UsedBindings[DescSet].set(NewBinding);
143static void replaceWithHandleFromBinding(
Module &M, CallInst *CI,
144 uint32_t DescSet, uint32_t
Binding,
148 Intrinsic::spv_resource_handlefromimplicitbinding &&
149 "unexpected implicit binding intrinsic");
151 Value *DescSetOp = Builder.getInt32(DescSet);
154 &M, Intrinsic::spv_resource_handlefrombinding, {CI->
getType()});
155 CallInst *NewCI = Builder.CreateCall(
156 NewFunc, {DescSetOp, BindingOp, IndexOp, RangeOp,
Name});
164static void replaceWithCounterHandleFromBinding(
Module &M, CallInst *CI,
168 Intrinsic::spv_resource_counterhandlefromimplicitbinding &&
169 "unexpected implicit binding intrinsic");
171 Value *DescSetOp = Builder.getInt32(DescSet);
176 &M, Intrinsic::spv_resource_counterhandlefrombinding, OverloadTys);
178 Builder.CreateCall(NewFunc, {MainHandle, DescSetOp, BindingOp});
184bool SPIRVLegalizeImplicitBindingImpl::replaceImplicitBindingCalls(
Module &M) {
189 if (!
F.isDeclaration())
193 if (
F.getIntrinsicID() == Intrinsic::spv_resource_handlefromimplicitbinding)
195 else if (
F.getIntrinsicID() ==
196 Intrinsic::spv_resource_counterhandlefromimplicitbinding)
201 for (User *U :
F.users()) {
218 uint32_t LastOrderId = -1;
219 uint32_t LastBinding = -1;
220 uint32_t LastDescSet = -1;
221 for (
auto &[OrderId, CI] : IBCalls) {
223 uint32_t DescSet = getDescSet(CI);
224 if (OrderId == LastOrderId) {
225 if (DescSet != LastDescSet)
227 "have the same descriptor set");
230 Binding = getAndReserveFirstUnusedBinding(DescSet);
235 Intrinsic::spv_resource_handlefromimplicitbinding)
236 replaceWithHandleFromBinding(M, CI, DescSet,
Binding,
240 replaceWithCounterHandleFromBinding(M, CI, DescSet,
Binding);
243 LastOrderId = OrderId;
245 LastDescSet = DescSet;
250bool SPIRVLegalizeImplicitBindingImpl::runOnModule(
Module &M) {
251 collectBindingInfo(M);
254 if (MayHaveImplicitBindings)
255 Changed |= replaceImplicitBindingCalls(M);
263 return SPIRVLegalizeImplicitBindingImpl().runOnModule(M)
268char SPIRVLegalizeImplicitBindingLegacy::ID = 0;
271 "legalize-spirv-implicit-binding",
272 "Legalize SPIR-V implicit bindings",
false,
false)
275 return new SPIRVLegalizeImplicitBindingLegacy();
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 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.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
void setCallingConv(CallingConv::ID CC)
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)
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.
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.
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.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
ModulePass * createSPIRVLegalizeImplicitBindingPass()