1 | //=== ParseHLSLRootSignature.cpp - Parse Root Signature -------------------===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "clang/Parse/ParseHLSLRootSignature.h" |
10 | |
11 | #include "clang/Lex/LiteralSupport.h" |
12 | |
13 | using namespace llvm::hlsl::rootsig; |
14 | |
15 | namespace clang { |
16 | namespace hlsl { |
17 | |
18 | using TokenKind = RootSignatureToken::Kind; |
19 | |
20 | RootSignatureParser::RootSignatureParser(SmallVector<RootElement> &Elements, |
21 | RootSignatureLexer &Lexer, |
22 | Preprocessor &PP) |
23 | : Elements(Elements), Lexer(Lexer), PP(PP), CurToken(SourceLocation()) {} |
24 | |
25 | bool 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 | |
70 | template <typename FlagType> |
71 | static 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 | |
79 | std::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 | |
125 | std::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 | |
171 | std::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 | |
234 | std::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 | |
284 | std::optional<DescriptorTableClause> |
285 | RootSignatureParser::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 | |
356 | std::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. |
427 | std::optional<RootSignatureParser::ParsedConstantParams> |
428 | RootSignatureParser::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 | |
502 | std::optional<RootSignatureParser::ParsedRootDescriptorParams> |
503 | RootSignatureParser::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 | |
577 | std::optional<RootSignatureParser::ParsedClauseParams> |
578 | RootSignatureParser::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 | |
682 | std::optional<RootSignatureParser::ParsedStaticSamplerParams> |
683 | RootSignatureParser::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 | |
910 | std::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 | |
920 | std::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 | |
953 | std::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 | |
986 | std::optional<llvm::hlsl::rootsig::ShaderVisibility> |
987 | RootSignatureParser::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 | |
1012 | std::optional<llvm::hlsl::rootsig::SamplerFilter> |
1013 | RootSignatureParser::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 | |
1038 | std::optional<llvm::hlsl::rootsig::TextureAddressMode> |
1039 | RootSignatureParser::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 | |
1064 | std::optional<llvm::hlsl::rootsig::ComparisonFunc> |
1065 | RootSignatureParser::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 | |
1090 | std::optional<llvm::hlsl::rootsig::StaticBorderColor> |
1091 | RootSignatureParser::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 | |
1116 | std::optional<llvm::hlsl::rootsig::RootDescriptorFlags> |
1117 | RootSignatureParser::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 | |
1155 | std::optional<llvm::hlsl::rootsig::DescriptorRangeFlags> |
1156 | RootSignatureParser::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 | |
1194 | std::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 | |
1217 | std::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 | |
1254 | std::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 | |
1315 | bool RootSignatureParser::verifyZeroFlag() { |
1316 | assert(CurToken.TokKind == TokenKind::int_literal); |
1317 | auto X = handleUIntLiteral(); |
1318 | return X.has_value() && X.value() == 0; |
1319 | } |
1320 | |
1321 | bool RootSignatureParser::peekExpectedToken(TokenKind Expected) { |
1322 | return peekExpectedToken(AnyExpected: ArrayRef{Expected}); |
1323 | } |
1324 | |
1325 | bool RootSignatureParser::peekExpectedToken(ArrayRef<TokenKind> AnyExpected) { |
1326 | RootSignatureToken Result = Lexer.peekNextToken(); |
1327 | return llvm::is_contained(Range&: AnyExpected, Element: Result.TokKind); |
1328 | } |
1329 | |
1330 | bool 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 | |
1353 | bool RootSignatureParser::tryConsumeExpectedToken(TokenKind Expected) { |
1354 | return tryConsumeExpectedToken(Expected: ArrayRef{Expected}); |
1355 | } |
1356 | |
1357 | bool 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 |
Definitions
- RootSignatureParser
- parse
- maybeOrFlag
- parseRootFlags
- parseRootConstants
- parseRootDescriptor
- parseDescriptorTable
- parseDescriptorTableClause
- parseStaticSampler
- parseRootConstantParams
- parseRootDescriptorParams
- parseDescriptorTableClauseParams
- parseStaticSamplerParams
- parseUIntParam
- parseRegister
- parseFloatParam
- parseShaderVisibility
- parseSamplerFilter
- parseTextureAddressMode
- parseComparisonFunc
- parseStaticBorderColor
- parseRootDescriptorFlags
- parseDescriptorRangeFlags
- handleUIntLiteral
- handleIntLiteral
- handleFloatLiteral
- verifyZeroFlag
- peekExpectedToken
- peekExpectedToken
- consumeExpectedToken
- tryConsumeExpectedToken
Learn to use CMake with our Intro Training
Find out more