//=- 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/ErrorHandling.h" #define DEBUG_TYPE "dxil-metadata-analysis" using namespace llvm; using namespace dxil; 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(ValidatorVerNode->getOperand(0)); auto *MajorMD = mdconst::extract(ValVerMD->getOperand(0)); auto *MinorMD = mdconst::extract(ValVerMD->getOperand(1)); MMDAI.ValidatorVersion = VersionTuple(MajorMD->getZExtValue(), MinorMD->getZExtValue()); } // 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 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"); } 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(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;