LLVM 23.0.0git
DXContainerGlobals.cpp
Go to the documentation of this file.
1//===- DXContainerGlobals.cpp - DXContainer global generator pass ---------===//
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//
9// DXContainerGlobalsPass implementation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "DXILRootSignature.h"
14#include "DXILShaderFlags.h"
15#include "DirectX.h"
18#include "llvm/ADT/StringRef.h"
22#include "llvm/CodeGen/Passes.h"
23#include "llvm/IR/Constants.h"
24#include "llvm/IR/Module.h"
29#include "llvm/Pass.h"
32#include "llvm/Support/MD5.h"
33#include "llvm/Support/Path.h"
36#include <cstdint>
37
38using namespace llvm;
39using namespace llvm::dxil;
40using namespace llvm::mcdxbc;
41
43 "dx-Zss", cl::desc("Compute Shader Hash considering source information"));
45 "dx-pdb-path",
46 cl::desc("Write debug information to the given file, or automatically "
47 "named file in directory when ending in '/'"),
48 cl::value_desc("filename"));
49
50namespace {
51class DXContainerGlobals : public llvm::ModulePass {
52
53 GlobalVariable *buildContainerGlobal(Module &M, Constant *Content,
56 StringRef SectionData, StringRef MetadataName,
58 GlobalVariable *getFeatureFlags(Module &M);
59 void computeShaderHashAndDebugName(Module &M,
61 GlobalVariable *buildSignature(Module &M, Signature &Sig, StringRef Name,
63 void addSignature(Module &M, SmallVector<GlobalValue *> &Globals);
64 void addRootSignature(Module &M, SmallVector<GlobalValue *> &Globals);
65 void addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV);
66 void addPipelineStateValidationInfo(Module &M,
68 void addCompilerVersion(Module &M, SmallVector<GlobalValue *> &Globals);
69 void addSourceInfo(Module &M, SmallVector<GlobalValue *> &Globals);
70
71public:
72 static char ID; // Pass identification, replacement for typeid
73 DXContainerGlobals() : ModulePass(ID) {}
74
75 StringRef getPassName() const override {
76 return "DXContainer Global Emitter";
77 }
78
79 bool runOnModule(Module &M) override;
80
81 void getAnalysisUsage(AnalysisUsage &AU) const override {
82 AU.setPreservesAll();
83 AU.addRequired<ShaderFlagsAnalysisWrapper>();
84 AU.addRequired<RootSignatureAnalysisWrapper>();
85 AU.addRequired<DXILMetadataAnalysisWrapperPass>();
86 AU.addRequired<DXILResourceTypeWrapperPass>();
87 AU.addRequired<DXILResourceWrapperPass>();
88 }
89};
90
91} // namespace
92
93bool DXContainerGlobals::runOnModule(Module &M) {
95 Globals.push_back(getFeatureFlags(M));
96 computeShaderHashAndDebugName(M, Globals);
97 addSignature(M, Globals);
98 addRootSignature(M, Globals);
99 addPipelineStateValidationInfo(M, Globals);
100 addCompilerVersion(M, Globals);
101 addSourceInfo(M, Globals);
102 appendToCompilerUsed(M, Globals);
103 return true;
104}
105
106GlobalVariable *DXContainerGlobals::getFeatureFlags(Module &M) {
107 uint64_t CombinedFeatureFlags = getAnalysis<ShaderFlagsAnalysisWrapper>()
108 .getShaderFlags()
109 .getCombinedFlags()
110 .getFeatureFlags();
111
112 Constant *FeatureFlagsConstant =
113 ConstantInt::get(M.getContext(), APInt(64, CombinedFeatureFlags));
114 return buildContainerGlobal(M, FeatureFlagsConstant, "dx.sfi0", "SFI0");
115}
116
117void DXContainerGlobals::addSection(Module &M,
119 StringRef SectionData,
120 StringRef MetadataName,
121 StringRef SectionName) {
122 Constant *SectionConstant = ConstantDataArray::getString(
123 M.getContext(), SectionData, /*AddNull*/ false);
124 Globals.emplace_back(
125 buildContainerGlobal(M, SectionConstant, MetadataName, SectionName));
126}
127
128void DXContainerGlobals::computeShaderHashAndDebugName(
129 Module &M, SmallVector<GlobalValue *> &Globals) {
130 ConstantDataArray *DXILConstant;
131 MD5 Digest;
132 dxbc::ShaderHash HashData = {0, {0}};
133
135 if (auto *ILDB = M.getNamedGlobal("dx.ildb")) {
136 DXILConstant = cast<ConstantDataArray>(ILDB->getInitializer());
137 HashData.Flags = static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
138 } else {
139 reportFatalUsageError("/Zss requires debug info (/Zi or /Zs)");
140 }
141 } else {
142 DXILConstant =
143 cast<ConstantDataArray>(M.getNamedGlobal("dx.dxil")->getInitializer());
144 }
145
146 Digest.update(DXILConstant->getRawDataValues());
147 MD5::MD5Result MD5 = Digest.final();
148
149 memcpy(reinterpret_cast<void *>(&HashData.Digest), MD5.data(), 16);
151 HashData.swapBytes();
152 StringRef Data(reinterpret_cast<char *>(&HashData), sizeof(dxbc::ShaderHash));
153
154 Constant *ModuleConstant =
156 Globals.emplace_back(
157 buildContainerGlobal(M, ModuleConstant, "dx.hash", "HASH"));
158
159 if (M.debug_compile_units().empty())
160 return;
161
162 SmallString<40> DebugNameStr;
163 Digest.stringifyResult(MD5, DebugNameStr);
164 DebugNameStr += ".pdb";
165 if (!PdbDebugPath.empty()) {
166 StringRef DebugFile = PdbDebugPath.getValue();
167 SmallString<256> AbsoluteDebugName;
168 if (sys::path::is_separator(DebugFile.back())) {
169 // If /Fd was specified as a directory, put the MD5.pdb file there.
170 AbsoluteDebugName = DebugFile;
171 sys::path::append(AbsoluteDebugName, DebugNameStr);
172 } else {
173 // Otherwise, use /Fd value as a user-provided PDB file name.
174 DebugNameStr = DebugFile;
175 AbsoluteDebugName = DebugNameStr;
176 }
177
178 // Pass PDB name to DXContainerPDBPass via PDBNAME section.
179 addSection(M, Globals, AbsoluteDebugName, "dx.pdb.name",
181 // Pass module hash to DXContainerPDBPass.
182 Globals.emplace_back(buildContainerGlobal(
183 M, ConstantDataArray::get(M.getContext(), ArrayRef(HashData.Digest)),
184 "dx.pdb.hash", ModuleHashSectionName));
185 }
186
187 // Emit ILDN part in debug info mode.
188 mcdxbc::DebugName DebugName;
189 DebugName.setFilename(DebugNameStr);
190 SmallString<64> ILDNData;
191 raw_svector_ostream OS(ILDNData);
192 DebugName.write(OS);
193 addSection(M, Globals, ILDNData, "dx.ildn", "ILDN");
194}
195
196GlobalVariable *DXContainerGlobals::buildContainerGlobal(
197 Module &M, Constant *Content, StringRef Name, StringRef SectionName) {
198 auto *GV = new llvm::GlobalVariable(
199 M, Content->getType(), true, GlobalValue::PrivateLinkage, Content, Name);
200 GV->setSection(SectionName);
201 GV->setAlignment(Align(4));
202 return GV;
203}
204
205GlobalVariable *DXContainerGlobals::buildSignature(Module &M, Signature &Sig,
206 StringRef Name,
207 StringRef SectionName) {
208 SmallString<256> Data;
209 raw_svector_ostream OS(Data);
210 Sig.write(OS);
212 ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
213 return buildContainerGlobal(M, Constant, Name, SectionName);
214}
215
216void DXContainerGlobals::addSignature(Module &M,
218 // FIXME: support graphics shader.
219 // see issue https://github.com/llvm/llvm-project/issues/90504.
220
221 Signature InputSig;
222 Globals.emplace_back(buildSignature(M, InputSig, "dx.isg1", "ISG1"));
223
224 Signature OutputSig;
225 Globals.emplace_back(buildSignature(M, OutputSig, "dx.osg1", "OSG1"));
226}
227
228void DXContainerGlobals::addRootSignature(Module &M,
230
231 dxil::ModuleMetadataInfo &MMI =
232 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
233
234 // Root Signature in Library don't compile to DXContainer.
236 return;
237
238 auto &RSA = getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo();
239 const Function *EntryFunction = nullptr;
240
242 assert(MMI.EntryPropertyVec.size() == 1);
243 EntryFunction = MMI.EntryPropertyVec[0].Entry;
244 }
245
246 const mcdxbc::RootSignatureDesc *RS = RSA.getDescForFunction(EntryFunction);
247 if (!RS)
248 return;
249
250 SmallString<256> Data;
251 raw_svector_ostream OS(Data);
252
253 RS->write(OS);
254
255 addSection(M, Globals, Data, "dx.rts0", "RTS0");
256}
257
258void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) {
259 const DXILResourceMap &DRM =
260 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
261 DXILResourceTypeMap &DRTM =
262 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
263
264 auto MakeBinding =
265 [](const dxil::ResourceInfo::ResourceBinding &Binding,
267 const dxbc::PSV::ResourceFlags Flags = dxbc::PSV::ResourceFlags()) {
268 dxbc::PSV::v2::ResourceBindInfo BindInfo;
269 BindInfo.Type = Type;
270 BindInfo.LowerBound = Binding.LowerBound;
271 assert(
272 (Binding.Size == 0 ||
273 (uint64_t)Binding.LowerBound + Binding.Size - 1 <= UINT32_MAX) &&
274 "Resource range is too large");
275 BindInfo.UpperBound = (Binding.Size == 0)
276 ? UINT32_MAX
277 : Binding.LowerBound + Binding.Size - 1;
278 BindInfo.Space = Binding.Space;
279 BindInfo.Kind = static_cast<dxbc::PSV::ResourceKind>(Kind);
280 BindInfo.Flags = Flags;
281 return BindInfo;
282 };
283
284 for (const dxil::ResourceInfo &RI : DRM.cbuffers()) {
285 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
286 PSV.Resources.push_back(MakeBinding(Binding, dxbc::PSV::ResourceType::CBV,
287 dxil::ResourceKind::CBuffer));
288 }
289 for (const dxil::ResourceInfo &RI : DRM.samplers()) {
290 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
291 PSV.Resources.push_back(MakeBinding(Binding,
292 dxbc::PSV::ResourceType::Sampler,
293 dxil::ResourceKind::Sampler));
294 }
295 for (const dxil::ResourceInfo &RI : DRM.srvs()) {
296 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
297
298 dxil::ResourceTypeInfo &TypeInfo = DRTM[RI.getHandleTy()];
300 if (TypeInfo.isStruct())
301 ResType = dxbc::PSV::ResourceType::SRVStructured;
302 else if (TypeInfo.isTyped())
303 ResType = dxbc::PSV::ResourceType::SRVTyped;
304 else
305 ResType = dxbc::PSV::ResourceType::SRVRaw;
306
307 PSV.Resources.push_back(
308 MakeBinding(Binding, ResType, TypeInfo.getResourceKind()));
309 }
310 for (const dxil::ResourceInfo &RI : DRM.uavs()) {
311 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
312
313 dxil::ResourceTypeInfo &TypeInfo = DRTM[RI.getHandleTy()];
315 if (RI.hasCounter())
316 ResType = dxbc::PSV::ResourceType::UAVStructuredWithCounter;
317 else if (TypeInfo.isStruct())
318 ResType = dxbc::PSV::ResourceType::UAVStructured;
319 else if (TypeInfo.isTyped())
320 ResType = dxbc::PSV::ResourceType::UAVTyped;
321 else
322 ResType = dxbc::PSV::ResourceType::UAVRaw;
323
324 dxbc::PSV::ResourceFlags Flags;
325 // TODO: Add support for dxbc::PSV::ResourceFlag::UsedByAtomic64, tracking
326 // with https://github.com/llvm/llvm-project/issues/104392
327 Flags.Flags = 0u;
328
329 PSV.Resources.push_back(
330 MakeBinding(Binding, ResType, TypeInfo.getResourceKind(), Flags));
331 }
332}
333
334void DXContainerGlobals::addPipelineStateValidationInfo(
335 Module &M, SmallVector<GlobalValue *> &Globals) {
336 SmallString<256> Data;
337 raw_svector_ostream OS(Data);
338 PSVRuntimeInfo PSV;
340 PSV.BaseData.MaximumWaveLaneCount = std::numeric_limits<uint32_t>::max();
341
342 dxil::ModuleMetadataInfo &MMI =
343 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
344 assert(MMI.EntryPropertyVec.size() == 1 ||
348 static_cast<uint8_t>(MMI.ShaderProfile - Triple::Pixel);
349
350 addResourcesForPSV(M, PSV);
351
352 // Hardcoded values here to unblock loading the shader into D3D.
353 //
354 // TODO: Lots more stuff to do here!
355 //
356 // See issue https://github.com/llvm/llvm-project/issues/96674.
357 switch (MMI.ShaderProfile) {
358 case Triple::Compute:
359 PSV.BaseData.NumThreadsX = MMI.EntryPropertyVec[0].NumThreadsX;
360 PSV.BaseData.NumThreadsY = MMI.EntryPropertyVec[0].NumThreadsY;
361 PSV.BaseData.NumThreadsZ = MMI.EntryPropertyVec[0].NumThreadsZ;
362 if (MMI.EntryPropertyVec[0].WaveSizeMin) {
363 PSV.BaseData.MinimumWaveLaneCount = MMI.EntryPropertyVec[0].WaveSizeMin;
365 MMI.EntryPropertyVec[0].WaveSizeMax
366 ? MMI.EntryPropertyVec[0].WaveSizeMax
367 : MMI.EntryPropertyVec[0].WaveSizeMin;
368 }
369 break;
370 default:
371 break;
372 }
373
374 if (MMI.ShaderProfile != Triple::Library &&
376 PSV.EntryName = MMI.EntryPropertyVec[0].Entry->getName();
377
378 PSV.finalize(MMI.ShaderProfile);
379 PSV.write(OS);
380 addSection(M, Globals, Data, "dx.psv0", "PSV0");
381}
382
383void DXContainerGlobals::addCompilerVersion(
384 Module &M, SmallVector<GlobalValue *> &Globals) {
385 if (M.debug_compile_units().empty())
386 return;
387
388 SmallString<256> Data;
389 raw_svector_ostream OS(Data);
390 mcdxbc::CompilerVersion CompilerVersion;
391 CompilerVersion.write(OS);
392 addSection(M, Globals, Data, "dx.vers", "VERS");
393}
394
395void DXContainerGlobals::addSourceInfo(Module &M,
397 dxil::ModuleMetadataInfo &MMI =
398 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
399
400 if (!MMI.SourceInfo)
401 return;
402
403 MMI.SourceInfo->computeEntries();
404 MMI.SourceInfo->finalize();
405 SmallString<256> Data;
406 raw_svector_ostream OS(Data);
407 MMI.SourceInfo->write(OS);
408 addSection(M, Globals, Data, "dx.srci", "SRCI");
409}
410
411char DXContainerGlobals::ID = 0;
412INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals",
413 "DXContainer Global Emitter", false, true)
418INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals",
419 "DXContainer Global Emitter", false, true)
420
422 return new DXContainerGlobals();
423}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
cl::opt< std::string > PdbDebugPath("dx-pdb-path", cl::desc("Write debug information to the given file, or automatically " "named file in directory when ending in '/'"), cl::value_desc("filename"))
static cl::opt< bool > ShaderHashDependsOnSource("dx-Zss", cl::desc("Compute Shader Hash considering source information"))
DXIL Resource Implicit Binding
Module.h This file contains the declarations for the Module class.
static Error addSection(const NewSectionInfo &NewSection, Object &Obj)
Machine Check Debug Module
#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 SmallVector class.
This file contains some functions that are useful when dealing with strings.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
static Constant * get(LLVMContext &Context, ArrayRef< ElementTy > Elts)
get() constructor - Return a constant with array type with an element count and element type matching...
Definition Constants.h:878
static LLVM_ABI Constant * getString(LLVMContext &Context, StringRef Initializer, bool AddNull=true, bool ByteString=false)
This method constructs a CDS and initializes it with a text string.
LLVM_ABI StringRef getRawDataValues() const
Return the raw, underlying, bytes of this data.
This is an important base class in LLVM.
Definition Constant.h:43
iterator_range< iterator > samplers()
iterator_range< iterator > srvs()
iterator_range< iterator > cbuffers()
iterator_range< iterator > uavs()
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition GlobalValue.h:61
LLVM_ABI void update(ArrayRef< uint8_t > Data)
Updates the hash for the byte stream provided.
Definition MD5.cpp:188
static LLVM_ABI void stringifyResult(MD5Result &Result, SmallVectorImpl< char > &Str)
Translates the bytes in Res to a hex string that is deposited into Str.
Definition MD5.cpp:286
LLVM_ABI void final(MD5Result &Result)
Finishes off the hash and puts the result in result.
Definition MD5.cpp:233
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
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
char back() const
Get the last character in the string.
Definition StringRef.h:153
@ RootSignature
Definition Triple.h:409
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
LLVM_ABI bool isTyped() const
LLVM_ABI bool isStruct() const
dxil::ResourceKind getResourceKind() const
Wrapper pass for the legacy pass manager.
LLVM_ABI void write(raw_ostream &OS)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
ResourceKind
The kind of resource for an SRV or UAV resource.
Definition DXILABI.h:44
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:467
LLVM_ABI bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
Definition Path.cpp:618
constexpr bool IsBigEndianHost
This is an optimization pass for GlobalISel generic memory operations.
ArrayRef< CharT > arrayRefFromStringRef(StringRef Input)
Construct an array ref of bytes from a string ref.
ModulePass * createDXContainerGlobalsPass()
Pass for generating DXContainer part globals.
static constexpr StringLiteral ModuleHashSectionName
Contains module hash.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.compiler.used list.
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
static constexpr StringLiteral PdbFileNameSectionName
Contains PDB output file name.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
std::optional< mcdxbc::SourceInfoBuilder > SourceInfo
Triple::EnvironmentType ShaderProfile
SmallVector< EntryProperties > EntryPropertyVec
LLVM_ABI void write(raw_ostream &OS) const
LLVM_ABI void setFilename(StringRef DebugFilename)
LLVM_ABI void write(raw_ostream &OS) const
dxbc::PSV::v3::RuntimeInfo BaseData
SmallVector< dxbc::PSV::v2::ResourceBindInfo > Resources
LLVM_ABI void finalize(Triple::EnvironmentType Stage, uint32_t Version=std::numeric_limits< uint32_t >::max())
LLVM_ABI void write(raw_ostream &OS, uint32_t Version=std::numeric_limits< uint32_t >::max()) const