LLVM 22.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"
27#include "llvm/Pass.h"
28#include "llvm/Support/MD5.h"
31#include <optional>
32
33using namespace llvm;
34using namespace llvm::dxil;
35using namespace llvm::mcdxbc;
36
37namespace {
38class DXContainerGlobals : public llvm::ModulePass {
39
40 GlobalVariable *buildContainerGlobal(Module &M, Constant *Content,
41 StringRef Name, StringRef SectionName);
42 GlobalVariable *getFeatureFlags(Module &M);
43 GlobalVariable *computeShaderHash(Module &M);
44 GlobalVariable *buildSignature(Module &M, Signature &Sig, StringRef Name,
45 StringRef SectionName);
46 void addSignature(Module &M, SmallVector<GlobalValue *> &Globals);
47 void addRootSignature(Module &M, SmallVector<GlobalValue *> &Globals);
48 void addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV);
49 void addPipelineStateValidationInfo(Module &M,
51
52public:
53 static char ID; // Pass identification, replacement for typeid
54 DXContainerGlobals() : ModulePass(ID) {}
55
56 StringRef getPassName() const override {
57 return "DXContainer Global Emitter";
58 }
59
60 bool runOnModule(Module &M) override;
61
62 void getAnalysisUsage(AnalysisUsage &AU) const override {
63 AU.setPreservesAll();
64 AU.addRequired<ShaderFlagsAnalysisWrapper>();
65 AU.addRequired<RootSignatureAnalysisWrapper>();
66 AU.addRequired<DXILMetadataAnalysisWrapperPass>();
67 AU.addRequired<DXILResourceTypeWrapperPass>();
68 AU.addRequired<DXILResourceWrapperPass>();
69 }
70};
71
72} // namespace
73
74bool DXContainerGlobals::runOnModule(Module &M) {
76 Globals.push_back(getFeatureFlags(M));
77 Globals.push_back(computeShaderHash(M));
78 addSignature(M, Globals);
79 addRootSignature(M, Globals);
80 addPipelineStateValidationInfo(M, Globals);
81 appendToCompilerUsed(M, Globals);
82 return true;
83}
84
85GlobalVariable *DXContainerGlobals::getFeatureFlags(Module &M) {
86 uint64_t CombinedFeatureFlags = getAnalysis<ShaderFlagsAnalysisWrapper>()
87 .getShaderFlags()
88 .getCombinedFlags()
89 .getFeatureFlags();
90
91 Constant *FeatureFlagsConstant =
92 ConstantInt::get(M.getContext(), APInt(64, CombinedFeatureFlags));
93 return buildContainerGlobal(M, FeatureFlagsConstant, "dx.sfi0", "SFI0");
94}
95
96GlobalVariable *DXContainerGlobals::computeShaderHash(Module &M) {
97 auto *DXILConstant =
98 cast<ConstantDataArray>(M.getNamedGlobal("dx.dxil")->getInitializer());
99 MD5 Digest;
100 Digest.update(DXILConstant->getRawDataValues());
101 MD5::MD5Result Result = Digest.final();
102
103 dxbc::ShaderHash HashData = {0, {0}};
104 // The Hash's IncludesSource flag gets set whenever the hashed shader includes
105 // debug information.
106 if (!M.debug_compile_units().empty())
107 HashData.Flags = static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
108
109 memcpy(reinterpret_cast<void *>(&HashData.Digest), Result.data(), 16);
111 HashData.swapBytes();
112 StringRef Data(reinterpret_cast<char *>(&HashData), sizeof(dxbc::ShaderHash));
113
114 Constant *ModuleConstant =
116 return buildContainerGlobal(M, ModuleConstant, "dx.hash", "HASH");
117}
118
119GlobalVariable *DXContainerGlobals::buildContainerGlobal(
120 Module &M, Constant *Content, StringRef Name, StringRef SectionName) {
121 auto *GV = new llvm::GlobalVariable(
122 M, Content->getType(), true, GlobalValue::PrivateLinkage, Content, Name);
123 GV->setSection(SectionName);
124 GV->setAlignment(Align(4));
125 return GV;
126}
127
128GlobalVariable *DXContainerGlobals::buildSignature(Module &M, Signature &Sig,
129 StringRef Name,
130 StringRef SectionName) {
131 SmallString<256> Data;
132 raw_svector_ostream OS(Data);
133 Sig.write(OS);
135 ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
136 return buildContainerGlobal(M, Constant, Name, SectionName);
137}
138
139void DXContainerGlobals::addSignature(Module &M,
141 // FIXME: support graphics shader.
142 // see issue https://github.com/llvm/llvm-project/issues/90504.
143
144 Signature InputSig;
145 Globals.emplace_back(buildSignature(M, InputSig, "dx.isg1", "ISG1"));
146
147 Signature OutputSig;
148 Globals.emplace_back(buildSignature(M, OutputSig, "dx.osg1", "OSG1"));
149}
150
151void DXContainerGlobals::addRootSignature(Module &M,
153
154 dxil::ModuleMetadataInfo &MMI =
155 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
156
157 // Root Signature in Library don't compile to DXContainer.
159 return;
160
161 auto &RSA = getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo();
162 const Function *EntryFunction = nullptr;
163
165 assert(MMI.EntryPropertyVec.size() == 1);
166 EntryFunction = MMI.EntryPropertyVec[0].Entry;
167 }
168
169 const mcdxbc::RootSignatureDesc *RS = RSA.getDescForFunction(EntryFunction);
170 if (!RS)
171 return;
172
173 SmallString<256> Data;
174 raw_svector_ostream OS(Data);
175
176 RS->write(OS);
177
179 ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
180 Globals.emplace_back(buildContainerGlobal(M, Constant, "dx.rts0", "RTS0"));
181}
182
183void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) {
184 const DXILResourceMap &DRM =
185 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
186 DXILResourceTypeMap &DRTM =
187 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
188
189 auto MakeBinding =
190 [](const dxil::ResourceInfo::ResourceBinding &Binding,
192 const dxbc::PSV::ResourceFlags Flags = dxbc::PSV::ResourceFlags()) {
193 dxbc::PSV::v2::ResourceBindInfo BindInfo;
194 BindInfo.Type = Type;
195 BindInfo.LowerBound = Binding.LowerBound;
196 BindInfo.UpperBound = Binding.LowerBound + Binding.Size - 1;
197 BindInfo.Space = Binding.Space;
198 BindInfo.Kind = static_cast<dxbc::PSV::ResourceKind>(Kind);
199 BindInfo.Flags = Flags;
200 return BindInfo;
201 };
202
203 for (const dxil::ResourceInfo &RI : DRM.cbuffers()) {
204 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
205 PSV.Resources.push_back(MakeBinding(Binding, dxbc::PSV::ResourceType::CBV,
206 dxil::ResourceKind::CBuffer));
207 }
208 for (const dxil::ResourceInfo &RI : DRM.samplers()) {
209 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
210 PSV.Resources.push_back(MakeBinding(Binding,
211 dxbc::PSV::ResourceType::Sampler,
212 dxil::ResourceKind::Sampler));
213 }
214 for (const dxil::ResourceInfo &RI : DRM.srvs()) {
215 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
216
217 dxil::ResourceTypeInfo &TypeInfo = DRTM[RI.getHandleTy()];
219 if (TypeInfo.isStruct())
220 ResType = dxbc::PSV::ResourceType::SRVStructured;
221 else if (TypeInfo.isTyped())
222 ResType = dxbc::PSV::ResourceType::SRVTyped;
223 else
224 ResType = dxbc::PSV::ResourceType::SRVRaw;
225
226 PSV.Resources.push_back(
227 MakeBinding(Binding, ResType, TypeInfo.getResourceKind()));
228 }
229 for (const dxil::ResourceInfo &RI : DRM.uavs()) {
230 const dxil::ResourceInfo::ResourceBinding &Binding = RI.getBinding();
231
232 dxil::ResourceTypeInfo &TypeInfo = DRTM[RI.getHandleTy()];
234 if (RI.hasCounter())
235 ResType = dxbc::PSV::ResourceType::UAVStructuredWithCounter;
236 else if (TypeInfo.isStruct())
237 ResType = dxbc::PSV::ResourceType::UAVStructured;
238 else if (TypeInfo.isTyped())
239 ResType = dxbc::PSV::ResourceType::UAVTyped;
240 else
241 ResType = dxbc::PSV::ResourceType::UAVRaw;
242
243 dxbc::PSV::ResourceFlags Flags;
244 // TODO: Add support for dxbc::PSV::ResourceFlag::UsedByAtomic64, tracking
245 // with https://github.com/llvm/llvm-project/issues/104392
246 Flags.Flags = 0u;
247
248 PSV.Resources.push_back(
249 MakeBinding(Binding, ResType, TypeInfo.getResourceKind(), Flags));
250 }
251}
252
253void DXContainerGlobals::addPipelineStateValidationInfo(
254 Module &M, SmallVector<GlobalValue *> &Globals) {
255 SmallString<256> Data;
256 raw_svector_ostream OS(Data);
257 PSVRuntimeInfo PSV;
259 PSV.BaseData.MaximumWaveLaneCount = std::numeric_limits<uint32_t>::max();
260
261 dxil::ModuleMetadataInfo &MMI =
262 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
263 assert(MMI.EntryPropertyVec.size() == 1 ||
267 static_cast<uint8_t>(MMI.ShaderProfile - Triple::Pixel);
268
269 addResourcesForPSV(M, PSV);
270
271 // Hardcoded values here to unblock loading the shader into D3D.
272 //
273 // TODO: Lots more stuff to do here!
274 //
275 // See issue https://github.com/llvm/llvm-project/issues/96674.
276 switch (MMI.ShaderProfile) {
277 case Triple::Compute:
278 PSV.BaseData.NumThreadsX = MMI.EntryPropertyVec[0].NumThreadsX;
279 PSV.BaseData.NumThreadsY = MMI.EntryPropertyVec[0].NumThreadsY;
280 PSV.BaseData.NumThreadsZ = MMI.EntryPropertyVec[0].NumThreadsZ;
281 break;
282 default:
283 break;
284 }
285
286 if (MMI.ShaderProfile != Triple::Library &&
288 PSV.EntryName = MMI.EntryPropertyVec[0].Entry->getName();
289
290 PSV.finalize(MMI.ShaderProfile);
291 PSV.write(OS);
293 ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
294 Globals.emplace_back(buildContainerGlobal(M, Constant, "dx.psv0", "PSV0"));
295}
296
297char DXContainerGlobals::ID = 0;
298INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals",
299 "DXContainer Global Emitter", false, true)
304INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals",
305 "DXContainer Global Emitter", false, true)
306
308 return new DXContainerGlobals();
309}
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.
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 LLVM_ABI Constant * getString(LLVMContext &Context, StringRef Initializer, bool AddNull=true)
This method constructs a CDS and initializes it with a text string.
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:715
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:189
LLVM_ABI void final(MD5Result &Result)
Finishes off the hash and puts the result in result.
Definition MD5.cpp:234
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:308
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
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:36
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:189
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:565
Triple::EnvironmentType ShaderProfile
SmallVector< EntryProperties > EntryPropertyVec
dxbc::PSV::v3::RuntimeInfo BaseData
SmallVector< dxbc::PSV::v2::ResourceBindInfo > Resources
void finalize(Triple::EnvironmentType Stage)
void write(raw_ostream &OS, uint32_t Version=std::numeric_limits< uint32_t >::max()) const
LLVM_ABI void write(raw_ostream &OS) const