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