1bdd1243dSDimitry Andric //===- DXContainerGlobals.cpp - DXContainer global generator pass ---------===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric // 9bdd1243dSDimitry Andric // DXContainerGlobalsPass implementation. 10bdd1243dSDimitry Andric // 11bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 12bdd1243dSDimitry Andric 13bdd1243dSDimitry Andric #include "DXILShaderFlags.h" 14bdd1243dSDimitry Andric #include "DirectX.h" 15*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h" 1606c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h" 17bdd1243dSDimitry Andric #include "llvm/ADT/StringRef.h" 18bdd1243dSDimitry Andric #include "llvm/BinaryFormat/DXContainer.h" 19bdd1243dSDimitry Andric #include "llvm/CodeGen/Passes.h" 20bdd1243dSDimitry Andric #include "llvm/IR/Constants.h" 21*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 22bdd1243dSDimitry Andric #include "llvm/InitializePasses.h" 23*0fca6ea1SDimitry Andric #include "llvm/MC/DXContainerPSVInfo.h" 24bdd1243dSDimitry Andric #include "llvm/Pass.h" 25bdd1243dSDimitry Andric #include "llvm/Support/MD5.h" 26bdd1243dSDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h" 27bdd1243dSDimitry Andric 28bdd1243dSDimitry Andric using namespace llvm; 29bdd1243dSDimitry Andric using namespace llvm::dxil; 30*0fca6ea1SDimitry Andric using namespace llvm::mcdxbc; 31bdd1243dSDimitry Andric 32bdd1243dSDimitry Andric namespace { 33bdd1243dSDimitry Andric class DXContainerGlobals : public llvm::ModulePass { 34bdd1243dSDimitry Andric 35*0fca6ea1SDimitry Andric GlobalVariable *buildContainerGlobal(Module &M, Constant *Content, 36*0fca6ea1SDimitry Andric StringRef Name, StringRef SectionName); 37*0fca6ea1SDimitry Andric GlobalVariable *getFeatureFlags(Module &M); 38bdd1243dSDimitry Andric GlobalVariable *computeShaderHash(Module &M); 39*0fca6ea1SDimitry Andric GlobalVariable *buildSignature(Module &M, Signature &Sig, StringRef Name, 40*0fca6ea1SDimitry Andric StringRef SectionName); 41*0fca6ea1SDimitry Andric void addSignature(Module &M, SmallVector<GlobalValue *> &Globals); 42*0fca6ea1SDimitry Andric void addPipelineStateValidationInfo(Module &M, 43*0fca6ea1SDimitry Andric SmallVector<GlobalValue *> &Globals); 44bdd1243dSDimitry Andric 45bdd1243dSDimitry Andric public: 46bdd1243dSDimitry Andric static char ID; // Pass identification, replacement for typeid 47bdd1243dSDimitry Andric DXContainerGlobals() : ModulePass(ID) { 48bdd1243dSDimitry Andric initializeDXContainerGlobalsPass(*PassRegistry::getPassRegistry()); 49bdd1243dSDimitry Andric } 50bdd1243dSDimitry Andric 51bdd1243dSDimitry Andric StringRef getPassName() const override { 52bdd1243dSDimitry Andric return "DXContainer Global Emitter"; 53bdd1243dSDimitry Andric } 54bdd1243dSDimitry Andric 55bdd1243dSDimitry Andric bool runOnModule(Module &M) override; 56bdd1243dSDimitry Andric 57bdd1243dSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 58bdd1243dSDimitry Andric AU.setPreservesAll(); 59bdd1243dSDimitry Andric AU.addRequired<ShaderFlagsAnalysisWrapper>(); 60bdd1243dSDimitry Andric } 61bdd1243dSDimitry Andric }; 62bdd1243dSDimitry Andric 63bdd1243dSDimitry Andric } // namespace 64bdd1243dSDimitry Andric 65bdd1243dSDimitry Andric bool DXContainerGlobals::runOnModule(Module &M) { 66bdd1243dSDimitry Andric llvm::SmallVector<GlobalValue *> Globals; 67*0fca6ea1SDimitry Andric Globals.push_back(getFeatureFlags(M)); 68bdd1243dSDimitry Andric Globals.push_back(computeShaderHash(M)); 69*0fca6ea1SDimitry Andric addSignature(M, Globals); 70*0fca6ea1SDimitry Andric addPipelineStateValidationInfo(M, Globals); 71bdd1243dSDimitry Andric appendToCompilerUsed(M, Globals); 72bdd1243dSDimitry Andric return true; 73bdd1243dSDimitry Andric } 74bdd1243dSDimitry Andric 75*0fca6ea1SDimitry Andric GlobalVariable *DXContainerGlobals::getFeatureFlags(Module &M) { 76*0fca6ea1SDimitry Andric const uint64_t FeatureFlags = 77*0fca6ea1SDimitry Andric static_cast<uint64_t>(getAnalysis<ShaderFlagsAnalysisWrapper>() 78*0fca6ea1SDimitry Andric .getShaderFlags() 79*0fca6ea1SDimitry Andric .getFeatureFlags()); 80bdd1243dSDimitry Andric 81*0fca6ea1SDimitry Andric Constant *FeatureFlagsConstant = 82*0fca6ea1SDimitry Andric ConstantInt::get(M.getContext(), APInt(64, FeatureFlags)); 83*0fca6ea1SDimitry Andric return buildContainerGlobal(M, FeatureFlagsConstant, "dx.sfi0", "SFI0"); 84bdd1243dSDimitry Andric } 85bdd1243dSDimitry Andric 86bdd1243dSDimitry Andric GlobalVariable *DXContainerGlobals::computeShaderHash(Module &M) { 87bdd1243dSDimitry Andric auto *DXILConstant = 88bdd1243dSDimitry Andric cast<ConstantDataArray>(M.getNamedGlobal("dx.dxil")->getInitializer()); 89bdd1243dSDimitry Andric MD5 Digest; 90bdd1243dSDimitry Andric Digest.update(DXILConstant->getRawDataValues()); 91bdd1243dSDimitry Andric MD5::MD5Result Result = Digest.final(); 92bdd1243dSDimitry Andric 93bdd1243dSDimitry Andric dxbc::ShaderHash HashData = {0, {0}}; 94bdd1243dSDimitry Andric // The Hash's IncludesSource flag gets set whenever the hashed shader includes 95bdd1243dSDimitry Andric // debug information. 96bdd1243dSDimitry Andric if (M.debug_compile_units_begin() != M.debug_compile_units_end()) 97bdd1243dSDimitry Andric HashData.Flags = static_cast<uint32_t>(dxbc::HashFlags::IncludesSource); 98bdd1243dSDimitry Andric 99bdd1243dSDimitry Andric memcpy(reinterpret_cast<void *>(&HashData.Digest), Result.data(), 16); 100bdd1243dSDimitry Andric if (sys::IsBigEndianHost) 101bdd1243dSDimitry Andric HashData.swapBytes(); 102bdd1243dSDimitry Andric StringRef Data(reinterpret_cast<char *>(&HashData), sizeof(dxbc::ShaderHash)); 103bdd1243dSDimitry Andric 104bdd1243dSDimitry Andric Constant *ModuleConstant = 105bdd1243dSDimitry Andric ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data)); 106*0fca6ea1SDimitry Andric return buildContainerGlobal(M, ModuleConstant, "dx.hash", "HASH"); 107*0fca6ea1SDimitry Andric } 108*0fca6ea1SDimitry Andric 109*0fca6ea1SDimitry Andric GlobalVariable *DXContainerGlobals::buildContainerGlobal( 110*0fca6ea1SDimitry Andric Module &M, Constant *Content, StringRef Name, StringRef SectionName) { 111*0fca6ea1SDimitry Andric auto *GV = new llvm::GlobalVariable( 112*0fca6ea1SDimitry Andric M, Content->getType(), true, GlobalValue::PrivateLinkage, Content, Name); 113*0fca6ea1SDimitry Andric GV->setSection(SectionName); 114bdd1243dSDimitry Andric GV->setAlignment(Align(4)); 115bdd1243dSDimitry Andric return GV; 116bdd1243dSDimitry Andric } 117bdd1243dSDimitry Andric 118*0fca6ea1SDimitry Andric GlobalVariable *DXContainerGlobals::buildSignature(Module &M, Signature &Sig, 119*0fca6ea1SDimitry Andric StringRef Name, 120*0fca6ea1SDimitry Andric StringRef SectionName) { 121*0fca6ea1SDimitry Andric SmallString<256> Data; 122*0fca6ea1SDimitry Andric raw_svector_ostream OS(Data); 123*0fca6ea1SDimitry Andric Sig.write(OS); 124*0fca6ea1SDimitry Andric Constant *Constant = 125*0fca6ea1SDimitry Andric ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false); 126*0fca6ea1SDimitry Andric return buildContainerGlobal(M, Constant, Name, SectionName); 127*0fca6ea1SDimitry Andric } 128*0fca6ea1SDimitry Andric 129*0fca6ea1SDimitry Andric void DXContainerGlobals::addSignature(Module &M, 130*0fca6ea1SDimitry Andric SmallVector<GlobalValue *> &Globals) { 131*0fca6ea1SDimitry Andric // FIXME: support graphics shader. 132*0fca6ea1SDimitry Andric // see issue https://github.com/llvm/llvm-project/issues/90504. 133*0fca6ea1SDimitry Andric 134*0fca6ea1SDimitry Andric Signature InputSig; 135*0fca6ea1SDimitry Andric Globals.emplace_back(buildSignature(M, InputSig, "dx.isg1", "ISG1")); 136*0fca6ea1SDimitry Andric 137*0fca6ea1SDimitry Andric Signature OutputSig; 138*0fca6ea1SDimitry Andric Globals.emplace_back(buildSignature(M, OutputSig, "dx.osg1", "OSG1")); 139*0fca6ea1SDimitry Andric } 140*0fca6ea1SDimitry Andric 141*0fca6ea1SDimitry Andric void DXContainerGlobals::addPipelineStateValidationInfo( 142*0fca6ea1SDimitry Andric Module &M, SmallVector<GlobalValue *> &Globals) { 143*0fca6ea1SDimitry Andric SmallString<256> Data; 144*0fca6ea1SDimitry Andric raw_svector_ostream OS(Data); 145*0fca6ea1SDimitry Andric PSVRuntimeInfo PSV; 146*0fca6ea1SDimitry Andric Triple TT(M.getTargetTriple()); 147*0fca6ea1SDimitry Andric PSV.BaseData.MinimumWaveLaneCount = 0; 148*0fca6ea1SDimitry Andric PSV.BaseData.MaximumWaveLaneCount = std::numeric_limits<uint32_t>::max(); 149*0fca6ea1SDimitry Andric PSV.BaseData.ShaderStage = 150*0fca6ea1SDimitry Andric static_cast<uint8_t>(TT.getEnvironment() - Triple::Pixel); 151*0fca6ea1SDimitry Andric 152*0fca6ea1SDimitry Andric // Hardcoded values here to unblock loading the shader into D3D. 153*0fca6ea1SDimitry Andric // 154*0fca6ea1SDimitry Andric // TODO: Lots more stuff to do here! 155*0fca6ea1SDimitry Andric // 156*0fca6ea1SDimitry Andric // See issue https://github.com/llvm/llvm-project/issues/96674. 157*0fca6ea1SDimitry Andric PSV.BaseData.NumThreadsX = 1; 158*0fca6ea1SDimitry Andric PSV.BaseData.NumThreadsY = 1; 159*0fca6ea1SDimitry Andric PSV.BaseData.NumThreadsZ = 1; 160*0fca6ea1SDimitry Andric PSV.EntryName = "main"; 161*0fca6ea1SDimitry Andric 162*0fca6ea1SDimitry Andric PSV.finalize(TT.getEnvironment()); 163*0fca6ea1SDimitry Andric PSV.write(OS); 164*0fca6ea1SDimitry Andric Constant *Constant = 165*0fca6ea1SDimitry Andric ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false); 166*0fca6ea1SDimitry Andric Globals.emplace_back(buildContainerGlobal(M, Constant, "dx.psv0", "PSV0")); 167*0fca6ea1SDimitry Andric } 168*0fca6ea1SDimitry Andric 169bdd1243dSDimitry Andric char DXContainerGlobals::ID = 0; 170bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals", 171bdd1243dSDimitry Andric "DXContainer Global Emitter", false, true) 172bdd1243dSDimitry Andric INITIALIZE_PASS_DEPENDENCY(ShaderFlagsAnalysisWrapper) 173bdd1243dSDimitry Andric INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals", 174bdd1243dSDimitry Andric "DXContainer Global Emitter", false, true) 175bdd1243dSDimitry Andric 176bdd1243dSDimitry Andric ModulePass *llvm::createDXContainerGlobalsPass() { 177bdd1243dSDimitry Andric return new DXContainerGlobals(); 178bdd1243dSDimitry Andric } 179