brintos

brintos / llvm-project-archived public Read only

0
0
Text · 53.0 KiB · 7be6eec Raw
1582 lines · cpp
1//=== ParseHLSLRootSignature.cpp - Parse Root Signature -------------------===//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#include "clang/Parse/ParseHLSLRootSignature.h"10#include "clang/AST/ASTConsumer.h"11#include "clang/Lex/LiteralSupport.h"12#include "clang/Parse/Parser.h"13#include "clang/Sema/Sema.h"14 15using namespace llvm::hlsl::rootsig;16 17namespace clang {18namespace hlsl {19 20using TokenKind = RootSignatureToken::Kind;21 22static const TokenKind RootElementKeywords[] = {23    TokenKind::kw_RootFlags,24    TokenKind::kw_CBV,25    TokenKind::kw_UAV,26    TokenKind::kw_SRV,27    TokenKind::kw_DescriptorTable,28    TokenKind::kw_StaticSampler,29};30 31RootSignatureParser::RootSignatureParser(32    llvm::dxbc::RootSignatureVersion Version, StringLiteral *Signature,33    Preprocessor &PP)34    : Version(Version), Signature(Signature), Lexer(Signature->getString()),35      PP(PP), CurToken(0) {}36 37bool RootSignatureParser::parse() {38  // Iterate as many RootSignatureElements as possible, until we hit the39  // end of the stream40  bool HadError = false;41  bool HasRootFlags = false;42  while (!peekExpectedToken(TokenKind::end_of_stream)) {43    if (tryConsumeExpectedToken(TokenKind::kw_RootFlags)) {44      if (HasRootFlags) {45        reportDiag(diag::err_hlsl_rootsig_repeat_param)46            << TokenKind::kw_RootFlags;47        HadError = true;48        skipUntilExpectedToken(RootElementKeywords);49        continue;50      }51      HasRootFlags = true;52 53      SourceLocation ElementLoc = getTokenLocation(CurToken);54      auto Flags = parseRootFlags();55      if (!Flags.has_value()) {56        HadError = true;57        skipUntilExpectedToken(RootElementKeywords);58        continue;59      }60 61      Elements.emplace_back(ElementLoc, *Flags);62    } else if (tryConsumeExpectedToken(TokenKind::kw_RootConstants)) {63      SourceLocation ElementLoc = getTokenLocation(CurToken);64      auto Constants = parseRootConstants();65      if (!Constants.has_value()) {66        HadError = true;67        skipUntilExpectedToken(RootElementKeywords);68        continue;69      }70      Elements.emplace_back(ElementLoc, *Constants);71    } else if (tryConsumeExpectedToken(TokenKind::kw_DescriptorTable)) {72      SourceLocation ElementLoc = getTokenLocation(CurToken);73      auto Table = parseDescriptorTable();74      if (!Table.has_value()) {75        HadError = true;76        // We are within a DescriptorTable, we will do our best to recover77        // by skipping until we encounter the expected closing ')'.78        skipUntilClosedParens();79        consumeNextToken();80        skipUntilExpectedToken(RootElementKeywords);81        continue;82      }83      Elements.emplace_back(ElementLoc, *Table);84    } else if (tryConsumeExpectedToken(85                   {TokenKind::kw_CBV, TokenKind::kw_SRV, TokenKind::kw_UAV})) {86      SourceLocation ElementLoc = getTokenLocation(CurToken);87      auto Descriptor = parseRootDescriptor();88      if (!Descriptor.has_value()) {89        HadError = true;90        skipUntilExpectedToken(RootElementKeywords);91        continue;92      }93      Elements.emplace_back(ElementLoc, *Descriptor);94    } else if (tryConsumeExpectedToken(TokenKind::kw_StaticSampler)) {95      SourceLocation ElementLoc = getTokenLocation(CurToken);96      auto Sampler = parseStaticSampler();97      if (!Sampler.has_value()) {98        HadError = true;99        skipUntilExpectedToken(RootElementKeywords);100        continue;101      }102      Elements.emplace_back(ElementLoc, *Sampler);103    } else {104      HadError = true;105      consumeNextToken(); // let diagnostic be at the start of invalid token106      reportDiag(diag::err_hlsl_invalid_token)107          << /*parameter=*/0 << /*param of*/ TokenKind::kw_RootSignature;108      skipUntilExpectedToken(RootElementKeywords);109      continue;110    }111 112    if (!tryConsumeExpectedToken(TokenKind::pu_comma)) {113      // ',' denotes another element, otherwise, expected to be at end of stream114      break;115    }116  }117 118  return HadError ||119         consumeExpectedToken(TokenKind::end_of_stream,120                              diag::err_expected_either, TokenKind::pu_comma);121}122 123template <typename FlagType>124static FlagType maybeOrFlag(std::optional<FlagType> Flags, FlagType Flag) {125  if (!Flags.has_value())126    return Flag;127 128  return static_cast<FlagType>(llvm::to_underlying(Flags.value()) |129                               llvm::to_underlying(Flag));130}131 132std::optional<llvm::dxbc::RootFlags> RootSignatureParser::parseRootFlags() {133  assert(CurToken.TokKind == TokenKind::kw_RootFlags &&134         "Expects to only be invoked starting at given keyword");135 136  if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,137                           CurToken.TokKind))138    return std::nullopt;139 140  std::optional<llvm::dxbc::RootFlags> Flags = llvm::dxbc::RootFlags::None;141 142  // Handle valid empty case143  if (tryConsumeExpectedToken(TokenKind::pu_r_paren))144    return Flags;145 146  // Handle the edge-case of '0' to specify no flags set147  if (tryConsumeExpectedToken(TokenKind::int_literal)) {148    if (!verifyZeroFlag()) {149      reportDiag(diag::err_hlsl_rootsig_non_zero_flag);150      return std::nullopt;151    }152  } else {153    // Otherwise, parse as many flags as possible154    TokenKind Expected[] = {155#define ROOT_FLAG_ENUM(NAME, LIT) TokenKind::en_##NAME,156#include "clang/Lex/HLSLRootSignatureTokenKinds.def"157    };158 159    do {160      if (tryConsumeExpectedToken(Expected)) {161        switch (CurToken.TokKind) {162#define ROOT_FLAG_ENUM(NAME, LIT)                                              \163  case TokenKind::en_##NAME:                                                   \164    Flags = maybeOrFlag<llvm::dxbc::RootFlags>(Flags,                          \165                                               llvm::dxbc::RootFlags::NAME);   \166    break;167#include "clang/Lex/HLSLRootSignatureTokenKinds.def"168        default:169          llvm_unreachable("Switch for consumed enum token was not provided");170        }171      } else {172        consumeNextToken(); // consume token to point at invalid token173        reportDiag(diag::err_hlsl_invalid_token)174            << /*value=*/1 << /*value of*/ TokenKind::kw_RootFlags;175        return std::nullopt;176      }177    } while (tryConsumeExpectedToken(TokenKind::pu_or));178  }179 180  if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either,181                           TokenKind::pu_comma))182    return std::nullopt;183 184  return Flags;185}186 187std::optional<RootConstants> RootSignatureParser::parseRootConstants() {188  assert(CurToken.TokKind == TokenKind::kw_RootConstants &&189         "Expects to only be invoked starting at given keyword");190 191  if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,192                           CurToken.TokKind))193    return std::nullopt;194 195  RootConstants Constants;196 197  auto Params = parseRootConstantParams();198  if (!Params.has_value())199    return std::nullopt;200 201  if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either,202                           TokenKind::pu_comma))203    return std::nullopt;204 205  // Check mandatory parameters where provided206  if (!Params->Num32BitConstants.has_value()) {207    reportDiag(diag::err_hlsl_rootsig_missing_param)208        << TokenKind::kw_num32BitConstants;209    return std::nullopt;210  }211 212  Constants.Num32BitConstants = Params->Num32BitConstants.value();213 214  if (!Params->Reg.has_value()) {215    reportDiag(diag::err_hlsl_rootsig_missing_param) << TokenKind::bReg;216    return std::nullopt;217  }218 219  Constants.Reg = Params->Reg.value();220 221  // Fill in optional parameters222  if (Params->Visibility.has_value())223    Constants.Visibility = Params->Visibility.value();224 225  if (Params->Space.has_value())226    Constants.Space = Params->Space.value();227 228  return Constants;229}230 231std::optional<RootDescriptor> RootSignatureParser::parseRootDescriptor() {232  assert((CurToken.TokKind == TokenKind::kw_CBV ||233          CurToken.TokKind == TokenKind::kw_SRV ||234          CurToken.TokKind == TokenKind::kw_UAV) &&235         "Expects to only be invoked starting at given keyword");236 237  TokenKind DescriptorKind = CurToken.TokKind;238 239  if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,240                           CurToken.TokKind))241    return std::nullopt;242 243  RootDescriptor Descriptor;244  TokenKind ExpectedReg;245  switch (DescriptorKind) {246  default:247    llvm_unreachable("Switch for consumed token was not provided");248  case TokenKind::kw_CBV:249    Descriptor.Type = ResourceClass::CBuffer;250    ExpectedReg = TokenKind::bReg;251    break;252  case TokenKind::kw_SRV:253    Descriptor.Type = ResourceClass::SRV;254    ExpectedReg = TokenKind::tReg;255    break;256  case TokenKind::kw_UAV:257    Descriptor.Type = ResourceClass::UAV;258    ExpectedReg = TokenKind::uReg;259    break;260  }261  Descriptor.setDefaultFlags(Version);262 263  auto Params = parseRootDescriptorParams(DescriptorKind, ExpectedReg);264  if (!Params.has_value())265    return std::nullopt;266 267  if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either,268                           TokenKind::pu_comma))269    return std::nullopt;270 271  // Check mandatory parameters were provided272  if (!Params->Reg.has_value()) {273    reportDiag(diag::err_hlsl_rootsig_missing_param) << ExpectedReg;274    return std::nullopt;275  }276 277  Descriptor.Reg = Params->Reg.value();278 279  // Fill in optional values280  if (Params->Space.has_value())281    Descriptor.Space = Params->Space.value();282 283  if (Params->Visibility.has_value())284    Descriptor.Visibility = Params->Visibility.value();285 286  if (Params->Flags.has_value())287    Descriptor.Flags = Params->Flags.value();288 289  return Descriptor;290}291 292std::optional<DescriptorTable> RootSignatureParser::parseDescriptorTable() {293  assert(CurToken.TokKind == TokenKind::kw_DescriptorTable &&294         "Expects to only be invoked starting at given keyword");295 296  if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,297                           CurToken.TokKind))298    return std::nullopt;299 300  DescriptorTable Table;301  std::optional<llvm::dxbc::ShaderVisibility> Visibility;302 303  // Iterate as many Clauses as possible, until we hit ')'304  while (!peekExpectedToken(TokenKind::pu_r_paren)) {305    if (tryConsumeExpectedToken({TokenKind::kw_CBV, TokenKind::kw_SRV,306                                 TokenKind::kw_UAV, TokenKind::kw_Sampler})) {307      // DescriptorTableClause - CBV, SRV, UAV, or Sampler308      SourceLocation ElementLoc = getTokenLocation(CurToken);309      auto Clause = parseDescriptorTableClause();310      if (!Clause.has_value()) {311        // We are within a DescriptorTableClause, we will do our best to recover312        // by skipping until we encounter the expected closing ')'313        skipUntilExpectedToken(TokenKind::pu_r_paren);314        consumeNextToken();315        return std::nullopt;316      }317      Elements.emplace_back(ElementLoc, *Clause);318      Table.NumClauses++;319    } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {320      // visibility = SHADER_VISIBILITY321      if (Visibility.has_value()) {322        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;323        return std::nullopt;324      }325 326      if (consumeExpectedToken(TokenKind::pu_equal))327        return std::nullopt;328 329      Visibility = parseShaderVisibility(TokenKind::kw_visibility);330      if (!Visibility.has_value())331        return std::nullopt;332    } else {333      consumeNextToken(); // let diagnostic be at the start of invalid token334      reportDiag(diag::err_hlsl_invalid_token)335          << /*parameter=*/0 << /*param of*/ TokenKind::kw_DescriptorTable;336      return std::nullopt;337    }338 339    // ',' denotes another element, otherwise, expected to be at ')'340    if (!tryConsumeExpectedToken(TokenKind::pu_comma))341      break;342  }343 344  if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either,345                           TokenKind::pu_comma))346    return std::nullopt;347 348  // Fill in optional visibility349  if (Visibility.has_value())350    Table.Visibility = Visibility.value();351 352  return Table;353}354 355std::optional<DescriptorTableClause>356RootSignatureParser::parseDescriptorTableClause() {357  assert((CurToken.TokKind == TokenKind::kw_CBV ||358          CurToken.TokKind == TokenKind::kw_SRV ||359          CurToken.TokKind == TokenKind::kw_UAV ||360          CurToken.TokKind == TokenKind::kw_Sampler) &&361         "Expects to only be invoked starting at given keyword");362 363  TokenKind ParamKind = CurToken.TokKind;364 365  if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,366                           CurToken.TokKind))367    return std::nullopt;368 369  DescriptorTableClause Clause;370  TokenKind ExpectedReg;371  switch (ParamKind) {372  default:373    llvm_unreachable("Switch for consumed token was not provided");374  case TokenKind::kw_CBV:375    Clause.Type = ResourceClass::CBuffer;376    ExpectedReg = TokenKind::bReg;377    break;378  case TokenKind::kw_SRV:379    Clause.Type = ResourceClass::SRV;380    ExpectedReg = TokenKind::tReg;381    break;382  case TokenKind::kw_UAV:383    Clause.Type = ResourceClass::UAV;384    ExpectedReg = TokenKind::uReg;385    break;386  case TokenKind::kw_Sampler:387    Clause.Type = ResourceClass::Sampler;388    ExpectedReg = TokenKind::sReg;389    break;390  }391  Clause.setDefaultFlags(Version);392 393  auto Params = parseDescriptorTableClauseParams(ParamKind, ExpectedReg);394  if (!Params.has_value())395    return std::nullopt;396 397  if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either,398                           TokenKind::pu_comma))399    return std::nullopt;400 401  // Check mandatory parameters were provided402  if (!Params->Reg.has_value()) {403    reportDiag(diag::err_hlsl_rootsig_missing_param) << ExpectedReg;404    return std::nullopt;405  }406 407  Clause.Reg = Params->Reg.value();408 409  // Fill in optional values410  if (Params->NumDescriptors.has_value())411    Clause.NumDescriptors = Params->NumDescriptors.value();412 413  if (Params->Space.has_value())414    Clause.Space = Params->Space.value();415 416  if (Params->Offset.has_value())417    Clause.Offset = Params->Offset.value();418 419  if (Params->Flags.has_value())420    Clause.Flags = Params->Flags.value();421 422  return Clause;423}424 425std::optional<StaticSampler> RootSignatureParser::parseStaticSampler() {426  assert(CurToken.TokKind == TokenKind::kw_StaticSampler &&427         "Expects to only be invoked starting at given keyword");428 429  if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,430                           CurToken.TokKind))431    return std::nullopt;432 433  StaticSampler Sampler;434 435  auto Params = parseStaticSamplerParams();436  if (!Params.has_value())437    return std::nullopt;438 439  if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either,440                           TokenKind::pu_comma))441    return std::nullopt;442 443  // Check mandatory parameters were provided444  if (!Params->Reg.has_value()) {445    reportDiag(diag::err_hlsl_rootsig_missing_param) << TokenKind::sReg;446    return std::nullopt;447  }448 449  Sampler.Reg = Params->Reg.value();450 451  // Fill in optional values452  if (Params->Filter.has_value())453    Sampler.Filter = Params->Filter.value();454 455  if (Params->AddressU.has_value())456    Sampler.AddressU = Params->AddressU.value();457 458  if (Params->AddressV.has_value())459    Sampler.AddressV = Params->AddressV.value();460 461  if (Params->AddressW.has_value())462    Sampler.AddressW = Params->AddressW.value();463 464  if (Params->MipLODBias.has_value())465    Sampler.MipLODBias = Params->MipLODBias.value();466 467  if (Params->MaxAnisotropy.has_value())468    Sampler.MaxAnisotropy = Params->MaxAnisotropy.value();469 470  if (Params->CompFunc.has_value())471    Sampler.CompFunc = Params->CompFunc.value();472 473  if (Params->BorderColor.has_value())474    Sampler.BorderColor = Params->BorderColor.value();475 476  if (Params->MinLOD.has_value())477    Sampler.MinLOD = Params->MinLOD.value();478 479  if (Params->MaxLOD.has_value())480    Sampler.MaxLOD = Params->MaxLOD.value();481 482  if (Params->Space.has_value())483    Sampler.Space = Params->Space.value();484 485  if (Params->Visibility.has_value())486    Sampler.Visibility = Params->Visibility.value();487 488  if (Params->Flags.has_value())489    Sampler.Flags = Params->Flags.value();490 491  return Sampler;492}493 494// Parameter arguments (eg. `bReg`, `space`, ...) can be specified in any495// order and only exactly once. The following methods will parse through as496// many arguments as possible reporting an error if a duplicate is seen.497std::optional<RootSignatureParser::ParsedConstantParams>498RootSignatureParser::parseRootConstantParams() {499  assert(CurToken.TokKind == TokenKind::pu_l_paren &&500         "Expects to only be invoked starting at given token");501 502  ParsedConstantParams Params;503  while (!peekExpectedToken(TokenKind::pu_r_paren)) {504    if (tryConsumeExpectedToken(TokenKind::kw_num32BitConstants)) {505      // `num32BitConstants` `=` POS_INT506      if (Params.Num32BitConstants.has_value()) {507        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;508        return std::nullopt;509      }510 511      if (consumeExpectedToken(TokenKind::pu_equal))512        return std::nullopt;513 514      auto Num32BitConstants = parseUIntParam();515      if (!Num32BitConstants.has_value())516        return std::nullopt;517      Params.Num32BitConstants = Num32BitConstants;518    } else if (tryConsumeExpectedToken(TokenKind::bReg)) {519      // `b` POS_INT520      if (Params.Reg.has_value()) {521        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;522        return std::nullopt;523      }524      auto Reg = parseRegister();525      if (!Reg.has_value())526        return std::nullopt;527      Params.Reg = Reg;528    } else if (tryConsumeExpectedToken(TokenKind::kw_space)) {529      // `space` `=` POS_INT530      if (Params.Space.has_value()) {531        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;532        return std::nullopt;533      }534 535      if (consumeExpectedToken(TokenKind::pu_equal))536        return std::nullopt;537 538      auto Space = parseUIntParam();539      if (!Space.has_value())540        return std::nullopt;541      Params.Space = Space;542    } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {543      // `visibility` `=` SHADER_VISIBILITY544      if (Params.Visibility.has_value()) {545        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;546        return std::nullopt;547      }548 549      if (consumeExpectedToken(TokenKind::pu_equal))550        return std::nullopt;551 552      auto Visibility = parseShaderVisibility(TokenKind::kw_visibility);553      if (!Visibility.has_value())554        return std::nullopt;555      Params.Visibility = Visibility;556    } else {557      consumeNextToken(); // let diagnostic be at the start of invalid token558      reportDiag(diag::err_hlsl_invalid_token)559          << /*parameter=*/0 << /*param of*/ TokenKind::kw_RootConstants;560      return std::nullopt;561    }562 563    // ',' denotes another element, otherwise, expected to be at ')'564    if (!tryConsumeExpectedToken(TokenKind::pu_comma))565      break;566  }567 568  return Params;569}570 571std::optional<RootSignatureParser::ParsedRootDescriptorParams>572RootSignatureParser::parseRootDescriptorParams(TokenKind DescKind,573                                               TokenKind RegType) {574  assert(CurToken.TokKind == TokenKind::pu_l_paren &&575         "Expects to only be invoked starting at given token");576 577  ParsedRootDescriptorParams Params;578  while (!peekExpectedToken(TokenKind::pu_r_paren)) {579    if (tryConsumeExpectedToken(RegType)) {580      // ( `b` | `t` | `u`) POS_INT581      if (Params.Reg.has_value()) {582        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;583        return std::nullopt;584      }585      auto Reg = parseRegister();586      if (!Reg.has_value())587        return std::nullopt;588      Params.Reg = Reg;589    } else if (tryConsumeExpectedToken(TokenKind::kw_space)) {590      // `space` `=` POS_INT591      if (Params.Space.has_value()) {592        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;593        return std::nullopt;594      }595 596      if (consumeExpectedToken(TokenKind::pu_equal))597        return std::nullopt;598 599      auto Space = parseUIntParam();600      if (!Space.has_value())601        return std::nullopt;602      Params.Space = Space;603    } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {604      // `visibility` `=` SHADER_VISIBILITY605      if (Params.Visibility.has_value()) {606        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;607        return std::nullopt;608      }609 610      if (consumeExpectedToken(TokenKind::pu_equal))611        return std::nullopt;612 613      auto Visibility = parseShaderVisibility(TokenKind::kw_visibility);614      if (!Visibility.has_value())615        return std::nullopt;616      Params.Visibility = Visibility;617    } else if (tryConsumeExpectedToken(TokenKind::kw_flags)) {618      // `flags` `=` ROOT_DESCRIPTOR_FLAGS619      if (Params.Flags.has_value()) {620        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;621        return std::nullopt;622      }623 624      if (consumeExpectedToken(TokenKind::pu_equal))625        return std::nullopt;626 627      auto Flags = parseRootDescriptorFlags(TokenKind::kw_flags);628      if (!Flags.has_value())629        return std::nullopt;630      Params.Flags = Flags;631    } else {632      consumeNextToken(); // let diagnostic be at the start of invalid token633      reportDiag(diag::err_hlsl_invalid_token)634          << /*parameter=*/0 << /*param of*/ DescKind;635      return std::nullopt;636    }637 638    // ',' denotes another element, otherwise, expected to be at ')'639    if (!tryConsumeExpectedToken(TokenKind::pu_comma))640      break;641  }642 643  return Params;644}645 646std::optional<RootSignatureParser::ParsedClauseParams>647RootSignatureParser::parseDescriptorTableClauseParams(TokenKind ClauseKind,648                                                      TokenKind RegType) {649  assert(CurToken.TokKind == TokenKind::pu_l_paren &&650         "Expects to only be invoked starting at given token");651 652  ParsedClauseParams Params;653  while (!peekExpectedToken(TokenKind::pu_r_paren)) {654    if (tryConsumeExpectedToken(RegType)) {655      // ( `b` | `t` | `u` | `s`) POS_INT656      if (Params.Reg.has_value()) {657        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;658        return std::nullopt;659      }660      auto Reg = parseRegister();661      if (!Reg.has_value())662        return std::nullopt;663      Params.Reg = Reg;664    } else if (tryConsumeExpectedToken(TokenKind::kw_numDescriptors)) {665      // `numDescriptors` `=` POS_INT | unbounded666      if (Params.NumDescriptors.has_value()) {667        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;668        return std::nullopt;669      }670 671      if (consumeExpectedToken(TokenKind::pu_equal))672        return std::nullopt;673 674      std::optional<uint32_t> NumDescriptors;675      if (tryConsumeExpectedToken(TokenKind::en_unbounded))676        NumDescriptors = NumDescriptorsUnbounded;677      else {678        NumDescriptors = parseUIntParam();679        if (!NumDescriptors.has_value())680          return std::nullopt;681      }682 683      Params.NumDescriptors = NumDescriptors;684    } else if (tryConsumeExpectedToken(TokenKind::kw_space)) {685      // `space` `=` POS_INT686      if (Params.Space.has_value()) {687        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;688        return std::nullopt;689      }690 691      if (consumeExpectedToken(TokenKind::pu_equal))692        return std::nullopt;693 694      auto Space = parseUIntParam();695      if (!Space.has_value())696        return std::nullopt;697      Params.Space = Space;698    } else if (tryConsumeExpectedToken(TokenKind::kw_offset)) {699      // `offset` `=` POS_INT | DESCRIPTOR_RANGE_OFFSET_APPEND700      if (Params.Offset.has_value()) {701        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;702        return std::nullopt;703      }704 705      if (consumeExpectedToken(TokenKind::pu_equal))706        return std::nullopt;707 708      std::optional<uint32_t> Offset;709      if (tryConsumeExpectedToken(TokenKind::en_DescriptorRangeOffsetAppend))710        Offset = DescriptorTableOffsetAppend;711      else {712        Offset = parseUIntParam();713        if (!Offset.has_value())714          return std::nullopt;715      }716 717      Params.Offset = Offset;718    } else if (tryConsumeExpectedToken(TokenKind::kw_flags)) {719      // `flags` `=` DESCRIPTOR_RANGE_FLAGS720      if (Params.Flags.has_value()) {721        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;722        return std::nullopt;723      }724 725      if (consumeExpectedToken(TokenKind::pu_equal))726        return std::nullopt;727 728      auto Flags = parseDescriptorRangeFlags(TokenKind::kw_flags);729      if (!Flags.has_value())730        return std::nullopt;731      Params.Flags = Flags;732    } else {733      consumeNextToken(); // let diagnostic be at the start of invalid token734      reportDiag(diag::err_hlsl_invalid_token)735          << /*parameter=*/0 << /*param of*/ ClauseKind;736      return std::nullopt;737    }738 739    // ',' denotes another element, otherwise, expected to be at ')'740    if (!tryConsumeExpectedToken(TokenKind::pu_comma))741      break;742  }743 744  return Params;745}746 747std::optional<RootSignatureParser::ParsedStaticSamplerParams>748RootSignatureParser::parseStaticSamplerParams() {749  assert(CurToken.TokKind == TokenKind::pu_l_paren &&750         "Expects to only be invoked starting at given token");751 752  ParsedStaticSamplerParams Params;753  while (!peekExpectedToken(TokenKind::pu_r_paren)) {754    if (tryConsumeExpectedToken(TokenKind::sReg)) {755      // `s` POS_INT756      if (Params.Reg.has_value()) {757        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;758        return std::nullopt;759      }760      auto Reg = parseRegister();761      if (!Reg.has_value())762        return std::nullopt;763      Params.Reg = Reg;764    } else if (tryConsumeExpectedToken(TokenKind::kw_filter)) {765      // `filter` `=` FILTER766      if (Params.Filter.has_value()) {767        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;768        return std::nullopt;769      }770 771      if (consumeExpectedToken(TokenKind::pu_equal))772        return std::nullopt;773 774      auto Filter = parseSamplerFilter(TokenKind::kw_filter);775      if (!Filter.has_value())776        return std::nullopt;777      Params.Filter = Filter;778    } else if (tryConsumeExpectedToken(TokenKind::kw_addressU)) {779      // `addressU` `=` TEXTURE_ADDRESS780      if (Params.AddressU.has_value()) {781        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;782        return std::nullopt;783      }784 785      if (consumeExpectedToken(TokenKind::pu_equal))786        return std::nullopt;787 788      auto AddressU = parseTextureAddressMode(TokenKind::kw_addressU);789      if (!AddressU.has_value())790        return std::nullopt;791      Params.AddressU = AddressU;792    } else if (tryConsumeExpectedToken(TokenKind::kw_addressV)) {793      // `addressV` `=` TEXTURE_ADDRESS794      if (Params.AddressV.has_value()) {795        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;796        return std::nullopt;797      }798 799      if (consumeExpectedToken(TokenKind::pu_equal))800        return std::nullopt;801 802      auto AddressV = parseTextureAddressMode(TokenKind::kw_addressV);803      if (!AddressV.has_value())804        return std::nullopt;805      Params.AddressV = AddressV;806    } else if (tryConsumeExpectedToken(TokenKind::kw_addressW)) {807      // `addressW` `=` TEXTURE_ADDRESS808      if (Params.AddressW.has_value()) {809        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;810        return std::nullopt;811      }812 813      if (consumeExpectedToken(TokenKind::pu_equal))814        return std::nullopt;815 816      auto AddressW = parseTextureAddressMode(TokenKind::kw_addressW);817      if (!AddressW.has_value())818        return std::nullopt;819      Params.AddressW = AddressW;820    } else if (tryConsumeExpectedToken(TokenKind::kw_mipLODBias)) {821      // `mipLODBias` `=` NUMBER822      if (Params.MipLODBias.has_value()) {823        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;824        return std::nullopt;825      }826 827      if (consumeExpectedToken(TokenKind::pu_equal))828        return std::nullopt;829 830      auto MipLODBias = parseFloatParam();831      if (!MipLODBias.has_value())832        return std::nullopt;833      Params.MipLODBias = MipLODBias;834    } else if (tryConsumeExpectedToken(TokenKind::kw_maxAnisotropy)) {835      // `maxAnisotropy` `=` POS_INT836      if (Params.MaxAnisotropy.has_value()) {837        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;838        return std::nullopt;839      }840 841      if (consumeExpectedToken(TokenKind::pu_equal))842        return std::nullopt;843 844      auto MaxAnisotropy = parseUIntParam();845      if (!MaxAnisotropy.has_value())846        return std::nullopt;847      Params.MaxAnisotropy = MaxAnisotropy;848    } else if (tryConsumeExpectedToken(TokenKind::kw_comparisonFunc)) {849      // `comparisonFunc` `=` COMPARISON_FUNC850      if (Params.CompFunc.has_value()) {851        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;852        return std::nullopt;853      }854 855      if (consumeExpectedToken(TokenKind::pu_equal))856        return std::nullopt;857 858      auto CompFunc = parseComparisonFunc(TokenKind::kw_comparisonFunc);859      if (!CompFunc.has_value())860        return std::nullopt;861      Params.CompFunc = CompFunc;862    } else if (tryConsumeExpectedToken(TokenKind::kw_borderColor)) {863      // `borderColor` `=` STATIC_BORDER_COLOR864      if (Params.BorderColor.has_value()) {865        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;866        return std::nullopt;867      }868 869      if (consumeExpectedToken(TokenKind::pu_equal))870        return std::nullopt;871 872      auto BorderColor = parseStaticBorderColor(TokenKind::kw_borderColor);873      if (!BorderColor.has_value())874        return std::nullopt;875      Params.BorderColor = BorderColor;876    } else if (tryConsumeExpectedToken(TokenKind::kw_minLOD)) {877      // `minLOD` `=` NUMBER878      if (Params.MinLOD.has_value()) {879        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;880        return std::nullopt;881      }882 883      if (consumeExpectedToken(TokenKind::pu_equal))884        return std::nullopt;885 886      auto MinLOD = parseFloatParam();887      if (!MinLOD.has_value())888        return std::nullopt;889      Params.MinLOD = MinLOD;890    } else if (tryConsumeExpectedToken(TokenKind::kw_maxLOD)) {891      // `maxLOD` `=` NUMBER892      if (Params.MaxLOD.has_value()) {893        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;894        return std::nullopt;895      }896 897      if (consumeExpectedToken(TokenKind::pu_equal))898        return std::nullopt;899 900      auto MaxLOD = parseFloatParam();901      if (!MaxLOD.has_value())902        return std::nullopt;903      Params.MaxLOD = MaxLOD;904    } else if (tryConsumeExpectedToken(TokenKind::kw_space)) {905      // `space` `=` POS_INT906      if (Params.Space.has_value()) {907        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;908        return std::nullopt;909      }910 911      if (consumeExpectedToken(TokenKind::pu_equal))912        return std::nullopt;913 914      auto Space = parseUIntParam();915      if (!Space.has_value())916        return std::nullopt;917      Params.Space = Space;918    } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {919      // `visibility` `=` SHADER_VISIBILITY920      if (Params.Visibility.has_value()) {921        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;922        return std::nullopt;923      }924 925      if (consumeExpectedToken(TokenKind::pu_equal))926        return std::nullopt;927 928      auto Visibility = parseShaderVisibility(TokenKind::kw_visibility);929      if (!Visibility.has_value())930        return std::nullopt;931      Params.Visibility = Visibility;932    } else if (tryConsumeExpectedToken(TokenKind::kw_flags)) {933      // `flags` `=` STATIC_SAMPLE_FLAGS934      if (Params.Flags.has_value()) {935        reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;936        return std::nullopt;937      }938 939      if (consumeExpectedToken(TokenKind::pu_equal))940        return std::nullopt;941 942      auto Flags = parseStaticSamplerFlags(TokenKind::kw_flags);943      if (!Flags.has_value())944        return std::nullopt;945      Params.Flags = Flags;946    } else {947      consumeNextToken(); // let diagnostic be at the start of invalid token948      reportDiag(diag::err_hlsl_invalid_token)949          << /*parameter=*/0 << /*param of*/ TokenKind::kw_StaticSampler;950      return std::nullopt;951    }952 953    // ',' denotes another element, otherwise, expected to be at ')'954    if (!tryConsumeExpectedToken(TokenKind::pu_comma))955      break;956  }957 958  return Params;959}960 961std::optional<uint32_t> RootSignatureParser::parseUIntParam() {962  assert(CurToken.TokKind == TokenKind::pu_equal &&963         "Expects to only be invoked starting at given keyword");964  tryConsumeExpectedToken(TokenKind::pu_plus);965  if (consumeExpectedToken(TokenKind::int_literal, diag::err_expected_after,966                           CurToken.TokKind))967    return std::nullopt;968  return handleUIntLiteral();969}970 971std::optional<Register> RootSignatureParser::parseRegister() {972  assert((CurToken.TokKind == TokenKind::bReg ||973          CurToken.TokKind == TokenKind::tReg ||974          CurToken.TokKind == TokenKind::uReg ||975          CurToken.TokKind == TokenKind::sReg) &&976         "Expects to only be invoked starting at given keyword");977 978  Register Reg;979  switch (CurToken.TokKind) {980  default:981    llvm_unreachable("Switch for consumed token was not provided");982  case TokenKind::bReg:983    Reg.ViewType = RegisterType::BReg;984    break;985  case TokenKind::tReg:986    Reg.ViewType = RegisterType::TReg;987    break;988  case TokenKind::uReg:989    Reg.ViewType = RegisterType::UReg;990    break;991  case TokenKind::sReg:992    Reg.ViewType = RegisterType::SReg;993    break;994  }995 996  auto Number = handleUIntLiteral();997  if (!Number.has_value())998    return std::nullopt; // propogate NumericLiteralParser error999 1000  Reg.Number = *Number;1001  return Reg;1002}1003 1004std::optional<float> RootSignatureParser::parseFloatParam() {1005  assert(CurToken.TokKind == TokenKind::pu_equal &&1006         "Expects to only be invoked starting at given keyword");1007  // Consume sign modifier1008  bool Signed =1009      tryConsumeExpectedToken({TokenKind::pu_plus, TokenKind::pu_minus});1010  bool Negated = Signed && CurToken.TokKind == TokenKind::pu_minus;1011 1012  // DXC will treat a postive signed integer as unsigned1013  if (!Negated && tryConsumeExpectedToken(TokenKind::int_literal)) {1014    std::optional<uint32_t> UInt = handleUIntLiteral();1015    if (!UInt.has_value())1016      return std::nullopt;1017    return float(UInt.value());1018  }1019 1020  if (Negated && tryConsumeExpectedToken(TokenKind::int_literal)) {1021    std::optional<int32_t> Int = handleIntLiteral(Negated);1022    if (!Int.has_value())1023      return std::nullopt;1024    return float(Int.value());1025  }1026 1027  if (tryConsumeExpectedToken(TokenKind::float_literal)) {1028    std::optional<float> Float = handleFloatLiteral(Negated);1029    if (!Float.has_value())1030      return std::nullopt;1031    return Float.value();1032  }1033 1034  return std::nullopt;1035}1036 1037std::optional<llvm::dxbc::ShaderVisibility>1038RootSignatureParser::parseShaderVisibility(TokenKind Context) {1039  assert(CurToken.TokKind == TokenKind::pu_equal &&1040         "Expects to only be invoked starting at given keyword");1041 1042  TokenKind Expected[] = {1043#define SHADER_VISIBILITY_ENUM(NAME, LIT) TokenKind::en_##NAME,1044#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1045  };1046 1047  if (!tryConsumeExpectedToken(Expected)) {1048    consumeNextToken(); // consume token to point at invalid token1049    reportDiag(diag::err_hlsl_invalid_token)1050        << /*value=*/1 << /*value of*/ Context;1051    return std::nullopt;1052  }1053 1054  switch (CurToken.TokKind) {1055#define SHADER_VISIBILITY_ENUM(NAME, LIT)                                      \1056  case TokenKind::en_##NAME:                                                   \1057    return llvm::dxbc::ShaderVisibility::NAME;                                 \1058    break;1059#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1060  default:1061    llvm_unreachable("Switch for consumed enum token was not provided");1062  }1063 1064  return std::nullopt;1065}1066 1067std::optional<llvm::dxbc::SamplerFilter>1068RootSignatureParser::parseSamplerFilter(TokenKind Context) {1069  assert(CurToken.TokKind == TokenKind::pu_equal &&1070         "Expects to only be invoked starting at given keyword");1071 1072  TokenKind Expected[] = {1073#define FILTER_ENUM(NAME, LIT) TokenKind::en_##NAME,1074#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1075  };1076 1077  if (!tryConsumeExpectedToken(Expected)) {1078    consumeNextToken(); // consume token to point at invalid token1079    reportDiag(diag::err_hlsl_invalid_token)1080        << /*value=*/1 << /*value of*/ Context;1081    return std::nullopt;1082  }1083 1084  switch (CurToken.TokKind) {1085#define FILTER_ENUM(NAME, LIT)                                                 \1086  case TokenKind::en_##NAME:                                                   \1087    return llvm::dxbc::SamplerFilter::NAME;                                    \1088    break;1089#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1090  default:1091    llvm_unreachable("Switch for consumed enum token was not provided");1092  }1093 1094  return std::nullopt;1095}1096 1097std::optional<llvm::dxbc::TextureAddressMode>1098RootSignatureParser::parseTextureAddressMode(TokenKind Context) {1099  assert(CurToken.TokKind == TokenKind::pu_equal &&1100         "Expects to only be invoked starting at given keyword");1101 1102  TokenKind Expected[] = {1103#define TEXTURE_ADDRESS_MODE_ENUM(NAME, LIT) TokenKind::en_##NAME,1104#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1105  };1106 1107  if (!tryConsumeExpectedToken(Expected)) {1108    consumeNextToken(); // consume token to point at invalid token1109    reportDiag(diag::err_hlsl_invalid_token)1110        << /*value=*/1 << /*value of*/ Context;1111    return std::nullopt;1112  }1113 1114  switch (CurToken.TokKind) {1115#define TEXTURE_ADDRESS_MODE_ENUM(NAME, LIT)                                   \1116  case TokenKind::en_##NAME:                                                   \1117    return llvm::dxbc::TextureAddressMode::NAME;                               \1118    break;1119#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1120  default:1121    llvm_unreachable("Switch for consumed enum token was not provided");1122  }1123 1124  return std::nullopt;1125}1126 1127std::optional<llvm::dxbc::ComparisonFunc>1128RootSignatureParser::parseComparisonFunc(TokenKind Context) {1129  assert(CurToken.TokKind == TokenKind::pu_equal &&1130         "Expects to only be invoked starting at given keyword");1131 1132  TokenKind Expected[] = {1133#define COMPARISON_FUNC_ENUM(NAME, LIT) TokenKind::en_##NAME,1134#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1135  };1136 1137  if (!tryConsumeExpectedToken(Expected)) {1138    consumeNextToken(); // consume token to point at invalid token1139    reportDiag(diag::err_hlsl_invalid_token)1140        << /*value=*/1 << /*value of*/ Context;1141    return std::nullopt;1142  }1143 1144  switch (CurToken.TokKind) {1145#define COMPARISON_FUNC_ENUM(NAME, LIT)                                        \1146  case TokenKind::en_##NAME:                                                   \1147    return llvm::dxbc::ComparisonFunc::NAME;                                   \1148    break;1149#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1150  default:1151    llvm_unreachable("Switch for consumed enum token was not provided");1152  }1153 1154  return std::nullopt;1155}1156 1157std::optional<llvm::dxbc::StaticBorderColor>1158RootSignatureParser::parseStaticBorderColor(TokenKind Context) {1159  assert(CurToken.TokKind == TokenKind::pu_equal &&1160         "Expects to only be invoked starting at given keyword");1161 1162  TokenKind Expected[] = {1163#define STATIC_BORDER_COLOR_ENUM(NAME, LIT) TokenKind::en_##NAME,1164#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1165  };1166 1167  if (!tryConsumeExpectedToken(Expected)) {1168    consumeNextToken(); // consume token to point at invalid token1169    reportDiag(diag::err_hlsl_invalid_token)1170        << /*value=*/1 << /*value of*/ Context;1171    return std::nullopt;1172  }1173 1174  switch (CurToken.TokKind) {1175#define STATIC_BORDER_COLOR_ENUM(NAME, LIT)                                    \1176  case TokenKind::en_##NAME:                                                   \1177    return llvm::dxbc::StaticBorderColor::NAME;                                \1178    break;1179#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1180  default:1181    llvm_unreachable("Switch for consumed enum token was not provided");1182  }1183 1184  return std::nullopt;1185}1186 1187std::optional<llvm::dxbc::RootDescriptorFlags>1188RootSignatureParser::parseRootDescriptorFlags(TokenKind Context) {1189  assert(CurToken.TokKind == TokenKind::pu_equal &&1190         "Expects to only be invoked starting at given keyword");1191 1192  // Handle the edge-case of '0' to specify no flags set1193  if (tryConsumeExpectedToken(TokenKind::int_literal)) {1194    if (!verifyZeroFlag()) {1195      reportDiag(diag::err_hlsl_rootsig_non_zero_flag);1196      return std::nullopt;1197    }1198    return llvm::dxbc::RootDescriptorFlags::None;1199  }1200 1201  TokenKind Expected[] = {1202#define ROOT_DESCRIPTOR_FLAG_ENUM(NAME, LIT) TokenKind::en_##NAME,1203#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1204  };1205 1206  std::optional<llvm::dxbc::RootDescriptorFlags> Flags;1207 1208  do {1209    if (tryConsumeExpectedToken(Expected)) {1210      switch (CurToken.TokKind) {1211#define ROOT_DESCRIPTOR_FLAG_ENUM(NAME, LIT)                                   \1212  case TokenKind::en_##NAME:                                                   \1213    Flags = maybeOrFlag<llvm::dxbc::RootDescriptorFlags>(                      \1214        Flags, llvm::dxbc::RootDescriptorFlags::NAME);                         \1215    break;1216#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1217      default:1218        llvm_unreachable("Switch for consumed enum token was not provided");1219      }1220    } else {1221      consumeNextToken(); // consume token to point at invalid token1222      reportDiag(diag::err_hlsl_invalid_token)1223          << /*value=*/1 << /*value of*/ Context;1224      return std::nullopt;1225    }1226  } while (tryConsumeExpectedToken(TokenKind::pu_or));1227 1228  return Flags;1229}1230 1231std::optional<llvm::dxbc::DescriptorRangeFlags>1232RootSignatureParser::parseDescriptorRangeFlags(TokenKind Context) {1233  assert(CurToken.TokKind == TokenKind::pu_equal &&1234         "Expects to only be invoked starting at given keyword");1235 1236  // Handle the edge-case of '0' to specify no flags set1237  if (tryConsumeExpectedToken(TokenKind::int_literal)) {1238    if (!verifyZeroFlag()) {1239      reportDiag(diag::err_hlsl_rootsig_non_zero_flag);1240      return std::nullopt;1241    }1242    return llvm::dxbc::DescriptorRangeFlags::None;1243  }1244 1245  TokenKind Expected[] = {1246#define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON) TokenKind::en_##NAME,1247#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1248  };1249 1250  std::optional<llvm::dxbc::DescriptorRangeFlags> Flags;1251 1252  do {1253    if (tryConsumeExpectedToken(Expected)) {1254      switch (CurToken.TokKind) {1255#define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON)                              \1256  case TokenKind::en_##NAME:                                                   \1257    Flags = maybeOrFlag<llvm::dxbc::DescriptorRangeFlags>(                     \1258        Flags, llvm::dxbc::DescriptorRangeFlags::NAME);                        \1259    break;1260#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1261      default:1262        llvm_unreachable("Switch for consumed enum token was not provided");1263      }1264    } else {1265      consumeNextToken(); // consume token to point at invalid token1266      reportDiag(diag::err_hlsl_invalid_token)1267          << /*value=*/1 << /*value of*/ Context;1268      return std::nullopt;1269    }1270  } while (tryConsumeExpectedToken(TokenKind::pu_or));1271 1272  return Flags;1273}1274 1275std::optional<llvm::dxbc::StaticSamplerFlags>1276RootSignatureParser::parseStaticSamplerFlags(TokenKind Context) {1277  assert(CurToken.TokKind == TokenKind::pu_equal &&1278         "Expects to only be invoked starting at given keyword");1279 1280  // Handle the edge-case of '0' to specify no flags set1281  if (tryConsumeExpectedToken(TokenKind::int_literal)) {1282    if (!verifyZeroFlag()) {1283      reportDiag(diag::err_hlsl_rootsig_non_zero_flag);1284      return std::nullopt;1285    }1286    return llvm::dxbc::StaticSamplerFlags::None;1287  }1288 1289  TokenKind Expected[] = {1290#define STATIC_SAMPLER_FLAG_ENUM(NAME, LIT) TokenKind::en_##NAME,1291#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1292  };1293 1294  std::optional<llvm::dxbc::StaticSamplerFlags> Flags;1295 1296  do {1297    if (tryConsumeExpectedToken(Expected)) {1298      switch (CurToken.TokKind) {1299#define STATIC_SAMPLER_FLAG_ENUM(NAME, LIT)                                    \1300  case TokenKind::en_##NAME:                                                   \1301    Flags = maybeOrFlag<llvm::dxbc::StaticSamplerFlags>(                       \1302        Flags, llvm::dxbc::StaticSamplerFlags::NAME);                          \1303    break;1304#include "clang/Lex/HLSLRootSignatureTokenKinds.def"1305      default:1306        llvm_unreachable("Switch for consumed enum token was not provided");1307      }1308    } else {1309      consumeNextToken(); // consume token to point at invalid token1310      reportDiag(diag::err_hlsl_invalid_token)1311          << /*value=*/1 << /*value of*/ Context;1312      return std::nullopt;1313    }1314  } while (tryConsumeExpectedToken(TokenKind::pu_or));1315 1316  return Flags;1317}1318 1319std::optional<uint32_t> RootSignatureParser::handleUIntLiteral() {1320  // Parse the numeric value and do semantic checks on its specification1321  clang::NumericLiteralParser Literal(1322      CurToken.NumSpelling, getTokenLocation(CurToken), PP.getSourceManager(),1323      PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics());1324  if (Literal.hadError)1325    return std::nullopt; // Error has already been reported so just return1326 1327  assert(Literal.isIntegerLiteral() &&1328         "NumSpelling can only consist of digits");1329 1330  llvm::APSInt Val(32, /*IsUnsigned=*/true);1331  if (Literal.GetIntegerValue(Val)) {1332    // Report that the value has overflowed1333    reportDiag(diag::err_hlsl_number_literal_overflow)1334        << /*integer type*/ 0 << /*is signed*/ 0;1335    return std::nullopt;1336  }1337 1338  return Val.getExtValue();1339}1340 1341std::optional<int32_t> RootSignatureParser::handleIntLiteral(bool Negated) {1342  // Parse the numeric value and do semantic checks on its specification1343  clang::NumericLiteralParser Literal(1344      CurToken.NumSpelling, getTokenLocation(CurToken), PP.getSourceManager(),1345      PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics());1346  if (Literal.hadError)1347    return std::nullopt; // Error has already been reported so just return1348 1349  assert(Literal.isIntegerLiteral() &&1350         "NumSpelling can only consist of digits");1351 1352  llvm::APSInt Val(32, /*IsUnsigned=*/true);1353  // GetIntegerValue will overwrite Val from the parsed Literal and return1354  // true if it overflows as a 32-bit unsigned int1355  bool Overflowed = Literal.GetIntegerValue(Val);1356 1357  // So we then need to check that it doesn't overflow as a 32-bit signed int:1358  int64_t MaxNegativeMagnitude = -int64_t(std::numeric_limits<int32_t>::min());1359  Overflowed |= (Negated && MaxNegativeMagnitude < Val.getExtValue());1360 1361  int64_t MaxPositiveMagnitude = int64_t(std::numeric_limits<int32_t>::max());1362  Overflowed |= (!Negated && MaxPositiveMagnitude < Val.getExtValue());1363 1364  if (Overflowed) {1365    // Report that the value has overflowed1366    reportDiag(diag::err_hlsl_number_literal_overflow)1367        << /*integer type*/ 0 << /*is signed*/ 1;1368    return std::nullopt;1369  }1370 1371  if (Negated)1372    Val = -Val;1373 1374  return int32_t(Val.getExtValue());1375}1376 1377std::optional<float> RootSignatureParser::handleFloatLiteral(bool Negated) {1378  // Parse the numeric value and do semantic checks on its specification1379  clang::NumericLiteralParser Literal(1380      CurToken.NumSpelling, getTokenLocation(CurToken), PP.getSourceManager(),1381      PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics());1382  if (Literal.hadError)1383    return std::nullopt; // Error has already been reported so just return1384 1385  assert(Literal.isFloatingLiteral() &&1386         "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "1387         "will be caught and reported by NumericLiteralParser.");1388 1389  // DXC used `strtod` to convert the token string to a float which corresponds1390  // to:1391  auto DXCSemantics = llvm::APFloat::Semantics::S_IEEEdouble;1392  auto DXCRoundingMode = llvm::RoundingMode::NearestTiesToEven;1393 1394  llvm::APFloat Val(llvm::APFloat::EnumToSemantics(DXCSemantics));1395  llvm::APFloat::opStatus Status(Literal.GetFloatValue(Val, DXCRoundingMode));1396 1397  // Note: we do not error when opStatus::opInexact by itself as this just1398  // denotes that rounding occured but not that it is invalid1399  assert(!(Status & llvm::APFloat::opStatus::opInvalidOp) &&1400         "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "1401         "will be caught and reported by NumericLiteralParser.");1402 1403  assert(!(Status & llvm::APFloat::opStatus::opDivByZero) &&1404         "It is not possible for a division to be performed when "1405         "constructing an APFloat from a string");1406 1407  if (Status & llvm::APFloat::opStatus::opUnderflow) {1408    // Report that the value has underflowed1409    reportDiag(diag::err_hlsl_number_literal_underflow);1410    return std::nullopt;1411  }1412 1413  if (Status & llvm::APFloat::opStatus::opOverflow) {1414    // Report that the value has overflowed1415    reportDiag(diag::err_hlsl_number_literal_overflow) << /*float type*/ 1;1416    return std::nullopt;1417  }1418 1419  if (Negated)1420    Val = -Val;1421 1422  double DoubleVal = Val.convertToDouble();1423  double FloatMax = double(std::numeric_limits<float>::max());1424  if (FloatMax < DoubleVal || DoubleVal < -FloatMax) {1425    // Report that the value has overflowed1426    reportDiag(diag::err_hlsl_number_literal_overflow) << /*float type*/ 1;1427    return std::nullopt;1428  }1429 1430  return static_cast<float>(DoubleVal);1431}1432 1433bool RootSignatureParser::verifyZeroFlag() {1434  assert(CurToken.TokKind == TokenKind::int_literal);1435  auto X = handleUIntLiteral();1436  return X.has_value() && X.value() == 0;1437}1438 1439bool RootSignatureParser::peekExpectedToken(TokenKind Expected) {1440  return peekExpectedToken(ArrayRef{Expected});1441}1442 1443bool RootSignatureParser::peekExpectedToken(ArrayRef<TokenKind> AnyExpected) {1444  RootSignatureToken Result = Lexer.peekNextToken();1445  return llvm::is_contained(AnyExpected, Result.TokKind);1446}1447 1448bool RootSignatureParser::consumeExpectedToken(TokenKind Expected,1449                                               unsigned DiagID,1450                                               TokenKind Context) {1451  if (tryConsumeExpectedToken(Expected))1452    return false;1453 1454  // Report unexpected token kind error1455  DiagnosticBuilder DB = reportDiag(DiagID);1456  switch (DiagID) {1457  case diag::err_expected:1458    DB << Expected;1459    break;1460  case diag::err_expected_either:1461    DB << Expected << Context;1462    break;1463  case diag::err_expected_after:1464    DB << Context << Expected;1465    break;1466  default:1467    break;1468  }1469  return true;1470}1471 1472bool RootSignatureParser::tryConsumeExpectedToken(TokenKind Expected) {1473  return tryConsumeExpectedToken(ArrayRef{Expected});1474}1475 1476bool RootSignatureParser::tryConsumeExpectedToken(1477    ArrayRef<TokenKind> AnyExpected) {1478  // If not the expected token just return1479  if (!peekExpectedToken(AnyExpected))1480    return false;1481  consumeNextToken();1482  return true;1483}1484 1485bool RootSignatureParser::skipUntilExpectedToken(TokenKind Expected) {1486  return skipUntilExpectedToken(ArrayRef{Expected});1487}1488 1489bool RootSignatureParser::skipUntilExpectedToken(1490    ArrayRef<TokenKind> AnyExpected) {1491 1492  while (!peekExpectedToken(AnyExpected)) {1493    if (peekExpectedToken(TokenKind::end_of_stream))1494      return false;1495    consumeNextToken();1496  }1497 1498  return true;1499}1500 1501bool RootSignatureParser::skipUntilClosedParens(uint32_t NumParens) {1502  TokenKind ParenKinds[] = {1503      TokenKind::pu_l_paren,1504      TokenKind::pu_r_paren,1505  };1506  while (skipUntilExpectedToken(ParenKinds)) {1507    consumeNextToken();1508    if (CurToken.TokKind == TokenKind::pu_r_paren)1509      NumParens--;1510    else1511      NumParens++;1512    if (NumParens == 0)1513      return true;1514  }1515 1516  return false;1517}1518 1519SourceLocation RootSignatureParser::getTokenLocation(RootSignatureToken Tok) {1520  return Signature->getLocationOfByte(Tok.LocOffset, PP.getSourceManager(),1521                                      PP.getLangOpts(), PP.getTargetInfo());1522}1523 1524IdentifierInfo *ParseHLSLRootSignature(Sema &Actions,1525                                       llvm::dxbc::RootSignatureVersion Version,1526                                       StringLiteral *Signature) {1527  // Construct our identifier1528  auto [DeclIdent, Found] =1529      Actions.HLSL().ActOnStartRootSignatureDecl(Signature->getString());1530  // If we haven't found an already defined DeclIdent then parse the root1531  // signature string and construct the in-memory elements1532  if (!Found) {1533    // Invoke the root signature parser to construct the in-memory constructs1534    hlsl::RootSignatureParser Parser(Version, Signature,1535                                     Actions.getPreprocessor());1536    if (Parser.parse())1537      return nullptr;1538 1539    // Construct the declaration.1540    Actions.HLSL().ActOnFinishRootSignatureDecl(1541        Signature->getBeginLoc(), DeclIdent, Parser.getElements());1542  }1543 1544  return DeclIdent;1545}1546 1547void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig) {1548  ASTConsumer *Consumer = &S.getASTConsumer();1549 1550  // Minimally initalize the parser. This does a couple things:1551  // - initializes Sema scope handling1552  // - invokes HLSLExternalSemaSource1553  // - invokes the preprocessor to lex the macros in the file1554  std::unique_ptr<Parser> P(new Parser(S.getPreprocessor(), S, true));1555  S.getPreprocessor().EnterMainSourceFile();1556 1557  bool HaveLexer = S.getPreprocessor().getCurrentLexer();1558  if (HaveLexer) {1559    P->Initialize();1560    S.ActOnStartOfTranslationUnit();1561 1562    // Skim through the file to parse to find the define1563    while (P->getCurToken().getKind() != tok::eof)1564      P->ConsumeAnyToken();1565 1566    HLSLRootSignatureDecl *SignatureDecl =1567        S.HLSL().lookupRootSignatureOverrideDecl(1568            S.getASTContext().getTranslationUnitDecl());1569 1570    if (SignatureDecl)1571      Consumer->HandleTopLevelDecl(DeclGroupRef(SignatureDecl));1572    else1573      S.getDiagnostics().Report(diag::err_hlsl_rootsignature_entry)1574          << EntryRootSig;1575  }1576 1577  Consumer->HandleTranslationUnit(S.getASTContext());1578}1579 1580} // namespace hlsl1581} // namespace clang1582