1use ptx_90_parser_construct::func;
2
3use crate::{
4 alt, c,
5 lexer::PtxToken,
6 mapc, ok,
7 parser::{
8 ParseErrorKind, PtxParseError, PtxParser, PtxTokenStream, Span,
9 util::{
10 alt, between, colon_p, comma_p, directive_exact_p, directive_p, identifier_p,
11 integer_p, langle_p, lbrace_p, lparen_p, many, map, minus_p, optional,
12 parse_signed_integer, parse_u32_literal, parse_unsigned_integer, plus_p, pure,
13 rangle_p, rbrace_p, register_p, rparen_p, semicolon_p, sep_by, sep_by1, seq, seq5,
14 skip_first, skip_second, skip_semicolon, string_literal_p, try_map, u32_p,
15 },
16 },
17 seq_n,
18 r#type::{
19 AliasFunctionDirective, AttributeDirective, BranchTargetsDirective, CallPrototypeDirective,
20 CallTargetsDirective, DataType, DwarfDirective, DwarfDirectiveKind, EntryFunctionDirective,
21 EntryFunctionHeaderDirective, FuncFunctionDirective, FuncFunctionHeaderDirective,
22 FunctionBody, FunctionDim, FunctionStatement, FunctionSymbol, Instruction, Label,
23 LocationDirective, LocationInlinedAt, ParameterDirective, PragmaDirective,
24 PragmaDirectiveKind, RegisterDirective, RegisterTarget, SectionDirective, SectionEntry,
25 StatementDirective, StatementSectionDirectiveLine, VariableDirective, VariableSymbol,
26 },
27};
28
29impl PtxParser for StatementDirective {
30 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
31 let branch_targets = try_map(
32 skip_semicolon(skip_first(
33 directive_exact_p("branchtargets"),
34 sep_by1(Label::parse(), comma_p()),
35 )),
36 |labels, span| {
37 let directive = BranchTargetsDirective {
38 labels,
39 span: span.clone(),
40 };
41 ok!(StatementDirective::BranchTargets { directive })
42 },
43 );
44
45 let call_targets = try_map(
46 skip_semicolon(skip_first(
47 directive_exact_p("calltargets"),
48 sep_by1(FunctionSymbol::parse(), comma_p()),
49 )),
50 |targets, span| {
51 let directive = CallTargetsDirective {
52 targets,
53 span: span.clone(),
54 };
55 ok!(StatementDirective::CallTargets { directive })
56 },
57 );
58
59 let call_prototype = try_map(
60 skip_semicolon(skip_first(
61 directive_exact_p("callprototype"),
62 seq5(
63 return_spec_parser(),
64 parameter_list_parser(),
65 noreturn_parser(),
66 abi_preserve_parser(),
67 abi_preserve_control_parser(),
68 ),
69 )),
70 |(return_param, params, noreturn, abi_preserve, abi_preserve_control), span| {
71 let directive = CallPrototypeDirective {
72 return_param,
73 params,
74 noreturn,
75 abi_preserve,
76 abi_preserve_control,
77 span: span.clone(),
78 };
79 ok!(StatementDirective::CallPrototype { directive })
80 },
81 );
82
83 let location = mapc!(location_directive(), StatementDirective::Loc { directive });
84
85 let reg_stmt = mapc!(register_statement(), StatementDirective::Reg { directive });
86
87 let local_stmt = mapc!(
88 skip_first(directive_exact_p("local"), VariableDirective::parse()),
89 StatementDirective::Local { directive }
90 );
91
92 let param_stmt = mapc!(
93 skip_first(directive_exact_p("param"), VariableDirective::parse()),
94 StatementDirective::Param { directive }
95 );
96
97 let shared_stmt = mapc!(
98 skip_first(directive_exact_p("shared"), VariableDirective::parse()),
99 StatementDirective::Shared { directive }
100 );
101
102 alt!(
103 location,
104 reg_stmt,
105 local_stmt,
106 param_stmt,
107 shared_stmt,
108 branch_targets,
109 call_targets,
110 call_prototype,
111 dwarf_directive(),
112 pragma_directive(),
113 section_directive()
114 )
115 }
116}
117
118impl PtxParser for SectionDirective {
119 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
120 map(
121 skip_first(
122 directive_exact_p("section"),
123 seq(section_name_parser(), section_body_parser()),
124 ),
125 |(name, entries), span| {
126 c!(SectionDirective {
127 name = name,
128 entries,
129 })
130 },
131 )
132 }
133}
134
135impl PtxParser for DwarfDirective {
136 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
137 skip_first(directive_exact_p("dwarf"), dwarf_kind_parser())
138 }
139}
140
141impl PtxParser for FunctionStatement {
142 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
143 let label_stmt = map(seq(Label::parse(), colon_p()), |(label, _), span| {
144 c!(FunctionStatement::Label { label })
145 });
146
147 let block_stmt = move |stream: &mut PtxTokenStream| {
148 map(
149 between(lbrace_p(), rbrace_p(), many(FunctionStatement::parse())),
150 |statements, span| c!(FunctionStatement::Block { statements }),
151 )(stream)
152 };
153
154 let directive_stmt = mapc!(
155 StatementDirective::parse(),
156 FunctionStatement::Directive { directive }
157 );
158
159 let instruction_stmt = mapc!(
160 Instruction::parse(),
161 FunctionStatement::Instruction { instruction }
162 );
163
164 alt!(label_stmt, block_stmt, directive_stmt, instruction_stmt)
165 }
166}
167
168fn return_spec_parser()
169-> impl Fn(&mut PtxTokenStream) -> Result<(Option<ParameterDirective>, Span), PtxParseError> {
170 alt(
171 map(ParameterDirective::parse(), |param, _| Some(param)),
172 map(underscore_placeholder(), |_, _| None),
173 )
174}
175
176fn underscore_placeholder() -> impl Fn(&mut PtxTokenStream) -> Result<((), Span), PtxParseError> {
177 try_map(identifier_p(), |name, span| {
178 if name == "_" {
179 Ok(())
180 } else {
181 Err(PtxParseError {
182 kind: ParseErrorKind::UnexpectedToken {
183 expected: vec!["identifier `_`".into()],
184 found: name,
185 },
186 span,
187 })
188 }
189 })
190}
191
192fn parameter_list_parser()
193-> impl Fn(&mut PtxTokenStream) -> Result<(Vec<ParameterDirective>, Span), PtxParseError> {
194 map(
195 between(
196 lparen_p(),
197 rparen_p(),
198 sep_by(ParameterDirective::parse(), comma_p()),
199 ),
200 |params, _| params,
201 )
202}
203
204fn noreturn_parser() -> impl Fn(&mut PtxTokenStream) -> Result<(bool, Span), PtxParseError> {
205 map(optional(directive_exact_p("noreturn")), |flag, _| {
206 flag.is_some()
207 })
208}
209
210fn abi_preserve_parser()
211-> impl Fn(&mut PtxTokenStream) -> Result<(Option<u32>, Span), PtxParseError> {
212 map(
213 optional(skip_first(directive_exact_p("abi_preserve"), u32_p())),
214 |value, _span| value,
215 )
216}
217
218fn abi_preserve_control_parser()
219-> impl Fn(&mut PtxTokenStream) -> Result<(Option<u32>, Span), PtxParseError> {
220 map(
221 optional(skip_first(
222 directive_exact_p("abi_preserve_control"),
223 u32_p(),
224 )),
225 |value, _span| value,
226 )
227}
228fn dwarf_directive()
229-> impl Fn(&mut PtxTokenStream) -> Result<(StatementDirective, Span), PtxParseError> {
230 mapc!(
231 skip_semicolon(DwarfDirective::parse()),
232 StatementDirective::Dwarf { directive }
233 )
234}
235
236fn dwarf_kind_parser()
237-> impl Fn(&mut PtxTokenStream) -> Result<(DwarfDirective, Span), PtxParseError> {
238 let byte_values = try_map(
239 seq(
240 directive_exact_p("byte"),
241 sep_by1(unsigned_integer_literal(), comma_p()),
242 ),
243 |(_, values), span| {
244 let mut parsed = Vec::new();
245 for (text, value_span) in values {
246 let value = parse_unsigned_integer(&text, value_span, 0, u8::MAX as u128)?;
247 parsed.push(value as u8);
248 }
249 ok!(DwarfDirective {
250 kind = DwarfDirectiveKind::ByteValues(parsed)
251 })
252 },
253 );
254
255 let four_byte_values = try_map(
256 seq(
257 four_byte_keyword(),
258 sep_by1(unsigned_integer_literal(), comma_p()),
259 ),
260 |(_, values), span| {
261 let mut parsed = Vec::new();
262 for (text, value_span) in values {
263 let value = parse_unsigned_integer(&text, value_span, 0, u32::MAX as u128)?;
264 parsed.push(value as u32);
265 }
266 ok!(DwarfDirective {
267 kind = DwarfDirectiveKind::FourByteValues(parsed)
268 })
269 },
270 );
271
272 let four_byte_label = try_map(
273 seq(four_byte_keyword(), Label::parse()),
274 |(_, label), span| {
275 ok!(DwarfDirective {
276 kind = DwarfDirectiveKind::FourByteLabel(label)
277 })
278 },
279 );
280
281 let quad_values = try_map(
282 seq(
283 directive_exact_p("quad"),
284 sep_by1(unsigned_integer_literal(), comma_p()),
285 ),
286 |(_, values), span| {
287 let mut parsed = Vec::new();
288 for (text, value_span) in values {
289 let value = parse_unsigned_integer(&text, value_span, 0, u64::MAX as u128)?;
290 parsed.push(value as u64);
291 }
292 ok!(DwarfDirective {
293 kind = DwarfDirectiveKind::QuadValues(parsed)
294 })
295 },
296 );
297
298 let quad_label = try_map(
299 seq(directive_exact_p("quad"), Label::parse()),
300 |(_, label), span| {
301 ok!(DwarfDirective {
302 kind = DwarfDirectiveKind::QuadLabel(label)
303 })
304 },
305 );
306
307 alt!(
308 byte_values,
309 four_byte_label,
310 quad_label,
311 four_byte_values,
312 quad_values
313 )
314}
315
316fn pragma_directive()
317-> impl Fn(&mut PtxTokenStream) -> Result<(StatementDirective, Span), PtxParseError> {
318 try_map(
319 skip_semicolon(seq(directive_exact_p("pragma"), string_literal_p())),
320 |(_, text), span| {
321 let kind = match text.trim() {
322 "nounroll" => PragmaDirectiveKind::Nounroll,
323 "enable_smem_spilling" => PragmaDirectiveKind::EnableSmemSpilling,
324 other if other.starts_with("used_bytes_mask") => {
325 let mask = other["used_bytes_mask".len()..].trim().to_string();
326 PragmaDirectiveKind::UsedBytesMask { mask }
327 }
328 other if other.starts_with("frequency") => {
329 let value_str = other["frequency".len()..].trim();
330 let value = parse_u32_literal(value_str, span)?;
331 PragmaDirectiveKind::Frequency { value }
332 }
333 other => PragmaDirectiveKind::Raw(other.to_string()),
334 };
335 let directive = c!(PragmaDirective { kind });
336 ok!(StatementDirective::Pragma { directive })
337 },
338 )
339}
340
341fn section_directive()
342-> impl Fn(&mut PtxTokenStream) -> Result<(StatementDirective, Span), PtxParseError> {
343 mapc!(
344 SectionDirective::parse(),
345 StatementDirective::Section { directive }
346 )
347}
348
349fn register_statement()
350-> impl Fn(&mut PtxTokenStream) -> Result<(RegisterDirective, Span), PtxParseError> {
351 mapc!(
352 skip_semicolon(seq(
353 skip_first(directive_exact_p("reg"), DataType::parse()),
354 register_targets_parser(),
355 )),
356 RegisterDirective { ty, registers }
357 )
358}
359
360fn register_targets_parser()
361-> impl Fn(&mut PtxTokenStream) -> Result<(Vec<RegisterTarget>, Span), PtxParseError> {
362 map(
363 sep_by1(
364 seq(register_symbol(), optional(register_count())),
365 comma_p(),
366 ),
367 |entries, _span| {
368 let registers = entries
369 .into_iter()
370 .map(|(symbol, range)| {
371 let symbol_span = symbol.span;
372 RegisterTarget {
373 name: symbol,
374 range,
375 span: symbol_span,
376 }
377 })
378 .collect();
379 registers
380 },
381 )
382}
383
384fn register_symbol() -> impl Fn(&mut PtxTokenStream) -> Result<(VariableSymbol, Span), PtxParseError>
385{
386 alt(
387 map(register_p(), |name, span| VariableSymbol {
388 val: name,
389 span,
390 }),
391 map(identifier_p(), |val, span| VariableSymbol { val, span }),
392 )
393}
394
395fn register_count() -> impl Fn(&mut PtxTokenStream) -> Result<(u32, Span), PtxParseError> {
396 between(langle_p(), rangle_p(), u32_p())
397}
398
399fn location_directive()
400-> impl Fn(&mut PtxTokenStream) -> Result<(LocationDirective, Span), PtxParseError> {
401 mapc!(
402 seq_n!(
403 skip_first(directive_exact_p("loc"), u32_p()),
404 u32_p(),
405 u32_p(),
406 pure(Option::<LocationInlinedAt>::None)
407 ),
408 LocationDirective {
409 file_index,
410 line,
411 column,
412 inlined_at,
413 }
414 )
415}
416
417fn section_name_parser() -> impl Fn(&mut PtxTokenStream) -> Result<(String, Span), PtxParseError> {
418 alt(
419 map(directive_p(), func!(|name| format!(".{name}"))),
420 identifier_p(),
421 )
422}
423
424fn section_body_parser()
425-> impl Fn(&mut PtxTokenStream) -> Result<(Vec<SectionEntry>, Span), PtxParseError> {
426 between(lbrace_p(), rbrace_p(), many(section_entry_parser()))
427}
428
429fn skip_optional_semicolon<T, P>(
430 parser: P,
431) -> impl Fn(&mut PtxTokenStream) -> Result<(T, Span), PtxParseError>
432where
433 P: Fn(&mut PtxTokenStream) -> Result<(T, Span), PtxParseError>,
434{
435 move |stream| {
436 let (value, span) = parser(stream)?;
437 let _ = optional(semicolon_p())(stream)?;
438 Ok((value, span))
439 }
440}
441
442fn section_entry_parser()
443-> impl Fn(&mut PtxTokenStream) -> Result<(SectionEntry, Span), PtxParseError> {
444 alt(
445 label_entry(),
446 map(
447 section_directive_line(),
448 func!(|line| SectionEntry::Directive(line)),
449 ),
450 )
451}
452
453fn label_entry() -> impl Fn(&mut PtxTokenStream) -> Result<(SectionEntry, Span), PtxParseError> {
454 map(seq(Label::parse(), colon_p()), |(label, _), span| {
455 SectionEntry::Label { label, span }
456 })
457}
458
459fn section_directive_line()
460-> impl Fn(&mut PtxTokenStream) -> Result<(StatementSectionDirectiveLine, Span), PtxParseError> {
461 let b8 = try_map(
462 skip_optional_semicolon(skip_first(
463 directive_exact_p("b8"),
464 sep_by1(signed_integer_literal(), comma_p()),
465 )),
466 func!(|values| {
467 let mut out = Vec::new();
468 for (text, value_span) in values {
469 let value = parse_signed_integer(&text, value_span, -128, 255)?;
470 out.push(value as i16);
471 }
472 ok!(StatementSectionDirectiveLine::B8 { values = out })
473 }),
474 );
475
476 let b16 = try_map(
477 skip_optional_semicolon(skip_first(
478 directive_exact_p("b16"),
479 sep_by1(signed_integer_literal(), comma_p()),
480 )),
481 |values, span| {
482 let mut out = Vec::new();
483 for (text, value_span) in values {
484 let value = parse_signed_integer(&text, value_span, -32_768, 65_535)?;
485 out.push(value as i32);
486 }
487 ok!(StatementSectionDirectiveLine::B16 { values = out })
488 },
489 );
490
491 let b32 = try_map(
492 skip_optional_semicolon(skip_first(
493 directive_exact_p("b32"),
494 b32_section_suffix(),
495 )),
496 |line, span| Ok(line.with_span(span)),
497 );
498
499 let b64 = try_map(
500 skip_optional_semicolon(skip_first(
501 directive_exact_p("b64"),
502 b64_section_suffix(),
503 )),
504 |line, span| Ok(line.with_span(span)),
505 );
506
507 alt!(b8, b16, b32, b64)
508}
509
510fn b32_section_suffix()
511-> impl Fn(&mut PtxTokenStream) -> Result<(StatementSectionDirectiveLine, Span), PtxParseError> {
512 let immediate = try_map(
513 sep_by1(signed_integer_literal(), comma_p()),
514 |values, span| {
515 let mut out = Vec::new();
516 for (text, value_span) in values {
517 let value =
518 parse_signed_integer(&text, value_span, i64::MIN as i128, i64::MAX as i128)?;
519 out.push(value as i64);
520 }
521 ok!(StatementSectionDirectiveLine::B32Immediate { values = out })
522 },
523 );
524
525 let label_diff = try_map(
526 seq_n!(Label::parse(), minus_p(), Label::parse()),
527 |(left, _, right), span| {
528 ok!(StatementSectionDirectiveLine::B32LabelDiff {
529 entries = (left, right)
530 })
531 },
532 );
533
534 let label_plus = try_map(
535 seq_n!(
536 Label::parse(),
537 alt(map(plus_p(), |_, _| 1i32), map(minus_p(), |_, _| -1i32)),
538 integer_p(),
539 ),
540 |(label, sign, digits), span| {
541 let limit = if sign < 0 {
542 (i32::MAX as u128) + 1
543 } else {
544 i32::MAX as u128
545 };
546 let magnitude = parse_unsigned_integer(&digits, span, 0, limit)? as i128;
547 let value = if sign < 0 { -magnitude } else { magnitude };
548 ok!(StatementSectionDirectiveLine::B32LabelPlusImm {
549 entries = (label, value as i32)
550 })
551 },
552 );
553
554 let label_only = map(
555 Label::parse(),
556 |label, span| c!(StatementSectionDirectiveLine::B32Label { labels = label }),
557 );
558
559 alt!(immediate, label_diff, label_plus, label_only)
560}
561
562fn b64_section_suffix()
563-> impl Fn(&mut PtxTokenStream) -> Result<(StatementSectionDirectiveLine, Span), PtxParseError> {
564 let immediate = try_map(
565 sep_by1(signed_integer_literal(), comma_p()),
566 |values, span| {
567 let mut out = Vec::new();
568 for (text, value_span) in values {
569 let value = parse_signed_integer(&text, value_span, i128::MIN, i128::MAX)?;
570 out.push(value);
571 }
572 ok!(StatementSectionDirectiveLine::B64Immediate { values = out })
573 },
574 );
575
576 let label_diff = try_map(
577 seq_n!(Label::parse(), minus_p(), Label::parse()),
578 |(left, _, right), span| {
579 ok!(StatementSectionDirectiveLine::B64LabelDiff {
580 entries = (left, right)
581 })
582 },
583 );
584
585 let label_plus = try_map(
586 seq_n!(
587 Label::parse(),
588 alt(map(plus_p(), |_, _| 1i32), map(minus_p(), |_, _| -1i32)),
589 integer_p(),
590 ),
591 |(label, sign, digits), span| {
592 let limit = if sign < 0 {
593 (i64::MAX as u128) + 1
594 } else {
595 i64::MAX as u128
596 };
597 let magnitude = parse_unsigned_integer(&digits, span, 0, limit)? as i128;
598 let value = if sign < 0 { -magnitude } else { magnitude };
599 ok!(StatementSectionDirectiveLine::B64LabelPlusImm {
600 entries = (label, value as i64)
601 })
602 },
603 );
604
605 let label_only = map(
606 Label::parse(),
607 |label, span| c!(StatementSectionDirectiveLine::B64Label { labels = label }),
608 );
609
610 alt!(immediate, label_diff, label_plus, label_only)
611}
612
613fn signed_integer_literal()
614-> impl Fn(&mut PtxTokenStream) -> Result<((String, Span), Span), PtxParseError> {
615 map(
616 seq(
617 optional(alt(map(minus_p(), |_, _| '-'), map(plus_p(), |_, _| '+'))),
618 integer_p(),
619 ),
620 |(sign, digits), span| {
621 let mut value = String::new();
622 if let Some(ch) = sign {
623 if ch == '-' {
624 value.push('-');
625 }
626 }
627 value.push_str(&digits);
628 (value, span)
629 },
630 )
631}
632
633fn unsigned_integer_literal()
634-> impl Fn(&mut PtxTokenStream) -> Result<((String, Span), Span), PtxParseError> {
635 map(integer_p(), |digits, span| (digits, span))
636}
637
638fn four_byte_keyword() -> impl Fn(&mut PtxTokenStream) -> Result<((), Span), PtxParseError> {
639 move |stream| {
640 stream.try_with_span(|stream| {
641 stream.expect(&PtxToken::Dot)?;
642 let (value, value_span) = integer_p()(stream)?;
643 if value != "4" {
644 return Err(crate::unexpected_value!(value_span, &["4"], value));
645 }
646 let (name, name_span) = identifier_p()(stream)?;
647 if name != "byte" {
648 return Err(crate::unexpected_value!(name_span, &["byte"], name));
649 }
650 Ok(())
651 })
652 }
653}
654
655impl PtxParser for AliasFunctionDirective {
656 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
657 use crate::parser::util::{comma_p, directive_exact_p, semicolon_p, skip_first};
658
659 try_map(
660 seq_n!(
661 skip_first(directive_exact_p("alias"), FunctionSymbol::parse()),
662 skip_first(comma_p(), FunctionSymbol::parse()),
663 semicolon_p()
664 ),
665 |(alias, target, _), span| ok!(AliasFunctionDirective { alias, target }),
666 )
667 }
668}
669
670impl PtxParser for FunctionBody {
671 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
672 try_map(
673 between(lbrace_p(), rbrace_p(), many(FunctionStatement::parse())),
674 |statements, span| ok!(FunctionBody { statements }),
675 )
676 }
677}
678
679impl PtxParser for FuncFunctionDirective {
680 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
681 let return_spec = alt(
682 map(
683 between(
684 lparen_p(),
685 rparen_p(),
686 optional(ParameterDirective::parse()),
687 ),
688 |param, _| param,
689 ),
690 map(optional(ParameterDirective::parse()), |param, _| param),
691 );
692
693 let body_or_prototype = alt(
694 map(FunctionBody::parse(), |body, _| Some(body)),
695 map(semicolon_p(), |_, _| None),
696 );
697
698 mapc!(
699 seq_n!(
700 skip_first(directive_exact_p("func"), many(AttributeDirective::parse())),
701 return_spec,
702 FunctionSymbol::parse(),
703 between(
704 lparen_p(),
705 rparen_p(),
706 sep_by(ParameterDirective::parse(), comma_p()),
707 ),
708 many(FuncFunctionHeaderDirective::parse()),
709 body_or_prototype,
710 ),
711 FuncFunctionDirective {
712 attributes,
713 return_param,
714 name,
715 params,
716 directives,
717 body
718 }
719 )
720 }
721}
722
723impl PtxParser for EntryFunctionDirective {
724 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
725 mapc!(
726 seq_n!(
727 skip_first(directive_exact_p("entry"), FunctionSymbol::parse()),
728 between(
729 lparen_p(),
730 rparen_p(),
731 sep_by(ParameterDirective::parse(), comma_p()),
732 ),
733 many(EntryFunctionHeaderDirective::parse()),
734 optional(FunctionBody::parse()),
735 ),
736 EntryFunctionDirective {
737 name,
738 params,
739 directives,
740 body,
741 }
742 )
743 }
744}
745
746impl PtxParser for FuncFunctionHeaderDirective {
747 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
748 alt!(
749 mapc!(
750 directive_exact_p("noreturn"),
751 FuncFunctionHeaderDirective::NoReturn {}
752 ),
753 mapc!(
754 skip_first(
755 directive_exact_p("pragma"),
756 seq(sep_by1(string_literal_p(), comma_p()), semicolon_p())
757 ),
758 FuncFunctionHeaderDirective::Pragma { args, _ }
759 ),
760 mapc!(
761 skip_first(directive_exact_p("abi_preserve"), u32_p()),
762 FuncFunctionHeaderDirective::AbiPreserve { value }
763 ),
764 mapc!(
765 skip_first(directive_exact_p("abi_preserve_control"), u32_p()),
766 FuncFunctionHeaderDirective::AbiPreserveControl { value }
767 )
768 )
769 }
770}
771
772impl PtxParser for EntryFunctionHeaderDirective {
773 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
774 alt!(
775 mapc!(
776 skip_first(directive_exact_p("maxnreg"), u32_p()),
777 EntryFunctionHeaderDirective::MaxNReg { value }
778 ),
779 try_map(
780 skip_first(directive_exact_p("maxntid"), sep_by1(u32_p(), comma_p())),
781 |dim_strs, span| {
782 let dim = parse_function_dim(&dim_strs, span)?;
783 ok!(EntryFunctionHeaderDirective::MaxNTid { dim })
784 }
785 ),
786 try_map(
787 skip_first(directive_exact_p("reqntid"), sep_by1(u32_p(), comma_p())),
788 |dim_strs, span| {
789 let dim = parse_function_dim(&dim_strs, span)?;
790 ok!(EntryFunctionHeaderDirective::ReqNTid { dim })
791 }
792 ),
793 mapc!(
794 skip_first(directive_exact_p("minnctapersm"), u32_p()),
795 EntryFunctionHeaderDirective::MinNCtaPerSm { value }
796 ),
797 mapc!(
798 skip_first(directive_exact_p("maxnctapersm"), u32_p()),
799 EntryFunctionHeaderDirective::MaxNCtaPerSm { value }
800 ),
801 mapc!(
802 skip_first(
803 directive_exact_p("pragma"),
804 skip_second(sep_by1(string_literal_p(), comma_p()), semicolon_p())
805 ),
806 EntryFunctionHeaderDirective::Pragma { args }
807 )
808 )
809 }
810}
811
812fn parse_function_dim(dims: &[u32], span: Span) -> Result<FunctionDim, PtxParseError> {
813 match dims.len() {
814 1 => {
815 let x = dims[0];
816 Ok(FunctionDim::X { x, span })
817 }
818 2 => {
819 let x = dims[0];
820 let y = dims[1];
821 Ok(FunctionDim::XY { x, y, span })
822 }
823 3 => {
824 let x = dims[0];
825 let y = dims[1];
826 let z = dims[2];
827 Ok(FunctionDim::XYZ { x, y, z, span })
828 }
829 _ => Err(PtxParseError {
830 kind: ParseErrorKind::InvalidLiteral(format!(
831 "expected 1-3 dimensions, got {}",
832 dims.len()
833 )),
834 span,
835 }),
836 }
837}