//===- DXContainerGlobals.cpp - DXContainer global generator pass ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // DXContainerGlobalsPass implementation. // //===----------------------------------------------------------------------===// #include "DXILShaderFlags.h" #include "DirectX.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/DXContainer.h" #include "llvm/CodeGen/Passes.h" #include "llvm/IR/Constants.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/MD5.h" #include "llvm/Transforms/Utils/ModuleUtils.h" using namespace llvm; using namespace llvm::dxil; namespace { class DXContainerGlobals : public llvm::ModulePass { GlobalVariable *getShaderFlags(Module &M); GlobalVariable *computeShaderHash(Module &M); public: static char ID; // Pass identification, replacement for typeid DXContainerGlobals() : ModulePass(ID) { initializeDXContainerGlobalsPass(*PassRegistry::getPassRegistry()); } StringRef getPassName() const override { return "DXContainer Global Emitter"; } bool runOnModule(Module &M) override; void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); AU.addRequired(); } }; } // namespace bool DXContainerGlobals::runOnModule(Module &M) { llvm::SmallVector Globals; Globals.push_back(getShaderFlags(M)); Globals.push_back(computeShaderHash(M)); appendToCompilerUsed(M, Globals); return true; } GlobalVariable *DXContainerGlobals::getShaderFlags(Module &M) { const uint64_t Flags = (uint64_t)(getAnalysis().getShaderFlags()); Constant *FlagsConstant = ConstantInt::get(M.getContext(), APInt(64, Flags)); auto *GV = new llvm::GlobalVariable(M, FlagsConstant->getType(), true, GlobalValue::PrivateLinkage, FlagsConstant, "dx.sfi0"); GV->setSection("SFI0"); GV->setAlignment(Align(4)); return GV; } GlobalVariable *DXContainerGlobals::computeShaderHash(Module &M) { auto *DXILConstant = cast(M.getNamedGlobal("dx.dxil")->getInitializer()); MD5 Digest; Digest.update(DXILConstant->getRawDataValues()); MD5::MD5Result Result = Digest.final(); dxbc::ShaderHash HashData = {0, {0}}; // The Hash's IncludesSource flag gets set whenever the hashed shader includes // debug information. if (M.debug_compile_units_begin() != M.debug_compile_units_end()) HashData.Flags = static_cast(dxbc::HashFlags::IncludesSource); memcpy(reinterpret_cast(&HashData.Digest), Result.data(), 16); if (sys::IsBigEndianHost) HashData.swapBytes(); StringRef Data(reinterpret_cast(&HashData), sizeof(dxbc::ShaderHash)); Constant *ModuleConstant = ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data)); auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true, GlobalValue::PrivateLinkage, ModuleConstant, "dx.hash"); GV->setSection("HASH"); GV->setAlignment(Align(4)); return GV; } char DXContainerGlobals::ID = 0; INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals", "DXContainer Global Emitter", false, true) INITIALIZE_PASS_DEPENDENCY(ShaderFlagsAnalysisWrapper) INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals", "DXContainer Global Emitter", false, true) ModulePass *llvm::createDXContainerGlobalsPass() { return new DXContainerGlobals(); }