xref: /llvm-project/llvm/lib/Target/DirectX/DXContainerGlobals.cpp (revision 3eca15cbb9888a992749ddd24f0fb666dad733bf)
16e05c8dfSChris Bieneman //===- DXContainerGlobals.cpp - DXContainer global generator pass ---------===//
26e05c8dfSChris Bieneman //
36e05c8dfSChris Bieneman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46e05c8dfSChris Bieneman // See https://llvm.org/LICENSE.txt for license information.
56e05c8dfSChris Bieneman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66e05c8dfSChris Bieneman //
76e05c8dfSChris Bieneman //===----------------------------------------------------------------------===//
86e05c8dfSChris Bieneman //
96e05c8dfSChris Bieneman // DXContainerGlobalsPass implementation.
106e05c8dfSChris Bieneman //
116e05c8dfSChris Bieneman //===----------------------------------------------------------------------===//
126e05c8dfSChris Bieneman 
136e05c8dfSChris Bieneman #include "DXILShaderFlags.h"
146e05c8dfSChris Bieneman #include "DirectX.h"
157d17114cSFangrui Song #include "llvm/ADT/SmallVector.h"
16a48f32d2SFangrui Song #include "llvm/ADT/StringExtras.h"
176e05c8dfSChris Bieneman #include "llvm/ADT/StringRef.h"
18eb2929d3SXiang Li #include "llvm/Analysis/DXILMetadataAnalysis.h"
19981bb9dcSXiang Li #include "llvm/Analysis/DXILResource.h"
20c861ea87SChris Bieneman #include "llvm/BinaryFormat/DXContainer.h"
216e05c8dfSChris Bieneman #include "llvm/CodeGen/Passes.h"
226e05c8dfSChris Bieneman #include "llvm/IR/Constants.h"
237d17114cSFangrui Song #include "llvm/IR/Module.h"
246e05c8dfSChris Bieneman #include "llvm/InitializePasses.h"
25a764f49bSXiang Li #include "llvm/MC/DXContainerPSVInfo.h"
266e05c8dfSChris Bieneman #include "llvm/Pass.h"
27c861ea87SChris Bieneman #include "llvm/Support/MD5.h"
286e05c8dfSChris Bieneman #include "llvm/Transforms/Utils/ModuleUtils.h"
296e05c8dfSChris Bieneman 
306e05c8dfSChris Bieneman using namespace llvm;
316e05c8dfSChris Bieneman using namespace llvm::dxil;
32a764f49bSXiang Li using namespace llvm::mcdxbc;
336e05c8dfSChris Bieneman 
346e05c8dfSChris Bieneman namespace {
356e05c8dfSChris Bieneman class DXContainerGlobals : public llvm::ModulePass {
366e05c8dfSChris Bieneman 
37a764f49bSXiang Li   GlobalVariable *buildContainerGlobal(Module &M, Constant *Content,
38a764f49bSXiang Li                                        StringRef Name, StringRef SectionName);
394dc03701SXiang Li   GlobalVariable *getFeatureFlags(Module &M);
40c861ea87SChris Bieneman   GlobalVariable *computeShaderHash(Module &M);
41a764f49bSXiang Li   GlobalVariable *buildSignature(Module &M, Signature &Sig, StringRef Name,
42a764f49bSXiang Li                                  StringRef SectionName);
43a764f49bSXiang Li   void addSignature(Module &M, SmallVector<GlobalValue *> &Globals);
44981bb9dcSXiang Li   void addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV);
45141bea8cSDamyan Pepper   void addPipelineStateValidationInfo(Module &M,
46141bea8cSDamyan Pepper                                       SmallVector<GlobalValue *> &Globals);
47c861ea87SChris Bieneman 
486e05c8dfSChris Bieneman public:
496e05c8dfSChris Bieneman   static char ID; // Pass identification, replacement for typeid
506e05c8dfSChris Bieneman   DXContainerGlobals() : ModulePass(ID) {
516e05c8dfSChris Bieneman     initializeDXContainerGlobalsPass(*PassRegistry::getPassRegistry());
526e05c8dfSChris Bieneman   }
536e05c8dfSChris Bieneman 
546e05c8dfSChris Bieneman   StringRef getPassName() const override {
556e05c8dfSChris Bieneman     return "DXContainer Global Emitter";
566e05c8dfSChris Bieneman   }
576e05c8dfSChris Bieneman 
586e05c8dfSChris Bieneman   bool runOnModule(Module &M) override;
596e05c8dfSChris Bieneman 
606e05c8dfSChris Bieneman   void getAnalysisUsage(AnalysisUsage &AU) const override {
616e05c8dfSChris Bieneman     AU.setPreservesAll();
626e05c8dfSChris Bieneman     AU.addRequired<ShaderFlagsAnalysisWrapper>();
63eb2929d3SXiang Li     AU.addRequired<DXILMetadataAnalysisWrapperPass>();
64*3eca15cbSJustin Bogner     AU.addRequired<DXILResourceTypeWrapperPass>();
65*3eca15cbSJustin Bogner     AU.addRequired<DXILResourceBindingWrapperPass>();
666e05c8dfSChris Bieneman   }
676e05c8dfSChris Bieneman };
686e05c8dfSChris Bieneman 
696e05c8dfSChris Bieneman } // namespace
706e05c8dfSChris Bieneman 
716e05c8dfSChris Bieneman bool DXContainerGlobals::runOnModule(Module &M) {
72c861ea87SChris Bieneman   llvm::SmallVector<GlobalValue *> Globals;
734dc03701SXiang Li   Globals.push_back(getFeatureFlags(M));
74c861ea87SChris Bieneman   Globals.push_back(computeShaderHash(M));
75a764f49bSXiang Li   addSignature(M, Globals);
76141bea8cSDamyan Pepper   addPipelineStateValidationInfo(M, Globals);
77c861ea87SChris Bieneman   appendToCompilerUsed(M, Globals);
78c861ea87SChris Bieneman   return true;
79c861ea87SChris Bieneman }
80c861ea87SChris Bieneman 
814dc03701SXiang Li GlobalVariable *DXContainerGlobals::getFeatureFlags(Module &M) {
8296547decSS. Bharadwaj Yadavalli   uint64_t CombinedFeatureFlags = getAnalysis<ShaderFlagsAnalysisWrapper>()
834dc03701SXiang Li                                       .getShaderFlags()
8496547decSS. Bharadwaj Yadavalli                                       .getCombinedFlags()
8596547decSS. Bharadwaj Yadavalli                                       .getFeatureFlags();
866e05c8dfSChris Bieneman 
874dc03701SXiang Li   Constant *FeatureFlagsConstant =
8896547decSS. Bharadwaj Yadavalli       ConstantInt::get(M.getContext(), APInt(64, CombinedFeatureFlags));
89a764f49bSXiang Li   return buildContainerGlobal(M, FeatureFlagsConstant, "dx.sfi0", "SFI0");
90c861ea87SChris Bieneman }
91c861ea87SChris Bieneman 
92c861ea87SChris Bieneman GlobalVariable *DXContainerGlobals::computeShaderHash(Module &M) {
93c861ea87SChris Bieneman   auto *DXILConstant =
94c861ea87SChris Bieneman       cast<ConstantDataArray>(M.getNamedGlobal("dx.dxil")->getInitializer());
95c861ea87SChris Bieneman   MD5 Digest;
96c861ea87SChris Bieneman   Digest.update(DXILConstant->getRawDataValues());
97c861ea87SChris Bieneman   MD5::MD5Result Result = Digest.final();
98c861ea87SChris Bieneman 
99c861ea87SChris Bieneman   dxbc::ShaderHash HashData = {0, {0}};
100c861ea87SChris Bieneman   // The Hash's IncludesSource flag gets set whenever the hashed shader includes
101c861ea87SChris Bieneman   // debug information.
102c861ea87SChris Bieneman   if (M.debug_compile_units_begin() != M.debug_compile_units_end())
103c861ea87SChris Bieneman     HashData.Flags = static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
104c861ea87SChris Bieneman 
105c861ea87SChris Bieneman   memcpy(reinterpret_cast<void *>(&HashData.Digest), Result.data(), 16);
106c861ea87SChris Bieneman   if (sys::IsBigEndianHost)
107c861ea87SChris Bieneman     HashData.swapBytes();
108c861ea87SChris Bieneman   StringRef Data(reinterpret_cast<char *>(&HashData), sizeof(dxbc::ShaderHash));
109c861ea87SChris Bieneman 
110c861ea87SChris Bieneman   Constant *ModuleConstant =
111c861ea87SChris Bieneman       ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data));
112a764f49bSXiang Li   return buildContainerGlobal(M, ModuleConstant, "dx.hash", "HASH");
113a764f49bSXiang Li }
114a764f49bSXiang Li 
115a764f49bSXiang Li GlobalVariable *DXContainerGlobals::buildContainerGlobal(
116a764f49bSXiang Li     Module &M, Constant *Content, StringRef Name, StringRef SectionName) {
117a764f49bSXiang Li   auto *GV = new llvm::GlobalVariable(
118a764f49bSXiang Li       M, Content->getType(), true, GlobalValue::PrivateLinkage, Content, Name);
119a764f49bSXiang Li   GV->setSection(SectionName);
120c861ea87SChris Bieneman   GV->setAlignment(Align(4));
121c861ea87SChris Bieneman   return GV;
1226e05c8dfSChris Bieneman }
1236e05c8dfSChris Bieneman 
124a764f49bSXiang Li GlobalVariable *DXContainerGlobals::buildSignature(Module &M, Signature &Sig,
125a764f49bSXiang Li                                                    StringRef Name,
126a764f49bSXiang Li                                                    StringRef SectionName) {
127a764f49bSXiang Li   SmallString<256> Data;
128a764f49bSXiang Li   raw_svector_ostream OS(Data);
129a764f49bSXiang Li   Sig.write(OS);
130a764f49bSXiang Li   Constant *Constant =
131a764f49bSXiang Li       ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
132a764f49bSXiang Li   return buildContainerGlobal(M, Constant, Name, SectionName);
133a764f49bSXiang Li }
134a764f49bSXiang Li 
135a764f49bSXiang Li void DXContainerGlobals::addSignature(Module &M,
136a764f49bSXiang Li                                       SmallVector<GlobalValue *> &Globals) {
137a764f49bSXiang Li   // FIXME: support graphics shader.
138a764f49bSXiang Li   //  see issue https://github.com/llvm/llvm-project/issues/90504.
139a764f49bSXiang Li 
140a764f49bSXiang Li   Signature InputSig;
141a764f49bSXiang Li   Globals.emplace_back(buildSignature(M, InputSig, "dx.isg1", "ISG1"));
142a764f49bSXiang Li 
143a764f49bSXiang Li   Signature OutputSig;
144a764f49bSXiang Li   Globals.emplace_back(buildSignature(M, OutputSig, "dx.osg1", "OSG1"));
145a764f49bSXiang Li }
146a764f49bSXiang Li 
147981bb9dcSXiang Li void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) {
148*3eca15cbSJustin Bogner   const DXILBindingMap &DBM =
149*3eca15cbSJustin Bogner       getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap();
150*3eca15cbSJustin Bogner   DXILResourceTypeMap &DRTM =
151*3eca15cbSJustin Bogner       getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
152981bb9dcSXiang Li 
153*3eca15cbSJustin Bogner   for (const dxil::ResourceBindingInfo &RBI : DBM) {
154*3eca15cbSJustin Bogner     const dxil::ResourceBindingInfo::ResourceBinding &Binding =
155*3eca15cbSJustin Bogner         RBI.getBinding();
156981bb9dcSXiang Li     dxbc::PSV::v2::ResourceBindInfo BindInfo;
157981bb9dcSXiang Li     BindInfo.LowerBound = Binding.LowerBound;
158981bb9dcSXiang Li     BindInfo.UpperBound = Binding.LowerBound + Binding.Size - 1;
159981bb9dcSXiang Li     BindInfo.Space = Binding.Space;
160981bb9dcSXiang Li 
161*3eca15cbSJustin Bogner     dxil::ResourceTypeInfo &TypeInfo = DRTM[RBI.getHandleTy()];
162981bb9dcSXiang Li     dxbc::PSV::ResourceType ResType = dxbc::PSV::ResourceType::Invalid;
163*3eca15cbSJustin Bogner     bool IsUAV = TypeInfo.getResourceClass() == dxil::ResourceClass::UAV;
164*3eca15cbSJustin Bogner     switch (TypeInfo.getResourceKind()) {
165981bb9dcSXiang Li     case dxil::ResourceKind::Sampler:
166981bb9dcSXiang Li       ResType = dxbc::PSV::ResourceType::Sampler;
167981bb9dcSXiang Li       break;
168981bb9dcSXiang Li     case dxil::ResourceKind::CBuffer:
169981bb9dcSXiang Li       ResType = dxbc::PSV::ResourceType::CBV;
170981bb9dcSXiang Li       break;
171981bb9dcSXiang Li     case dxil::ResourceKind::StructuredBuffer:
172981bb9dcSXiang Li       ResType = IsUAV ? dxbc::PSV::ResourceType::UAVStructured
173981bb9dcSXiang Li                       : dxbc::PSV::ResourceType::SRVStructured;
174*3eca15cbSJustin Bogner       if (IsUAV && TypeInfo.getUAV().HasCounter)
175981bb9dcSXiang Li         ResType = dxbc::PSV::ResourceType::UAVStructuredWithCounter;
176981bb9dcSXiang Li       break;
177981bb9dcSXiang Li     case dxil::ResourceKind::RTAccelerationStructure:
178981bb9dcSXiang Li       ResType = dxbc::PSV::ResourceType::SRVRaw;
179981bb9dcSXiang Li       break;
180981bb9dcSXiang Li     case dxil::ResourceKind::RawBuffer:
181981bb9dcSXiang Li       ResType = IsUAV ? dxbc::PSV::ResourceType::UAVRaw
182981bb9dcSXiang Li                       : dxbc::PSV::ResourceType::SRVRaw;
183981bb9dcSXiang Li       break;
184981bb9dcSXiang Li     default:
185981bb9dcSXiang Li       ResType = IsUAV ? dxbc::PSV::ResourceType::UAVTyped
186981bb9dcSXiang Li                       : dxbc::PSV::ResourceType::SRVTyped;
187981bb9dcSXiang Li       break;
188981bb9dcSXiang Li     }
189981bb9dcSXiang Li     BindInfo.Type = ResType;
190981bb9dcSXiang Li 
191981bb9dcSXiang Li     BindInfo.Kind =
192*3eca15cbSJustin Bogner         static_cast<dxbc::PSV::ResourceKind>(TypeInfo.getResourceKind());
193981bb9dcSXiang Li     // TODO: Add support for dxbc::PSV::ResourceFlag::UsedByAtomic64, tracking
194981bb9dcSXiang Li     // with https://github.com/llvm/llvm-project/issues/104392
195981bb9dcSXiang Li     BindInfo.Flags.Flags = 0u;
196981bb9dcSXiang Li 
197981bb9dcSXiang Li     PSV.Resources.emplace_back(BindInfo);
198981bb9dcSXiang Li   }
199981bb9dcSXiang Li }
200981bb9dcSXiang Li 
201141bea8cSDamyan Pepper void DXContainerGlobals::addPipelineStateValidationInfo(
202141bea8cSDamyan Pepper     Module &M, SmallVector<GlobalValue *> &Globals) {
203141bea8cSDamyan Pepper   SmallString<256> Data;
204141bea8cSDamyan Pepper   raw_svector_ostream OS(Data);
205141bea8cSDamyan Pepper   PSVRuntimeInfo PSV;
206141bea8cSDamyan Pepper   PSV.BaseData.MinimumWaveLaneCount = 0;
207141bea8cSDamyan Pepper   PSV.BaseData.MaximumWaveLaneCount = std::numeric_limits<uint32_t>::max();
208eb2929d3SXiang Li 
209eb2929d3SXiang Li   dxil::ModuleMetadataInfo &MMI =
210eb2929d3SXiang Li       getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
211eb2929d3SXiang Li   assert(MMI.EntryPropertyVec.size() == 1 ||
2123734fa8cSS. Bharadwaj Yadavalli          MMI.ShaderProfile == Triple::Library);
213141bea8cSDamyan Pepper   PSV.BaseData.ShaderStage =
2143734fa8cSS. Bharadwaj Yadavalli       static_cast<uint8_t>(MMI.ShaderProfile - Triple::Pixel);
215141bea8cSDamyan Pepper 
216981bb9dcSXiang Li   addResourcesForPSV(M, PSV);
217981bb9dcSXiang Li 
218141bea8cSDamyan Pepper   // Hardcoded values here to unblock loading the shader into D3D.
219141bea8cSDamyan Pepper   //
220141bea8cSDamyan Pepper   // TODO: Lots more stuff to do here!
221141bea8cSDamyan Pepper   //
222141bea8cSDamyan Pepper   // See issue https://github.com/llvm/llvm-project/issues/96674.
2233734fa8cSS. Bharadwaj Yadavalli   switch (MMI.ShaderProfile) {
224eb2929d3SXiang Li   case Triple::Compute:
225eb2929d3SXiang Li     PSV.BaseData.NumThreadsX = MMI.EntryPropertyVec[0].NumThreadsX;
226eb2929d3SXiang Li     PSV.BaseData.NumThreadsY = MMI.EntryPropertyVec[0].NumThreadsY;
227eb2929d3SXiang Li     PSV.BaseData.NumThreadsZ = MMI.EntryPropertyVec[0].NumThreadsZ;
228eb2929d3SXiang Li     break;
229eb2929d3SXiang Li   default:
230eb2929d3SXiang Li     break;
231eb2929d3SXiang Li   }
232141bea8cSDamyan Pepper 
2333734fa8cSS. Bharadwaj Yadavalli   if (MMI.ShaderProfile != Triple::Library)
234eb2929d3SXiang Li     PSV.EntryName = MMI.EntryPropertyVec[0].Entry->getName();
235eb2929d3SXiang Li 
2363734fa8cSS. Bharadwaj Yadavalli   PSV.finalize(MMI.ShaderProfile);
237141bea8cSDamyan Pepper   PSV.write(OS);
238141bea8cSDamyan Pepper   Constant *Constant =
239141bea8cSDamyan Pepper       ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
240141bea8cSDamyan Pepper   Globals.emplace_back(buildContainerGlobal(M, Constant, "dx.psv0", "PSV0"));
241141bea8cSDamyan Pepper }
242141bea8cSDamyan Pepper 
2436e05c8dfSChris Bieneman char DXContainerGlobals::ID = 0;
2446e05c8dfSChris Bieneman INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals",
2456e05c8dfSChris Bieneman                       "DXContainer Global Emitter", false, true)
2466e05c8dfSChris Bieneman INITIALIZE_PASS_DEPENDENCY(ShaderFlagsAnalysisWrapper)
247eb2929d3SXiang Li INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass)
248*3eca15cbSJustin Bogner INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
249*3eca15cbSJustin Bogner INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
2506e05c8dfSChris Bieneman INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals",
2516e05c8dfSChris Bieneman                     "DXContainer Global Emitter", false, true)
2526e05c8dfSChris Bieneman 
2536e05c8dfSChris Bieneman ModulePass *llvm::createDXContainerGlobalsPass() {
2546e05c8dfSChris Bieneman   return new DXContainerGlobals();
2556e05c8dfSChris Bieneman }
256