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