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