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