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