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"
28#include "llvm/Pass.h"
30#include "llvm/Support/MD5.h"
33#include <cstdint>
34
35using namespace llvm;
36using namespace llvm::dxil;
37using namespace llvm::mcdxbc;
38
39namespace {
40class DXContainerGlobals : public llvm::ModulePass {
41
42 GlobalVariable *buildContainerGlobal(Module &M, Constant *Content,
43 StringRef Name, StringRef SectionName);
45 StringRef SectionData, StringRef MetadataName,
46 StringRef SectionName);
47 GlobalVariable *getFeatureFlags(Module &M);
48 void computeShaderHashAndDebugName(Module &M,
50 GlobalVariable *buildSignature(Module &M, Signature &Sig, StringRef Name,
51 StringRef SectionName);
52 void addSignature(Module &M, SmallVector<GlobalValue *> &Globals);
53 void addRootSignature(Module &M, SmallVector<GlobalValue *> &Globals);
54 void addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV);
55 void addPipelineStateValidationInfo(Module &M,
57 void addCompilerVersion(Module &M, SmallVector<GlobalValue *> &Globals);
58 void addSourceInfo(Module &M, SmallVector<GlobalValue *> &Globals);
59
60public:
61 static char ID; // Pass identification, replacement for typeid
62 DXContainerGlobals() : ModulePass(ID) {}
63
64 StringRef getPassName() const override {
65 return "DXContainer Global Emitter";
66 }
67
68 bool runOnModule(Module &M) override;
69
70 void getAnalysisUsage(AnalysisUsage &AU) const override {
71 AU.setPreservesAll();
72 AU.addRequired<ShaderFlagsAnalysisWrapper>();
73 AU.addRequired<RootSignatureAnalysisWrapper>();
74 AU.addRequired<DXILMetadataAnalysisWrapperPass>();
75 AU.addRequired<DXILResourceTypeWrapperPass>();
76 AU.addRequired<DXILResourceWrapperPass>();
77 }
78};
79
80} // namespace
81
82bool DXContainerGlobals::runOnModule(Module &M) {
84 Globals.push_back(getFeatureFlags(M));
85 computeShaderHashAndDebugName(M, Globals);
86 addSignature(M, Globals);
87 addRootSignature(M, Globals);
88 addPipelineStateValidationInfo(M, Globals);
89 addCompilerVersion(M, Globals);
90 addSourceInfo(M, Globals);
91 appendToCompilerUsed(M, Globals);
92 return true;
93}
94
95GlobalVariable *DXContainerGlobals::getFeatureFlags(Module &M) {
96 uint64_t CombinedFeatureFlags = getAnalysis<ShaderFlagsAnalysisWrapper>()
97 .getShaderFlags()
98 .getCombinedFlags()
99 .getFeatureFlags();
100
101 Constant *FeatureFlagsConstant =
102 ConstantInt::get(M.getContext(), APInt(64, CombinedFeatureFlags));
103 return buildContainerGlobal(M, FeatureFlagsConstant, "dx.sfi0", "SFI0");
104}
105
106void DXContainerGlobals::addSection(Module &M,
108 StringRef SectionData,
109 StringRef MetadataName,
110 StringRef SectionName) {
111 Constant *SectionConstant = ConstantDataArray::getString(
112 M.getContext(), SectionData, /*AddNull*/ false);
113 Globals.emplace_back(
114 buildContainerGlobal(M, SectionConstant, MetadataName, SectionName));
115}
116
117void DXContainerGlobals::computeShaderHashAndDebugName(
118 Module &M, SmallVector<GlobalValue *> &Globals) {
119 // TODO: Add -Zss flag to enable/disable calculating shader hash from ILDB.
120 auto *DXILConstant =
121 cast<ConstantDataArray>(M.getNamedGlobal("dx.dxil")->getInitializer());
122 MD5 Digest;
123 Digest.update(DXILConstant->getRawDataValues());
124 MD5::MD5Result Result = Digest.final();
125 dxbc::ShaderHash HashData = {0, {0}};
126
127 memcpy(reinterpret_cast<void *>(&HashData.Digest), Result.data(), 16);
129 HashData.swapBytes();
130 StringRef Data(reinterpret_cast<char *>(&HashData), sizeof(dxbc::ShaderHash));
131
132 Constant *ModuleConstant =
134 Globals.emplace_back(
135 buildContainerGlobal(M, ModuleConstant, "dx.hash", "HASH"));
136
137 // Emit ILDN part in debug info mode.
138 // DXIL bitcode hash is used, which corresponds to DXC behavior with
139 // `/Zi /Qembed_debug /Zsb` flags.
140 if (M.debug_compile_units().empty())
141 return;
142
143 SmallString<40> DebugNameStr;
144 Digest.stringifyResult(Result, DebugNameStr);
145 DebugNameStr += ".pdb";
146
147 mcdxbc::DebugName DebugName;
148 DebugName.setFilename(DebugNameStr);
149
150 SmallString<64> ILDNData;
151 raw_svector_ostream OS(ILDNData);
152 DebugName.write(OS);
153 addSection(M, Globals, ILDNData, "dx.ildn", "ILDN");
154}
155
156GlobalVariable *DXContainerGlobals::buildContainerGlobal(
157 Module &M, Constant *Content, StringRef Name, StringRef SectionName) {
158 auto *GV = new llvm::GlobalVariable(
159 M, Content->getType(), true, GlobalValue::PrivateLinkage, Content, Name);
160 GV->setSection(SectionName);
161 GV->setAlignment(Align(4));
162 return GV;
163}
164
165GlobalVariable *DXContainerGlobals::buildSignature(Module &M, Signature &Sig,
166 StringRef Name,
167 StringRef SectionName) {
168 SmallString<256> Data;
169 raw_svector_ostream OS(Data);
170 Sig.write(OS);
172 ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
173 return buildContainerGlobal(M, Constant, Name, SectionName);
174}
175
176void DXContainerGlobals::addSignature(Module &M,
178 // FIXME: support graphics shader.
179 // see issue https://github.com/llvm/llvm-project/issues/90504.
180
181 Signature InputSig;
182 Globals.emplace_back(buildSignature(M, InputSig, "dx.isg1", "ISG1"));
183
184 Signature OutputSig;
185 Globals.emplace_back(buildSignature(M, OutputSig, "dx.osg1", "OSG1"));
186}
187
188void DXContainerGlobals::addRootSignature(Module &M,
190
191 dxil::ModuleMetadataInfo &MMI =
192 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
193
194 // Root Signature in Library don't compile to DXContainer.
196 return;
197
198 auto &RSA = getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo();
199 const Function *EntryFunction = nullptr;
200
202 assert(MMI.EntryPropertyVec.size() == 1);
203 EntryFunction = MMI.EntryPropertyVec[0].Entry;
204 }
205
206 const mcdxbc::RootSignatureDesc *RS = RSA.getDescForFunction(EntryFunction);
207 if (!RS)
208 return;
209
210 SmallString<256> Data;
211 raw_svector_ostream OS(Data);
212
213 RS->write(OS);
214
215 addSection(M, Globals, Data, "dx.rts0", "RTS0");
216}
217
218void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) {
219 const DXILResourceMap &DRM =
220 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
221 DXILResourceTypeMap &DRTM =
222 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
223
224 auto MakeBinding =
225 [](const dxil::ResourceInfo::ResourceBinding &Binding,
227 const dxbc::PSV::ResourceFlags Flags = dxbc::PSV::ResourceFlags()) {
228 dxbc::PSV::v2::ResourceBindInfo BindInfo;
229 BindInfo.Type = Type;
230 BindInfo.LowerBound = Binding.LowerBound;
231 assert(
232 (Binding.Size == 0 ||
233 (uint64_t)Binding.LowerBound + Binding.Size - 1 <= UINT32_MAX) &&
234 "Resource range is too large");
235 BindInfo.UpperBound = (Binding.Size == 0)
236 ? UINT32_MAX
237 : Binding.LowerBound + Binding.Size - 1;
238 BindInfo.Space = Binding.Space;
239 BindInfo.Kind = static_cast<dxbc::PSV::ResourceKind>(Kind);
240 BindInfo.Flags = Flags;
241 return BindInfo;
242 };
243
244 for (const dxil::ResourceInfo &RI : DRM.cbuffers()) {
245 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
246 PSV.Resources.push_back(MakeBinding(Binding, dxbc::PSV::ResourceType::CBV,
247 dxil::ResourceKind::CBuffer));
248 }
249 for (const dxil::ResourceInfo &RI : DRM.samplers()) {
250 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
251 PSV.Resources.push_back(MakeBinding(Binding,
252 dxbc::PSV::ResourceType::Sampler,
253 dxil::ResourceKind::Sampler));
254 }
255 for (const dxil::ResourceInfo &RI : DRM.srvs()) {
256 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
257
258 dxil::ResourceTypeInfo &TypeInfo = DRTM[RI.getHandleTy()];
260 if (TypeInfo.isStruct())
261 ResType = dxbc::PSV::ResourceType::SRVStructured;
262 else if (TypeInfo.isTyped())
263 ResType = dxbc::PSV::ResourceType::SRVTyped;
264 else
265 ResType = dxbc::PSV::ResourceType::SRVRaw;
266
267 PSV.Resources.push_back(
268 MakeBinding(Binding, ResType, TypeInfo.getResourceKind()));
269 }
270 for (const dxil::ResourceInfo &RI : DRM.uavs()) {
271 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
272
273 dxil::ResourceTypeInfo &TypeInfo = DRTM[RI.getHandleTy()];
275 if (RI.hasCounter())
276 ResType = dxbc::PSV::ResourceType::UAVStructuredWithCounter;
277 else if (TypeInfo.isStruct())
278 ResType = dxbc::PSV::ResourceType::UAVStructured;
279 else if (TypeInfo.isTyped())
280 ResType = dxbc::PSV::ResourceType::UAVTyped;
281 else
282 ResType = dxbc::PSV::ResourceType::UAVRaw;
283
284 dxbc::PSV::ResourceFlags Flags;
285 // TODO: Add support for dxbc::PSV::ResourceFlag::UsedByAtomic64, tracking
286 // with https://github.com/llvm/llvm-project/issues/104392
287 Flags.Flags = 0u;
288
289 PSV.Resources.push_back(
290 MakeBinding(Binding, ResType, TypeInfo.getResourceKind(), Flags));
291 }
292}
293
294void DXContainerGlobals::addPipelineStateValidationInfo(
295 Module &M, SmallVector<GlobalValue *> &Globals) {
296 SmallString<256> Data;
297 raw_svector_ostream OS(Data);
298 PSVRuntimeInfo PSV;
300 PSV.BaseData.MaximumWaveLaneCount = std::numeric_limits<uint32_t>::max();
301
302 dxil::ModuleMetadataInfo &MMI =
303 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
304 assert(MMI.EntryPropertyVec.size() == 1 ||
308 static_cast<uint8_t>(MMI.ShaderProfile - Triple::Pixel);
309
310 addResourcesForPSV(M, PSV);
311
312 // Hardcoded values here to unblock loading the shader into D3D.
313 //
314 // TODO: Lots more stuff to do here!
315 //
316 // See issue https://github.com/llvm/llvm-project/issues/96674.
317 switch (MMI.ShaderProfile) {
318 case Triple::Compute:
319 PSV.BaseData.NumThreadsX = MMI.EntryPropertyVec[0].NumThreadsX;
320 PSV.BaseData.NumThreadsY = MMI.EntryPropertyVec[0].NumThreadsY;
321 PSV.BaseData.NumThreadsZ = MMI.EntryPropertyVec[0].NumThreadsZ;
322 if (MMI.EntryPropertyVec[0].WaveSizeMin) {
323 PSV.BaseData.MinimumWaveLaneCount = MMI.EntryPropertyVec[0].WaveSizeMin;
325 MMI.EntryPropertyVec[0].WaveSizeMax
326 ? MMI.EntryPropertyVec[0].WaveSizeMax
327 : MMI.EntryPropertyVec[0].WaveSizeMin;
328 }
329 break;
330 default:
331 break;
332 }
333
334 if (MMI.ShaderProfile != Triple::Library &&
336 PSV.EntryName = MMI.EntryPropertyVec[0].Entry->getName();
337
338 PSV.finalize(MMI.ShaderProfile);
339 PSV.write(OS);
340 addSection(M, Globals, Data, "dx.psv0", "PSV0");
341}
342
343void DXContainerGlobals::addCompilerVersion(
344 Module &M, SmallVector<GlobalValue *> &Globals) {
345 if (M.debug_compile_units().empty())
346 return;
347
348 SmallString<256> Data;
349 raw_svector_ostream OS(Data);
350 mcdxbc::CompilerVersion CompilerVersion;
351 CompilerVersion.write(OS);
352 addSection(M, Globals, Data, "dx.vers", "VERS");
353}
354
355void DXContainerGlobals::addSourceInfo(Module &M,
357 dxil::ModuleMetadataInfo &MMI =
358 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
359
360 if (!MMI.SourceInfo)
361 return;
362
363 MMI.SourceInfo->computeEntries();
364 MMI.SourceInfo->finalize();
365 SmallString<256> Data;
366 raw_svector_ostream OS(Data);
367 MMI.SourceInfo->write(OS);
369 ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
370 Globals.emplace_back(buildContainerGlobal(M, Constant, "dx.srci", "SRCI"));
371}
372
373char DXContainerGlobals::ID = 0;
374INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals",
375 "DXContainer Global Emitter", false, true)
380INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals",
381 "DXContainer Global Emitter", false, true)
382
384 return new DXContainerGlobals();
385}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
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:872
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.
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)
@ RootSignature
Definition Triple.h:323
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.
ResourceKind
The kind of resource for an SRV or UAV resource.
Definition DXILABI.h:44
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.compiler.used list.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
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