brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.3 KiB · ac3c7dd Raw
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