23#include "llvm/IR/IntrinsicsSPIRV.h"
32class SPIRVLegalizeImplicitBindingImpl {
34 bool runOnModule(
Module &M);
37 void collectBindingInfo(
Module &M);
38 uint32_t getAndReserveFirstUnusedBinding(uint32_t DescSet);
39 void replaceImplicitBindingCalls(
Module &M);
40 void replaceResourceHandleCall(
Module &M, CallInst *OldCI,
42 void replaceCounterHandleCall(
Module &M, CallInst *OldCI,
44 void verifyUniqueOrderIdPerResource(SmallVectorImpl<CallInst *> &Calls);
47 std::vector<BitVector> UsedBindings;
52class SPIRVLegalizeImplicitBindingLegacy :
public ModulePass {
55 SPIRVLegalizeImplicitBindingLegacy() : ModulePass(ID) {}
56 StringRef getPassName()
const override {
57 return "SPIRV Legalize Implicit Binding";
59 bool runOnModule(
Module &M)
override {
60 return SPIRVLegalizeImplicitBindingImpl().runOnModule(M);
64struct BindingInfoCollector :
public InstVisitor<BindingInfoCollector> {
65 std::vector<BitVector> &UsedBindings;
68 BindingInfoCollector(std::vector<BitVector> &UsedBindings,
70 : UsedBindings(UsedBindings), ImplicitBindingCalls(ImplicitBindingCalls) {
73 void addBinding(uint32_t DescSet, uint32_t
Binding) {
74 if (UsedBindings.size() <= DescSet) {
75 UsedBindings.resize(DescSet + 1);
76 UsedBindings[DescSet].resize(64);
79 UsedBindings[DescSet].resize(2 *
Binding + 1);
81 UsedBindings[DescSet].set(
Binding);
84 void visitCallInst(CallInst &CI) {
85 if (CI.
getIntrinsicID() == Intrinsic::spv_resource_handlefrombinding) {
86 const uint32_t DescSet =
92 Intrinsic::spv_resource_handlefromimplicitbinding) {
93 ImplicitBindingCalls.push_back(&CI);
95 Intrinsic::spv_resource_counterhandlefrombinding) {
96 const uint32_t DescSet =
102 Intrinsic::spv_resource_counterhandlefromimplicitbinding) {
103 ImplicitBindingCalls.push_back(&CI);
111 case Intrinsic::spv_resource_handlefromimplicitbinding:
114 case Intrinsic::spv_resource_counterhandlefromimplicitbinding:
126 case Intrinsic::spv_resource_handlefromimplicitbinding:
127 case Intrinsic::spv_resource_handlefrombinding:
130 case Intrinsic::spv_resource_counterhandlefromimplicitbinding:
131 case Intrinsic::spv_resource_counterhandlefrombinding:
140void SPIRVLegalizeImplicitBindingImpl::collectBindingInfo(
Module &M) {
141 BindingInfoCollector InfoCollector(UsedBindings, ImplicitBindingCalls);
142 InfoCollector.visit(M);
145 std::sort(ImplicitBindingCalls.
begin(), ImplicitBindingCalls.
end(),
146 [](
const CallInst *
A,
const CallInst *
B) {
147 return getOrderId(A) < getOrderId(B);
151void SPIRVLegalizeImplicitBindingImpl::verifyUniqueOrderIdPerResource(
152 SmallVectorImpl<CallInst *> &Calls) {
154 for (uint32_t i = 1; i < Calls.
size(); ++i) {
155 const uint32_t OrderA = getOrderId(Calls[i - 1]);
156 const uint32_t OrderB = getOrderId(Calls[i]);
157 if (OrderA == OrderB) {
158 const uint32_t DescSetA = getDescSet(Calls[i - 1]);
159 const uint32_t DescSetB = getDescSet(Calls[i]);
160 if (DescSetA != DescSetB) {
162 "have the same descriptor set");
168uint32_t SPIRVLegalizeImplicitBindingImpl::getAndReserveFirstUnusedBinding(
170 if (UsedBindings.size() <= DescSet) {
171 UsedBindings.resize(DescSet + 1);
172 UsedBindings[DescSet].resize(64);
175 int NewBinding = UsedBindings[DescSet].find_first_unset();
176 if (NewBinding == -1) {
177 NewBinding = UsedBindings[DescSet].size();
178 UsedBindings[DescSet].resize(2 * NewBinding + 1);
181 UsedBindings[DescSet].set(NewBinding);
185void SPIRVLegalizeImplicitBindingImpl::replaceImplicitBindingCalls(
Module &M) {
186 uint32_t lastOrderId = -1;
187 uint32_t lastBindingNumber = -1;
189 for (CallInst *OldCI : ImplicitBindingCalls) {
190 const uint32_t OrderId = getOrderId(OldCI);
191 uint32_t BindingNumber;
192 if (OrderId == lastOrderId) {
193 BindingNumber = lastBindingNumber;
195 const uint32_t DescSet = getDescSet(OldCI);
196 BindingNumber = getAndReserveFirstUnusedBinding(DescSet);
199 if (OldCI->getIntrinsicID() ==
200 Intrinsic::spv_resource_handlefromimplicitbinding) {
201 replaceResourceHandleCall(M, OldCI, BindingNumber);
203 assert(OldCI->getIntrinsicID() ==
204 Intrinsic::spv_resource_counterhandlefromimplicitbinding &&
205 "Unexpected implicit binding intrinsic");
206 replaceCounterHandleCall(M, OldCI, BindingNumber);
208 lastOrderId = OrderId;
209 lastBindingNumber = BindingNumber;
213bool SPIRVLegalizeImplicitBindingImpl::runOnModule(
Module &M) {
214 collectBindingInfo(M);
215 if (ImplicitBindingCalls.empty()) {
218 verifyUniqueOrderIdPerResource(ImplicitBindingCalls);
220 replaceImplicitBindingCalls(M);
227 return SPIRVLegalizeImplicitBindingImpl().runOnModule(M)
232char SPIRVLegalizeImplicitBindingLegacy::ID = 0;
235 "legalize-spirv-implicit-binding",
236 "Legalize SPIR-V implicit bindings",
false,
false)
239 return new SPIRVLegalizeImplicitBindingLegacy();
242void SPIRVLegalizeImplicitBindingImpl::replaceResourceHandleCall(
243 Module &M, CallInst *OldCI, uint32_t NewBinding) {
245 const uint32_t DescSet =
248 SmallVector<Value *, 8>
Args;
249 Args.push_back(Builder.getInt32(DescSet));
250 Args.push_back(Builder.getInt32(NewBinding));
253 for (uint32_t i = 2; i < OldCI->
arg_size(); ++i) {
258 &M, Intrinsic::spv_resource_handlefrombinding, OldCI->
getType());
259 CallInst *NewCI = Builder.CreateCall(NewFunc, Args);
266void SPIRVLegalizeImplicitBindingImpl::replaceCounterHandleCall(
267 Module &M, CallInst *OldCI, uint32_t NewBinding) {
269 const uint32_t DescSet =
272 SmallVector<Value *, 8>
Args;
274 Args.push_back(Builder.getInt32(NewBinding));
275 Args.push_back(Builder.getInt32(DescSet));
279 &M, Intrinsic::spv_resource_counterhandlefrombinding, Tys);
280 CallInst *NewCI = Builder.CreateCall(NewFunc, Args);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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)
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...
unsigned arg_size() const
This class represents a function call, abstracting a target machine's calling convention.
Base class for instruction visitors.
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.
A set of analyses that are preserved following a run of a transformation pass.
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)
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 Args[]
Key for Kernel::Metadata::mArgs.
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.
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()