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