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