brintos

brintos / llvm-project-archived public Read only

0
0
Text · 29.7 KiB · 132a280 Raw
792 lines · cpp
1//===- RootSignatureMetadata.h - HLSL Root Signature helpers --------------===//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 implements a library for working with HLSL Root Signatures10/// and their metadata representation.11///12//===----------------------------------------------------------------------===//13 14#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"15#include "llvm/Frontend/HLSL/RootSignatureValidations.h"16#include "llvm/IR/IRBuilder.h"17#include "llvm/IR/Metadata.h"18#include "llvm/Support/DXILABI.h"19#include "llvm/Support/ScopedPrinter.h"20 21using namespace llvm;22 23namespace llvm {24namespace hlsl {25namespace rootsig {26 27char RootSignatureValidationError::ID;28 29static std::optional<uint32_t> extractMdIntValue(MDNode *Node,30                                                 unsigned int OpId) {31  if (auto *CI =32          mdconst::dyn_extract<ConstantInt>(Node->getOperand(OpId).get()))33    return CI->getZExtValue();34  return std::nullopt;35}36 37static std::optional<float> extractMdFloatValue(MDNode *Node,38                                                unsigned int OpId) {39  if (auto *CI = mdconst::dyn_extract<ConstantFP>(Node->getOperand(OpId).get()))40    return CI->getValueAPF().convertToFloat();41  return std::nullopt;42}43 44static std::optional<StringRef> extractMdStringValue(MDNode *Node,45                                                     unsigned int OpId) {46  MDString *NodeText = dyn_cast<MDString>(Node->getOperand(OpId));47  if (NodeText == nullptr)48    return std::nullopt;49  return NodeText->getString();50}51 52namespace {53 54// We use the OverloadVisit with std::visit to ensure the compiler catches if a55// new RootElement variant type is added but it's metadata generation isn't56// handled.57template <class... Ts> struct OverloadedVisit : Ts... {58  using Ts::operator()...;59};60template <class... Ts> OverloadedVisit(Ts...) -> OverloadedVisit<Ts...>;61 62struct FmtRange {63  dxil::ResourceClass Type;64  uint32_t Register;65  uint32_t Space;66 67  FmtRange(const mcdxbc::DescriptorRange &Range)68      : Type(Range.RangeType), Register(Range.BaseShaderRegister),69        Space(Range.RegisterSpace) {}70};71 72raw_ostream &operator<<(llvm::raw_ostream &OS, const FmtRange &Range) {73  OS << getResourceClassName(Range.Type) << "(register=" << Range.Register74     << ", space=" << Range.Space << ")";75  return OS;76}77 78struct FmtMDNode {79  const MDNode *Node;80 81  FmtMDNode(const MDNode *Node) : Node(Node) {}82};83 84raw_ostream &operator<<(llvm::raw_ostream &OS, FmtMDNode Fmt) {85  Fmt.Node->printTree(OS);86  return OS;87}88 89static Error makeRSError(const Twine &Msg) {90  return make_error<RootSignatureValidationError>(Msg);91}92} // namespace93 94template <typename T, typename = std::enable_if_t<95                          std::is_enum_v<T> &&96                          std::is_same_v<std::underlying_type_t<T>, uint32_t>>>97static Expected<T>98extractEnumValue(MDNode *Node, unsigned int OpId, StringRef ErrText,99                 llvm::function_ref<bool(uint32_t)> VerifyFn) {100  if (std::optional<uint32_t> Val = extractMdIntValue(Node, OpId)) {101    if (!VerifyFn(*Val))102      return makeRSError(formatv("Invalid value for {0}: {1}", ErrText, Val));103    return static_cast<T>(*Val);104  }105  return makeRSError(formatv("Invalid value for {0}:", ErrText));106}107 108MDNode *MetadataBuilder::BuildRootSignature() {109  const auto Visitor = OverloadedVisit{110      [this](const dxbc::RootFlags &Flags) -> MDNode * {111        return BuildRootFlags(Flags);112      },113      [this](const RootConstants &Constants) -> MDNode * {114        return BuildRootConstants(Constants);115      },116      [this](const RootDescriptor &Descriptor) -> MDNode * {117        return BuildRootDescriptor(Descriptor);118      },119      [this](const DescriptorTableClause &Clause) -> MDNode * {120        return BuildDescriptorTableClause(Clause);121      },122      [this](const DescriptorTable &Table) -> MDNode * {123        return BuildDescriptorTable(Table);124      },125      [this](const StaticSampler &Sampler) -> MDNode * {126        return BuildStaticSampler(Sampler);127      },128  };129 130  for (const RootElement &Element : Elements) {131    MDNode *ElementMD = std::visit(Visitor, Element);132    assert(ElementMD != nullptr &&133           "Root Element must be initialized and validated");134    GeneratedMetadata.push_back(ElementMD);135  }136 137  return MDNode::get(Ctx, GeneratedMetadata);138}139 140MDNode *MetadataBuilder::BuildRootFlags(const dxbc::RootFlags &Flags) {141  IRBuilder<> Builder(Ctx);142  Metadata *Operands[] = {143      MDString::get(Ctx, "RootFlags"),144      ConstantAsMetadata::get(Builder.getInt32(to_underlying(Flags))),145  };146  return MDNode::get(Ctx, Operands);147}148 149MDNode *MetadataBuilder::BuildRootConstants(const RootConstants &Constants) {150  IRBuilder<> Builder(Ctx);151  Metadata *Operands[] = {152      MDString::get(Ctx, "RootConstants"),153      ConstantAsMetadata::get(154          Builder.getInt32(to_underlying(Constants.Visibility))),155      ConstantAsMetadata::get(Builder.getInt32(Constants.Reg.Number)),156      ConstantAsMetadata::get(Builder.getInt32(Constants.Space)),157      ConstantAsMetadata::get(Builder.getInt32(Constants.Num32BitConstants)),158  };159  return MDNode::get(Ctx, Operands);160}161 162MDNode *MetadataBuilder::BuildRootDescriptor(const RootDescriptor &Descriptor) {163  IRBuilder<> Builder(Ctx);164  StringRef ResName = dxil::getResourceClassName(Descriptor.Type);165  assert(!ResName.empty() && "Provided an invalid Resource Class");166  SmallString<7> Name({"Root", ResName});167  Metadata *Operands[] = {168      MDString::get(Ctx, Name),169      ConstantAsMetadata::get(170          Builder.getInt32(to_underlying(Descriptor.Visibility))),171      ConstantAsMetadata::get(Builder.getInt32(Descriptor.Reg.Number)),172      ConstantAsMetadata::get(Builder.getInt32(Descriptor.Space)),173      ConstantAsMetadata::get(174          Builder.getInt32(to_underlying(Descriptor.Flags))),175  };176  return MDNode::get(Ctx, Operands);177}178 179MDNode *MetadataBuilder::BuildDescriptorTable(const DescriptorTable &Table) {180  IRBuilder<> Builder(Ctx);181  SmallVector<Metadata *> TableOperands;182  // Set the mandatory arguments183  TableOperands.push_back(MDString::get(Ctx, "DescriptorTable"));184  TableOperands.push_back(ConstantAsMetadata::get(185      Builder.getInt32(to_underlying(Table.Visibility))));186 187  // Remaining operands are references to the table's clauses. The in-memory188  // representation of the Root Elements created from parsing will ensure that189  // the previous N elements are the clauses for this table.190  assert(Table.NumClauses <= GeneratedMetadata.size() &&191         "Table expected all owned clauses to be generated already");192  // So, add a refence to each clause to our operands193  TableOperands.append(GeneratedMetadata.end() - Table.NumClauses,194                       GeneratedMetadata.end());195  // Then, remove those clauses from the general list of Root Elements196  GeneratedMetadata.pop_back_n(Table.NumClauses);197 198  return MDNode::get(Ctx, TableOperands);199}200 201MDNode *MetadataBuilder::BuildDescriptorTableClause(202    const DescriptorTableClause &Clause) {203  IRBuilder<> Builder(Ctx);204  StringRef ResName = dxil::getResourceClassName(Clause.Type);205  assert(!ResName.empty() && "Provided an invalid Resource Class");206  Metadata *Operands[] = {207      MDString::get(Ctx, ResName),208      ConstantAsMetadata::get(Builder.getInt32(Clause.NumDescriptors)),209      ConstantAsMetadata::get(Builder.getInt32(Clause.Reg.Number)),210      ConstantAsMetadata::get(Builder.getInt32(Clause.Space)),211      ConstantAsMetadata::get(Builder.getInt32(Clause.Offset)),212      ConstantAsMetadata::get(Builder.getInt32(to_underlying(Clause.Flags))),213  };214  return MDNode::get(Ctx, Operands);215}216 217MDNode *MetadataBuilder::BuildStaticSampler(const StaticSampler &Sampler) {218  IRBuilder<> Builder(Ctx);219  Metadata *Operands[] = {220      MDString::get(Ctx, "StaticSampler"),221      ConstantAsMetadata::get(Builder.getInt32(to_underlying(Sampler.Filter))),222      ConstantAsMetadata::get(223          Builder.getInt32(to_underlying(Sampler.AddressU))),224      ConstantAsMetadata::get(225          Builder.getInt32(to_underlying(Sampler.AddressV))),226      ConstantAsMetadata::get(227          Builder.getInt32(to_underlying(Sampler.AddressW))),228      ConstantAsMetadata::get(229          ConstantFP::get(Type::getFloatTy(Ctx), Sampler.MipLODBias)),230      ConstantAsMetadata::get(Builder.getInt32(Sampler.MaxAnisotropy)),231      ConstantAsMetadata::get(232          Builder.getInt32(to_underlying(Sampler.CompFunc))),233      ConstantAsMetadata::get(234          Builder.getInt32(to_underlying(Sampler.BorderColor))),235      ConstantAsMetadata::get(236          ConstantFP::get(Type::getFloatTy(Ctx), Sampler.MinLOD)),237      ConstantAsMetadata::get(238          ConstantFP::get(Type::getFloatTy(Ctx), Sampler.MaxLOD)),239      ConstantAsMetadata::get(Builder.getInt32(Sampler.Reg.Number)),240      ConstantAsMetadata::get(Builder.getInt32(Sampler.Space)),241      ConstantAsMetadata::get(242          Builder.getInt32(to_underlying(Sampler.Visibility))),243      ConstantAsMetadata::get(Builder.getInt32(to_underlying(Sampler.Flags))),244  };245  return MDNode::get(Ctx, Operands);246}247 248Error MetadataParser::parseRootFlags(mcdxbc::RootSignatureDesc &RSD,249                                     MDNode *RootFlagNode) {250  if (RootFlagNode->getNumOperands() != 2)251    return makeRSError("Invalid format for RootFlags Element");252 253  if (std::optional<uint32_t> Val = extractMdIntValue(RootFlagNode, 1))254    RSD.Flags = *Val;255  else256    return makeRSError("Invalid value for RootFlag");257 258  return Error::success();259}260 261Error MetadataParser::parseRootConstants(mcdxbc::RootSignatureDesc &RSD,262                                         MDNode *RootConstantNode) {263  if (RootConstantNode->getNumOperands() != 5)264    return makeRSError("Invalid format for RootConstants Element");265 266  Expected<dxbc::ShaderVisibility> Visibility =267      extractEnumValue<dxbc::ShaderVisibility>(RootConstantNode, 1,268                                               "ShaderVisibility",269                                               dxbc::isValidShaderVisibility);270  if (auto E = Visibility.takeError())271    return Error(std::move(E));272 273  mcdxbc::RootConstants Constants;274  if (std::optional<uint32_t> Val = extractMdIntValue(RootConstantNode, 2))275    Constants.ShaderRegister = *Val;276  else277    return makeRSError("Invalid value for ShaderRegister");278 279  if (std::optional<uint32_t> Val = extractMdIntValue(RootConstantNode, 3))280    Constants.RegisterSpace = *Val;281  else282    return makeRSError("Invalid value for RegisterSpace");283 284  if (std::optional<uint32_t> Val = extractMdIntValue(RootConstantNode, 4))285    Constants.Num32BitValues = *Val;286  else287    return makeRSError("Invalid value for Num32BitValues");288 289  RSD.ParametersContainer.addParameter(dxbc::RootParameterType::Constants32Bit,290                                       *Visibility, Constants);291 292  return Error::success();293}294 295Error MetadataParser::parseRootDescriptors(296    mcdxbc::RootSignatureDesc &RSD, MDNode *RootDescriptorNode,297    RootSignatureElementKind ElementKind) {298  assert((ElementKind == RootSignatureElementKind::SRV ||299          ElementKind == RootSignatureElementKind::UAV ||300          ElementKind == RootSignatureElementKind::CBV) &&301         "parseRootDescriptors should only be called with RootDescriptor "302         "element kind.");303  if (RootDescriptorNode->getNumOperands() != 5)304    return makeRSError("Invalid format for Root Descriptor Element");305 306  dxbc::RootParameterType Type;307  switch (ElementKind) {308  case RootSignatureElementKind::SRV:309    Type = dxbc::RootParameterType::SRV;310    break;311  case RootSignatureElementKind::UAV:312    Type = dxbc::RootParameterType::UAV;313    break;314  case RootSignatureElementKind::CBV:315    Type = dxbc::RootParameterType::CBV;316    break;317  default:318    llvm_unreachable("invalid Root Descriptor kind");319    break;320  }321 322  Expected<dxbc::ShaderVisibility> Visibility =323      extractEnumValue<dxbc::ShaderVisibility>(RootDescriptorNode, 1,324                                               "ShaderVisibility",325                                               dxbc::isValidShaderVisibility);326  if (auto E = Visibility.takeError())327    return Error(std::move(E));328 329  mcdxbc::RootDescriptor Descriptor;330  if (std::optional<uint32_t> Val = extractMdIntValue(RootDescriptorNode, 2))331    Descriptor.ShaderRegister = *Val;332  else333    return makeRSError("Invalid value for ShaderRegister");334 335  if (std::optional<uint32_t> Val = extractMdIntValue(RootDescriptorNode, 3))336    Descriptor.RegisterSpace = *Val;337  else338    return makeRSError("Invalid value for RegisterSpace");339 340  if (std::optional<uint32_t> Val = extractMdIntValue(RootDescriptorNode, 4))341    Descriptor.Flags = *Val;342  else343    return makeRSError("Invalid value for Root Descriptor Flags");344 345  RSD.ParametersContainer.addParameter(Type, *Visibility, Descriptor);346  return Error::success();347}348 349Error MetadataParser::parseDescriptorRange(mcdxbc::DescriptorTable &Table,350                                           MDNode *RangeDescriptorNode) {351  if (RangeDescriptorNode->getNumOperands() != 6)352    return makeRSError("Invalid format for Descriptor Range");353 354  mcdxbc::DescriptorRange Range;355 356  std::optional<StringRef> ElementText =357      extractMdStringValue(RangeDescriptorNode, 0);358 359  if (!ElementText.has_value())360    return makeRSError("Invalid format for Descriptor Range");361 362  if (*ElementText == "CBV")363    Range.RangeType = dxil::ResourceClass::CBuffer;364  else if (*ElementText == "SRV")365    Range.RangeType = dxil::ResourceClass::SRV;366  else if (*ElementText == "UAV")367    Range.RangeType = dxil::ResourceClass::UAV;368  else if (*ElementText == "Sampler")369    Range.RangeType = dxil::ResourceClass::Sampler;370  else371    return makeRSError(formatv("Invalid Descriptor Range type.\n{0}",372                               FmtMDNode{RangeDescriptorNode}));373 374  if (std::optional<uint32_t> Val = extractMdIntValue(RangeDescriptorNode, 1))375    Range.NumDescriptors = *Val;376  else377    return makeRSError(formatv("Invalid number of Descriptor in Range.\n{0}",378                               FmtMDNode{RangeDescriptorNode}));379 380  if (std::optional<uint32_t> Val = extractMdIntValue(RangeDescriptorNode, 2))381    Range.BaseShaderRegister = *Val;382  else383    return makeRSError("Invalid value for BaseShaderRegister");384 385  if (std::optional<uint32_t> Val = extractMdIntValue(RangeDescriptorNode, 3))386    Range.RegisterSpace = *Val;387  else388    return makeRSError("Invalid value for RegisterSpace");389 390  if (std::optional<uint32_t> Val = extractMdIntValue(RangeDescriptorNode, 4))391    Range.OffsetInDescriptorsFromTableStart = *Val;392  else393    return makeRSError("Invalid value for OffsetInDescriptorsFromTableStart");394 395  if (std::optional<uint32_t> Val = extractMdIntValue(RangeDescriptorNode, 5))396    Range.Flags = *Val;397  else398    return makeRSError("Invalid value for Descriptor Range Flags");399 400  Table.Ranges.push_back(Range);401  return Error::success();402}403 404Error MetadataParser::parseDescriptorTable(mcdxbc::RootSignatureDesc &RSD,405                                           MDNode *DescriptorTableNode) {406  const unsigned int NumOperands = DescriptorTableNode->getNumOperands();407  if (NumOperands < 2)408    return makeRSError("Invalid format for Descriptor Table");409 410  Expected<dxbc::ShaderVisibility> Visibility =411      extractEnumValue<dxbc::ShaderVisibility>(DescriptorTableNode, 1,412                                               "ShaderVisibility",413                                               dxbc::isValidShaderVisibility);414  if (auto E = Visibility.takeError())415    return Error(std::move(E));416 417  mcdxbc::DescriptorTable Table;418 419  for (unsigned int I = 2; I < NumOperands; I++) {420    MDNode *Element = dyn_cast<MDNode>(DescriptorTableNode->getOperand(I));421    if (Element == nullptr)422      return makeRSError(formatv("Missing Root Element Metadata Node.\n{0}",423                                 FmtMDNode{DescriptorTableNode}));424 425    if (auto Err = parseDescriptorRange(Table, Element))426      return Err;427  }428 429  RSD.ParametersContainer.addParameter(dxbc::RootParameterType::DescriptorTable,430                                       *Visibility, Table);431  return Error::success();432}433 434Error MetadataParser::parseStaticSampler(mcdxbc::RootSignatureDesc &RSD,435                                         MDNode *StaticSamplerNode) {436  if (StaticSamplerNode->getNumOperands() != 15)437    return makeRSError("Invalid format for Static Sampler");438 439  mcdxbc::StaticSampler Sampler;440 441  Expected<dxbc::SamplerFilter> Filter = extractEnumValue<dxbc::SamplerFilter>(442      StaticSamplerNode, 1, "Filter", dxbc::isValidSamplerFilter);443  if (auto E = Filter.takeError())444    return Error(std::move(E));445  Sampler.Filter = *Filter;446 447  Expected<dxbc::TextureAddressMode> AddressU =448      extractEnumValue<dxbc::TextureAddressMode>(449          StaticSamplerNode, 2, "AddressU", dxbc::isValidAddress);450  if (auto E = AddressU.takeError())451    return Error(std::move(E));452  Sampler.AddressU = *AddressU;453 454  Expected<dxbc::TextureAddressMode> AddressV =455      extractEnumValue<dxbc::TextureAddressMode>(456          StaticSamplerNode, 3, "AddressV", dxbc::isValidAddress);457  if (auto E = AddressV.takeError())458    return Error(std::move(E));459  Sampler.AddressV = *AddressV;460 461  Expected<dxbc::TextureAddressMode> AddressW =462      extractEnumValue<dxbc::TextureAddressMode>(463          StaticSamplerNode, 4, "AddressW", dxbc::isValidAddress);464  if (auto E = AddressW.takeError())465    return Error(std::move(E));466  Sampler.AddressW = *AddressW;467 468  if (std::optional<float> Val = extractMdFloatValue(StaticSamplerNode, 5))469    Sampler.MipLODBias = *Val;470  else471    return makeRSError("Invalid value for MipLODBias");472 473  if (std::optional<uint32_t> Val = extractMdIntValue(StaticSamplerNode, 6))474    Sampler.MaxAnisotropy = *Val;475  else476    return makeRSError("Invalid value for MaxAnisotropy");477 478  Expected<dxbc::ComparisonFunc> ComparisonFunc =479      extractEnumValue<dxbc::ComparisonFunc>(480          StaticSamplerNode, 7, "ComparisonFunc", dxbc::isValidComparisonFunc);481  if (auto E = ComparisonFunc.takeError())482    return Error(std::move(E));483  Sampler.ComparisonFunc = *ComparisonFunc;484 485  Expected<dxbc::StaticBorderColor> BorderColor =486      extractEnumValue<dxbc::StaticBorderColor>(487          StaticSamplerNode, 8, "BorderColor", dxbc::isValidBorderColor);488  if (auto E = BorderColor.takeError())489    return Error(std::move(E));490  Sampler.BorderColor = *BorderColor;491 492  if (std::optional<float> Val = extractMdFloatValue(StaticSamplerNode, 9))493    Sampler.MinLOD = *Val;494  else495    return makeRSError("Invalid value for MinLOD");496 497  if (std::optional<float> Val = extractMdFloatValue(StaticSamplerNode, 10))498    Sampler.MaxLOD = *Val;499  else500    return makeRSError("Invalid value for MaxLOD");501 502  if (std::optional<uint32_t> Val = extractMdIntValue(StaticSamplerNode, 11))503    Sampler.ShaderRegister = *Val;504  else505    return makeRSError("Invalid value for ShaderRegister");506 507  if (std::optional<uint32_t> Val = extractMdIntValue(StaticSamplerNode, 12))508    Sampler.RegisterSpace = *Val;509  else510    return makeRSError("Invalid value for RegisterSpace");511 512  Expected<dxbc::ShaderVisibility> Visibility =513      extractEnumValue<dxbc::ShaderVisibility>(StaticSamplerNode, 13,514                                               "ShaderVisibility",515                                               dxbc::isValidShaderVisibility);516  if (auto E = Visibility.takeError())517    return Error(std::move(E));518  Sampler.ShaderVisibility = *Visibility;519 520  if (std::optional<uint32_t> Val = extractMdIntValue(StaticSamplerNode, 14))521    Sampler.Flags = *Val;522  else523    return makeRSError("Invalid value for Static Sampler Flags");524 525  RSD.StaticSamplers.push_back(Sampler);526  return Error::success();527}528 529Error MetadataParser::parseRootSignatureElement(mcdxbc::RootSignatureDesc &RSD,530                                                MDNode *Element) {531  std::optional<StringRef> ElementText = extractMdStringValue(Element, 0);532  if (!ElementText.has_value())533    return makeRSError("Invalid format for Root Element");534 535  RootSignatureElementKind ElementKind =536      StringSwitch<RootSignatureElementKind>(*ElementText)537          .Case("RootFlags", RootSignatureElementKind::RootFlags)538          .Case("RootConstants", RootSignatureElementKind::RootConstants)539          .Case("RootCBV", RootSignatureElementKind::CBV)540          .Case("RootSRV", RootSignatureElementKind::SRV)541          .Case("RootUAV", RootSignatureElementKind::UAV)542          .Case("DescriptorTable", RootSignatureElementKind::DescriptorTable)543          .Case("StaticSampler", RootSignatureElementKind::StaticSamplers)544          .Default(RootSignatureElementKind::Error);545 546  switch (ElementKind) {547 548  case RootSignatureElementKind::RootFlags:549    return parseRootFlags(RSD, Element);550  case RootSignatureElementKind::RootConstants:551    return parseRootConstants(RSD, Element);552  case RootSignatureElementKind::CBV:553  case RootSignatureElementKind::SRV:554  case RootSignatureElementKind::UAV:555    return parseRootDescriptors(RSD, Element, ElementKind);556  case RootSignatureElementKind::DescriptorTable:557    return parseDescriptorTable(RSD, Element);558  case RootSignatureElementKind::StaticSamplers:559    return parseStaticSampler(RSD, Element);560  case RootSignatureElementKind::Error:561    return makeRSError(562        formatv("Invalid Root Signature Element\n{0}", FmtMDNode{Element}));563  }564 565  llvm_unreachable("Unhandled RootSignatureElementKind enum.");566}567 568static Error569validateDescriptorTableSamplerMixin(const mcdxbc::DescriptorTable &Table,570                                    uint32_t Location) {571  dxil::ResourceClass CurrRC = dxil::ResourceClass::Sampler;572  for (const mcdxbc::DescriptorRange &Range : Table.Ranges) {573    if (Range.RangeType == dxil::ResourceClass::Sampler &&574        CurrRC != dxil::ResourceClass::Sampler)575      return makeRSError(576          formatv("Samplers cannot be mixed with other resource types in a "577                  "descriptor table, {0}(location={1})",578                  getResourceClassName(CurrRC), Location));579    CurrRC = Range.RangeType;580  }581  return Error::success();582}583 584static Error585validateDescriptorTableRegisterOverflow(const mcdxbc::DescriptorTable &Table,586                                        uint32_t Location) {587  uint64_t Offset = 0;588  bool IsPrevUnbound = false;589  for (const mcdxbc::DescriptorRange &Range : Table.Ranges) {590    // Validation of NumDescriptors should have happened by this point.591    if (Range.NumDescriptors == 0)592      continue;593 594    const uint64_t RangeBound = llvm::hlsl::rootsig::computeRangeBound(595        Range.BaseShaderRegister, Range.NumDescriptors);596 597    if (!verifyNoOverflowedOffset(RangeBound))598      return makeRSError(599          formatv("Overflow for shader register range: {0}", FmtRange{Range}));600 601    bool IsAppending =602        Range.OffsetInDescriptorsFromTableStart == DescriptorTableOffsetAppend;603    if (!IsAppending)604      Offset = Range.OffsetInDescriptorsFromTableStart;605 606    if (IsPrevUnbound && IsAppending)607      return makeRSError(608          formatv("Range {0} cannot be appended after an unbounded range",609                  FmtRange{Range}));610 611    const uint64_t OffsetBound =612        llvm::hlsl::rootsig::computeRangeBound(Offset, Range.NumDescriptors);613 614    if (!verifyNoOverflowedOffset(OffsetBound))615      return makeRSError(formatv("Offset overflow for descriptor range: {0}.",616                                 FmtRange{Range}));617 618    Offset = OffsetBound + 1;619    IsPrevUnbound =620        Range.NumDescriptors == llvm::hlsl::rootsig::NumDescriptorsUnbounded;621  }622 623  return Error::success();624}625 626Error MetadataParser::validateRootSignature(627    const mcdxbc::RootSignatureDesc &RSD) {628  Error DeferredErrs = Error::success();629  if (!hlsl::rootsig::verifyVersion(RSD.Version)) {630    DeferredErrs = joinErrors(631        std::move(DeferredErrs),632        makeRSError(formatv("Invalid value for Version: {0}", RSD.Version)));633  }634 635  if (!hlsl::rootsig::verifyRootFlag(RSD.Flags)) {636    DeferredErrs = joinErrors(637        std::move(DeferredErrs),638        makeRSError(formatv("Invalid value for RootFlags: {0}", RSD.Flags)));639  }640 641  for (const mcdxbc::RootParameterInfo &Info : RSD.ParametersContainer) {642 643    switch (Info.Type) {644    case dxbc::RootParameterType::Constants32Bit:645      break;646 647    case dxbc::RootParameterType::CBV:648    case dxbc::RootParameterType::UAV:649    case dxbc::RootParameterType::SRV: {650      const mcdxbc::RootDescriptor &Descriptor =651          RSD.ParametersContainer.getRootDescriptor(Info.Location);652      if (!hlsl::rootsig::verifyRegisterValue(Descriptor.ShaderRegister))653        DeferredErrs = joinErrors(654            std::move(DeferredErrs),655            makeRSError(formatv("Invalid value for ShaderRegister: {0}",656                                Descriptor.ShaderRegister)));657 658      if (!hlsl::rootsig::verifyRegisterSpace(Descriptor.RegisterSpace))659        DeferredErrs = joinErrors(660            std::move(DeferredErrs),661            makeRSError(formatv("Invalid value for RegisterSpace: {0}",662                                Descriptor.RegisterSpace)));663 664      bool IsValidFlag =665          dxbc::isValidRootDesciptorFlags(Descriptor.Flags) &&666          hlsl::rootsig::verifyRootDescriptorFlag(667              RSD.Version, dxbc::RootDescriptorFlags(Descriptor.Flags));668      if (!IsValidFlag)669        DeferredErrs = joinErrors(670            std::move(DeferredErrs),671            makeRSError(formatv("Invalid value for RootDescriptorFlag: {0}",672                                Descriptor.Flags)));673      break;674    }675    case dxbc::RootParameterType::DescriptorTable: {676      const mcdxbc::DescriptorTable &Table =677          RSD.ParametersContainer.getDescriptorTable(Info.Location);678      for (const mcdxbc::DescriptorRange &Range : Table) {679        if (!hlsl::rootsig::verifyRegisterSpace(Range.RegisterSpace))680          DeferredErrs = joinErrors(681              std::move(DeferredErrs),682              makeRSError(formatv("Invalid value for RegisterSpace: {0}",683                                  Range.RegisterSpace)));684 685        if (!hlsl::rootsig::verifyNumDescriptors(Range.NumDescriptors))686          DeferredErrs = joinErrors(687              std::move(DeferredErrs),688              makeRSError(formatv("Invalid value for NumDescriptors: {0}",689                                  Range.NumDescriptors)));690 691        bool IsValidFlag = dxbc::isValidDescriptorRangeFlags(Range.Flags) &&692                           hlsl::rootsig::verifyDescriptorRangeFlag(693                               RSD.Version, Range.RangeType,694                               dxbc::DescriptorRangeFlags(Range.Flags));695        if (!IsValidFlag)696          DeferredErrs = joinErrors(697              std::move(DeferredErrs),698              makeRSError(formatv("Invalid value for DescriptorFlag: {0}",699                                  Range.Flags)));700 701        if (Error Err =702                validateDescriptorTableSamplerMixin(Table, Info.Location))703          DeferredErrs = joinErrors(std::move(DeferredErrs), std::move(Err));704 705        if (Error Err =706                validateDescriptorTableRegisterOverflow(Table, Info.Location))707          DeferredErrs = joinErrors(std::move(DeferredErrs), std::move(Err));708      }709      break;710    }711    }712  }713 714  for (const mcdxbc::StaticSampler &Sampler : RSD.StaticSamplers) {715 716    if (!hlsl::rootsig::verifyMipLODBias(Sampler.MipLODBias))717      DeferredErrs =718          joinErrors(std::move(DeferredErrs),719                     makeRSError(formatv("Invalid value for MipLODBias: {0:e}",720                                         Sampler.MipLODBias)));721 722    if (!hlsl::rootsig::verifyMaxAnisotropy(Sampler.MaxAnisotropy))723      DeferredErrs =724          joinErrors(std::move(DeferredErrs),725                     makeRSError(formatv("Invalid value for MaxAnisotropy: {0}",726                                         Sampler.MaxAnisotropy)));727 728    if (!hlsl::rootsig::verifyLOD(Sampler.MinLOD))729      DeferredErrs =730          joinErrors(std::move(DeferredErrs),731                     makeRSError(formatv("Invalid value for MinLOD: {0}",732                                         Sampler.MinLOD)));733 734    if (!hlsl::rootsig::verifyLOD(Sampler.MaxLOD))735      DeferredErrs =736          joinErrors(std::move(DeferredErrs),737                     makeRSError(formatv("Invalid value for MaxLOD: {0}",738                                         Sampler.MaxLOD)));739 740    if (!hlsl::rootsig::verifyRegisterValue(Sampler.ShaderRegister))741      DeferredErrs = joinErrors(742          std::move(DeferredErrs),743          makeRSError(formatv("Invalid value for ShaderRegister: {0}",744                              Sampler.ShaderRegister)));745 746    if (!hlsl::rootsig::verifyRegisterSpace(Sampler.RegisterSpace))747      DeferredErrs =748          joinErrors(std::move(DeferredErrs),749                     makeRSError(formatv("Invalid value for RegisterSpace: {0}",750                                         Sampler.RegisterSpace)));751    bool IsValidFlag =752        dxbc::isValidStaticSamplerFlags(Sampler.Flags) &&753        hlsl::rootsig::verifyStaticSamplerFlags(754            RSD.Version, dxbc::StaticSamplerFlags(Sampler.Flags));755    if (!IsValidFlag)756      DeferredErrs = joinErrors(757          std::move(DeferredErrs),758          makeRSError(formatv("Invalid value for Static Sampler Flag: {0}",759                              Sampler.Flags)));760  }761 762  return DeferredErrs;763}764 765Expected<mcdxbc::RootSignatureDesc>766MetadataParser::ParseRootSignature(uint32_t Version) {767  Error DeferredErrs = Error::success();768  mcdxbc::RootSignatureDesc RSD;769  RSD.Version = Version;770  for (const auto &Operand : Root->operands()) {771    MDNode *Element = dyn_cast<MDNode>(Operand);772    if (Element == nullptr)773      return joinErrors(774          std::move(DeferredErrs),775          makeRSError(formatv("Missing Root Element Metadata Node.")));776 777    if (auto Err = parseRootSignatureElement(RSD, Element))778      DeferredErrs = joinErrors(std::move(DeferredErrs), std::move(Err));779  }780 781  if (auto Err = validateRootSignature(RSD))782    DeferredErrs = joinErrors(std::move(DeferredErrs), std::move(Err));783 784  if (DeferredErrs)785    return std::move(DeferredErrs);786 787  return std::move(RSD);788}789} // namespace rootsig790} // namespace hlsl791} // namespace llvm792