22#include "llvm/IR/IntrinsicsSPIRV.h"
31class SPIRVLegalizeImplicitBinding :
public ModulePass {
34 SPIRVLegalizeImplicitBinding() : ModulePass(ID) {}
36 bool runOnModule(
Module &M)
override;
39 void collectBindingInfo(
Module &M);
40 uint32_t getAndReserveFirstUnusedBinding(uint32_t DescSet);
41 void replaceImplicitBindingCalls(
Module &M);
42 void verifyUniqueOrderIdPerResource(SmallVectorImpl<CallInst *> &Calls);
45 std::vector<BitVector> UsedBindings;
50struct BindingInfoCollector :
public InstVisitor<BindingInfoCollector> {
51 std::vector<BitVector> &UsedBindings;
54 BindingInfoCollector(std::vector<BitVector> &UsedBindings,
56 : UsedBindings(UsedBindings), ImplicitBindingCalls(ImplicitBindingCalls) {
59 void visitCallInst(CallInst &CI) {
60 if (CI.
getIntrinsicID() == Intrinsic::spv_resource_handlefrombinding) {
61 const uint32_t DescSet =
66 if (UsedBindings.size() <= DescSet) {
67 UsedBindings.resize(DescSet + 1);
68 UsedBindings[DescSet].resize(64);
71 UsedBindings[DescSet].resize(2 *
Binding + 1);
73 UsedBindings[DescSet].set(
Binding);
75 Intrinsic::spv_resource_handlefromimplicitbinding) {
76 ImplicitBindingCalls.push_back(&CI);
81void SPIRVLegalizeImplicitBinding::collectBindingInfo(
Module &M) {
82 BindingInfoCollector InfoCollector(UsedBindings, ImplicitBindingCalls);
83 InfoCollector.visit(M);
87 ImplicitBindingCalls.
begin(), ImplicitBindingCalls.
end(),
88 [](
const CallInst *
A,
const CallInst *
B) {
89 const uint32_t OrderIdArgIdx = 0;
90 const uint32_t OrderA =
91 cast<ConstantInt>(A->getArgOperand(OrderIdArgIdx))->getZExtValue();
92 const uint32_t OrderB =
93 cast<ConstantInt>(B->getArgOperand(OrderIdArgIdx))->getZExtValue();
94 return OrderA < OrderB;
98void SPIRVLegalizeImplicitBinding::verifyUniqueOrderIdPerResource(
99 SmallVectorImpl<CallInst *> &Calls) {
101 for (uint32_t i = 1; i < Calls.
size(); ++i) {
102 const uint32_t OrderIdArgIdx = 0;
103 const uint32_t DescSetArgIdx = 1;
104 const uint32_t OrderA =
107 const uint32_t OrderB =
110 if (OrderA == OrderB) {
111 const uint32_t DescSetA =
114 const uint32_t DescSetB =
117 if (DescSetA != DescSetB) {
119 "have the same descriptor set");
125uint32_t SPIRVLegalizeImplicitBinding::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);
142void SPIRVLegalizeImplicitBinding::replaceImplicitBindingCalls(
Module &M) {
143 uint32_t lastOrderId = -1;
144 uint32_t lastBindingNumber = -1;
146 for (CallInst *OldCI : ImplicitBindingCalls) {
148 const uint32_t OrderId =
150 const uint32_t DescSet =
155 const uint32_t NewBinding = (lastOrderId == OrderId)
157 : getAndReserveFirstUnusedBinding(DescSet);
158 lastOrderId = OrderId;
159 lastBindingNumber = NewBinding;
161 SmallVector<Value *, 8>
Args;
162 Args.push_back(Builder.getInt32(DescSet));
163 Args.push_back(Builder.getInt32(NewBinding));
166 for (uint32_t i = 2; i < OldCI->arg_size(); ++i) {
167 Args.push_back(OldCI->getArgOperand(i));
171 &M, Intrinsic::spv_resource_handlefrombinding, OldCI->getType());
172 CallInst *NewCI = Builder.CreateCall(NewFunc, Args);
175 OldCI->replaceAllUsesWith(NewCI);
176 OldCI->eraseFromParent();
180bool SPIRVLegalizeImplicitBinding::runOnModule(
Module &M) {
181 collectBindingInfo(M);
182 if (ImplicitBindingCalls.empty()) {
185 verifyUniqueOrderIdPerResource(ImplicitBindingCalls);
187 replaceImplicitBindingCalls(M);
192char SPIRVLegalizeImplicitBinding::ID = 0;
195 "Legalize SPIR-V implicit bindings",
false,
false)
198 return new SPIRVLegalizeImplicitBinding();
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
This file implements the BitVector class.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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)
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...
Base class for instruction visitors.
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.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
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.
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 * createSPIRVLegalizeImplicitBindingPass()