| //=- DXILMetadataAnalysis.cpp - Representation of Module metadata -*- C++ -*=// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/Analysis/DXILMetadataAnalysis.h" | |
| #include "llvm/ADT/APInt.h" | |
| #include "llvm/ADT/StringExtras.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include "llvm/IR/Constants.h" | |
| #include "llvm/IR/Instructions.h" | |
| #include "llvm/IR/Metadata.h" | |
| #include "llvm/IR/Module.h" | |
| #include "llvm/InitializePasses.h" | |
| #include "llvm/Support/CommandLine.h" | |
| #include "llvm/Support/Compression.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #define DEBUG_TYPE "dxil-metadata-analysis" | |
| using namespace llvm; | |
| using namespace dxil; | |
| cl::OptionCategory DXContainerCategory("DXContainer Options"); | |
| static cl::opt<dxbc::SourceInfo::Contents::CompressionType> CompressSRCI( | |
| "compress-srci", cl::ValueOptional, | |
| cl::desc("Choose SCRI part compression:"), | |
| cl::values(clEnumValN(dxbc::SourceInfo::Contents::CompressionType::None, | |
| "none", "No compression"), | |
| clEnumValN(dxbc::SourceInfo::Contents::CompressionType::Zlib, | |
| "zlib", "Use zlib")), | |
| cl::cat(DXContainerCategory)); | |
| static ModuleMetadataInfo collectMetadataInfo(Module &M) { | |
| ModuleMetadataInfo MMDAI; | |
| const Triple &TT = M.getTargetTriple(); | |
| MMDAI.DXILVersion = TT.getDXILVersion(); | |
| MMDAI.ShaderModelVersion = TT.getOSVersion(); | |
| MMDAI.ShaderProfile = TT.getEnvironment(); | |
| NamedMDNode *ValidatorVerNode = M.getNamedMetadata("dx.valver"); | |
| if (ValidatorVerNode) { | |
| auto *ValVerMD = cast<MDNode>(ValidatorVerNode->getOperand(0)); | |
| auto *MajorMD = mdconst::extract<ConstantInt>(ValVerMD->getOperand(0)); | |
| auto *MinorMD = mdconst::extract<ConstantInt>(ValVerMD->getOperand(1)); | |
| MMDAI.ValidatorVersion = | |
| VersionTuple(MajorMD->getZExtValue(), MinorMD->getZExtValue()); | |
| } | |
| NamedMDNode *ContentsNode = M.getNamedMetadata("dx.source.contents"); | |
| NamedMDNode *ArgsNode = M.getNamedMetadata("dx.source.args"); | |
| if (ContentsNode && ArgsNode) { | |
| MMDAI.SourceInfo.emplace(); | |
| if (CompressSRCI.getNumOccurrences() > 0) { | |
| MMDAI.SourceInfo->setCompressionType(CompressSRCI); | |
| } else { | |
| // If the option is not specified, pick zlib if available. | |
| MMDAI.SourceInfo->setCompressionType( | |
| compression::zlib::isAvailable() | |
| ? dxbc::SourceInfo::Contents::CompressionType::Zlib | |
| : dxbc::SourceInfo::Contents::CompressionType::None); | |
| } | |
| for (Metadata *FileInfoNode : ContentsNode->operands()) { | |
| auto *FileInfo = cast<MDTuple>(FileInfoNode); | |
| MMDAI.SourceInfo->addFile( | |
| cast<MDString>(FileInfo->getOperand(0))->getString(), | |
| cast<MDString>(FileInfo->getOperand(1))->getString()); | |
| } | |
| for (Metadata *ArgNode : ArgsNode->getOperand(0)->operands()) | |
| MMDAI.SourceInfo->addArg(cast<MDString>(ArgNode)->getString(), ""); | |
| } | |
| // For all HLSL Shader functions | |
| for (auto &F : M.functions()) { | |
| if (!F.hasFnAttribute("hlsl.shader")) | |
| continue; | |
| EntryProperties EFP(&F); | |
| // Get "hlsl.shader" attribute | |
| Attribute EntryAttr = F.getFnAttribute("hlsl.shader"); | |
| assert(EntryAttr.isValid() && | |
| "Invalid value specified for HLSL function attribute hlsl.shader"); | |
| StringRef EntryProfile = EntryAttr.getValueAsString(); | |
| Triple T("", "", "", EntryProfile); | |
| EFP.ShaderStage = T.getEnvironment(); | |
| // Get numthreads attribute value, if one exists | |
| StringRef NumThreadsStr = | |
| F.getFnAttribute("hlsl.numthreads").getValueAsString(); | |
| if (!NumThreadsStr.empty()) { | |
| SmallVector<StringRef> NumThreadsVec; | |
| NumThreadsStr.split(NumThreadsVec, ','); | |
| assert(NumThreadsVec.size() == 3 && "Invalid numthreads specified"); | |
| // Read in the three component values of numthreads | |
| [[maybe_unused]] bool Success = | |
| llvm::to_integer(NumThreadsVec[0], EFP.NumThreadsX, 10); | |
| assert(Success && "Failed to parse X component of numthreads"); | |
| Success = llvm::to_integer(NumThreadsVec[1], EFP.NumThreadsY, 10); | |
| assert(Success && "Failed to parse Y component of numthreads"); | |
| Success = llvm::to_integer(NumThreadsVec[2], EFP.NumThreadsZ, 10); | |
| assert(Success && "Failed to parse Z component of numthreads"); | |
| } | |
| // Get wavesize attribute value, if one exists | |
| StringRef WaveSizeStr = | |
| F.getFnAttribute("hlsl.wavesize").getValueAsString(); | |
| if (!WaveSizeStr.empty()) { | |
| SmallVector<StringRef> WaveSizeVec; | |
| WaveSizeStr.split(WaveSizeVec, ','); | |
| assert(WaveSizeVec.size() == 3 && "Invalid wavesize specified"); | |
| // Read in the three component values of numthreads | |
| [[maybe_unused]] bool Success = | |
| llvm::to_integer(WaveSizeVec[0], EFP.WaveSizeMin, 10); | |
| assert(Success && "Failed to parse Min component of wavesize"); | |
| Success = llvm::to_integer(WaveSizeVec[1], EFP.WaveSizeMax, 10); | |
| assert(Success && "Failed to parse Max component of wavesize"); | |
| Success = llvm::to_integer(WaveSizeVec[2], EFP.WaveSizePref, 10); | |
| assert(Success && "Failed to parse Preferred component of wavesize"); | |
| } | |
| MMDAI.EntryPropertyVec.push_back(EFP); | |
| } | |
| return MMDAI; | |
| } | |
| void ModuleMetadataInfo::print(raw_ostream &OS) const { | |
| OS << "Shader Model Version : " << ShaderModelVersion.getAsString() << "\n"; | |
| OS << "DXIL Version : " << DXILVersion.getAsString() << "\n"; | |
| OS << "Target Shader Stage : " | |
| << Triple::getEnvironmentTypeName(ShaderProfile) << "\n"; | |
| OS << "Validator Version : " << ValidatorVersion.getAsString() << "\n"; | |
| for (const auto &EP : EntryPropertyVec) { | |
| OS << " " << EP.Entry->getName() << "\n"; | |
| OS << " Function Shader Stage : " | |
| << Triple::getEnvironmentTypeName(EP.ShaderStage) << "\n"; | |
| OS << " NumThreads: " << EP.NumThreadsX << "," << EP.NumThreadsY << "," | |
| << EP.NumThreadsZ << "\n"; | |
| } | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // DXILMetadataAnalysis and DXILMetadataAnalysisPrinterPass | |
| // Provide an explicit template instantiation for the static ID. | |
| AnalysisKey DXILMetadataAnalysis::Key; | |
| llvm::dxil::ModuleMetadataInfo | |
| DXILMetadataAnalysis::run(Module &M, ModuleAnalysisManager &AM) { | |
| return collectMetadataInfo(M); | |
| } | |
| PreservedAnalyses | |
| DXILMetadataAnalysisPrinterPass::run(Module &M, ModuleAnalysisManager &AM) { | |
| llvm::dxil::ModuleMetadataInfo &Data = AM.getResult<DXILMetadataAnalysis>(M); | |
| Data.print(OS); | |
| return PreservedAnalyses::all(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // DXILMetadataAnalysisWrapperPass | |
| DXILMetadataAnalysisWrapperPass::DXILMetadataAnalysisWrapperPass() | |
| : ModulePass(ID) {} | |
| DXILMetadataAnalysisWrapperPass::~DXILMetadataAnalysisWrapperPass() = default; | |
| void DXILMetadataAnalysisWrapperPass::getAnalysisUsage( | |
| AnalysisUsage &AU) const { | |
| AU.setPreservesAll(); | |
| } | |
| bool DXILMetadataAnalysisWrapperPass::runOnModule(Module &M) { | |
| MetadataInfo.reset(new ModuleMetadataInfo(collectMetadataInfo(M))); | |
| return false; | |
| } | |
| void DXILMetadataAnalysisWrapperPass::releaseMemory() { MetadataInfo.reset(); } | |
| void DXILMetadataAnalysisWrapperPass::print(raw_ostream &OS, | |
| const Module *) const { | |
| if (!MetadataInfo) { | |
| OS << "No module metadata info has been built!\n"; | |
| return; | |
| } | |
| MetadataInfo->print(dbgs()); | |
| } | |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | |
| LLVM_DUMP_METHOD | |
| void DXILMetadataAnalysisWrapperPass::dump() const { print(dbgs(), nullptr); } | |
| #endif | |
| INITIALIZE_PASS(DXILMetadataAnalysisWrapperPass, "dxil-metadata-analysis", | |
| "DXIL Module Metadata analysis", false, true) | |
| char DXILMetadataAnalysisWrapperPass::ID = 0; |