260 lines · cpp
1//===- DXILRootSignature.cpp - DXIL Root Signature helper objects -------===//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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file This file contains helper objects and APIs for working with DXIL10/// Root Signatures.11///12//===----------------------------------------------------------------------===//13#include "DXILRootSignature.h"14#include "DirectX.h"15#include "llvm/ADT/StringSwitch.h"16#include "llvm/ADT/Twine.h"17#include "llvm/Analysis/DXILMetadataAnalysis.h"18#include "llvm/BinaryFormat/DXContainer.h"19#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"20#include "llvm/IR/Constants.h"21#include "llvm/IR/DiagnosticInfo.h"22#include "llvm/IR/Function.h"23#include "llvm/IR/LLVMContext.h"24#include "llvm/IR/Metadata.h"25#include "llvm/IR/Module.h"26#include "llvm/InitializePasses.h"27#include "llvm/MC/DXContainerRootSignature.h"28#include "llvm/Pass.h"29#include "llvm/Support/Error.h"30#include "llvm/Support/ErrorHandling.h"31#include "llvm/Support/ScopedPrinter.h"32#include "llvm/Support/raw_ostream.h"33#include <cstdint>34 35using namespace llvm;36using namespace llvm::dxil;37 38static std::optional<uint32_t> extractMdIntValue(MDNode *Node,39 unsigned int OpId) {40 if (auto *CI =41 mdconst::dyn_extract<ConstantInt>(Node->getOperand(OpId).get()))42 return CI->getZExtValue();43 return std::nullopt;44}45 46static bool reportError(LLVMContext *Ctx, Twine Message,47 DiagnosticSeverity Severity = DS_Error) {48 Ctx->diagnose(DiagnosticInfoGeneric(Message, Severity));49 return true;50}51 52static SmallDenseMap<const Function *, mcdxbc::RootSignatureDesc>53analyzeModule(Module &M) {54 55 /** Root Signature are specified as following in the metadata:56 57 !dx.rootsignatures = !{!2} ; list of function/root signature pairs58 !2 = !{ ptr @main, !3 } ; function, root signature59 !3 = !{ !4, !5, !6, !7 } ; list of root signature elements60 61 So for each MDNode inside dx.rootsignatures NamedMDNode62 (the Root parameter of this function), the parsing process needs63 to loop through each of its operands and process the function,64 signature pair.65 */66 67 LLVMContext *Ctx = &M.getContext();68 69 SmallDenseMap<const Function *, mcdxbc::RootSignatureDesc> RSDMap;70 71 NamedMDNode *RootSignatureNode = M.getNamedMetadata("dx.rootsignatures");72 if (RootSignatureNode == nullptr)73 return RSDMap;74 75 bool AllowNullFunctions = false;76 if (M.getTargetTriple().getEnvironment() ==77 Triple::EnvironmentType::RootSignature) {78 assert(RootSignatureNode->getNumOperands() == 1);79 AllowNullFunctions = true;80 }81 82 for (const auto &RSDefNode : RootSignatureNode->operands()) {83 if (RSDefNode->getNumOperands() != 3) {84 reportError(Ctx, "Invalid Root Signature metadata - expected function, "85 "signature, and version.");86 continue;87 }88 89 // Function was pruned during compilation.90 Function *F = nullptr;91 92 if (!AllowNullFunctions) {93 const MDOperand &FunctionPointerMdNode = RSDefNode->getOperand(0);94 if (FunctionPointerMdNode == nullptr) {95 reportError(96 Ctx, "Function associated with Root Signature definition is null.");97 continue;98 }99 100 ValueAsMetadata *VAM =101 llvm::dyn_cast<ValueAsMetadata>(FunctionPointerMdNode.get());102 if (VAM == nullptr) {103 reportError(Ctx, "First element of root signature is not a Value");104 continue;105 }106 107 F = dyn_cast<Function>(VAM->getValue());108 if (F == nullptr) {109 reportError(Ctx, "First element of root signature is not a Function");110 continue;111 }112 }113 114 Metadata *RootElementListOperand = RSDefNode->getOperand(1).get();115 116 if (RootElementListOperand == nullptr) {117 reportError(Ctx, "Root Element mdnode is null.");118 continue;119 }120 121 MDNode *RootElementListNode = dyn_cast<MDNode>(RootElementListOperand);122 if (RootElementListNode == nullptr) {123 reportError(Ctx, "Root Element is not a metadata node.");124 continue;125 }126 std::optional<uint32_t> V = extractMdIntValue(RSDefNode, 2);127 if (!V.has_value()) {128 reportError(Ctx, "Invalid RSDefNode value, expected constant int");129 continue;130 }131 132 llvm::hlsl::rootsig::MetadataParser MDParser(RootElementListNode);133 llvm::Expected<mcdxbc::RootSignatureDesc> RSDOrErr =134 MDParser.ParseRootSignature(V.value());135 136 if (!RSDOrErr) {137 handleAllErrors(RSDOrErr.takeError(), [&](ErrorInfoBase &EIB) {138 Ctx->emitError(EIB.message());139 });140 continue;141 }142 143 auto &RSD = *RSDOrErr;144 145 // Clang emits the root signature data in dxcontainer following a specific146 // sequence. First the header, then the root parameters. So the header147 // offset will always equal to the header size.148 RSD.RootParameterOffset = sizeof(dxbc::RTS0::v1::RootSignatureHeader);149 150 // static sampler offset is calculated when writting dxcontainer.151 RSD.StaticSamplersOffset = 0u;152 153 RSDMap.insert(std::make_pair(F, RSD));154 }155 156 return RSDMap;157}158 159AnalysisKey RootSignatureAnalysis::Key;160 161RootSignatureAnalysis::Result162RootSignatureAnalysis::run(Module &M, ModuleAnalysisManager &AM) {163 return RootSignatureBindingInfo(analyzeModule(M));164}165 166//===----------------------------------------------------------------------===//167 168PreservedAnalyses RootSignatureAnalysisPrinter::run(Module &M,169 ModuleAnalysisManager &AM) {170 171 RootSignatureBindingInfo &RSDMap = AM.getResult<RootSignatureAnalysis>(M);172 173 OS << "Root Signature Definitions"174 << "\n";175 for (const Function &F : M) {176 auto It = RSDMap.find(&F);177 if (It == RSDMap.end())178 continue;179 const auto &RS = It->second;180 OS << "Definition for '" << F.getName() << "':\n";181 // start root signature header182 OS << "Flags: " << format_hex(RS.Flags, 8) << "\n"183 << "Version: " << RS.Version << "\n"184 << "RootParametersOffset: " << RS.RootParameterOffset << "\n"185 << "NumParameters: " << RS.ParametersContainer.size() << "\n";186 for (size_t I = 0; I < RS.ParametersContainer.size(); I++) {187 const mcdxbc::RootParameterInfo &Info = RS.ParametersContainer.getInfo(I);188 189 OS << "- Parameter Type: "190 << enumToStringRef(Info.Type, dxbc::getRootParameterTypes()) << "\n"191 << " Shader Visibility: "192 << enumToStringRef(Info.Visibility, dxbc::getShaderVisibility())193 << "\n";194 switch (Info.Type) {195 case dxbc::RootParameterType::Constants32Bit: {196 const mcdxbc::RootConstants &Constants =197 RS.ParametersContainer.getConstant(Info.Location);198 OS << " Register Space: " << Constants.RegisterSpace << "\n"199 << " Shader Register: " << Constants.ShaderRegister << "\n"200 << " Num 32 Bit Values: " << Constants.Num32BitValues << "\n";201 break;202 }203 case dxbc::RootParameterType::CBV:204 case dxbc::RootParameterType::UAV:205 case dxbc::RootParameterType::SRV: {206 const mcdxbc::RootDescriptor &Descriptor =207 RS.ParametersContainer.getRootDescriptor(Info.Location);208 OS << " Register Space: " << Descriptor.RegisterSpace << "\n"209 << " Shader Register: " << Descriptor.ShaderRegister << "\n";210 if (RS.Version > 1)211 OS << " Flags: " << Descriptor.Flags << "\n";212 break;213 }214 case dxbc::RootParameterType::DescriptorTable: {215 const mcdxbc::DescriptorTable &Table =216 RS.ParametersContainer.getDescriptorTable(Info.Location);217 OS << " NumRanges: " << Table.Ranges.size() << "\n";218 219 for (const mcdxbc::DescriptorRange &Range : Table) {220 OS << " - Range Type: "221 << dxil::getResourceClassName(Range.RangeType) << "\n"222 << " Register Space: " << Range.RegisterSpace << "\n"223 << " Base Shader Register: " << Range.BaseShaderRegister << "\n"224 << " Num Descriptors: " << Range.NumDescriptors << "\n"225 << " Offset In Descriptors From Table Start: "226 << Range.OffsetInDescriptorsFromTableStart << "\n";227 if (RS.Version > 1)228 OS << " Flags: " << Range.Flags << "\n";229 }230 break;231 }232 }233 }234 OS << "NumStaticSamplers: " << 0 << "\n";235 OS << "StaticSamplersOffset: " << RS.StaticSamplersOffset << "\n";236 }237 return PreservedAnalyses::all();238}239 240//===----------------------------------------------------------------------===//241bool RootSignatureAnalysisWrapper::runOnModule(Module &M) {242 FuncToRsMap = std::make_unique<RootSignatureBindingInfo>(243 RootSignatureBindingInfo(analyzeModule(M)));244 return false;245}246 247void RootSignatureAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const {248 AU.setPreservesAll();249 AU.addPreserved<DXILMetadataAnalysisWrapperPass>();250}251 252char RootSignatureAnalysisWrapper::ID = 0;253 254INITIALIZE_PASS_BEGIN(RootSignatureAnalysisWrapper,255 "dxil-root-signature-analysis",256 "DXIL Root Signature Analysis", true, true)257INITIALIZE_PASS_END(RootSignatureAnalysisWrapper,258 "dxil-root-signature-analysis",259 "DXIL Root Signature Analysis", true, true)260