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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Parse/ParseHLSLRootSignature.h" 10 11 #include "clang/Lex/LiteralSupport.h" 12 13 using namespace llvm::hlsl::rootsig; 14 15 namespace clang { 16 namespace hlsl { 17 18 using TokenKind = RootSignatureToken::Kind; 19 20 static const TokenKind RootElementKeywords[] = { 21 TokenKind::kw_RootFlags, 22 TokenKind::kw_CBV, 23 TokenKind::kw_UAV, 24 TokenKind::kw_SRV, 25 TokenKind::kw_DescriptorTable, 26 TokenKind::kw_StaticSampler, 27 }; 28 29 RootSignatureParser::RootSignatureParser( 30 llvm::dxbc::RootSignatureVersion Version, 31 SmallVector<RootSignatureElement> &Elements, StringLiteral *Signature, 32 Preprocessor &PP) 33 : Version(Version), Elements(Elements), Signature(Signature), 34 Lexer(Signature->getString()), PP(PP), CurToken(0) {} 35 36 bool RootSignatureParser::parse() { 37 // Iterate as many RootSignatureElements as possible, until we hit the 38 // end of the stream 39 bool HadError = false; 40 while (!peekExpectedToken(TokenKind::end_of_stream)) { 41 if (tryConsumeExpectedToken(TokenKind::kw_RootFlags)) { 42 SourceLocation ElementLoc = getTokenLocation(CurToken); 43 auto Flags = parseRootFlags(); 44 if (!Flags.has_value()) { 45 HadError = true; 46 skipUntilExpectedToken(RootElementKeywords); 47 continue; 48 } 49 50 Elements.emplace_back(ElementLoc, *Flags); 51 } else if (tryConsumeExpectedToken(TokenKind::kw_RootConstants)) { 52 SourceLocation ElementLoc = getTokenLocation(CurToken); 53 auto Constants = parseRootConstants(); 54 if (!Constants.has_value()) { 55 HadError = true; 56 skipUntilExpectedToken(RootElementKeywords); 57 continue; 58 } 59 Elements.emplace_back(ElementLoc, *Constants); 60 } else if (tryConsumeExpectedToken(TokenKind::kw_DescriptorTable)) { 61 SourceLocation ElementLoc = getTokenLocation(CurToken); 62 auto Table = parseDescriptorTable(); 63 if (!Table.has_value()) { 64 HadError = true; 65 // We are within a DescriptorTable, we will do our best to recover 66 // by skipping until we encounter the expected closing ')'. 67 skipUntilClosedParens(); 68 consumeNextToken(); 69 skipUntilExpectedToken(RootElementKeywords); 70 continue; 71 } 72 Elements.emplace_back(ElementLoc, *Table); 73 } else if (tryConsumeExpectedToken( 74 {TokenKind::kw_CBV, TokenKind::kw_SRV, TokenKind::kw_UAV})) { 75 SourceLocation ElementLoc = getTokenLocation(CurToken); 76 auto Descriptor = parseRootDescriptor(); 77 if (!Descriptor.has_value()) { 78 HadError = true; 79 skipUntilExpectedToken(RootElementKeywords); 80 continue; 81 } 82 Elements.emplace_back(ElementLoc, *Descriptor); 83 } else if (tryConsumeExpectedToken(TokenKind::kw_StaticSampler)) { 84 SourceLocation ElementLoc = getTokenLocation(CurToken); 85 auto Sampler = parseStaticSampler(); 86 if (!Sampler.has_value()) { 87 HadError = true; 88 skipUntilExpectedToken(RootElementKeywords); 89 continue; 90 } 91 Elements.emplace_back(ElementLoc, *Sampler); 92 } else { 93 HadError = true; 94 consumeNextToken(); // let diagnostic be at the start of invalid token 95 reportDiag(diag::err_hlsl_invalid_token) 96 << /*parameter=*/0 << /*param of*/ TokenKind::kw_RootSignature; 97 skipUntilExpectedToken(RootElementKeywords); 98 continue; 99 } 100 101 if (!tryConsumeExpectedToken(TokenKind::pu_comma)) { 102 // ',' denotes another element, otherwise, expected to be at end of stream 103 break; 104 } 105 } 106 107 return HadError || 108 consumeExpectedToken(TokenKind::end_of_stream, 109 diag::err_expected_either, TokenKind::pu_comma); 110 } 111 112 template <typename FlagType> 113 static FlagType maybeOrFlag(std::optional<FlagType> Flags, FlagType Flag) { 114 if (!Flags.has_value()) 115 return Flag; 116 117 return static_cast<FlagType>(llvm::to_underlying(Flags.value()) | 118 llvm::to_underlying(Flag)); 119 } 120 121 std::optional<llvm::dxbc::RootFlags> RootSignatureParser::parseRootFlags() { 122 assert(CurToken.TokKind == TokenKind::kw_RootFlags && 123 "Expects to only be invoked starting at given keyword"); 124 125 if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after, 126 CurToken.TokKind)) 127 return std::nullopt; 128 129 std::optional<llvm::dxbc::RootFlags> Flags = llvm::dxbc::RootFlags::None; 130 131 // Handle valid empty case 132 if (tryConsumeExpectedToken(TokenKind::pu_r_paren)) 133 return Flags; 134 135 // Handle the edge-case of '0' to specify no flags set 136 if (tryConsumeExpectedToken(TokenKind::int_literal)) { 137 if (!verifyZeroFlag()) { 138 reportDiag(diag::err_hlsl_rootsig_non_zero_flag); 139 return std::nullopt; 140 } 141 } else { 142 // Otherwise, parse as many flags as possible 143 TokenKind Expected[] = { 144 #define ROOT_FLAG_ENUM(NAME, LIT) TokenKind::en_##NAME, 145 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 146 }; 147 148 do { 149 if (tryConsumeExpectedToken(Expected)) { 150 switch (CurToken.TokKind) { 151 #define ROOT_FLAG_ENUM(NAME, LIT) \ 152 case TokenKind::en_##NAME: \ 153 Flags = maybeOrFlag<llvm::dxbc::RootFlags>(Flags, \ 154 llvm::dxbc::RootFlags::NAME); \ 155 break; 156 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 157 default: 158 llvm_unreachable("Switch for consumed enum token was not provided"); 159 } 160 } else { 161 consumeNextToken(); // consume token to point at invalid token 162 reportDiag(diag::err_hlsl_invalid_token) 163 << /*value=*/1 << /*value of*/ TokenKind::kw_RootFlags; 164 return std::nullopt; 165 } 166 } while (tryConsumeExpectedToken(TokenKind::pu_or)); 167 } 168 169 if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either, 170 TokenKind::pu_comma)) 171 return std::nullopt; 172 173 return Flags; 174 } 175 176 std::optional<RootConstants> RootSignatureParser::parseRootConstants() { 177 assert(CurToken.TokKind == TokenKind::kw_RootConstants && 178 "Expects to only be invoked starting at given keyword"); 179 180 if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after, 181 CurToken.TokKind)) 182 return std::nullopt; 183 184 RootConstants Constants; 185 186 auto Params = parseRootConstantParams(); 187 if (!Params.has_value()) 188 return std::nullopt; 189 190 if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either, 191 TokenKind::pu_comma)) 192 return std::nullopt; 193 194 // Check mandatory parameters where provided 195 if (!Params->Num32BitConstants.has_value()) { 196 reportDiag(diag::err_hlsl_rootsig_missing_param) 197 << TokenKind::kw_num32BitConstants; 198 return std::nullopt; 199 } 200 201 Constants.Num32BitConstants = Params->Num32BitConstants.value(); 202 203 if (!Params->Reg.has_value()) { 204 reportDiag(diag::err_hlsl_rootsig_missing_param) << TokenKind::bReg; 205 return std::nullopt; 206 } 207 208 Constants.Reg = Params->Reg.value(); 209 210 // Fill in optional parameters 211 if (Params->Visibility.has_value()) 212 Constants.Visibility = Params->Visibility.value(); 213 214 if (Params->Space.has_value()) 215 Constants.Space = Params->Space.value(); 216 217 return Constants; 218 } 219 220 std::optional<RootDescriptor> RootSignatureParser::parseRootDescriptor() { 221 assert((CurToken.TokKind == TokenKind::kw_CBV || 222 CurToken.TokKind == TokenKind::kw_SRV || 223 CurToken.TokKind == TokenKind::kw_UAV) && 224 "Expects to only be invoked starting at given keyword"); 225 226 TokenKind DescriptorKind = CurToken.TokKind; 227 228 if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after, 229 CurToken.TokKind)) 230 return std::nullopt; 231 232 RootDescriptor Descriptor; 233 TokenKind ExpectedReg; 234 switch (DescriptorKind) { 235 default: 236 llvm_unreachable("Switch for consumed token was not provided"); 237 case TokenKind::kw_CBV: 238 Descriptor.Type = DescriptorType::CBuffer; 239 ExpectedReg = TokenKind::bReg; 240 break; 241 case TokenKind::kw_SRV: 242 Descriptor.Type = DescriptorType::SRV; 243 ExpectedReg = TokenKind::tReg; 244 break; 245 case TokenKind::kw_UAV: 246 Descriptor.Type = DescriptorType::UAV; 247 ExpectedReg = TokenKind::uReg; 248 break; 249 } 250 Descriptor.setDefaultFlags(Version); 251 252 auto Params = parseRootDescriptorParams(DescriptorKind, ExpectedReg); 253 if (!Params.has_value()) 254 return std::nullopt; 255 256 if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either, 257 TokenKind::pu_comma)) 258 return std::nullopt; 259 260 // Check mandatory parameters were provided 261 if (!Params->Reg.has_value()) { 262 reportDiag(diag::err_hlsl_rootsig_missing_param) << ExpectedReg; 263 return std::nullopt; 264 } 265 266 Descriptor.Reg = Params->Reg.value(); 267 268 // Fill in optional values 269 if (Params->Space.has_value()) 270 Descriptor.Space = Params->Space.value(); 271 272 if (Params->Visibility.has_value()) 273 Descriptor.Visibility = Params->Visibility.value(); 274 275 if (Params->Flags.has_value()) 276 Descriptor.Flags = Params->Flags.value(); 277 278 return Descriptor; 279 } 280 281 std::optional<DescriptorTable> RootSignatureParser::parseDescriptorTable() { 282 assert(CurToken.TokKind == TokenKind::kw_DescriptorTable && 283 "Expects to only be invoked starting at given keyword"); 284 285 if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after, 286 CurToken.TokKind)) 287 return std::nullopt; 288 289 DescriptorTable Table; 290 std::optional<llvm::dxbc::ShaderVisibility> Visibility; 291 292 // Iterate as many Clauses as possible, until we hit ')' 293 while (!peekExpectedToken(TokenKind::pu_r_paren)) { 294 if (tryConsumeExpectedToken({TokenKind::kw_CBV, TokenKind::kw_SRV, 295 TokenKind::kw_UAV, TokenKind::kw_Sampler})) { 296 // DescriptorTableClause - CBV, SRV, UAV, or Sampler 297 SourceLocation ElementLoc = getTokenLocation(CurToken); 298 auto Clause = parseDescriptorTableClause(); 299 if (!Clause.has_value()) { 300 // We are within a DescriptorTableClause, we will do our best to recover 301 // by skipping until we encounter the expected closing ')' 302 skipUntilExpectedToken(TokenKind::pu_r_paren); 303 consumeNextToken(); 304 return std::nullopt; 305 } 306 Elements.emplace_back(ElementLoc, *Clause); 307 Table.NumClauses++; 308 } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) { 309 // visibility = SHADER_VISIBILITY 310 if (Visibility.has_value()) { 311 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 312 return std::nullopt; 313 } 314 315 if (consumeExpectedToken(TokenKind::pu_equal)) 316 return std::nullopt; 317 318 Visibility = parseShaderVisibility(TokenKind::kw_visibility); 319 if (!Visibility.has_value()) 320 return std::nullopt; 321 } else { 322 consumeNextToken(); // let diagnostic be at the start of invalid token 323 reportDiag(diag::err_hlsl_invalid_token) 324 << /*parameter=*/0 << /*param of*/ TokenKind::kw_DescriptorTable; 325 return std::nullopt; 326 } 327 328 // ',' denotes another element, otherwise, expected to be at ')' 329 if (!tryConsumeExpectedToken(TokenKind::pu_comma)) 330 break; 331 } 332 333 if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either, 334 TokenKind::pu_comma)) 335 return std::nullopt; 336 337 // Fill in optional visibility 338 if (Visibility.has_value()) 339 Table.Visibility = Visibility.value(); 340 341 return Table; 342 } 343 344 std::optional<DescriptorTableClause> 345 RootSignatureParser::parseDescriptorTableClause() { 346 assert((CurToken.TokKind == TokenKind::kw_CBV || 347 CurToken.TokKind == TokenKind::kw_SRV || 348 CurToken.TokKind == TokenKind::kw_UAV || 349 CurToken.TokKind == TokenKind::kw_Sampler) && 350 "Expects to only be invoked starting at given keyword"); 351 352 TokenKind ParamKind = CurToken.TokKind; 353 354 if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after, 355 CurToken.TokKind)) 356 return std::nullopt; 357 358 DescriptorTableClause Clause; 359 TokenKind ExpectedReg; 360 switch (ParamKind) { 361 default: 362 llvm_unreachable("Switch for consumed token was not provided"); 363 case TokenKind::kw_CBV: 364 Clause.Type = ClauseType::CBuffer; 365 ExpectedReg = TokenKind::bReg; 366 break; 367 case TokenKind::kw_SRV: 368 Clause.Type = ClauseType::SRV; 369 ExpectedReg = TokenKind::tReg; 370 break; 371 case TokenKind::kw_UAV: 372 Clause.Type = ClauseType::UAV; 373 ExpectedReg = TokenKind::uReg; 374 break; 375 case TokenKind::kw_Sampler: 376 Clause.Type = ClauseType::Sampler; 377 ExpectedReg = TokenKind::sReg; 378 break; 379 } 380 Clause.setDefaultFlags(Version); 381 382 auto Params = parseDescriptorTableClauseParams(ParamKind, ExpectedReg); 383 if (!Params.has_value()) 384 return std::nullopt; 385 386 if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either, 387 TokenKind::pu_comma)) 388 return std::nullopt; 389 390 // Check mandatory parameters were provided 391 if (!Params->Reg.has_value()) { 392 reportDiag(diag::err_hlsl_rootsig_missing_param) << ExpectedReg; 393 return std::nullopt; 394 } 395 396 Clause.Reg = Params->Reg.value(); 397 398 // Fill in optional values 399 if (Params->NumDescriptors.has_value()) 400 Clause.NumDescriptors = Params->NumDescriptors.value(); 401 402 if (Params->Space.has_value()) 403 Clause.Space = Params->Space.value(); 404 405 if (Params->Offset.has_value()) 406 Clause.Offset = Params->Offset.value(); 407 408 if (Params->Flags.has_value()) 409 Clause.Flags = Params->Flags.value(); 410 411 return Clause; 412 } 413 414 std::optional<StaticSampler> RootSignatureParser::parseStaticSampler() { 415 assert(CurToken.TokKind == TokenKind::kw_StaticSampler && 416 "Expects to only be invoked starting at given keyword"); 417 418 if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after, 419 CurToken.TokKind)) 420 return std::nullopt; 421 422 StaticSampler Sampler; 423 424 auto Params = parseStaticSamplerParams(); 425 if (!Params.has_value()) 426 return std::nullopt; 427 428 if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_either, 429 TokenKind::pu_comma)) 430 return std::nullopt; 431 432 // Check mandatory parameters were provided 433 if (!Params->Reg.has_value()) { 434 reportDiag(diag::err_hlsl_rootsig_missing_param) << TokenKind::sReg; 435 return std::nullopt; 436 } 437 438 Sampler.Reg = Params->Reg.value(); 439 440 // Fill in optional values 441 if (Params->Filter.has_value()) 442 Sampler.Filter = Params->Filter.value(); 443 444 if (Params->AddressU.has_value()) 445 Sampler.AddressU = Params->AddressU.value(); 446 447 if (Params->AddressV.has_value()) 448 Sampler.AddressV = Params->AddressV.value(); 449 450 if (Params->AddressW.has_value()) 451 Sampler.AddressW = Params->AddressW.value(); 452 453 if (Params->MipLODBias.has_value()) 454 Sampler.MipLODBias = Params->MipLODBias.value(); 455 456 if (Params->MaxAnisotropy.has_value()) 457 Sampler.MaxAnisotropy = Params->MaxAnisotropy.value(); 458 459 if (Params->CompFunc.has_value()) 460 Sampler.CompFunc = Params->CompFunc.value(); 461 462 if (Params->BorderColor.has_value()) 463 Sampler.BorderColor = Params->BorderColor.value(); 464 465 if (Params->MinLOD.has_value()) 466 Sampler.MinLOD = Params->MinLOD.value(); 467 468 if (Params->MaxLOD.has_value()) 469 Sampler.MaxLOD = Params->MaxLOD.value(); 470 471 if (Params->Space.has_value()) 472 Sampler.Space = Params->Space.value(); 473 474 if (Params->Visibility.has_value()) 475 Sampler.Visibility = Params->Visibility.value(); 476 477 return Sampler; 478 } 479 480 // Parameter arguments (eg. `bReg`, `space`, ...) can be specified in any 481 // order and only exactly once. The following methods will parse through as 482 // many arguments as possible reporting an error if a duplicate is seen. 483 std::optional<RootSignatureParser::ParsedConstantParams> 484 RootSignatureParser::parseRootConstantParams() { 485 assert(CurToken.TokKind == TokenKind::pu_l_paren && 486 "Expects to only be invoked starting at given token"); 487 488 ParsedConstantParams Params; 489 while (!peekExpectedToken(TokenKind::pu_r_paren)) { 490 if (tryConsumeExpectedToken(TokenKind::kw_num32BitConstants)) { 491 // `num32BitConstants` `=` POS_INT 492 if (Params.Num32BitConstants.has_value()) { 493 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 494 return std::nullopt; 495 } 496 497 if (consumeExpectedToken(TokenKind::pu_equal)) 498 return std::nullopt; 499 500 auto Num32BitConstants = parseUIntParam(); 501 if (!Num32BitConstants.has_value()) 502 return std::nullopt; 503 Params.Num32BitConstants = Num32BitConstants; 504 } else if (tryConsumeExpectedToken(TokenKind::bReg)) { 505 // `b` POS_INT 506 if (Params.Reg.has_value()) { 507 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 508 return std::nullopt; 509 } 510 auto Reg = parseRegister(); 511 if (!Reg.has_value()) 512 return std::nullopt; 513 Params.Reg = Reg; 514 } else if (tryConsumeExpectedToken(TokenKind::kw_space)) { 515 // `space` `=` POS_INT 516 if (Params.Space.has_value()) { 517 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 518 return std::nullopt; 519 } 520 521 if (consumeExpectedToken(TokenKind::pu_equal)) 522 return std::nullopt; 523 524 auto Space = parseUIntParam(); 525 if (!Space.has_value()) 526 return std::nullopt; 527 Params.Space = Space; 528 } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) { 529 // `visibility` `=` SHADER_VISIBILITY 530 if (Params.Visibility.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 Visibility = parseShaderVisibility(TokenKind::kw_visibility); 539 if (!Visibility.has_value()) 540 return std::nullopt; 541 Params.Visibility = Visibility; 542 } else { 543 consumeNextToken(); // let diagnostic be at the start of invalid token 544 reportDiag(diag::err_hlsl_invalid_token) 545 << /*parameter=*/0 << /*param of*/ TokenKind::kw_RootConstants; 546 return std::nullopt; 547 } 548 549 // ',' denotes another element, otherwise, expected to be at ')' 550 if (!tryConsumeExpectedToken(TokenKind::pu_comma)) 551 break; 552 } 553 554 return Params; 555 } 556 557 std::optional<RootSignatureParser::ParsedRootDescriptorParams> 558 RootSignatureParser::parseRootDescriptorParams(TokenKind DescKind, 559 TokenKind RegType) { 560 assert(CurToken.TokKind == TokenKind::pu_l_paren && 561 "Expects to only be invoked starting at given token"); 562 563 ParsedRootDescriptorParams Params; 564 while (!peekExpectedToken(TokenKind::pu_r_paren)) { 565 if (tryConsumeExpectedToken(RegType)) { 566 // ( `b` | `t` | `u`) POS_INT 567 if (Params.Reg.has_value()) { 568 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 569 return std::nullopt; 570 } 571 auto Reg = parseRegister(); 572 if (!Reg.has_value()) 573 return std::nullopt; 574 Params.Reg = Reg; 575 } else if (tryConsumeExpectedToken(TokenKind::kw_space)) { 576 // `space` `=` POS_INT 577 if (Params.Space.has_value()) { 578 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 579 return std::nullopt; 580 } 581 582 if (consumeExpectedToken(TokenKind::pu_equal)) 583 return std::nullopt; 584 585 auto Space = parseUIntParam(); 586 if (!Space.has_value()) 587 return std::nullopt; 588 Params.Space = Space; 589 } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) { 590 // `visibility` `=` SHADER_VISIBILITY 591 if (Params.Visibility.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 Visibility = parseShaderVisibility(TokenKind::kw_visibility); 600 if (!Visibility.has_value()) 601 return std::nullopt; 602 Params.Visibility = Visibility; 603 } else if (tryConsumeExpectedToken(TokenKind::kw_flags)) { 604 // `flags` `=` ROOT_DESCRIPTOR_FLAGS 605 if (Params.Flags.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 Flags = parseRootDescriptorFlags(TokenKind::kw_flags); 614 if (!Flags.has_value()) 615 return std::nullopt; 616 Params.Flags = Flags; 617 } else { 618 consumeNextToken(); // let diagnostic be at the start of invalid token 619 reportDiag(diag::err_hlsl_invalid_token) 620 << /*parameter=*/0 << /*param of*/ DescKind; 621 return std::nullopt; 622 } 623 624 // ',' denotes another element, otherwise, expected to be at ')' 625 if (!tryConsumeExpectedToken(TokenKind::pu_comma)) 626 break; 627 } 628 629 return Params; 630 } 631 632 std::optional<RootSignatureParser::ParsedClauseParams> 633 RootSignatureParser::parseDescriptorTableClauseParams(TokenKind ClauseKind, 634 TokenKind RegType) { 635 assert(CurToken.TokKind == TokenKind::pu_l_paren && 636 "Expects to only be invoked starting at given token"); 637 638 ParsedClauseParams Params; 639 while (!peekExpectedToken(TokenKind::pu_r_paren)) { 640 if (tryConsumeExpectedToken(RegType)) { 641 // ( `b` | `t` | `u` | `s`) POS_INT 642 if (Params.Reg.has_value()) { 643 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 644 return std::nullopt; 645 } 646 auto Reg = parseRegister(); 647 if (!Reg.has_value()) 648 return std::nullopt; 649 Params.Reg = Reg; 650 } else if (tryConsumeExpectedToken(TokenKind::kw_numDescriptors)) { 651 // `numDescriptors` `=` POS_INT | unbounded 652 if (Params.NumDescriptors.has_value()) { 653 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 654 return std::nullopt; 655 } 656 657 if (consumeExpectedToken(TokenKind::pu_equal)) 658 return std::nullopt; 659 660 std::optional<uint32_t> NumDescriptors; 661 if (tryConsumeExpectedToken(TokenKind::en_unbounded)) 662 NumDescriptors = NumDescriptorsUnbounded; 663 else { 664 NumDescriptors = parseUIntParam(); 665 if (!NumDescriptors.has_value()) 666 return std::nullopt; 667 } 668 669 Params.NumDescriptors = NumDescriptors; 670 } else if (tryConsumeExpectedToken(TokenKind::kw_space)) { 671 // `space` `=` POS_INT 672 if (Params.Space.has_value()) { 673 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 674 return std::nullopt; 675 } 676 677 if (consumeExpectedToken(TokenKind::pu_equal)) 678 return std::nullopt; 679 680 auto Space = parseUIntParam(); 681 if (!Space.has_value()) 682 return std::nullopt; 683 Params.Space = Space; 684 } else if (tryConsumeExpectedToken(TokenKind::kw_offset)) { 685 // `offset` `=` POS_INT | DESCRIPTOR_RANGE_OFFSET_APPEND 686 if (Params.Offset.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 std::optional<uint32_t> Offset; 695 if (tryConsumeExpectedToken(TokenKind::en_DescriptorRangeOffsetAppend)) 696 Offset = DescriptorTableOffsetAppend; 697 else { 698 Offset = parseUIntParam(); 699 if (!Offset.has_value()) 700 return std::nullopt; 701 } 702 703 Params.Offset = Offset; 704 } else if (tryConsumeExpectedToken(TokenKind::kw_flags)) { 705 // `flags` `=` DESCRIPTOR_RANGE_FLAGS 706 if (Params.Flags.has_value()) { 707 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 708 return std::nullopt; 709 } 710 711 if (consumeExpectedToken(TokenKind::pu_equal)) 712 return std::nullopt; 713 714 auto Flags = parseDescriptorRangeFlags(TokenKind::kw_flags); 715 if (!Flags.has_value()) 716 return std::nullopt; 717 Params.Flags = Flags; 718 } else { 719 consumeNextToken(); // let diagnostic be at the start of invalid token 720 reportDiag(diag::err_hlsl_invalid_token) 721 << /*parameter=*/0 << /*param of*/ ClauseKind; 722 return std::nullopt; 723 } 724 725 // ',' denotes another element, otherwise, expected to be at ')' 726 if (!tryConsumeExpectedToken(TokenKind::pu_comma)) 727 break; 728 } 729 730 return Params; 731 } 732 733 std::optional<RootSignatureParser::ParsedStaticSamplerParams> 734 RootSignatureParser::parseStaticSamplerParams() { 735 assert(CurToken.TokKind == TokenKind::pu_l_paren && 736 "Expects to only be invoked starting at given token"); 737 738 ParsedStaticSamplerParams Params; 739 while (!peekExpectedToken(TokenKind::pu_r_paren)) { 740 if (tryConsumeExpectedToken(TokenKind::sReg)) { 741 // `s` POS_INT 742 if (Params.Reg.has_value()) { 743 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 744 return std::nullopt; 745 } 746 auto Reg = parseRegister(); 747 if (!Reg.has_value()) 748 return std::nullopt; 749 Params.Reg = Reg; 750 } else if (tryConsumeExpectedToken(TokenKind::kw_filter)) { 751 // `filter` `=` FILTER 752 if (Params.Filter.has_value()) { 753 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind; 754 return std::nullopt; 755 } 756 757 if (consumeExpectedToken(TokenKind::pu_equal)) 758 return std::nullopt; 759 760 auto Filter = parseSamplerFilter(TokenKind::kw_filter); 761 if (!Filter.has_value()) 762 return std::nullopt; 763 Params.Filter = Filter; 764 } else if (tryConsumeExpectedToken(TokenKind::kw_addressU)) { 765 // `addressU` `=` TEXTURE_ADDRESS 766 if (Params.AddressU.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 AddressU = parseTextureAddressMode(TokenKind::kw_addressU); 775 if (!AddressU.has_value()) 776 return std::nullopt; 777 Params.AddressU = AddressU; 778 } else if (tryConsumeExpectedToken(TokenKind::kw_addressV)) { 779 // `addressV` `=` TEXTURE_ADDRESS 780 if (Params.AddressV.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 AddressV = parseTextureAddressMode(TokenKind::kw_addressV); 789 if (!AddressV.has_value()) 790 return std::nullopt; 791 Params.AddressV = AddressV; 792 } else if (tryConsumeExpectedToken(TokenKind::kw_addressW)) { 793 // `addressW` `=` TEXTURE_ADDRESS 794 if (Params.AddressW.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 AddressW = parseTextureAddressMode(TokenKind::kw_addressW); 803 if (!AddressW.has_value()) 804 return std::nullopt; 805 Params.AddressW = AddressW; 806 } else if (tryConsumeExpectedToken(TokenKind::kw_mipLODBias)) { 807 // `mipLODBias` `=` NUMBER 808 if (Params.MipLODBias.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 MipLODBias = parseFloatParam(); 817 if (!MipLODBias.has_value()) 818 return std::nullopt; 819 Params.MipLODBias = MipLODBias; 820 } else if (tryConsumeExpectedToken(TokenKind::kw_maxAnisotropy)) { 821 // `maxAnisotropy` `=` POS_INT 822 if (Params.MaxAnisotropy.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 MaxAnisotropy = parseUIntParam(); 831 if (!MaxAnisotropy.has_value()) 832 return std::nullopt; 833 Params.MaxAnisotropy = MaxAnisotropy; 834 } else if (tryConsumeExpectedToken(TokenKind::kw_comparisonFunc)) { 835 // `comparisonFunc` `=` COMPARISON_FUNC 836 if (Params.CompFunc.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 CompFunc = parseComparisonFunc(TokenKind::kw_comparisonFunc); 845 if (!CompFunc.has_value()) 846 return std::nullopt; 847 Params.CompFunc = CompFunc; 848 } else if (tryConsumeExpectedToken(TokenKind::kw_borderColor)) { 849 // `borderColor` `=` STATIC_BORDER_COLOR 850 if (Params.BorderColor.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 BorderColor = parseStaticBorderColor(TokenKind::kw_borderColor); 859 if (!BorderColor.has_value()) 860 return std::nullopt; 861 Params.BorderColor = BorderColor; 862 } else if (tryConsumeExpectedToken(TokenKind::kw_minLOD)) { 863 // `minLOD` `=` NUMBER 864 if (Params.MinLOD.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 MinLOD = parseFloatParam(); 873 if (!MinLOD.has_value()) 874 return std::nullopt; 875 Params.MinLOD = MinLOD; 876 } else if (tryConsumeExpectedToken(TokenKind::kw_maxLOD)) { 877 // `maxLOD` `=` NUMBER 878 if (Params.MaxLOD.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 MaxLOD = parseFloatParam(); 887 if (!MaxLOD.has_value()) 888 return std::nullopt; 889 Params.MaxLOD = MaxLOD; 890 } else if (tryConsumeExpectedToken(TokenKind::kw_space)) { 891 // `space` `=` POS_INT 892 if (Params.Space.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 Space = parseUIntParam(); 901 if (!Space.has_value()) 902 return std::nullopt; 903 Params.Space = Space; 904 } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) { 905 // `visibility` `=` SHADER_VISIBILITY 906 if (Params.Visibility.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 Visibility = parseShaderVisibility(TokenKind::kw_visibility); 915 if (!Visibility.has_value()) 916 return std::nullopt; 917 Params.Visibility = Visibility; 918 } else { 919 consumeNextToken(); // let diagnostic be at the start of invalid token 920 reportDiag(diag::err_hlsl_invalid_token) 921 << /*parameter=*/0 << /*param of*/ TokenKind::kw_StaticSampler; 922 return std::nullopt; 923 } 924 925 // ',' denotes another element, otherwise, expected to be at ')' 926 if (!tryConsumeExpectedToken(TokenKind::pu_comma)) 927 break; 928 } 929 930 return Params; 931 } 932 933 std::optional<uint32_t> RootSignatureParser::parseUIntParam() { 934 assert(CurToken.TokKind == TokenKind::pu_equal && 935 "Expects to only be invoked starting at given keyword"); 936 tryConsumeExpectedToken(TokenKind::pu_plus); 937 if (consumeExpectedToken(TokenKind::int_literal, diag::err_expected_after, 938 CurToken.TokKind)) 939 return std::nullopt; 940 return handleUIntLiteral(); 941 } 942 943 std::optional<Register> RootSignatureParser::parseRegister() { 944 assert((CurToken.TokKind == TokenKind::bReg || 945 CurToken.TokKind == TokenKind::tReg || 946 CurToken.TokKind == TokenKind::uReg || 947 CurToken.TokKind == TokenKind::sReg) && 948 "Expects to only be invoked starting at given keyword"); 949 950 Register Reg; 951 switch (CurToken.TokKind) { 952 default: 953 llvm_unreachable("Switch for consumed token was not provided"); 954 case TokenKind::bReg: 955 Reg.ViewType = RegisterType::BReg; 956 break; 957 case TokenKind::tReg: 958 Reg.ViewType = RegisterType::TReg; 959 break; 960 case TokenKind::uReg: 961 Reg.ViewType = RegisterType::UReg; 962 break; 963 case TokenKind::sReg: 964 Reg.ViewType = RegisterType::SReg; 965 break; 966 } 967 968 auto Number = handleUIntLiteral(); 969 if (!Number.has_value()) 970 return std::nullopt; // propogate NumericLiteralParser error 971 972 Reg.Number = *Number; 973 return Reg; 974 } 975 976 std::optional<float> RootSignatureParser::parseFloatParam() { 977 assert(CurToken.TokKind == TokenKind::pu_equal && 978 "Expects to only be invoked starting at given keyword"); 979 // Consume sign modifier 980 bool Signed = 981 tryConsumeExpectedToken({TokenKind::pu_plus, TokenKind::pu_minus}); 982 bool Negated = Signed && CurToken.TokKind == TokenKind::pu_minus; 983 984 // DXC will treat a postive signed integer as unsigned 985 if (!Negated && tryConsumeExpectedToken(TokenKind::int_literal)) { 986 std::optional<uint32_t> UInt = handleUIntLiteral(); 987 if (!UInt.has_value()) 988 return std::nullopt; 989 return float(UInt.value()); 990 } 991 992 if (Negated && tryConsumeExpectedToken(TokenKind::int_literal)) { 993 std::optional<int32_t> Int = handleIntLiteral(Negated); 994 if (!Int.has_value()) 995 return std::nullopt; 996 return float(Int.value()); 997 } 998 999 if (tryConsumeExpectedToken(TokenKind::float_literal)) { 1000 std::optional<float> Float = handleFloatLiteral(Negated); 1001 if (!Float.has_value()) 1002 return std::nullopt; 1003 return Float.value(); 1004 } 1005 1006 return std::nullopt; 1007 } 1008 1009 std::optional<llvm::dxbc::ShaderVisibility> 1010 RootSignatureParser::parseShaderVisibility(TokenKind Context) { 1011 assert(CurToken.TokKind == TokenKind::pu_equal && 1012 "Expects to only be invoked starting at given keyword"); 1013 1014 TokenKind Expected[] = { 1015 #define SHADER_VISIBILITY_ENUM(NAME, LIT) TokenKind::en_##NAME, 1016 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1017 }; 1018 1019 if (!tryConsumeExpectedToken(Expected)) { 1020 consumeNextToken(); // consume token to point at invalid token 1021 reportDiag(diag::err_hlsl_invalid_token) 1022 << /*value=*/1 << /*value of*/ Context; 1023 return std::nullopt; 1024 } 1025 1026 switch (CurToken.TokKind) { 1027 #define SHADER_VISIBILITY_ENUM(NAME, LIT) \ 1028 case TokenKind::en_##NAME: \ 1029 return llvm::dxbc::ShaderVisibility::NAME; \ 1030 break; 1031 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1032 default: 1033 llvm_unreachable("Switch for consumed enum token was not provided"); 1034 } 1035 1036 return std::nullopt; 1037 } 1038 1039 std::optional<llvm::dxbc::SamplerFilter> 1040 RootSignatureParser::parseSamplerFilter(TokenKind Context) { 1041 assert(CurToken.TokKind == TokenKind::pu_equal && 1042 "Expects to only be invoked starting at given keyword"); 1043 1044 TokenKind Expected[] = { 1045 #define FILTER_ENUM(NAME, LIT) TokenKind::en_##NAME, 1046 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1047 }; 1048 1049 if (!tryConsumeExpectedToken(Expected)) { 1050 consumeNextToken(); // consume token to point at invalid token 1051 reportDiag(diag::err_hlsl_invalid_token) 1052 << /*value=*/1 << /*value of*/ Context; 1053 return std::nullopt; 1054 } 1055 1056 switch (CurToken.TokKind) { 1057 #define FILTER_ENUM(NAME, LIT) \ 1058 case TokenKind::en_##NAME: \ 1059 return llvm::dxbc::SamplerFilter::NAME; \ 1060 break; 1061 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1062 default: 1063 llvm_unreachable("Switch for consumed enum token was not provided"); 1064 } 1065 1066 return std::nullopt; 1067 } 1068 1069 std::optional<llvm::dxbc::TextureAddressMode> 1070 RootSignatureParser::parseTextureAddressMode(TokenKind Context) { 1071 assert(CurToken.TokKind == TokenKind::pu_equal && 1072 "Expects to only be invoked starting at given keyword"); 1073 1074 TokenKind Expected[] = { 1075 #define TEXTURE_ADDRESS_MODE_ENUM(NAME, LIT) TokenKind::en_##NAME, 1076 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1077 }; 1078 1079 if (!tryConsumeExpectedToken(Expected)) { 1080 consumeNextToken(); // consume token to point at invalid token 1081 reportDiag(diag::err_hlsl_invalid_token) 1082 << /*value=*/1 << /*value of*/ Context; 1083 return std::nullopt; 1084 } 1085 1086 switch (CurToken.TokKind) { 1087 #define TEXTURE_ADDRESS_MODE_ENUM(NAME, LIT) \ 1088 case TokenKind::en_##NAME: \ 1089 return llvm::dxbc::TextureAddressMode::NAME; \ 1090 break; 1091 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1092 default: 1093 llvm_unreachable("Switch for consumed enum token was not provided"); 1094 } 1095 1096 return std::nullopt; 1097 } 1098 1099 std::optional<llvm::dxbc::ComparisonFunc> 1100 RootSignatureParser::parseComparisonFunc(TokenKind Context) { 1101 assert(CurToken.TokKind == TokenKind::pu_equal && 1102 "Expects to only be invoked starting at given keyword"); 1103 1104 TokenKind Expected[] = { 1105 #define COMPARISON_FUNC_ENUM(NAME, LIT) TokenKind::en_##NAME, 1106 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1107 }; 1108 1109 if (!tryConsumeExpectedToken(Expected)) { 1110 consumeNextToken(); // consume token to point at invalid token 1111 reportDiag(diag::err_hlsl_invalid_token) 1112 << /*value=*/1 << /*value of*/ Context; 1113 return std::nullopt; 1114 } 1115 1116 switch (CurToken.TokKind) { 1117 #define COMPARISON_FUNC_ENUM(NAME, LIT) \ 1118 case TokenKind::en_##NAME: \ 1119 return llvm::dxbc::ComparisonFunc::NAME; \ 1120 break; 1121 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1122 default: 1123 llvm_unreachable("Switch for consumed enum token was not provided"); 1124 } 1125 1126 return std::nullopt; 1127 } 1128 1129 std::optional<llvm::dxbc::StaticBorderColor> 1130 RootSignatureParser::parseStaticBorderColor(TokenKind Context) { 1131 assert(CurToken.TokKind == TokenKind::pu_equal && 1132 "Expects to only be invoked starting at given keyword"); 1133 1134 TokenKind Expected[] = { 1135 #define STATIC_BORDER_COLOR_ENUM(NAME, LIT) TokenKind::en_##NAME, 1136 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1137 }; 1138 1139 if (!tryConsumeExpectedToken(Expected)) { 1140 consumeNextToken(); // consume token to point at invalid token 1141 reportDiag(diag::err_hlsl_invalid_token) 1142 << /*value=*/1 << /*value of*/ Context; 1143 return std::nullopt; 1144 } 1145 1146 switch (CurToken.TokKind) { 1147 #define STATIC_BORDER_COLOR_ENUM(NAME, LIT) \ 1148 case TokenKind::en_##NAME: \ 1149 return llvm::dxbc::StaticBorderColor::NAME; \ 1150 break; 1151 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1152 default: 1153 llvm_unreachable("Switch for consumed enum token was not provided"); 1154 } 1155 1156 return std::nullopt; 1157 } 1158 1159 std::optional<llvm::dxbc::RootDescriptorFlags> 1160 RootSignatureParser::parseRootDescriptorFlags(TokenKind Context) { 1161 assert(CurToken.TokKind == TokenKind::pu_equal && 1162 "Expects to only be invoked starting at given keyword"); 1163 1164 // Handle the edge-case of '0' to specify no flags set 1165 if (tryConsumeExpectedToken(TokenKind::int_literal)) { 1166 if (!verifyZeroFlag()) { 1167 reportDiag(diag::err_hlsl_rootsig_non_zero_flag); 1168 return std::nullopt; 1169 } 1170 return llvm::dxbc::RootDescriptorFlags::None; 1171 } 1172 1173 TokenKind Expected[] = { 1174 #define ROOT_DESCRIPTOR_FLAG_ENUM(NAME, LIT) TokenKind::en_##NAME, 1175 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1176 }; 1177 1178 std::optional<llvm::dxbc::RootDescriptorFlags> Flags; 1179 1180 do { 1181 if (tryConsumeExpectedToken(Expected)) { 1182 switch (CurToken.TokKind) { 1183 #define ROOT_DESCRIPTOR_FLAG_ENUM(NAME, LIT) \ 1184 case TokenKind::en_##NAME: \ 1185 Flags = maybeOrFlag<llvm::dxbc::RootDescriptorFlags>( \ 1186 Flags, llvm::dxbc::RootDescriptorFlags::NAME); \ 1187 break; 1188 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1189 default: 1190 llvm_unreachable("Switch for consumed enum token was not provided"); 1191 } 1192 } else { 1193 consumeNextToken(); // consume token to point at invalid token 1194 reportDiag(diag::err_hlsl_invalid_token) 1195 << /*value=*/1 << /*value of*/ Context; 1196 return std::nullopt; 1197 } 1198 } while (tryConsumeExpectedToken(TokenKind::pu_or)); 1199 1200 return Flags; 1201 } 1202 1203 std::optional<llvm::dxbc::DescriptorRangeFlags> 1204 RootSignatureParser::parseDescriptorRangeFlags(TokenKind Context) { 1205 assert(CurToken.TokKind == TokenKind::pu_equal && 1206 "Expects to only be invoked starting at given keyword"); 1207 1208 // Handle the edge-case of '0' to specify no flags set 1209 if (tryConsumeExpectedToken(TokenKind::int_literal)) { 1210 if (!verifyZeroFlag()) { 1211 reportDiag(diag::err_hlsl_rootsig_non_zero_flag); 1212 return std::nullopt; 1213 } 1214 return llvm::dxbc::DescriptorRangeFlags::None; 1215 } 1216 1217 TokenKind Expected[] = { 1218 #define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON) TokenKind::en_##NAME, 1219 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1220 }; 1221 1222 std::optional<llvm::dxbc::DescriptorRangeFlags> Flags; 1223 1224 do { 1225 if (tryConsumeExpectedToken(Expected)) { 1226 switch (CurToken.TokKind) { 1227 #define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON) \ 1228 case TokenKind::en_##NAME: \ 1229 Flags = maybeOrFlag<llvm::dxbc::DescriptorRangeFlags>( \ 1230 Flags, llvm::dxbc::DescriptorRangeFlags::NAME); \ 1231 break; 1232 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 1233 default: 1234 llvm_unreachable("Switch for consumed enum token was not provided"); 1235 } 1236 } else { 1237 consumeNextToken(); // consume token to point at invalid token 1238 reportDiag(diag::err_hlsl_invalid_token) 1239 << /*value=*/1 << /*value of*/ Context; 1240 return std::nullopt; 1241 } 1242 } while (tryConsumeExpectedToken(TokenKind::pu_or)); 1243 1244 return Flags; 1245 } 1246 1247 std::optional<uint32_t> RootSignatureParser::handleUIntLiteral() { 1248 // Parse the numeric value and do semantic checks on its specification 1249 clang::NumericLiteralParser Literal( 1250 CurToken.NumSpelling, getTokenLocation(CurToken), PP.getSourceManager(), 1251 PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics()); 1252 if (Literal.hadError) 1253 return std::nullopt; // Error has already been reported so just return 1254 1255 assert(Literal.isIntegerLiteral() && 1256 "NumSpelling can only consist of digits"); 1257 1258 llvm::APSInt Val(32, /*IsUnsigned=*/true); 1259 if (Literal.GetIntegerValue(Val)) { 1260 // Report that the value has overflowed 1261 reportDiag(diag::err_hlsl_number_literal_overflow) 1262 << /*integer type*/ 0 << /*is signed*/ 0; 1263 return std::nullopt; 1264 } 1265 1266 return Val.getExtValue(); 1267 } 1268 1269 std::optional<int32_t> RootSignatureParser::handleIntLiteral(bool Negated) { 1270 // Parse the numeric value and do semantic checks on its specification 1271 clang::NumericLiteralParser Literal( 1272 CurToken.NumSpelling, getTokenLocation(CurToken), PP.getSourceManager(), 1273 PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics()); 1274 if (Literal.hadError) 1275 return std::nullopt; // Error has already been reported so just return 1276 1277 assert(Literal.isIntegerLiteral() && 1278 "NumSpelling can only consist of digits"); 1279 1280 llvm::APSInt Val(32, /*IsUnsigned=*/true); 1281 // GetIntegerValue will overwrite Val from the parsed Literal and return 1282 // true if it overflows as a 32-bit unsigned int 1283 bool Overflowed = Literal.GetIntegerValue(Val); 1284 1285 // So we then need to check that it doesn't overflow as a 32-bit signed int: 1286 int64_t MaxNegativeMagnitude = -int64_t(std::numeric_limits<int32_t>::min()); 1287 Overflowed |= (Negated && MaxNegativeMagnitude < Val.getExtValue()); 1288 1289 int64_t MaxPositiveMagnitude = int64_t(std::numeric_limits<int32_t>::max()); 1290 Overflowed |= (!Negated && MaxPositiveMagnitude < Val.getExtValue()); 1291 1292 if (Overflowed) { 1293 // Report that the value has overflowed 1294 reportDiag(diag::err_hlsl_number_literal_overflow) 1295 << /*integer type*/ 0 << /*is signed*/ 1; 1296 return std::nullopt; 1297 } 1298 1299 if (Negated) 1300 Val = -Val; 1301 1302 return int32_t(Val.getExtValue()); 1303 } 1304 1305 std::optional<float> RootSignatureParser::handleFloatLiteral(bool Negated) { 1306 // Parse the numeric value and do semantic checks on its specification 1307 clang::NumericLiteralParser Literal( 1308 CurToken.NumSpelling, getTokenLocation(CurToken), PP.getSourceManager(), 1309 PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics()); 1310 if (Literal.hadError) 1311 return std::nullopt; // Error has already been reported so just return 1312 1313 assert(Literal.isFloatingLiteral() && 1314 "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling " 1315 "will be caught and reported by NumericLiteralParser."); 1316 1317 // DXC used `strtod` to convert the token string to a float which corresponds 1318 // to: 1319 auto DXCSemantics = llvm::APFloat::Semantics::S_IEEEdouble; 1320 auto DXCRoundingMode = llvm::RoundingMode::NearestTiesToEven; 1321 1322 llvm::APFloat Val(llvm::APFloat::EnumToSemantics(DXCSemantics)); 1323 llvm::APFloat::opStatus Status(Literal.GetFloatValue(Val, DXCRoundingMode)); 1324 1325 // Note: we do not error when opStatus::opInexact by itself as this just 1326 // denotes that rounding occured but not that it is invalid 1327 assert(!(Status & llvm::APFloat::opStatus::opInvalidOp) && 1328 "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling " 1329 "will be caught and reported by NumericLiteralParser."); 1330 1331 assert(!(Status & llvm::APFloat::opStatus::opDivByZero) && 1332 "It is not possible for a division to be performed when " 1333 "constructing an APFloat from a string"); 1334 1335 if (Status & llvm::APFloat::opStatus::opUnderflow) { 1336 // Report that the value has underflowed 1337 reportDiag(diag::err_hlsl_number_literal_underflow); 1338 return std::nullopt; 1339 } 1340 1341 if (Status & llvm::APFloat::opStatus::opOverflow) { 1342 // Report that the value has overflowed 1343 reportDiag(diag::err_hlsl_number_literal_overflow) << /*float type*/ 1; 1344 return std::nullopt; 1345 } 1346 1347 if (Negated) 1348 Val = -Val; 1349 1350 double DoubleVal = Val.convertToDouble(); 1351 double FloatMax = double(std::numeric_limits<float>::max()); 1352 if (FloatMax < DoubleVal || DoubleVal < -FloatMax) { 1353 // Report that the value has overflowed 1354 reportDiag(diag::err_hlsl_number_literal_overflow) << /*float type*/ 1; 1355 return std::nullopt; 1356 } 1357 1358 return static_cast<float>(DoubleVal); 1359 } 1360 1361 bool RootSignatureParser::verifyZeroFlag() { 1362 assert(CurToken.TokKind == TokenKind::int_literal); 1363 auto X = handleUIntLiteral(); 1364 return X.has_value() && X.value() == 0; 1365 } 1366 1367 bool RootSignatureParser::peekExpectedToken(TokenKind Expected) { 1368 return peekExpectedToken(ArrayRef{Expected}); 1369 } 1370 1371 bool RootSignatureParser::peekExpectedToken(ArrayRef<TokenKind> AnyExpected) { 1372 RootSignatureToken Result = Lexer.peekNextToken(); 1373 return llvm::is_contained(AnyExpected, Result.TokKind); 1374 } 1375 1376 bool RootSignatureParser::consumeExpectedToken(TokenKind Expected, 1377 unsigned DiagID, 1378 TokenKind Context) { 1379 if (tryConsumeExpectedToken(Expected)) 1380 return false; 1381 1382 // Report unexpected token kind error 1383 DiagnosticBuilder DB = reportDiag(DiagID); 1384 switch (DiagID) { 1385 case diag::err_expected: 1386 DB << Expected; 1387 break; 1388 case diag::err_expected_either: 1389 DB << Expected << Context; 1390 break; 1391 case diag::err_expected_after: 1392 DB << Context << Expected; 1393 break; 1394 default: 1395 break; 1396 } 1397 return true; 1398 } 1399 1400 bool RootSignatureParser::tryConsumeExpectedToken(TokenKind Expected) { 1401 return tryConsumeExpectedToken(ArrayRef{Expected}); 1402 } 1403 1404 bool RootSignatureParser::tryConsumeExpectedToken( 1405 ArrayRef<TokenKind> AnyExpected) { 1406 // If not the expected token just return 1407 if (!peekExpectedToken(AnyExpected)) 1408 return false; 1409 consumeNextToken(); 1410 return true; 1411 } 1412 1413 bool RootSignatureParser::skipUntilExpectedToken(TokenKind Expected) { 1414 return skipUntilExpectedToken(ArrayRef{Expected}); 1415 } 1416 1417 bool RootSignatureParser::skipUntilExpectedToken( 1418 ArrayRef<TokenKind> AnyExpected) { 1419 1420 while (!peekExpectedToken(AnyExpected)) { 1421 if (peekExpectedToken(TokenKind::end_of_stream)) 1422 return false; 1423 consumeNextToken(); 1424 } 1425 1426 return true; 1427 } 1428 1429 bool RootSignatureParser::skipUntilClosedParens(uint32_t NumParens) { 1430 TokenKind ParenKinds[] = { 1431 TokenKind::pu_l_paren, 1432 TokenKind::pu_r_paren, 1433 }; 1434 while (skipUntilExpectedToken(ParenKinds)) { 1435 consumeNextToken(); 1436 if (CurToken.TokKind == TokenKind::pu_r_paren) 1437 NumParens--; 1438 else 1439 NumParens++; 1440 if (NumParens == 0) 1441 return true; 1442 } 1443 1444 return false; 1445 } 1446 1447 SourceLocation RootSignatureParser::getTokenLocation(RootSignatureToken Tok) { 1448 return Signature->getLocationOfByte(Tok.LocOffset, PP.getSourceManager(), 1449 PP.getLangOpts(), PP.getTargetInfo()); 1450 } 1451 1452 } // namespace hlsl 1453 } // namespace clang 1454