LLVM 22.0.0git
SPIRVLegalizeImplicitBinding.cpp
Go to the documentation of this file.
1//===- SPIRVLegalizeImplicitBinding.cpp - Legalize implicit bindings ----*- C++
2//-*-===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9//
10// This pass legalizes the @llvm.spv.resource.handlefromimplicitbinding
11// intrinsic by replacing it with a call to
12// @llvm.spv.resource.handlefrombinding.
13//
14//===----------------------------------------------------------------------===//
15
16#include "SPIRV.h"
17#include "llvm/ADT/BitVector.h"
19#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/InstVisitor.h"
21#include "llvm/IR/Intrinsics.h"
22#include "llvm/IR/IntrinsicsSPIRV.h"
23#include "llvm/IR/Module.h"
24#include "llvm/Pass.h"
25#include <algorithm>
26#include <vector>
27
28using namespace llvm;
29
30namespace {
31class SPIRVLegalizeImplicitBinding : public ModulePass {
32public:
33 static char ID;
34 SPIRVLegalizeImplicitBinding() : ModulePass(ID) {}
35
36 bool runOnModule(Module &M) override;
37
38private:
39 void collectBindingInfo(Module &M);
40 uint32_t getAndReserveFirstUnusedBinding(uint32_t DescSet);
41 void replaceImplicitBindingCalls(Module &M);
42
43 // A map from descriptor set to a bit vector of used binding numbers.
44 std::vector<BitVector> UsedBindings;
45 // A list of all implicit binding calls, to be sorted by order ID.
46 SmallVector<CallInst *, 16> ImplicitBindingCalls;
47};
48
49struct BindingInfoCollector : public InstVisitor<BindingInfoCollector> {
50 std::vector<BitVector> &UsedBindings;
51 SmallVector<CallInst *, 16> &ImplicitBindingCalls;
52
53 BindingInfoCollector(std::vector<BitVector> &UsedBindings,
54 SmallVector<CallInst *, 16> &ImplicitBindingCalls)
55 : UsedBindings(UsedBindings), ImplicitBindingCalls(ImplicitBindingCalls) {
56 }
57
58 void visitCallInst(CallInst &CI) {
59 if (CI.getIntrinsicID() == Intrinsic::spv_resource_handlefrombinding) {
60 const uint32_t DescSet =
61 cast<ConstantInt>(CI.getArgOperand(0))->getZExtValue();
62 const uint32_t Binding =
63 cast<ConstantInt>(CI.getArgOperand(1))->getZExtValue();
64
65 if (UsedBindings.size() <= DescSet) {
66 UsedBindings.resize(DescSet + 1);
67 UsedBindings[DescSet].resize(64);
68 }
69 if (UsedBindings[DescSet].size() <= Binding) {
70 UsedBindings[DescSet].resize(2 * Binding + 1);
71 }
72 UsedBindings[DescSet].set(Binding);
73 } else if (CI.getIntrinsicID() ==
74 Intrinsic::spv_resource_handlefromimplicitbinding) {
75 ImplicitBindingCalls.push_back(&CI);
76 }
77 }
78};
79
80void SPIRVLegalizeImplicitBinding::collectBindingInfo(Module &M) {
81 BindingInfoCollector InfoCollector(UsedBindings, ImplicitBindingCalls);
82 InfoCollector.visit(M);
83
84 // Sort the collected calls by their order ID.
85 std::sort(
86 ImplicitBindingCalls.begin(), ImplicitBindingCalls.end(),
87 [](const CallInst *A, const CallInst *B) {
88 const uint32_t OrderIdArgIdx = 0;
89 const uint32_t OrderA =
90 cast<ConstantInt>(A->getArgOperand(OrderIdArgIdx))->getZExtValue();
91 const uint32_t OrderB =
92 cast<ConstantInt>(B->getArgOperand(OrderIdArgIdx))->getZExtValue();
93 return OrderA < OrderB;
94 });
95}
96
97uint32_t SPIRVLegalizeImplicitBinding::getAndReserveFirstUnusedBinding(
98 uint32_t DescSet) {
99 if (UsedBindings.size() <= DescSet) {
100 UsedBindings.resize(DescSet + 1);
101 UsedBindings[DescSet].resize(64);
102 }
103
104 int NewBinding = UsedBindings[DescSet].find_first_unset();
105 if (NewBinding == -1) {
106 NewBinding = UsedBindings[DescSet].size();
107 UsedBindings[DescSet].resize(2 * NewBinding + 1);
108 }
109
110 UsedBindings[DescSet].set(NewBinding);
111 return NewBinding;
112}
113
114void SPIRVLegalizeImplicitBinding::replaceImplicitBindingCalls(Module &M) {
115 for (CallInst *OldCI : ImplicitBindingCalls) {
116 IRBuilder<> Builder(OldCI);
117 const uint32_t DescSet =
118 cast<ConstantInt>(OldCI->getArgOperand(1))->getZExtValue();
119 const uint32_t NewBinding = getAndReserveFirstUnusedBinding(DescSet);
120
121 SmallVector<Value *, 8> Args;
122 Args.push_back(Builder.getInt32(DescSet));
123 Args.push_back(Builder.getInt32(NewBinding));
124
125 // Copy the remaining arguments from the old call.
126 for (uint32_t i = 2; i < OldCI->arg_size(); ++i) {
127 Args.push_back(OldCI->getArgOperand(i));
128 }
129
131 &M, Intrinsic::spv_resource_handlefrombinding, OldCI->getType());
132 CallInst *NewCI = Builder.CreateCall(NewFunc, Args);
133 NewCI->setCallingConv(OldCI->getCallingConv());
134
135 OldCI->replaceAllUsesWith(NewCI);
136 OldCI->eraseFromParent();
137 }
138}
139
140bool SPIRVLegalizeImplicitBinding::runOnModule(Module &M) {
141 collectBindingInfo(M);
142 if (ImplicitBindingCalls.empty()) {
143 return false;
144 }
145
146 replaceImplicitBindingCalls(M);
147 return true;
148}
149} // namespace
150
151char SPIRVLegalizeImplicitBinding::ID = 0;
152
153INITIALIZE_PASS(SPIRVLegalizeImplicitBinding, "legalize-spirv-implicit-binding",
154 "Legalize SPIR-V implicit bindings", false, false)
155
157 return new SPIRVLegalizeImplicitBinding();
158}
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)
Definition PassSupport.h:56
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.
Definition InstVisitor.h:78
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
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.
Definition STLExtras.h:1685
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.
Definition Casting.h:565
ModulePass * createSPIRVLegalizeImplicitBindingPass()