clang 22.0.0git
ParseHLSLRootSignature.cpp
Go to the documentation of this file.
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
12#include "clang/Parse/Parser.h"
13#include "clang/Sema/Sema.h"
14
15using namespace llvm::hlsl::rootsig;
16
17namespace clang {
18namespace hlsl {
19
21
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
32 llvm::dxbc::RootSignatureVersion Version, StringLiteral *Signature,
33 Preprocessor &PP)
34 : Version(Version), Signature(Signature), Lexer(Signature->getString()),
35 PP(PP), CurToken(0) {}
36
38 // Iterate as many RootSignatureElements as possible, until we hit the
39 // end of the stream
40 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 recover
77 // 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 token
106 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 stream
114 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 case
143 if (tryConsumeExpectedToken(TokenKind::pu_r_paren))
144 return Flags;
145
146 // Handle the edge-case of '0' to specify no flags set
147 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 possible
154 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 token
173 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 provided
206 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 parameters
222 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 provided
272 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 values
280 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 Sampler
308 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 recover
312 // 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_VISIBILITY
321 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 token
334 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 visibility
349 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 provided
402 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 values
410 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 provided
444 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 values
452 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 return Sampler;
489}
490
491// Parameter arguments (eg. `bReg`, `space`, ...) can be specified in any
492// order and only exactly once. The following methods will parse through as
493// many arguments as possible reporting an error if a duplicate is seen.
494std::optional<RootSignatureParser::ParsedConstantParams>
495RootSignatureParser::parseRootConstantParams() {
496 assert(CurToken.TokKind == TokenKind::pu_l_paren &&
497 "Expects to only be invoked starting at given token");
498
499 ParsedConstantParams Params;
500 while (!peekExpectedToken(TokenKind::pu_r_paren)) {
501 if (tryConsumeExpectedToken(TokenKind::kw_num32BitConstants)) {
502 // `num32BitConstants` `=` POS_INT
503 if (Params.Num32BitConstants.has_value()) {
504 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
505 return std::nullopt;
506 }
507
508 if (consumeExpectedToken(TokenKind::pu_equal))
509 return std::nullopt;
510
511 auto Num32BitConstants = parseUIntParam();
512 if (!Num32BitConstants.has_value())
513 return std::nullopt;
514 Params.Num32BitConstants = Num32BitConstants;
515 } else if (tryConsumeExpectedToken(TokenKind::bReg)) {
516 // `b` POS_INT
517 if (Params.Reg.has_value()) {
518 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
519 return std::nullopt;
520 }
521 auto Reg = parseRegister();
522 if (!Reg.has_value())
523 return std::nullopt;
524 Params.Reg = Reg;
525 } else if (tryConsumeExpectedToken(TokenKind::kw_space)) {
526 // `space` `=` POS_INT
527 if (Params.Space.has_value()) {
528 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
529 return std::nullopt;
530 }
531
532 if (consumeExpectedToken(TokenKind::pu_equal))
533 return std::nullopt;
534
535 auto Space = parseUIntParam();
536 if (!Space.has_value())
537 return std::nullopt;
538 Params.Space = Space;
539 } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {
540 // `visibility` `=` SHADER_VISIBILITY
541 if (Params.Visibility.has_value()) {
542 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
543 return std::nullopt;
544 }
545
546 if (consumeExpectedToken(TokenKind::pu_equal))
547 return std::nullopt;
548
549 auto Visibility = parseShaderVisibility(TokenKind::kw_visibility);
550 if (!Visibility.has_value())
551 return std::nullopt;
552 Params.Visibility = Visibility;
553 } else {
554 consumeNextToken(); // let diagnostic be at the start of invalid token
555 reportDiag(diag::err_hlsl_invalid_token)
556 << /*parameter=*/0 << /*param of*/ TokenKind::kw_RootConstants;
557 return std::nullopt;
558 }
559
560 // ',' denotes another element, otherwise, expected to be at ')'
561 if (!tryConsumeExpectedToken(TokenKind::pu_comma))
562 break;
563 }
564
565 return Params;
566}
567
568std::optional<RootSignatureParser::ParsedRootDescriptorParams>
569RootSignatureParser::parseRootDescriptorParams(TokenKind DescKind,
570 TokenKind RegType) {
571 assert(CurToken.TokKind == TokenKind::pu_l_paren &&
572 "Expects to only be invoked starting at given token");
573
574 ParsedRootDescriptorParams Params;
575 while (!peekExpectedToken(TokenKind::pu_r_paren)) {
576 if (tryConsumeExpectedToken(RegType)) {
577 // ( `b` | `t` | `u`) POS_INT
578 if (Params.Reg.has_value()) {
579 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
580 return std::nullopt;
581 }
582 auto Reg = parseRegister();
583 if (!Reg.has_value())
584 return std::nullopt;
585 Params.Reg = Reg;
586 } else if (tryConsumeExpectedToken(TokenKind::kw_space)) {
587 // `space` `=` POS_INT
588 if (Params.Space.has_value()) {
589 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
590 return std::nullopt;
591 }
592
593 if (consumeExpectedToken(TokenKind::pu_equal))
594 return std::nullopt;
595
596 auto Space = parseUIntParam();
597 if (!Space.has_value())
598 return std::nullopt;
599 Params.Space = Space;
600 } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {
601 // `visibility` `=` SHADER_VISIBILITY
602 if (Params.Visibility.has_value()) {
603 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
604 return std::nullopt;
605 }
606
607 if (consumeExpectedToken(TokenKind::pu_equal))
608 return std::nullopt;
609
610 auto Visibility = parseShaderVisibility(TokenKind::kw_visibility);
611 if (!Visibility.has_value())
612 return std::nullopt;
613 Params.Visibility = Visibility;
614 } else if (tryConsumeExpectedToken(TokenKind::kw_flags)) {
615 // `flags` `=` ROOT_DESCRIPTOR_FLAGS
616 if (Params.Flags.has_value()) {
617 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
618 return std::nullopt;
619 }
620
621 if (consumeExpectedToken(TokenKind::pu_equal))
622 return std::nullopt;
623
624 auto Flags = parseRootDescriptorFlags(TokenKind::kw_flags);
625 if (!Flags.has_value())
626 return std::nullopt;
627 Params.Flags = Flags;
628 } else {
629 consumeNextToken(); // let diagnostic be at the start of invalid token
630 reportDiag(diag::err_hlsl_invalid_token)
631 << /*parameter=*/0 << /*param of*/ DescKind;
632 return std::nullopt;
633 }
634
635 // ',' denotes another element, otherwise, expected to be at ')'
636 if (!tryConsumeExpectedToken(TokenKind::pu_comma))
637 break;
638 }
639
640 return Params;
641}
642
643std::optional<RootSignatureParser::ParsedClauseParams>
644RootSignatureParser::parseDescriptorTableClauseParams(TokenKind ClauseKind,
645 TokenKind RegType) {
646 assert(CurToken.TokKind == TokenKind::pu_l_paren &&
647 "Expects to only be invoked starting at given token");
648
649 ParsedClauseParams Params;
650 while (!peekExpectedToken(TokenKind::pu_r_paren)) {
651 if (tryConsumeExpectedToken(RegType)) {
652 // ( `b` | `t` | `u` | `s`) POS_INT
653 if (Params.Reg.has_value()) {
654 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
655 return std::nullopt;
656 }
657 auto Reg = parseRegister();
658 if (!Reg.has_value())
659 return std::nullopt;
660 Params.Reg = Reg;
661 } else if (tryConsumeExpectedToken(TokenKind::kw_numDescriptors)) {
662 // `numDescriptors` `=` POS_INT | unbounded
663 if (Params.NumDescriptors.has_value()) {
664 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
665 return std::nullopt;
666 }
667
668 if (consumeExpectedToken(TokenKind::pu_equal))
669 return std::nullopt;
670
671 std::optional<uint32_t> NumDescriptors;
672 if (tryConsumeExpectedToken(TokenKind::en_unbounded))
673 NumDescriptors = NumDescriptorsUnbounded;
674 else {
675 NumDescriptors = parseUIntParam();
676 if (!NumDescriptors.has_value())
677 return std::nullopt;
678 }
679
680 Params.NumDescriptors = NumDescriptors;
681 } else if (tryConsumeExpectedToken(TokenKind::kw_space)) {
682 // `space` `=` POS_INT
683 if (Params.Space.has_value()) {
684 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
685 return std::nullopt;
686 }
687
688 if (consumeExpectedToken(TokenKind::pu_equal))
689 return std::nullopt;
690
691 auto Space = parseUIntParam();
692 if (!Space.has_value())
693 return std::nullopt;
694 Params.Space = Space;
695 } else if (tryConsumeExpectedToken(TokenKind::kw_offset)) {
696 // `offset` `=` POS_INT | DESCRIPTOR_RANGE_OFFSET_APPEND
697 if (Params.Offset.has_value()) {
698 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
699 return std::nullopt;
700 }
701
702 if (consumeExpectedToken(TokenKind::pu_equal))
703 return std::nullopt;
704
705 std::optional<uint32_t> Offset;
706 if (tryConsumeExpectedToken(TokenKind::en_DescriptorRangeOffsetAppend))
707 Offset = DescriptorTableOffsetAppend;
708 else {
709 Offset = parseUIntParam();
710 if (!Offset.has_value())
711 return std::nullopt;
712 }
713
714 Params.Offset = Offset;
715 } else if (tryConsumeExpectedToken(TokenKind::kw_flags)) {
716 // `flags` `=` DESCRIPTOR_RANGE_FLAGS
717 if (Params.Flags.has_value()) {
718 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
719 return std::nullopt;
720 }
721
722 if (consumeExpectedToken(TokenKind::pu_equal))
723 return std::nullopt;
724
725 auto Flags = parseDescriptorRangeFlags(TokenKind::kw_flags);
726 if (!Flags.has_value())
727 return std::nullopt;
728 Params.Flags = Flags;
729 } else {
730 consumeNextToken(); // let diagnostic be at the start of invalid token
731 reportDiag(diag::err_hlsl_invalid_token)
732 << /*parameter=*/0 << /*param of*/ ClauseKind;
733 return std::nullopt;
734 }
735
736 // ',' denotes another element, otherwise, expected to be at ')'
737 if (!tryConsumeExpectedToken(TokenKind::pu_comma))
738 break;
739 }
740
741 return Params;
742}
743
744std::optional<RootSignatureParser::ParsedStaticSamplerParams>
745RootSignatureParser::parseStaticSamplerParams() {
746 assert(CurToken.TokKind == TokenKind::pu_l_paren &&
747 "Expects to only be invoked starting at given token");
748
749 ParsedStaticSamplerParams Params;
750 while (!peekExpectedToken(TokenKind::pu_r_paren)) {
751 if (tryConsumeExpectedToken(TokenKind::sReg)) {
752 // `s` POS_INT
753 if (Params.Reg.has_value()) {
754 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
755 return std::nullopt;
756 }
757 auto Reg = parseRegister();
758 if (!Reg.has_value())
759 return std::nullopt;
760 Params.Reg = Reg;
761 } else if (tryConsumeExpectedToken(TokenKind::kw_filter)) {
762 // `filter` `=` FILTER
763 if (Params.Filter.has_value()) {
764 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
765 return std::nullopt;
766 }
767
768 if (consumeExpectedToken(TokenKind::pu_equal))
769 return std::nullopt;
770
771 auto Filter = parseSamplerFilter(TokenKind::kw_filter);
772 if (!Filter.has_value())
773 return std::nullopt;
774 Params.Filter = Filter;
775 } else if (tryConsumeExpectedToken(TokenKind::kw_addressU)) {
776 // `addressU` `=` TEXTURE_ADDRESS
777 if (Params.AddressU.has_value()) {
778 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
779 return std::nullopt;
780 }
781
782 if (consumeExpectedToken(TokenKind::pu_equal))
783 return std::nullopt;
784
785 auto AddressU = parseTextureAddressMode(TokenKind::kw_addressU);
786 if (!AddressU.has_value())
787 return std::nullopt;
788 Params.AddressU = AddressU;
789 } else if (tryConsumeExpectedToken(TokenKind::kw_addressV)) {
790 // `addressV` `=` TEXTURE_ADDRESS
791 if (Params.AddressV.has_value()) {
792 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
793 return std::nullopt;
794 }
795
796 if (consumeExpectedToken(TokenKind::pu_equal))
797 return std::nullopt;
798
799 auto AddressV = parseTextureAddressMode(TokenKind::kw_addressV);
800 if (!AddressV.has_value())
801 return std::nullopt;
802 Params.AddressV = AddressV;
803 } else if (tryConsumeExpectedToken(TokenKind::kw_addressW)) {
804 // `addressW` `=` TEXTURE_ADDRESS
805 if (Params.AddressW.has_value()) {
806 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
807 return std::nullopt;
808 }
809
810 if (consumeExpectedToken(TokenKind::pu_equal))
811 return std::nullopt;
812
813 auto AddressW = parseTextureAddressMode(TokenKind::kw_addressW);
814 if (!AddressW.has_value())
815 return std::nullopt;
816 Params.AddressW = AddressW;
817 } else if (tryConsumeExpectedToken(TokenKind::kw_mipLODBias)) {
818 // `mipLODBias` `=` NUMBER
819 if (Params.MipLODBias.has_value()) {
820 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
821 return std::nullopt;
822 }
823
824 if (consumeExpectedToken(TokenKind::pu_equal))
825 return std::nullopt;
826
827 auto MipLODBias = parseFloatParam();
828 if (!MipLODBias.has_value())
829 return std::nullopt;
830 Params.MipLODBias = MipLODBias;
831 } else if (tryConsumeExpectedToken(TokenKind::kw_maxAnisotropy)) {
832 // `maxAnisotropy` `=` POS_INT
833 if (Params.MaxAnisotropy.has_value()) {
834 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
835 return std::nullopt;
836 }
837
838 if (consumeExpectedToken(TokenKind::pu_equal))
839 return std::nullopt;
840
841 auto MaxAnisotropy = parseUIntParam();
842 if (!MaxAnisotropy.has_value())
843 return std::nullopt;
844 Params.MaxAnisotropy = MaxAnisotropy;
845 } else if (tryConsumeExpectedToken(TokenKind::kw_comparisonFunc)) {
846 // `comparisonFunc` `=` COMPARISON_FUNC
847 if (Params.CompFunc.has_value()) {
848 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
849 return std::nullopt;
850 }
851
852 if (consumeExpectedToken(TokenKind::pu_equal))
853 return std::nullopt;
854
855 auto CompFunc = parseComparisonFunc(TokenKind::kw_comparisonFunc);
856 if (!CompFunc.has_value())
857 return std::nullopt;
858 Params.CompFunc = CompFunc;
859 } else if (tryConsumeExpectedToken(TokenKind::kw_borderColor)) {
860 // `borderColor` `=` STATIC_BORDER_COLOR
861 if (Params.BorderColor.has_value()) {
862 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
863 return std::nullopt;
864 }
865
866 if (consumeExpectedToken(TokenKind::pu_equal))
867 return std::nullopt;
868
869 auto BorderColor = parseStaticBorderColor(TokenKind::kw_borderColor);
870 if (!BorderColor.has_value())
871 return std::nullopt;
872 Params.BorderColor = BorderColor;
873 } else if (tryConsumeExpectedToken(TokenKind::kw_minLOD)) {
874 // `minLOD` `=` NUMBER
875 if (Params.MinLOD.has_value()) {
876 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
877 return std::nullopt;
878 }
879
880 if (consumeExpectedToken(TokenKind::pu_equal))
881 return std::nullopt;
882
883 auto MinLOD = parseFloatParam();
884 if (!MinLOD.has_value())
885 return std::nullopt;
886 Params.MinLOD = MinLOD;
887 } else if (tryConsumeExpectedToken(TokenKind::kw_maxLOD)) {
888 // `maxLOD` `=` NUMBER
889 if (Params.MaxLOD.has_value()) {
890 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
891 return std::nullopt;
892 }
893
894 if (consumeExpectedToken(TokenKind::pu_equal))
895 return std::nullopt;
896
897 auto MaxLOD = parseFloatParam();
898 if (!MaxLOD.has_value())
899 return std::nullopt;
900 Params.MaxLOD = MaxLOD;
901 } else if (tryConsumeExpectedToken(TokenKind::kw_space)) {
902 // `space` `=` POS_INT
903 if (Params.Space.has_value()) {
904 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
905 return std::nullopt;
906 }
907
908 if (consumeExpectedToken(TokenKind::pu_equal))
909 return std::nullopt;
910
911 auto Space = parseUIntParam();
912 if (!Space.has_value())
913 return std::nullopt;
914 Params.Space = Space;
915 } else if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {
916 // `visibility` `=` SHADER_VISIBILITY
917 if (Params.Visibility.has_value()) {
918 reportDiag(diag::err_hlsl_rootsig_repeat_param) << CurToken.TokKind;
919 return std::nullopt;
920 }
921
922 if (consumeExpectedToken(TokenKind::pu_equal))
923 return std::nullopt;
924
925 auto Visibility = parseShaderVisibility(TokenKind::kw_visibility);
926 if (!Visibility.has_value())
927 return std::nullopt;
928 Params.Visibility = Visibility;
929 } else {
930 consumeNextToken(); // let diagnostic be at the start of invalid token
931 reportDiag(diag::err_hlsl_invalid_token)
932 << /*parameter=*/0 << /*param of*/ TokenKind::kw_StaticSampler;
933 return std::nullopt;
934 }
935
936 // ',' denotes another element, otherwise, expected to be at ')'
937 if (!tryConsumeExpectedToken(TokenKind::pu_comma))
938 break;
939 }
940
941 return Params;
942}
943
944std::optional<uint32_t> RootSignatureParser::parseUIntParam() {
945 assert(CurToken.TokKind == TokenKind::pu_equal &&
946 "Expects to only be invoked starting at given keyword");
947 tryConsumeExpectedToken(TokenKind::pu_plus);
948 if (consumeExpectedToken(TokenKind::int_literal, diag::err_expected_after,
949 CurToken.TokKind))
950 return std::nullopt;
951 return handleUIntLiteral();
952}
953
954std::optional<Register> RootSignatureParser::parseRegister() {
955 assert((CurToken.TokKind == TokenKind::bReg ||
956 CurToken.TokKind == TokenKind::tReg ||
957 CurToken.TokKind == TokenKind::uReg ||
958 CurToken.TokKind == TokenKind::sReg) &&
959 "Expects to only be invoked starting at given keyword");
960
961 Register Reg;
962 switch (CurToken.TokKind) {
963 default:
964 llvm_unreachable("Switch for consumed token was not provided");
965 case TokenKind::bReg:
966 Reg.ViewType = RegisterType::BReg;
967 break;
968 case TokenKind::tReg:
969 Reg.ViewType = RegisterType::TReg;
970 break;
971 case TokenKind::uReg:
972 Reg.ViewType = RegisterType::UReg;
973 break;
974 case TokenKind::sReg:
975 Reg.ViewType = RegisterType::SReg;
976 break;
977 }
978
979 auto Number = handleUIntLiteral();
980 if (!Number.has_value())
981 return std::nullopt; // propogate NumericLiteralParser error
982
983 Reg.Number = *Number;
984 return Reg;
985}
986
987std::optional<float> RootSignatureParser::parseFloatParam() {
988 assert(CurToken.TokKind == TokenKind::pu_equal &&
989 "Expects to only be invoked starting at given keyword");
990 // Consume sign modifier
991 bool Signed =
992 tryConsumeExpectedToken({TokenKind::pu_plus, TokenKind::pu_minus});
993 bool Negated = Signed && CurToken.TokKind == TokenKind::pu_minus;
994
995 // DXC will treat a postive signed integer as unsigned
996 if (!Negated && tryConsumeExpectedToken(TokenKind::int_literal)) {
997 std::optional<uint32_t> UInt = handleUIntLiteral();
998 if (!UInt.has_value())
999 return std::nullopt;
1000 return float(UInt.value());
1001 }
1002
1003 if (Negated && tryConsumeExpectedToken(TokenKind::int_literal)) {
1004 std::optional<int32_t> Int = handleIntLiteral(Negated);
1005 if (!Int.has_value())
1006 return std::nullopt;
1007 return float(Int.value());
1008 }
1009
1010 if (tryConsumeExpectedToken(TokenKind::float_literal)) {
1011 std::optional<float> Float = handleFloatLiteral(Negated);
1012 if (!Float.has_value())
1013 return std::nullopt;
1014 return Float.value();
1015 }
1016
1017 return std::nullopt;
1018}
1019
1020std::optional<llvm::dxbc::ShaderVisibility>
1021RootSignatureParser::parseShaderVisibility(TokenKind Context) {
1022 assert(CurToken.TokKind == TokenKind::pu_equal &&
1023 "Expects to only be invoked starting at given keyword");
1024
1025 TokenKind Expected[] = {
1026#define SHADER_VISIBILITY_ENUM(NAME, LIT) TokenKind::en_##NAME,
1027#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1028 };
1029
1030 if (!tryConsumeExpectedToken(Expected)) {
1031 consumeNextToken(); // consume token to point at invalid token
1032 reportDiag(diag::err_hlsl_invalid_token)
1033 << /*value=*/1 << /*value of*/ Context;
1034 return std::nullopt;
1035 }
1036
1037 switch (CurToken.TokKind) {
1038#define SHADER_VISIBILITY_ENUM(NAME, LIT) \
1039 case TokenKind::en_##NAME: \
1040 return llvm::dxbc::ShaderVisibility::NAME; \
1041 break;
1042#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1043 default:
1044 llvm_unreachable("Switch for consumed enum token was not provided");
1045 }
1046
1047 return std::nullopt;
1048}
1049
1050std::optional<llvm::dxbc::SamplerFilter>
1051RootSignatureParser::parseSamplerFilter(TokenKind Context) {
1052 assert(CurToken.TokKind == TokenKind::pu_equal &&
1053 "Expects to only be invoked starting at given keyword");
1054
1055 TokenKind Expected[] = {
1056#define FILTER_ENUM(NAME, LIT) TokenKind::en_##NAME,
1057#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1058 };
1059
1060 if (!tryConsumeExpectedToken(Expected)) {
1061 consumeNextToken(); // consume token to point at invalid token
1062 reportDiag(diag::err_hlsl_invalid_token)
1063 << /*value=*/1 << /*value of*/ Context;
1064 return std::nullopt;
1065 }
1066
1067 switch (CurToken.TokKind) {
1068#define FILTER_ENUM(NAME, LIT) \
1069 case TokenKind::en_##NAME: \
1070 return llvm::dxbc::SamplerFilter::NAME; \
1071 break;
1072#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1073 default:
1074 llvm_unreachable("Switch for consumed enum token was not provided");
1075 }
1076
1077 return std::nullopt;
1078}
1079
1080std::optional<llvm::dxbc::TextureAddressMode>
1081RootSignatureParser::parseTextureAddressMode(TokenKind Context) {
1082 assert(CurToken.TokKind == TokenKind::pu_equal &&
1083 "Expects to only be invoked starting at given keyword");
1084
1085 TokenKind Expected[] = {
1086#define TEXTURE_ADDRESS_MODE_ENUM(NAME, LIT) TokenKind::en_##NAME,
1087#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1088 };
1089
1090 if (!tryConsumeExpectedToken(Expected)) {
1091 consumeNextToken(); // consume token to point at invalid token
1092 reportDiag(diag::err_hlsl_invalid_token)
1093 << /*value=*/1 << /*value of*/ Context;
1094 return std::nullopt;
1095 }
1096
1097 switch (CurToken.TokKind) {
1098#define TEXTURE_ADDRESS_MODE_ENUM(NAME, LIT) \
1099 case TokenKind::en_##NAME: \
1100 return llvm::dxbc::TextureAddressMode::NAME; \
1101 break;
1102#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1103 default:
1104 llvm_unreachable("Switch for consumed enum token was not provided");
1105 }
1106
1107 return std::nullopt;
1108}
1109
1110std::optional<llvm::dxbc::ComparisonFunc>
1111RootSignatureParser::parseComparisonFunc(TokenKind Context) {
1112 assert(CurToken.TokKind == TokenKind::pu_equal &&
1113 "Expects to only be invoked starting at given keyword");
1114
1115 TokenKind Expected[] = {
1116#define COMPARISON_FUNC_ENUM(NAME, LIT) TokenKind::en_##NAME,
1117#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1118 };
1119
1120 if (!tryConsumeExpectedToken(Expected)) {
1121 consumeNextToken(); // consume token to point at invalid token
1122 reportDiag(diag::err_hlsl_invalid_token)
1123 << /*value=*/1 << /*value of*/ Context;
1124 return std::nullopt;
1125 }
1126
1127 switch (CurToken.TokKind) {
1128#define COMPARISON_FUNC_ENUM(NAME, LIT) \
1129 case TokenKind::en_##NAME: \
1130 return llvm::dxbc::ComparisonFunc::NAME; \
1131 break;
1132#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1133 default:
1134 llvm_unreachable("Switch for consumed enum token was not provided");
1135 }
1136
1137 return std::nullopt;
1138}
1139
1140std::optional<llvm::dxbc::StaticBorderColor>
1141RootSignatureParser::parseStaticBorderColor(TokenKind Context) {
1142 assert(CurToken.TokKind == TokenKind::pu_equal &&
1143 "Expects to only be invoked starting at given keyword");
1144
1145 TokenKind Expected[] = {
1146#define STATIC_BORDER_COLOR_ENUM(NAME, LIT) TokenKind::en_##NAME,
1147#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1148 };
1149
1150 if (!tryConsumeExpectedToken(Expected)) {
1151 consumeNextToken(); // consume token to point at invalid token
1152 reportDiag(diag::err_hlsl_invalid_token)
1153 << /*value=*/1 << /*value of*/ Context;
1154 return std::nullopt;
1155 }
1156
1157 switch (CurToken.TokKind) {
1158#define STATIC_BORDER_COLOR_ENUM(NAME, LIT) \
1159 case TokenKind::en_##NAME: \
1160 return llvm::dxbc::StaticBorderColor::NAME; \
1161 break;
1162#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1163 default:
1164 llvm_unreachable("Switch for consumed enum token was not provided");
1165 }
1166
1167 return std::nullopt;
1168}
1169
1170std::optional<llvm::dxbc::RootDescriptorFlags>
1171RootSignatureParser::parseRootDescriptorFlags(TokenKind Context) {
1172 assert(CurToken.TokKind == TokenKind::pu_equal &&
1173 "Expects to only be invoked starting at given keyword");
1174
1175 // Handle the edge-case of '0' to specify no flags set
1176 if (tryConsumeExpectedToken(TokenKind::int_literal)) {
1177 if (!verifyZeroFlag()) {
1178 reportDiag(diag::err_hlsl_rootsig_non_zero_flag);
1179 return std::nullopt;
1180 }
1181 return llvm::dxbc::RootDescriptorFlags::None;
1182 }
1183
1184 TokenKind Expected[] = {
1185#define ROOT_DESCRIPTOR_FLAG_ENUM(NAME, LIT) TokenKind::en_##NAME,
1186#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1187 };
1188
1189 std::optional<llvm::dxbc::RootDescriptorFlags> Flags;
1190
1191 do {
1192 if (tryConsumeExpectedToken(Expected)) {
1193 switch (CurToken.TokKind) {
1194#define ROOT_DESCRIPTOR_FLAG_ENUM(NAME, LIT) \
1195 case TokenKind::en_##NAME: \
1196 Flags = maybeOrFlag<llvm::dxbc::RootDescriptorFlags>( \
1197 Flags, llvm::dxbc::RootDescriptorFlags::NAME); \
1198 break;
1199#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1200 default:
1201 llvm_unreachable("Switch for consumed enum token was not provided");
1202 }
1203 } else {
1204 consumeNextToken(); // consume token to point at invalid token
1205 reportDiag(diag::err_hlsl_invalid_token)
1206 << /*value=*/1 << /*value of*/ Context;
1207 return std::nullopt;
1208 }
1209 } while (tryConsumeExpectedToken(TokenKind::pu_or));
1210
1211 return Flags;
1212}
1213
1214std::optional<llvm::dxbc::DescriptorRangeFlags>
1215RootSignatureParser::parseDescriptorRangeFlags(TokenKind Context) {
1216 assert(CurToken.TokKind == TokenKind::pu_equal &&
1217 "Expects to only be invoked starting at given keyword");
1218
1219 // Handle the edge-case of '0' to specify no flags set
1220 if (tryConsumeExpectedToken(TokenKind::int_literal)) {
1221 if (!verifyZeroFlag()) {
1222 reportDiag(diag::err_hlsl_rootsig_non_zero_flag);
1223 return std::nullopt;
1224 }
1225 return llvm::dxbc::DescriptorRangeFlags::None;
1226 }
1227
1228 TokenKind Expected[] = {
1229#define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON) TokenKind::en_##NAME,
1230#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1231 };
1232
1233 std::optional<llvm::dxbc::DescriptorRangeFlags> Flags;
1234
1235 do {
1236 if (tryConsumeExpectedToken(Expected)) {
1237 switch (CurToken.TokKind) {
1238#define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON) \
1239 case TokenKind::en_##NAME: \
1240 Flags = maybeOrFlag<llvm::dxbc::DescriptorRangeFlags>( \
1241 Flags, llvm::dxbc::DescriptorRangeFlags::NAME); \
1242 break;
1243#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
1244 default:
1245 llvm_unreachable("Switch for consumed enum token was not provided");
1246 }
1247 } else {
1248 consumeNextToken(); // consume token to point at invalid token
1249 reportDiag(diag::err_hlsl_invalid_token)
1250 << /*value=*/1 << /*value of*/ Context;
1251 return std::nullopt;
1252 }
1253 } while (tryConsumeExpectedToken(TokenKind::pu_or));
1254
1255 return Flags;
1256}
1257
1258std::optional<uint32_t> RootSignatureParser::handleUIntLiteral() {
1259 // Parse the numeric value and do semantic checks on its specification
1260 clang::NumericLiteralParser Literal(
1261 CurToken.NumSpelling, getTokenLocation(CurToken), PP.getSourceManager(),
1262 PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics());
1263 if (Literal.hadError)
1264 return std::nullopt; // Error has already been reported so just return
1265
1266 assert(Literal.isIntegerLiteral() &&
1267 "NumSpelling can only consist of digits");
1268
1269 llvm::APSInt Val(32, /*IsUnsigned=*/true);
1270 if (Literal.GetIntegerValue(Val)) {
1271 // Report that the value has overflowed
1272 reportDiag(diag::err_hlsl_number_literal_overflow)
1273 << /*integer type*/ 0 << /*is signed*/ 0;
1274 return std::nullopt;
1275 }
1276
1277 return Val.getExtValue();
1278}
1279
1280std::optional<int32_t> RootSignatureParser::handleIntLiteral(bool Negated) {
1281 // Parse the numeric value and do semantic checks on its specification
1282 clang::NumericLiteralParser Literal(
1283 CurToken.NumSpelling, getTokenLocation(CurToken), PP.getSourceManager(),
1284 PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics());
1285 if (Literal.hadError)
1286 return std::nullopt; // Error has already been reported so just return
1287
1288 assert(Literal.isIntegerLiteral() &&
1289 "NumSpelling can only consist of digits");
1290
1291 llvm::APSInt Val(32, /*IsUnsigned=*/true);
1292 // GetIntegerValue will overwrite Val from the parsed Literal and return
1293 // true if it overflows as a 32-bit unsigned int
1294 bool Overflowed = Literal.GetIntegerValue(Val);
1295
1296 // So we then need to check that it doesn't overflow as a 32-bit signed int:
1297 int64_t MaxNegativeMagnitude = -int64_t(std::numeric_limits<int32_t>::min());
1298 Overflowed |= (Negated && MaxNegativeMagnitude < Val.getExtValue());
1299
1300 int64_t MaxPositiveMagnitude = int64_t(std::numeric_limits<int32_t>::max());
1301 Overflowed |= (!Negated && MaxPositiveMagnitude < Val.getExtValue());
1302
1303 if (Overflowed) {
1304 // Report that the value has overflowed
1305 reportDiag(diag::err_hlsl_number_literal_overflow)
1306 << /*integer type*/ 0 << /*is signed*/ 1;
1307 return std::nullopt;
1308 }
1309
1310 if (Negated)
1311 Val = -Val;
1312
1313 return int32_t(Val.getExtValue());
1314}
1315
1316std::optional<float> RootSignatureParser::handleFloatLiteral(bool Negated) {
1317 // Parse the numeric value and do semantic checks on its specification
1318 clang::NumericLiteralParser Literal(
1319 CurToken.NumSpelling, getTokenLocation(CurToken), PP.getSourceManager(),
1320 PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics());
1321 if (Literal.hadError)
1322 return std::nullopt; // Error has already been reported so just return
1323
1324 assert(Literal.isFloatingLiteral() &&
1325 "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "
1326 "will be caught and reported by NumericLiteralParser.");
1327
1328 // DXC used `strtod` to convert the token string to a float which corresponds
1329 // to:
1330 auto DXCSemantics = llvm::APFloat::Semantics::S_IEEEdouble;
1331 auto DXCRoundingMode = llvm::RoundingMode::NearestTiesToEven;
1332
1333 llvm::APFloat Val(llvm::APFloat::EnumToSemantics(DXCSemantics));
1334 llvm::APFloat::opStatus Status(Literal.GetFloatValue(Val, DXCRoundingMode));
1335
1336 // Note: we do not error when opStatus::opInexact by itself as this just
1337 // denotes that rounding occured but not that it is invalid
1338 assert(!(Status & llvm::APFloat::opStatus::opInvalidOp) &&
1339 "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "
1340 "will be caught and reported by NumericLiteralParser.");
1341
1342 assert(!(Status & llvm::APFloat::opStatus::opDivByZero) &&
1343 "It is not possible for a division to be performed when "
1344 "constructing an APFloat from a string");
1345
1346 if (Status & llvm::APFloat::opStatus::opUnderflow) {
1347 // Report that the value has underflowed
1348 reportDiag(diag::err_hlsl_number_literal_underflow);
1349 return std::nullopt;
1350 }
1351
1352 if (Status & llvm::APFloat::opStatus::opOverflow) {
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 if (Negated)
1359 Val = -Val;
1360
1361 double DoubleVal = Val.convertToDouble();
1362 double FloatMax = double(std::numeric_limits<float>::max());
1363 if (FloatMax < DoubleVal || DoubleVal < -FloatMax) {
1364 // Report that the value has overflowed
1365 reportDiag(diag::err_hlsl_number_literal_overflow) << /*float type*/ 1;
1366 return std::nullopt;
1367 }
1368
1369 return static_cast<float>(DoubleVal);
1370}
1371
1372bool RootSignatureParser::verifyZeroFlag() {
1373 assert(CurToken.TokKind == TokenKind::int_literal);
1374 auto X = handleUIntLiteral();
1375 return X.has_value() && X.value() == 0;
1376}
1377
1378bool RootSignatureParser::peekExpectedToken(TokenKind Expected) {
1379 return peekExpectedToken(ArrayRef{Expected});
1380}
1381
1382bool RootSignatureParser::peekExpectedToken(ArrayRef<TokenKind> AnyExpected) {
1383 RootSignatureToken Result = Lexer.peekNextToken();
1384 return llvm::is_contained(AnyExpected, Result.TokKind);
1385}
1386
1387bool RootSignatureParser::consumeExpectedToken(TokenKind Expected,
1388 unsigned DiagID,
1389 TokenKind Context) {
1390 if (tryConsumeExpectedToken(Expected))
1391 return false;
1392
1393 // Report unexpected token kind error
1394 DiagnosticBuilder DB = reportDiag(DiagID);
1395 switch (DiagID) {
1396 case diag::err_expected:
1397 DB << Expected;
1398 break;
1399 case diag::err_expected_either:
1400 DB << Expected << Context;
1401 break;
1402 case diag::err_expected_after:
1403 DB << Context << Expected;
1404 break;
1405 default:
1406 break;
1407 }
1408 return true;
1409}
1410
1411bool RootSignatureParser::tryConsumeExpectedToken(TokenKind Expected) {
1412 return tryConsumeExpectedToken(ArrayRef{Expected});
1413}
1414
1415bool RootSignatureParser::tryConsumeExpectedToken(
1416 ArrayRef<TokenKind> AnyExpected) {
1417 // If not the expected token just return
1418 if (!peekExpectedToken(AnyExpected))
1419 return false;
1420 consumeNextToken();
1421 return true;
1422}
1423
1424bool RootSignatureParser::skipUntilExpectedToken(TokenKind Expected) {
1425 return skipUntilExpectedToken(ArrayRef{Expected});
1426}
1427
1428bool RootSignatureParser::skipUntilExpectedToken(
1429 ArrayRef<TokenKind> AnyExpected) {
1430
1431 while (!peekExpectedToken(AnyExpected)) {
1432 if (peekExpectedToken(TokenKind::end_of_stream))
1433 return false;
1434 consumeNextToken();
1435 }
1436
1437 return true;
1438}
1439
1440bool RootSignatureParser::skipUntilClosedParens(uint32_t NumParens) {
1441 TokenKind ParenKinds[] = {
1442 TokenKind::pu_l_paren,
1443 TokenKind::pu_r_paren,
1444 };
1445 while (skipUntilExpectedToken(ParenKinds)) {
1446 consumeNextToken();
1447 if (CurToken.TokKind == TokenKind::pu_r_paren)
1448 NumParens--;
1449 else
1450 NumParens++;
1451 if (NumParens == 0)
1452 return true;
1453 }
1454
1455 return false;
1456}
1457
1458SourceLocation RootSignatureParser::getTokenLocation(RootSignatureToken Tok) {
1459 return Signature->getLocationOfByte(Tok.LocOffset, PP.getSourceManager(),
1460 PP.getLangOpts(), PP.getTargetInfo());
1461}
1462
1464 llvm::dxbc::RootSignatureVersion Version,
1465 StringLiteral *Signature) {
1466 // Construct our identifier
1467 auto [DeclIdent, Found] =
1468 Actions.HLSL().ActOnStartRootSignatureDecl(Signature->getString());
1469 // If we haven't found an already defined DeclIdent then parse the root
1470 // signature string and construct the in-memory elements
1471 if (!Found) {
1472 // Invoke the root signature parser to construct the in-memory constructs
1473 hlsl::RootSignatureParser Parser(Version, Signature,
1474 Actions.getPreprocessor());
1475 if (Parser.parse())
1476 return nullptr;
1477
1478 // Construct the declaration.
1480 Signature->getBeginLoc(), DeclIdent, Parser.getElements());
1481 }
1482
1483 return DeclIdent;
1484}
1485
1486void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig) {
1487 ASTConsumer *Consumer = &S.getASTConsumer();
1488
1489 // Minimally initalize the parser. This does a couple things:
1490 // - initializes Sema scope handling
1491 // - invokes HLSLExternalSemaSource
1492 // - invokes the preprocessor to lex the macros in the file
1493 std::unique_ptr<Parser> P(new Parser(S.getPreprocessor(), S, true));
1495
1496 bool HaveLexer = S.getPreprocessor().getCurrentLexer();
1497 if (HaveLexer) {
1498 P->Initialize();
1500
1501 // Skim through the file to parse to find the define
1502 while (P->getCurToken().getKind() != tok::eof)
1503 P->ConsumeAnyToken();
1504
1505 HLSLRootSignatureDecl *SignatureDecl =
1508
1509 if (SignatureDecl)
1510 Consumer->HandleTopLevelDecl(DeclGroupRef(SignatureDecl));
1511 else
1512 S.getDiagnostics().Report(diag::err_hlsl_rootsignature_entry)
1513 << EntryRootSig;
1514 }
1515
1516 Consumer->HandleTranslationUnit(S.getASTContext());
1517}
1518
1519} // namespace hlsl
1520} // namespace clang
Token Tok
The Token.
#define X(type, name)
Definition Value.h:97
__device__ double
__device__ float
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition ASTConsumer.h:34
virtual void HandleTranslationUnit(ASTContext &Ctx)
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Definition ASTConsumer.h:67
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
TranslationUnitDecl * getTranslationUnitDecl() const
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
One of these records is kept for each identifier that is lexed.
Parser - This implements a parser for the C family of languages.
Definition Parser.h:171
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
PreprocessorLexer * getCurrentLexer() const
Return the current lexer being lexed from.
void EnterMainSourceFile()
Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc.
HLSLRootSignatureDecl * lookupRootSignatureOverrideDecl(DeclContext *DC) const
std::pair< IdentifierInfo *, bool > ActOnStartRootSignatureDecl(StringRef Signature)
Computes the unique Root Signature identifier from the given signature, then lookup if there is a pre...
void ActOnFinishRootSignatureDecl(SourceLocation Loc, IdentifierInfo *DeclIdent, ArrayRef< hlsl::RootSignatureElement > Elements)
Creates the Root Signature decl of the parsed Root Signature elements onto the AST and push it onto c...
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:854
Preprocessor & getPreprocessor() const
Definition Sema.h:924
DiagnosticsEngine & getDiagnostics() const
Definition Sema.h:922
ASTContext & getASTContext() const
Definition Sema.h:925
ASTConsumer & getASTConsumer() const
Definition Sema.h:926
SemaHLSL & HLSL()
Definition Sema.h:1455
void ActOnStartOfTranslationUnit()
This is called before the very first declaration in the translation unit is parsed.
Definition Sema.cpp:1165
Encodes a location in the source.
StringLiteral - This represents a string literal expression, e.g.
Definition Expr.h:1801
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Expr.h:1975
StringRef getString() const
Definition Expr.h:1869
bool parse()
Consumes tokens from the Lexer and constructs the in-memory representations of the RootElements.
RootSignatureParser(llvm::dxbc::RootSignatureVersion Version, StringLiteral *Signature, Preprocessor &PP)
uint32_t Literal
Literals are represented as positive integers.
Definition CNFFormula.h:35
void HandleRootSignatureTarget(Sema &S, StringRef EntryRootSig)
IdentifierInfo * ParseHLSLRootSignature(Sema &Actions, llvm::dxbc::RootSignatureVersion Version, StringLiteral *Signature)
static FlagType maybeOrFlag(std::optional< FlagType > Flags, FlagType Flag)
static const TokenKind RootElementKeywords[]
RootSignatureToken::Kind TokenKind
llvm::cl::opt< std::string > Filter
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
Visibility
Describes the different kinds of visibility that a declaration may have.
Definition Visibility.h:34
long int64_t