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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang/lib/Parse/ParseHLSLRootSignature.cpp