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 | DiagID: diag::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<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 | |
126 | std::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 | |
172 | std::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 | |
235 | std::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 | |
285 | std::optional<DescriptorTableClause> |
286 | RootSignatureParser::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 | |
357 | std::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. |
428 | std::optional<RootSignatureParser::ParsedConstantParams> |
429 | RootSignatureParser::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 | |
503 | std::optional<RootSignatureParser::ParsedRootDescriptorParams> |
504 | RootSignatureParser::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 | |
578 | std::optional<RootSignatureParser::ParsedClauseParams> |
579 | RootSignatureParser::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 | |
683 | std::optional<RootSignatureParser::ParsedStaticSamplerParams> |
684 | RootSignatureParser::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 | |
911 | std::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 | |
921 | std::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 | |
954 | std::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 | |
987 | std::optional<llvm::dxbc::ShaderVisibility> |
988 | RootSignatureParser::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 | |
1013 | std::optional<llvm::dxbc::SamplerFilter> |
1014 | RootSignatureParser::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 | |
1039 | std::optional<llvm::dxbc::TextureAddressMode> |
1040 | RootSignatureParser::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 | |
1065 | std::optional<llvm::dxbc::ComparisonFunc> |
1066 | RootSignatureParser::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 | |
1091 | std::optional<llvm::dxbc::StaticBorderColor> |
1092 | RootSignatureParser::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 | |
1117 | std::optional<llvm::dxbc::RootDescriptorFlags> |
1118 | RootSignatureParser::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 | |
1156 | std::optional<llvm::dxbc::DescriptorRangeFlags> |
1157 | RootSignatureParser::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 | |
1195 | std::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 | |
1218 | std::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 | |
1255 | std::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 | |
1316 | bool RootSignatureParser::verifyZeroFlag() { |
1317 | assert(CurToken.TokKind == TokenKind::int_literal); |
1318 | auto X = handleUIntLiteral(); |
1319 | return X.has_value() && X.value() == 0; |
1320 | } |
1321 | |
1322 | bool RootSignatureParser::peekExpectedToken(TokenKind Expected) { |
1323 | return peekExpectedToken(AnyExpected: ArrayRef{Expected}); |
1324 | } |
1325 | |
1326 | bool RootSignatureParser::peekExpectedToken(ArrayRef<TokenKind> AnyExpected) { |
1327 | RootSignatureToken Result = Lexer.peekNextToken(); |
1328 | return llvm::is_contained(Range&: AnyExpected, Element: Result.TokKind); |
1329 | } |
1330 | |
1331 | bool 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 | |
1354 | bool RootSignatureParser::tryConsumeExpectedToken(TokenKind Expected) { |
1355 | return tryConsumeExpectedToken(Expected: ArrayRef{Expected}); |
1356 | } |
1357 | |
1358 | bool 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 | |