1*bdd1243dSDimitry Andric //===- DXContainerGlobals.cpp - DXContainer global generator pass ---------===// 2*bdd1243dSDimitry Andric // 3*bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*bdd1243dSDimitry Andric // 7*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8*bdd1243dSDimitry Andric // 9*bdd1243dSDimitry Andric // DXContainerGlobalsPass implementation. 10*bdd1243dSDimitry Andric // 11*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 12*bdd1243dSDimitry Andric 13*bdd1243dSDimitry Andric #include "DXILShaderFlags.h" 14*bdd1243dSDimitry Andric #include "DirectX.h" 15*bdd1243dSDimitry Andric #include "llvm/ADT/StringRef.h" 16*bdd1243dSDimitry Andric #include "llvm/BinaryFormat/DXContainer.h" 17*bdd1243dSDimitry Andric #include "llvm/CodeGen/Passes.h" 18*bdd1243dSDimitry Andric #include "llvm/IR/Constants.h" 19*bdd1243dSDimitry Andric #include "llvm/InitializePasses.h" 20*bdd1243dSDimitry Andric #include "llvm/Pass.h" 21*bdd1243dSDimitry Andric #include "llvm/Support/MD5.h" 22*bdd1243dSDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h" 23*bdd1243dSDimitry Andric 24*bdd1243dSDimitry Andric using namespace llvm; 25*bdd1243dSDimitry Andric using namespace llvm::dxil; 26*bdd1243dSDimitry Andric 27*bdd1243dSDimitry Andric namespace { 28*bdd1243dSDimitry Andric class DXContainerGlobals : public llvm::ModulePass { 29*bdd1243dSDimitry Andric 30*bdd1243dSDimitry Andric GlobalVariable *getShaderFlags(Module &M); 31*bdd1243dSDimitry Andric GlobalVariable *computeShaderHash(Module &M); 32*bdd1243dSDimitry Andric 33*bdd1243dSDimitry Andric public: 34*bdd1243dSDimitry Andric static char ID; // Pass identification, replacement for typeid 35*bdd1243dSDimitry Andric DXContainerGlobals() : ModulePass(ID) { 36*bdd1243dSDimitry Andric initializeDXContainerGlobalsPass(*PassRegistry::getPassRegistry()); 37*bdd1243dSDimitry Andric } 38*bdd1243dSDimitry Andric 39*bdd1243dSDimitry Andric StringRef getPassName() const override { 40*bdd1243dSDimitry Andric return "DXContainer Global Emitter"; 41*bdd1243dSDimitry Andric } 42*bdd1243dSDimitry Andric 43*bdd1243dSDimitry Andric bool runOnModule(Module &M) override; 44*bdd1243dSDimitry Andric 45*bdd1243dSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 46*bdd1243dSDimitry Andric AU.setPreservesAll(); 47*bdd1243dSDimitry Andric AU.addRequired<ShaderFlagsAnalysisWrapper>(); 48*bdd1243dSDimitry Andric } 49*bdd1243dSDimitry Andric }; 50*bdd1243dSDimitry Andric 51*bdd1243dSDimitry Andric } // namespace 52*bdd1243dSDimitry Andric 53*bdd1243dSDimitry Andric bool DXContainerGlobals::runOnModule(Module &M) { 54*bdd1243dSDimitry Andric llvm::SmallVector<GlobalValue *> Globals; 55*bdd1243dSDimitry Andric Globals.push_back(getShaderFlags(M)); 56*bdd1243dSDimitry Andric Globals.push_back(computeShaderHash(M)); 57*bdd1243dSDimitry Andric 58*bdd1243dSDimitry Andric appendToCompilerUsed(M, Globals); 59*bdd1243dSDimitry Andric return true; 60*bdd1243dSDimitry Andric } 61*bdd1243dSDimitry Andric 62*bdd1243dSDimitry Andric GlobalVariable *DXContainerGlobals::getShaderFlags(Module &M) { 63*bdd1243dSDimitry Andric const uint64_t Flags = 64*bdd1243dSDimitry Andric (uint64_t)(getAnalysis<ShaderFlagsAnalysisWrapper>().getShaderFlags()); 65*bdd1243dSDimitry Andric 66*bdd1243dSDimitry Andric Constant *FlagsConstant = ConstantInt::get(M.getContext(), APInt(64, Flags)); 67*bdd1243dSDimitry Andric auto *GV = new llvm::GlobalVariable(M, FlagsConstant->getType(), true, 68*bdd1243dSDimitry Andric GlobalValue::PrivateLinkage, 69*bdd1243dSDimitry Andric FlagsConstant, "dx.sfi0"); 70*bdd1243dSDimitry Andric GV->setSection("SFI0"); 71*bdd1243dSDimitry Andric GV->setAlignment(Align(4)); 72*bdd1243dSDimitry Andric return GV; 73*bdd1243dSDimitry Andric } 74*bdd1243dSDimitry Andric 75*bdd1243dSDimitry Andric GlobalVariable *DXContainerGlobals::computeShaderHash(Module &M) { 76*bdd1243dSDimitry Andric auto *DXILConstant = 77*bdd1243dSDimitry Andric cast<ConstantDataArray>(M.getNamedGlobal("dx.dxil")->getInitializer()); 78*bdd1243dSDimitry Andric MD5 Digest; 79*bdd1243dSDimitry Andric Digest.update(DXILConstant->getRawDataValues()); 80*bdd1243dSDimitry Andric MD5::MD5Result Result = Digest.final(); 81*bdd1243dSDimitry Andric 82*bdd1243dSDimitry Andric dxbc::ShaderHash HashData = {0, {0}}; 83*bdd1243dSDimitry Andric // The Hash's IncludesSource flag gets set whenever the hashed shader includes 84*bdd1243dSDimitry Andric // debug information. 85*bdd1243dSDimitry Andric if (M.debug_compile_units_begin() != M.debug_compile_units_end()) 86*bdd1243dSDimitry Andric HashData.Flags = static_cast<uint32_t>(dxbc::HashFlags::IncludesSource); 87*bdd1243dSDimitry Andric 88*bdd1243dSDimitry Andric memcpy(reinterpret_cast<void *>(&HashData.Digest), Result.data(), 16); 89*bdd1243dSDimitry Andric if (sys::IsBigEndianHost) 90*bdd1243dSDimitry Andric HashData.swapBytes(); 91*bdd1243dSDimitry Andric StringRef Data(reinterpret_cast<char *>(&HashData), sizeof(dxbc::ShaderHash)); 92*bdd1243dSDimitry Andric 93*bdd1243dSDimitry Andric Constant *ModuleConstant = 94*bdd1243dSDimitry Andric ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data)); 95*bdd1243dSDimitry Andric auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true, 96*bdd1243dSDimitry Andric GlobalValue::PrivateLinkage, 97*bdd1243dSDimitry Andric ModuleConstant, "dx.hash"); 98*bdd1243dSDimitry Andric GV->setSection("HASH"); 99*bdd1243dSDimitry Andric GV->setAlignment(Align(4)); 100*bdd1243dSDimitry Andric return GV; 101*bdd1243dSDimitry Andric } 102*bdd1243dSDimitry Andric 103*bdd1243dSDimitry Andric char DXContainerGlobals::ID = 0; 104*bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals", 105*bdd1243dSDimitry Andric "DXContainer Global Emitter", false, true) 106*bdd1243dSDimitry Andric INITIALIZE_PASS_DEPENDENCY(ShaderFlagsAnalysisWrapper) 107*bdd1243dSDimitry Andric INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals", 108*bdd1243dSDimitry Andric "DXContainer Global Emitter", false, true) 109*bdd1243dSDimitry Andric 110*bdd1243dSDimitry Andric ModulePass *llvm::createDXContainerGlobalsPass() { 111*bdd1243dSDimitry Andric return new DXContainerGlobals(); 112*bdd1243dSDimitry Andric } 113