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