LLVM 22.0.0git
DXILPostOptimizationValidation.cpp
Go to the documentation of this file.
1//===- DXILPostOptimizationValidation.cpp - Opt DXIL validation ----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "DXILRootSignature.h"
11#include "DXILShaderFlags.h"
12#include "DirectX.h"
18#include "llvm/IR/IntrinsicsDirectX.h"
19#include "llvm/IR/Module.h"
22
23#define DEBUG_TYPE "dxil-post-optimization-validation"
24
25using namespace llvm;
26using namespace llvm::dxil;
27
29 using namespace dxbc;
30 switch (Type) {
31 case RootParameterType::Constants32Bit:
33 case RootParameterType::SRV:
34 return ResourceClass::SRV;
35 case RootParameterType::UAV:
36 return ResourceClass::UAV;
37 case RootParameterType::CBV:
39 case dxbc::RootParameterType::DescriptorTable:
40 llvm_unreachable("DescriptorTable is not convertible to ResourceClass");
41 }
42 llvm_unreachable("Unknown RootParameterType");
43}
44
46 for (const auto &UAV : DRM.uavs()) {
47 if (UAV.CounterDirection != ResourceCounterDirection::Invalid)
48 continue;
49
50 CallInst *ResourceHandle = nullptr;
51 for (CallInst *MaybeHandle : DRM.calls()) {
52 if (*DRM.find(MaybeHandle) == UAV) {
53 ResourceHandle = MaybeHandle;
54 break;
55 }
56 }
57
58 StringRef Message = "RWStructuredBuffers may increment or decrement their "
59 "counters, but not both.";
60 for (const auto &U : ResourceHandle->users()) {
61 const CallInst *CI = dyn_cast<CallInst>(U);
62 if (!CI && CI->getIntrinsicID() != Intrinsic::dx_resource_updatecounter)
63 continue;
64
65 M.getContext().diagnose(DiagnosticInfoGenericWithLoc(
66 Message, *CI->getFunction(), CI->getDebugLoc()));
67 }
68 }
69}
70
73 SmallString<128> Message;
74 raw_svector_ostream OS(Message);
75 OS << "resource " << R1.getName() << " at register "
76 << R1.getBinding().LowerBound << " overlaps with resource " << R2.getName()
77 << " at register " << R2.getBinding().LowerBound << " in space "
78 << R2.getBinding().Space;
79 M.getContext().diagnose(DiagnosticInfoGeneric(Message));
80}
81
83 [[maybe_unused]] bool ErrorFound = false;
84 for (const auto &ResList :
85 {DRM.srvs(), DRM.uavs(), DRM.cbuffers(), DRM.samplers()}) {
86 if (ResList.empty())
87 continue;
88 const ResourceInfo *PrevRI = &*ResList.begin();
89 for (auto *I = ResList.begin() + 1; I != ResList.end(); ++I) {
90 const ResourceInfo *CurrentRI = &*I;
91 const ResourceInfo *RI = CurrentRI;
92 while (RI != ResList.end() &&
93 PrevRI->getBinding().overlapsWith(RI->getBinding())) {
94 reportOverlappingError(M, *PrevRI, *RI);
95 ErrorFound = true;
96 RI++;
97 }
98 PrevRI = CurrentRI;
99 }
100 }
101 assert(ErrorFound && "this function should be called only when if "
102 "DXILResourceBindingInfo::hasOverlapingBinding() is "
103 "true, yet no overlapping binding was found");
104}
105
108 SmallString<160> Message;
109 raw_svector_ostream OS(Message);
110 StringRef RCName = getResourceClassName(RC);
111 OS << RCName << " at register " << Binding.LowerBound << " and space "
112 << Binding.Space << " is bound to a texture or typed buffer. " << RCName
113 << " root descriptors can only be Raw or Structured buffers.";
114 M.getContext().diagnose(DiagnosticInfoGeneric(Message));
115}
116
118 const llvm::hlsl::Binding &R2) {
119 SmallString<128> Message;
120
121 raw_svector_ostream OS(Message);
122 OS << "resource " << getResourceClassName(R1.RC) << " (space=" << R1.Space
123 << ", registers=[" << R1.LowerBound << ", " << R1.UpperBound
124 << "]) overlaps with resource " << getResourceClassName(R2.RC)
125 << " (space=" << R2.Space << ", registers=[" << R2.LowerBound << ", "
126 << R2.UpperBound << "])";
127 M.getContext().diagnose(DiagnosticInfoGeneric(Message));
128}
129
130static void
133 SmallString<128> Message;
134 raw_svector_ostream OS(Message);
135 OS << getResourceClassName(Class) << " register " << Unbound.LowerBound
136 << " in space " << Unbound.Space
137 << " does not have a binding in the Root Signature";
138 M.getContext().diagnose(DiagnosticInfoGeneric(Message));
139}
140
143 switch (ET) {
144 case Triple::Pixel:
145 return dxbc::ShaderVisibility::Pixel;
146 case Triple::Vertex:
147 return dxbc::ShaderVisibility::Vertex;
148 case Triple::Geometry:
149 return dxbc::ShaderVisibility::Geometry;
150 case Triple::Hull:
151 return dxbc::ShaderVisibility::Hull;
152 case Triple::Domain:
153 return dxbc::ShaderVisibility::Domain;
154 case Triple::Mesh:
155 return dxbc::ShaderVisibility::Mesh;
156 case Triple::Compute:
157 return dxbc::ShaderVisibility::All;
158 default:
159 llvm_unreachable("Invalid triple to shader stage conversion");
160 }
161}
162
164 const mcdxbc::RootSignatureDesc &RSD,
166 DXILResourceMap &DRM,
167 DXILResourceTypeMap &DRTM) {
168
171
172 for (const mcdxbc::RootParameterInfo &ParamInfo : RSD.ParametersContainer) {
173 dxbc::ShaderVisibility ParamVisibility =
175 if (ParamVisibility != dxbc::ShaderVisibility::All &&
176 ParamVisibility != Visibility)
177 continue;
179 switch (ParamType) {
180 case dxbc::RootParameterType::Constants32Bit: {
183 Builder.trackBinding(dxil::ResourceClass::CBuffer, Const.RegisterSpace,
184 Const.ShaderRegister, Const.ShaderRegister,
185 &ParamInfo);
186 break;
187 }
188
189 case dxbc::RootParameterType::SRV:
190 case dxbc::RootParameterType::UAV:
191 case dxbc::RootParameterType::CBV: {
194 Builder.trackBinding(toResourceClass(ParamInfo.Type), Desc.RegisterSpace,
195 Desc.ShaderRegister, Desc.ShaderRegister,
196 &ParamInfo);
197
198 break;
199 }
200 case dxbc::RootParameterType::DescriptorTable: {
201 const mcdxbc::DescriptorTable &Table =
203
204 for (const mcdxbc::DescriptorRange &Range : Table.Ranges) {
205 uint32_t UpperBound =
206 Range.NumDescriptors == ~0U
207 ? Range.BaseShaderRegister
208 : Range.BaseShaderRegister + Range.NumDescriptors - 1;
209 Builder.trackBinding(Range.RangeType, Range.RegisterSpace,
210 Range.BaseShaderRegister, UpperBound, &ParamInfo);
211 }
212 break;
213 }
214 }
215 }
216
217 for (const mcdxbc::StaticSampler &S : RSD.StaticSamplers)
218 Builder.trackBinding(dxil::ResourceClass::Sampler, S.RegisterSpace,
220
221 Builder.calculateBindingInfo(
222 [&M](const llvm::hlsl::BindingInfoBuilder &Builder,
223 const llvm::hlsl::Binding &ReportedBinding) {
224 const llvm::hlsl::Binding &Overlaping =
225 Builder.findOverlapping(ReportedBinding);
226 reportOverlappingRegisters(M, ReportedBinding, Overlaping);
227 });
228 const hlsl::BoundRegs &BoundRegs = Builder.takeBoundRegs();
229 for (const ResourceInfo &RI : DRM) {
230 const ResourceInfo::ResourceBinding &Binding = RI.getBinding();
231 const dxil::ResourceTypeInfo &RTI = DRTM[RI.getHandleTy()];
234
235 const llvm::hlsl::Binding *Reg =
236 BoundRegs.findBoundReg(RC, Binding.Space, Binding.LowerBound,
237 Binding.LowerBound + Binding.Size - 1);
238
239 if (Reg != nullptr) {
240 const auto *ParamInfo =
241 static_cast<const mcdxbc::RootParameterInfo *>(Reg->Cookie);
242
243 if (RC != ResourceClass::SRV && RC != ResourceClass::UAV)
244 continue;
245
246 if (ParamInfo->Type == dxbc::RootParameterType::DescriptorTable)
247 continue;
248
251 } else {
253 }
254 }
255}
256
260 if (MMI.EntryPropertyVec.size() == 0)
261 return nullptr;
262 return RSBI.getDescForFunction(MMI.EntryPropertyVec[0].Entry);
263}
264
269 DXILResourceTypeMap &DRTM) {
272
273 if (DRBI.hasOverlappingBinding())
275
276 assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in "
277 "DXILResourceImplicitBinding pass");
278
279 if (mcdxbc::RootSignatureDesc *RSD = getRootSignature(RSBI, MMI))
280 validateRootSignature(M, *RSD, MMI, DRM, DRTM);
281}
282
285 DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
288 ModuleMetadataInfo &MMI = MAM.getResult<DXILMetadataAnalysis>(M);
290
291 reportErrors(M, DRM, DRBI, RSBI, MMI, DRTM);
292 return PreservedAnalyses::all();
293}
294
295namespace {
296class DXILPostOptimizationValidationLegacy : public ModulePass {
297public:
298 bool runOnModule(Module &M) override {
299 DXILResourceMap &DRM =
300 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
302 getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo();
304 getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo();
306 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
307 DXILResourceTypeMap &DRTM =
308 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
309
310 reportErrors(M, DRM, DRBI, RSBI, MMI, DRTM);
311 return false;
312 }
313 StringRef getPassName() const override {
314 return "DXIL Post Optimization Validation";
315 }
316 DXILPostOptimizationValidationLegacy() : ModulePass(ID) {}
317
318 static char ID; // Pass identification.
319 void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
320 AU.addRequired<DXILResourceWrapperPass>();
321 AU.addRequired<DXILResourceBindingWrapperPass>();
322 AU.addRequired<DXILMetadataAnalysisWrapperPass>();
323 AU.addRequired<RootSignatureAnalysisWrapper>();
324 AU.addRequired<DXILResourceTypeWrapperPass>();
325 AU.addPreserved<DXILResourceWrapperPass>();
326 AU.addPreserved<DXILResourceBindingWrapperPass>();
327 AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
328 AU.addPreserved<ShaderFlagsAnalysisWrapper>();
329 AU.addPreserved<RootSignatureAnalysisWrapper>();
330 }
331};
332char DXILPostOptimizationValidationLegacy::ID = 0;
333} // end anonymous namespace
334
335INITIALIZE_PASS_BEGIN(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
336 "DXIL Post Optimization Validation", false, false)
343INITIALIZE_PASS_END(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
344 "DXIL Post Optimization Validation", false, false)
345
347 return new DXILPostOptimizationValidationLegacy();
348}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static dxbc::ShaderVisibility tripleToVisibility(llvm::Triple::EnvironmentType ET)
static void reportRegNotBound(Module &M, ResourceClass Class, const llvm::dxil::ResourceInfo::ResourceBinding &Unbound)
static ResourceClass toResourceClass(dxbc::RootParameterType Type)
static void reportOverlappingError(Module &M, ResourceInfo R1, ResourceInfo R2)
static void reportErrors(Module &M, DXILResourceMap &DRM, DXILResourceBindingInfo &DRBI, RootSignatureBindingInfo &RSBI, dxil::ModuleMetadataInfo &MMI, DXILResourceTypeMap &DRTM)
static void validateRootSignature(Module &M, const mcdxbc::RootSignatureDesc &RSD, dxil::ModuleMetadataInfo &MMI, DXILResourceMap &DRM, DXILResourceTypeMap &DRTM)
static void reportInvalidHandleTyError(Module &M, ResourceClass RC, ResourceInfo::ResourceBinding Binding)
static mcdxbc::RootSignatureDesc * getRootSignature(RootSignatureBindingInfo &RSBI, dxil::ModuleMetadataInfo &MMI)
static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM)
static void reportInvalidDirection(Module &M, DXILResourceMap &DRM)
static void reportOverlappingRegisters(Module &M, const llvm::hlsl::Binding &R1, const llvm::hlsl::Binding &R2)
DXIL Resource Implicit Binding
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
#define I(x, y, z)
Definition MD5.cpp:58
Register Reg
#define R2(n)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
ModuleAnalysisManager MAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
This file defines the SmallString class.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
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.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
iterator find(const CallInst *Key)
bool hasInvalidCounterDirection() const
iterator_range< iterator > samplers()
iterator_range< iterator > srvs()
iterator_range< iterator > cbuffers()
iterator_range< iterator > uavs()
iterator_range< call_iterator > calls()
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
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
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
iterator_range< user_iterator > users()
Definition Value.h:426
StringRef getName() const
const ResourceBinding & getBinding() const
dxil::ResourceClass getResourceClass() const
dxil::ResourceKind getResourceKind() const
Wrapper pass for the legacy pass manager.
mcdxbc::RootSignatureDesc * getDescForFunction(const Function *F)
Builder class for creating a /c BindingInfo.
const Binding * findBoundReg(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound, uint32_t UpperBound) const
A raw_ostream that writes to an SmallVector or SmallString.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
LLVM_ABI StringRef getResourceClassName(ResourceClass RC)
Definition DXILABI.cpp:21
ResourceKind
The kind of resource for an SRV or UAV resource.
Definition DXILABI.h:36
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:649
ModulePass * createDXILPostOptimizationValidationLegacyPass()
Pass to lowering LLVM intrinsic call to DXIL op function call.
Op::Description Desc
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
Triple::EnvironmentType ShaderProfile
SmallVector< EntryProperties > EntryPropertyVec
bool overlapsWith(const ResourceBinding &RHS) const
dxil::ResourceClass RC
SmallVector< DescriptorRange > Ranges
const RootDescriptor & getRootDescriptor(size_t Index) const
const DescriptorTable & getDescriptorTable(size_t Index) const
const RootConstants & getConstant(size_t Index) const
SmallVector< StaticSampler > StaticSamplers
mcdxbc::RootParametersContainer ParametersContainer