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 (RangeType) {
31 case DescriptorRangeType::SRV:
32 return ResourceClass::SRV;
33 case DescriptorRangeType::UAV:
34 return ResourceClass::UAV;
35 case DescriptorRangeType::CBV:
36 return ResourceClass::CBuffer;
37 case DescriptorRangeType::Sampler:
38 return ResourceClass::Sampler;
39 }
40 llvm_unreachable("Unknown DescriptorRangeType");
41}
42
44 using namespace dxbc;
45 switch (Type) {
46 case RootParameterType::Constants32Bit:
47 return ResourceClass::CBuffer;
48 case RootParameterType::SRV:
49 return ResourceClass::SRV;
50 case RootParameterType::UAV:
51 return ResourceClass::UAV;
52 case RootParameterType::CBV:
53 return ResourceClass::CBuffer;
54 case dxbc::RootParameterType::DescriptorTable:
55 llvm_unreachable("DescriptorTable is not convertible to ResourceClass");
56 }
57 llvm_unreachable("Unknown RootParameterType");
58}
59
61 for (const auto &UAV : DRM.uavs()) {
62 if (UAV.CounterDirection != ResourceCounterDirection::Invalid)
63 continue;
64
65 CallInst *ResourceHandle = nullptr;
66 for (CallInst *MaybeHandle : DRM.calls()) {
67 if (*DRM.find(MaybeHandle) == UAV) {
68 ResourceHandle = MaybeHandle;
69 break;
70 }
71 }
72
73 StringRef Message = "RWStructuredBuffers may increment or decrement their "
74 "counters, but not both.";
75 for (const auto &U : ResourceHandle->users()) {
76 const CallInst *CI = dyn_cast<CallInst>(U);
77 if (!CI && CI->getIntrinsicID() != Intrinsic::dx_resource_updatecounter)
78 continue;
79
80 M.getContext().diagnose(DiagnosticInfoGenericWithLoc(
81 Message, *CI->getFunction(), CI->getDebugLoc()));
82 }
83 }
84}
85
88 SmallString<128> Message;
89 raw_svector_ostream OS(Message);
90 OS << "resource " << R1.getName() << " at register "
91 << R1.getBinding().LowerBound << " overlaps with resource " << R2.getName()
92 << " at register " << R2.getBinding().LowerBound << " in space "
93 << R2.getBinding().Space;
94 M.getContext().diagnose(DiagnosticInfoGeneric(Message));
95}
96
98 [[maybe_unused]] bool ErrorFound = false;
99 for (const auto &ResList :
100 {DRM.srvs(), DRM.uavs(), DRM.cbuffers(), DRM.samplers()}) {
101 if (ResList.empty())
102 continue;
103 const ResourceInfo *PrevRI = &*ResList.begin();
104 for (auto *I = ResList.begin() + 1; I != ResList.end(); ++I) {
105 const ResourceInfo *CurrentRI = &*I;
106 const ResourceInfo *RI = CurrentRI;
107 while (RI != ResList.end() &&
108 PrevRI->getBinding().overlapsWith(RI->getBinding())) {
109 reportOverlappingError(M, *PrevRI, *RI);
110 ErrorFound = true;
111 RI++;
112 }
113 PrevRI = CurrentRI;
114 }
115 }
116 assert(ErrorFound && "this function should be called only when if "
117 "DXILResourceBindingInfo::hasOverlapingBinding() is "
118 "true, yet no overlapping binding was found");
119}
120
122 const llvm::hlsl::Binding &R2) {
123 SmallString<128> Message;
124
125 raw_svector_ostream OS(Message);
126 OS << "resource " << getResourceClassName(R1.RC) << " (space=" << R1.Space
127 << ", registers=[" << R1.LowerBound << ", " << R1.UpperBound
128 << "]) overlaps with resource " << getResourceClassName(R2.RC)
129 << " (space=" << R2.Space << ", registers=[" << R2.LowerBound << ", "
130 << R2.UpperBound << "])";
131 M.getContext().diagnose(DiagnosticInfoGeneric(Message));
132}
133
134static void
137 SmallString<128> Message;
138 raw_svector_ostream OS(Message);
139 OS << getResourceClassName(Class) << " register " << Unbound.LowerBound
140 << " in space " << Unbound.Space
141 << " does not have a binding in the Root Signature";
142 M.getContext().diagnose(DiagnosticInfoGeneric(Message));
143}
144
147 switch (ET) {
148 case Triple::Pixel:
149 return dxbc::ShaderVisibility::Pixel;
150 case Triple::Vertex:
151 return dxbc::ShaderVisibility::Vertex;
152 case Triple::Geometry:
153 return dxbc::ShaderVisibility::Geometry;
154 case Triple::Hull:
155 return dxbc::ShaderVisibility::Hull;
156 case Triple::Domain:
157 return dxbc::ShaderVisibility::Domain;
158 case Triple::Mesh:
159 return dxbc::ShaderVisibility::Mesh;
160 case Triple::Compute:
161 return dxbc::ShaderVisibility::All;
162 default:
163 llvm_unreachable("Invalid triple to shader stage conversion");
164 }
165}
166
168 const mcdxbc::RootSignatureDesc &RSD,
170 DXILResourceMap &DRM,
171 DXILResourceTypeMap &DRTM) {
172
175
176 for (const mcdxbc::RootParameterInfo &ParamInfo : RSD.ParametersContainer) {
177 dxbc::ShaderVisibility ParamVisibility =
179 if (ParamVisibility != dxbc::ShaderVisibility::All &&
180 ParamVisibility != Visibility)
181 continue;
183 switch (ParamType) {
184 case dxbc::RootParameterType::Constants32Bit: {
187 Builder.trackBinding(dxil::ResourceClass::CBuffer, Const.RegisterSpace,
188 Const.ShaderRegister, Const.ShaderRegister,
189 &ParamInfo);
190 break;
191 }
192
193 case dxbc::RootParameterType::SRV:
194 case dxbc::RootParameterType::UAV:
195 case dxbc::RootParameterType::CBV: {
198 Builder.trackBinding(toResourceClass(ParamInfo.Type), Desc.RegisterSpace,
199 Desc.ShaderRegister, Desc.ShaderRegister,
200 &ParamInfo);
201
202 break;
203 }
204 case dxbc::RootParameterType::DescriptorTable: {
205 const mcdxbc::DescriptorTable &Table =
207
208 for (const dxbc::RTS0::v2::DescriptorRange &Range : Table.Ranges) {
209 uint32_t UpperBound =
210 Range.NumDescriptors == ~0U
211 ? Range.BaseShaderRegister
212 : Range.BaseShaderRegister + Range.NumDescriptors - 1;
213 Builder.trackBinding(
215 static_cast<dxbc::DescriptorRangeType>(Range.RangeType)),
216 Range.RegisterSpace, Range.BaseShaderRegister, UpperBound,
217 &ParamInfo);
218 }
219 break;
220 }
221 }
222 }
223
225 Builder.trackBinding(dxil::ResourceClass::Sampler, S.RegisterSpace,
227
228 Builder.calculateBindingInfo(
229 [&M](const llvm::hlsl::BindingInfoBuilder &Builder,
230 const llvm::hlsl::Binding &ReportedBinding) {
231 const llvm::hlsl::Binding &Overlaping =
232 Builder.findOverlapping(ReportedBinding);
233 reportOverlappingRegisters(M, ReportedBinding, Overlaping);
234 });
235 const hlsl::BoundRegs &BoundRegs = Builder.takeBoundRegs();
236 for (const ResourceInfo &RI : DRM) {
237 const ResourceInfo::ResourceBinding &Binding = RI.getBinding();
238 ResourceClass RC = DRTM[RI.getHandleTy()].getResourceClass();
239 if (!BoundRegs.isBound(RC, Binding.Space, Binding.LowerBound,
240 Binding.LowerBound + Binding.Size - 1))
242 }
243}
244
248 if (MMI.EntryPropertyVec.size() == 0)
249 return nullptr;
250 return RSBI.getDescForFunction(MMI.EntryPropertyVec[0].Entry);
251}
252
257 DXILResourceTypeMap &DRTM) {
260
261 if (DRBI.hasOverlappingBinding())
263
264 assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in "
265 "DXILResourceImplicitBinding pass");
266
267 if (mcdxbc::RootSignatureDesc *RSD = getRootSignature(RSBI, MMI))
268 validateRootSignature(M, *RSD, MMI, DRM, DRTM);
269}
270
278
279 reportErrors(M, DRM, DRBI, RSBI, MMI, DRTM);
280 return PreservedAnalyses::all();
281}
282
283namespace {
284class DXILPostOptimizationValidationLegacy : public ModulePass {
285public:
286 bool runOnModule(Module &M) override {
287 DXILResourceMap &DRM =
288 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
290 getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo();
292 getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo();
294 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
295 DXILResourceTypeMap &DRTM =
296 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
297
298 reportErrors(M, DRM, DRBI, RSBI, MMI, DRTM);
299 return false;
300 }
301 StringRef getPassName() const override {
302 return "DXIL Post Optimization Validation";
303 }
304 DXILPostOptimizationValidationLegacy() : ModulePass(ID) {}
305
306 static char ID; // Pass identification.
307 void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
318 }
319};
320char DXILPostOptimizationValidationLegacy::ID = 0;
321} // end anonymous namespace
322
323INITIALIZE_PASS_BEGIN(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
324 "DXIL Post Optimization Validation", false, false)
331INITIALIZE_PASS_END(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
333
335 return new DXILPostOptimizationValidationLegacy();
336}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
DXIL Post Optimization Validation
static dxbc::ShaderVisibility tripleToVisibility(llvm::Triple::EnvironmentType ET)
static ResourceClass toResourceClass(dxbc::DescriptorRangeType RangeType)
static void reportRegNotBound(Module &M, ResourceClass Class, const llvm::dxil::ResourceInfo::ResourceBinding &Unbound)
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 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
#define R2(n)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
PowerPC MI Peephole Optimization
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
raw_pwrite_stream & OS
This file defines the SmallString class.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:255
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:412
Represent the analysis usage information of a pass.
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)
Definition: DXILResource.h:505
bool hasInvalidCounterDirection() const
Definition: DXILResource.h:570
iterator_range< iterator > samplers()
Definition: DXILResource.h:548
iterator_range< iterator > srvs()
Definition: DXILResource.h:519
iterator_range< iterator > cbuffers()
Definition: DXILResource.h:537
iterator_range< iterator > uavs()
Definition: DXILResource.h:528
iterator_range< call_iterator > calls()
Definition: DXILResource.h:566
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
Definition: Instruction.h:513
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
Definition: Instruction.cpp:82
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
Definition: DXILResource.h:395
const ResourceBinding & getBinding() const
Definition: DXILResource.h:393
Wrapper pass for the legacy pass manager.
mcdxbc::RootSignatureDesc * getDescForFunction(const Function *F)
Wrapper pass for the legacy pass manager.
Builder class for creating a /c BindingInfo.
Definition: HLSLBinding.h:151
LLVM_ABI const Binding & findOverlapping(const Binding &ReportedBinding) const
For use in the ReportOverlap callback of calculateBindingInfo - finds a binding that the ReportedBind...
void trackBinding(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound, uint32_t UpperBound, const void *Cookie)
Definition: HLSLBinding.h:156
LLVM_ABI BindingInfo calculateBindingInfo(llvm::function_ref< void(const BindingInfoBuilder &Builder, const Binding &Overlapping)> ReportOverlap)
Calculate the binding info - ReportOverlap will be called once for each overlapping binding.
Definition: HLSLBinding.cpp:69
LLVM_ABI BoundRegs takeBoundRegs()
Definition: HLSLBinding.h:175
bool isBound(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound, uint32_t UpperBound) const
Definition: HLSLBinding.h:136
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:692
#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
ResourceClass
Definition: DXILABI.h:26
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
ModulePass * createDXILPostOptimizationValidationLegacyPass()
Pass to lowering LLVM intrinsic call to DXIL op function call.
Description of the encoding of one expression Op.
Triple::EnvironmentType ShaderProfile
SmallVector< EntryProperties > EntryPropertyVec
bool overlapsWith(const ResourceBinding &RHS) const
Definition: DXILResource.h:362
dxil::ResourceClass RC
Definition: HLSLBinding.h:104
SmallVector< dxbc::RTS0::v2::DescriptorRange > Ranges
const RootDescriptor & getRootDescriptor(size_t Index) const
const DescriptorTable & getDescriptorTable(size_t Index) const
const RootConstants & getConstant(size_t Index) const
SmallVector< dxbc::RTS0::v1::StaticSampler > StaticSamplers
mcdxbc::RootParametersContainer ParametersContainer