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