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