ptx_parser/parser/
function.rs

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}