1use crate::{
2 alt, c, err, mapc, ok,
3 parser::{
4 ParseErrorKind, PtxParseError, PtxParser, PtxTokenStream, Span,
5 util::{
6 alt, at_p, between, comma_p, directive_exact_p, directive_p, exclamation_p,
7 identifier_p, lbrace_p, lbracket_p, literal_p, lparen_p, map, minus_p, optional,
8 parse_index_suffix, plus_p, rbrace_p, rbracket_p, register_p, rparen_p, sep_by1, seq,
9 skip_first, try_map, u64_p,
10 },
11 },
12 seq_n, span,
13 span::Spanned,
14 r#type::{
15 AddressBase, AddressOffset, AddressOperand, AttributeDirective, Axis, CodeLinkage,
16 DataLinkage, DataType, FunctionSymbol, GeneralOperand, Immediate, Instruction, Label,
17 Operand, ParamStateSpace, Predicate, PredicateRegister, RegisterOperand, Sign,
18 SpecialRegister, TexHandler2, TexHandler3, TexHandler3Optional, VariableSymbol,
19 VectorOperand,
20 },
21};
22
23const CODE_LINKAGE_EXPECTED: [&str; 3] = [".visible", ".extern", ".weak"];
24
25impl PtxParser for CodeLinkage {
26 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
27 try_map(directive_p(), |name, span| {
28 let node = match name.as_str() {
29 "visible" => c!(CodeLinkage::Visible),
30 "extern" => c!(CodeLinkage::Extern),
31 "weak" => c!(CodeLinkage::Weak),
32 _ => {
33 return err!(ParseErrorKind::UnexpectedToken {
34 expected: CODE_LINKAGE_EXPECTED
35 .iter()
36 .map(|s| s.to_string())
37 .collect(),
38 found: format!(".{name}"),
39 });
40 }
41 };
42 Ok(node)
43 })
44 }
45}
46
47const DATA_LINKAGE_EXPECTED: [&str; 4] = [".visible", ".extern", ".weak", ".common"];
48
49impl PtxParser for DataLinkage {
50 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
51 try_map(directive_p(), |name, span| {
52 let node = match name.as_str() {
53 "visible" => c!(DataLinkage::Visible),
54 "extern" => c!(DataLinkage::Extern),
55 "weak" => c!(DataLinkage::Weak),
56 "common" => c!(DataLinkage::Common),
57 _ => {
58 return err!(ParseErrorKind::UnexpectedToken {
59 expected: DATA_LINKAGE_EXPECTED
60 .iter()
61 .map(|s| s.to_string())
62 .collect(),
63 found: format!(".{name}"),
64 });
65 }
66 };
67 Ok(node)
68 })
69 }
70}
71
72const DATA_TYPE_EXPECTED: [&str; 21] = [
73 ".u8",
74 ".u16",
75 ".u32",
76 ".u64",
77 ".s8",
78 ".s16",
79 ".s32",
80 ".s64",
81 ".f16",
82 ".f16x2",
83 ".f32",
84 ".f64",
85 ".b8",
86 ".b16",
87 ".b32",
88 ".b64",
89 ".b128",
90 ".pred",
91 ".texref",
92 ".samplerref",
93 ".surfref",
94];
95
96impl PtxParser for DataType {
97 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
98 try_map(directive_p(), |name, span| {
99 let node = match name.as_str() {
100 "u8" => c!(DataType::U8),
101 "u16" => c!(DataType::U16),
102 "u32" => c!(DataType::U32),
103 "u64" => c!(DataType::U64),
104 "s8" => c!(DataType::S8),
105 "s16" => c!(DataType::S16),
106 "s32" => c!(DataType::S32),
107 "s64" => c!(DataType::S64),
108 "f16" => c!(DataType::F16),
109 "f16x2" => c!(DataType::F16x2),
110 "f32" => c!(DataType::F32),
111 "f64" => c!(DataType::F64),
112 "b8" => c!(DataType::B8),
113 "b16" => c!(DataType::B16),
114 "b32" => c!(DataType::B32),
115 "b64" => c!(DataType::B64),
116 "b128" => c!(DataType::B128),
117 "pred" => c!(DataType::Pred),
118 "texref" => c!(DataType::TexRef),
119 "samplerref" => c!(DataType::SamplerRef),
120 "surfref" => c!(DataType::SurfRef),
121 _ => {
122 return err!(ParseErrorKind::UnexpectedToken {
123 expected: DATA_TYPE_EXPECTED.iter().map(|s| s.to_string()).collect(),
124 found: format!(".{name}"),
125 });
126 }
127 };
128 Ok(node)
129 })
130 }
131}
132
133impl PtxParser for AttributeDirective {
134 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
135 try_map(
139 seq(
140 directive_exact_p("attribute"),
141 between(
142 lparen_p(),
143 rparen_p(),
144 alt(
145 map(directive_exact_p("managed"), |_, span| {
146 c!(AttributeDirective::Managed)
147 }),
148 mapc!(
149 skip_first(
150 directive_exact_p("unified"),
151 between(
152 lparen_p(),
153 rparen_p(),
154 seq_n!(u64_p(), skip_first(comma_p(), u64_p()))
155 ),
156 ),
157 AttributeDirective::Unified { uuid1, uuid2 }
158 ),
159 ),
160 ),
161 ),
162 |(_, attribute), span| Ok(attribute.with_span(span)),
163 )
164 }
165}
166
167impl PtxParser for Sign {
168 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
169 alt(
170 map(plus_p(), |_, span| c!(Sign::Positive)),
171 map(minus_p(), |_, span| c!(Sign::Negative)),
172 )
173 }
174}
175
176impl PtxParser for RegisterOperand {
177 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
178 try_map(register_p(), |mut raw, span| {
179 let component = if let Some(idx) = raw.rfind('.') {
180 if idx + 1 >= raw.len() {
181 return err!(ParseErrorKind::InvalidLiteral(
182 "register component missing after '.'".into(),
183 ));
184 }
185 let suffix = raw[idx + 1..].to_string();
186 raw.truncate(idx);
187 Some(suffix)
188 } else {
189 None
190 };
191 let name = raw;
192 ok!(RegisterOperand { name, component })
193 })
194 }
195}
196
197impl PtxParser for VariableSymbol {
198 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
199 map(identifier_p(), |val, span| c!(VariableSymbol { val }))
200 }
201}
202
203impl PtxParser for FunctionSymbol {
204 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
205 map(identifier_p(), |val, span| c!(FunctionSymbol { val }))
206 }
207}
208
209impl PtxParser for Label {
210 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
211 alt(
212 map(identifier_p(), |val, span| c!(Label { val })),
213 map(directive_p(), |name, span| {
214 c!(Label {
215 val = format!(".{name}")
216 })
217 }),
218 )
219 }
220}
221
222impl PtxParser for PredicateRegister {
223 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
224 try_map(register_p(), |name, span| {
225 if name.starts_with("%p") {
226 ok!(PredicateRegister { name })
227 } else {
228 err!(ParseErrorKind::InvalidLiteral(
229 "expected predicate register (%pX)".into(),
230 ))
231 }
232 })
233 }
234}
235
236impl PtxParser for Predicate {
237 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
238 try_map(
239 seq_n!(at_p(), optional(exclamation_p()), Operand::parse()),
240 |(_, negation, operand), span| {
241 let negated = negation.is_some();
242 ok!(Predicate { negated, operand })
243 },
244 )
245 }
246}
247
248impl PtxParser for Instruction {
249 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
250 use crate::r#type::instruction::Inst;
251
252 try_map(
253 seq(optional(Predicate::parse()), Inst::parse()),
254 |(predicate, inst), span| ok!(Instruction { predicate, inst }),
255 )
256 }
257}
258
259impl PtxParser for ParamStateSpace {
260 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
261 alt!(
262 map(directive_exact_p("const"), |_, span| {
263 c!(ParamStateSpace::Const)
264 }),
265 map(directive_exact_p("global"), |_, span| {
266 c!(ParamStateSpace::Global)
267 }),
268 map(directive_exact_p("local"), |_, span| {
269 c!(ParamStateSpace::Local)
270 }),
271 map(directive_exact_p("shared"), |_, span| {
272 c!(ParamStateSpace::Shared)
273 }),
274 )
275 }
276}
277
278impl PtxParser for Operand {
279 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
280 let register = mapc!(RegisterOperand::parse(), Operand::Register { operand });
281 let immediate = map(
282 seq(optional(Sign::parse()), Immediate::parse()),
283 |(sign, mut operand), span| {
284 if matches!(sign, Some(Sign::Negative { .. })) && !operand.value.starts_with('-') {
285 operand.value = format!("-{}", operand.value);
286 }
287 c!(Operand::Immediate { operand })
288 },
289 );
290 let symbol_offset = map(
291 seq_n!(identifier_p(), plus_p(), Immediate::parse()),
292 |(symbol, _, offset), span| c!(Operand::SymbolOffset { symbol, offset }),
293 );
294 let vector_symbol_component = try_map(
295 seq(identifier_p(), directive_p()),
296 |(symbol, component), span| match component.as_str() {
297 "x" | "y" | "z" | "w" | "r" | "g" | "b" | "a" => {
298 ok!(Operand::VectorSymbolComponent { symbol, component })
299 }
300 _ => err!(ParseErrorKind::InvalidLiteral(format!(
301 "invalid named vector register component .{component}"
302 ))),
303 },
304 );
305 let symbol = mapc!(identifier_p(), Operand::Symbol { name });
306 alt!(
307 register,
308 immediate,
309 symbol_offset,
310 vector_symbol_component,
311 symbol
312 )
313 }
314}
315
316impl PtxParser for VectorOperand {
317 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
318 try_map(
319 between(lbrace_p(), rbrace_p(), sep_by1(Operand::parse(), comma_p())),
320 |operands, span| match operands.len() {
321 1 => {
322 let mut iter = operands.into_iter();
323 let operand = iter.next().unwrap();
324 ok!(VectorOperand::Vector1 { operand })
325 }
326 2 => {
327 let mut iter = operands.into_iter();
328 let operands = [iter.next().unwrap(), iter.next().unwrap()];
329 ok!(VectorOperand::Vector2 { operands })
330 }
331 3 => {
332 let mut iter = operands.into_iter();
333 let operands = [
334 iter.next().unwrap(),
335 iter.next().unwrap(),
336 iter.next().unwrap(),
337 ];
338 ok!(VectorOperand::Vector3 { operands })
339 }
340 4 => {
341 let mut iter = operands.into_iter();
342 let operands = [
343 iter.next().unwrap(),
344 iter.next().unwrap(),
345 iter.next().unwrap(),
346 iter.next().unwrap(),
347 ];
348 ok!(VectorOperand::Vector4 { operands })
349 }
350 8 => {
351 let mut iter = operands.into_iter();
352 let operands = [
353 iter.next().unwrap(),
354 iter.next().unwrap(),
355 iter.next().unwrap(),
356 iter.next().unwrap(),
357 iter.next().unwrap(),
358 iter.next().unwrap(),
359 iter.next().unwrap(),
360 iter.next().unwrap(),
361 ];
362 ok!(VectorOperand::Vector8 { operands })
363 }
364 _ => {
365 let span = operands.first().map(Spanned::span).unwrap_or(span!(0..0));
366 Err(PtxParseError {
367 kind: ParseErrorKind::UnexpectedToken {
368 expected: vec!["vector with 1,2,3,4, or 8 operands".into()],
369 found: format!("vector with {} operands", operands.len()),
370 },
371 span,
372 })
373 }
374 },
375 )
376 }
377}
378
379impl PtxParser for GeneralOperand {
380 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
381 alt(
382 mapc!(VectorOperand::parse(), GeneralOperand::Vec { operand }),
383 mapc!(Operand::parse(), GeneralOperand::Single { operand }),
384 )
385 }
386}
387
388fn handler_len_error(ty: &str, expected: &str, found: usize) -> PtxParseError {
389 PtxParseError {
390 kind: ParseErrorKind::InvalidLiteral(format!("{ty} expects {expected}, found {found}")),
391 span: Span::new(0, 0),
392 }
393}
394
395fn tex_operands()
396-> impl Fn(&mut PtxTokenStream) -> Result<(Vec<GeneralOperand>, Span), PtxParseError> {
397 between(
398 lbracket_p(),
399 rbracket_p(),
400 sep_by1(GeneralOperand::parse(), comma_p()),
401 )
402}
403
404impl PtxParser for TexHandler2 {
405 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
406 try_map(tex_operands(), |operands, span| {
407 if operands.len() != 2 {
408 return Err(handler_len_error(
409 "TexHandler2",
410 "exactly 2 operands",
411 operands.len(),
412 ));
413 }
414 let mut iter = operands.into_iter();
415 let first = iter.next().unwrap();
416 let second = iter.next().unwrap();
417 let operands = [first, second];
418 ok!(TexHandler2 { operands })
419 })
420 }
421}
422
423impl PtxParser for TexHandler3 {
424 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
425 try_map(tex_operands(), |operands, span| {
426 if operands.len() != 3 {
427 return Err(handler_len_error(
428 "TexHandler3",
429 "exactly 3 operands",
430 operands.len(),
431 ));
432 }
433 let mut iter = operands.into_iter();
434 let handle = iter.next().unwrap();
435 let sampler = iter.next().unwrap();
436 let coords = iter.next().unwrap();
437 ok!(TexHandler3 {
438 handle,
439 sampler,
440 coords
441 })
442 })
443 }
444}
445
446impl PtxParser for TexHandler3Optional {
447 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
448 try_map(tex_operands(), |operands, span| match operands.len() {
449 2 => {
450 let mut iter = operands.into_iter();
451 let handle = iter.next().unwrap();
452 let coords = iter.next().unwrap();
453 let sampler = None;
454 ok!(TexHandler3Optional {
455 handle,
456 sampler,
457 coords
458 })
459 }
460 3 => {
461 let mut iter = operands.into_iter();
462 let handle = iter.next().unwrap();
463 let sampler = Some(iter.next().unwrap());
464 let coords = iter.next().unwrap();
465 ok!(TexHandler3Optional {
466 handle,
467 sampler,
468 coords
469 })
470 }
471 other => Err(handler_len_error(
472 "TexHandler3Optional",
473 "2 or 3 operands",
474 other,
475 )),
476 })
477 }
478}
479
480impl PtxParser for SpecialRegister {
481 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
482 try_map(register_p(), |name, span| {
483 let raw = name.strip_prefix('%').ok_or_else(|| PtxParseError {
484 kind: ParseErrorKind::InvalidLiteral("expected % prefix".into()),
485 span,
486 })?;
487
488 let (base, axis_suffix) = split_axis_suffix(raw).map_err(|msg| PtxParseError {
489 kind: ParseErrorKind::InvalidLiteral(msg.into()),
490 span,
491 })?;
492 let base_lower = base.to_ascii_lowercase();
493
494 let mut node = match base_lower.as_str() {
495 "aggr_smem_size" => {
496 ensure_no_axis(axis_suffix, span)?;
497 c!(SpecialRegister::AggrSmemSize)
498 }
499 "dynamic_smem_size" => {
500 ensure_no_axis(axis_suffix, span)?;
501 c!(SpecialRegister::DynamicSmemSize)
502 }
503 "lanemask_gt" => {
504 ensure_no_axis(axis_suffix, span)?;
505 c!(SpecialRegister::LanemaskGt)
506 }
507 "reserved_smem_offset_begin" => {
508 ensure_no_axis(axis_suffix, span)?;
509 c!(SpecialRegister::ReservedSmemOffsetBegin)
510 }
511 "clock" => {
512 ensure_no_axis(axis_suffix, span)?;
513 c!(SpecialRegister::Clock)
514 }
515 "lanemask_le" => {
516 ensure_no_axis(axis_suffix, span)?;
517 c!(SpecialRegister::LanemaskLe)
518 }
519 "reserved_smem_offset_cap" => {
520 ensure_no_axis(axis_suffix, span)?;
521 c!(SpecialRegister::ReservedSmemOffsetCap)
522 }
523 "clock64" => {
524 ensure_no_axis(axis_suffix, span)?;
525 c!(SpecialRegister::Clock64)
526 }
527 "globaltimer" => {
528 ensure_no_axis(axis_suffix, span)?;
529 c!(SpecialRegister::Globaltimer)
530 }
531 "lanemask_lt" => {
532 ensure_no_axis(axis_suffix, span)?;
533 c!(SpecialRegister::LanemaskLt)
534 }
535 "reserved_smem_offset_end" => {
536 ensure_no_axis(axis_suffix, span)?;
537 c!(SpecialRegister::ReservedSmemOffsetEnd)
538 }
539 "globaltimer_hi" => {
540 ensure_no_axis(axis_suffix, span)?;
541 c!(SpecialRegister::GlobaltimerHi)
542 }
543 "nclusterid" => {
544 ensure_no_axis(axis_suffix, span)?;
545 c!(SpecialRegister::Nclusterid)
546 }
547 "smid" => {
548 ensure_no_axis(axis_suffix, span)?;
549 c!(SpecialRegister::Smid)
550 }
551 "globaltimer_lo" => {
552 ensure_no_axis(axis_suffix, span)?;
553 c!(SpecialRegister::GlobaltimerLo)
554 }
555 "gridid" => {
556 ensure_no_axis(axis_suffix, span)?;
557 c!(SpecialRegister::Gridid)
558 }
559 "nsmid" => {
560 ensure_no_axis(axis_suffix, span)?;
561 c!(SpecialRegister::Nsmid)
562 }
563 "total_smem_size" => {
564 ensure_no_axis(axis_suffix, span)?;
565 c!(SpecialRegister::TotalSmemSize)
566 }
567 "is_explicit_cluster" => {
568 ensure_no_axis(axis_suffix, span)?;
569 c!(SpecialRegister::IsExplicitCluster)
570 }
571 "warpid" => {
572 ensure_no_axis(axis_suffix, span)?;
573 c!(SpecialRegister::Warpid)
574 }
575 "clusterid" => {
576 ensure_no_axis(axis_suffix, span)?;
577 c!(SpecialRegister::Clusterid)
578 }
579 "laneid" => {
580 ensure_no_axis(axis_suffix, span)?;
581 c!(SpecialRegister::Laneid)
582 }
583 "nwarpid" => {
584 ensure_no_axis(axis_suffix, span)?;
585 c!(SpecialRegister::Nwarpid)
586 }
587 "warpsz" => {
588 ensure_no_axis(axis_suffix, span)?;
589 c!(SpecialRegister::WARPSZ)
590 }
591 "lanemask_eq" => {
592 ensure_no_axis(axis_suffix, span)?;
593 c!(SpecialRegister::LanemaskEq)
594 }
595 "current_graph_exec" => {
596 ensure_no_axis(axis_suffix, span)?;
597 c!(SpecialRegister::CurrentGraphExec)
598 }
599 "lanemask_ge" => {
600 ensure_no_axis(axis_suffix, span)?;
601 c!(SpecialRegister::LanemaskGe)
602 }
603 "cluster_ctaid" => {
604 let axis = axis_with_span(axis_suffix, &span)?;
605 c!(SpecialRegister::ClusterCtaid { axis })
606 }
607 "cluster_ctarank" => {
608 let axis = axis_with_span(axis_suffix, &span)?;
609 c!(SpecialRegister::ClusterCtarank { axis })
610 }
611 "nctaid" => {
612 let axis = axis_with_span(axis_suffix, &span)?;
613 c!(SpecialRegister::Nctaid { axis })
614 }
615 "tid" => {
616 let axis = axis_with_span(axis_suffix, &span)?;
617 c!(SpecialRegister::Tid { axis })
618 }
619 "cluster_nctaid" => {
620 let axis = axis_with_span(axis_suffix, &span)?;
621 c!(SpecialRegister::ClusterNctaid { axis })
622 }
623 "cluster_nctarank" => {
624 let axis = axis_with_span(axis_suffix, &span)?;
625 c!(SpecialRegister::ClusterNctarank { axis })
626 }
627 "ntid" => {
628 let axis = axis_with_span(axis_suffix, &span)?;
629 c!(SpecialRegister::Ntid { axis })
630 }
631 "ctaid" => {
632 let axis = axis_with_span(axis_suffix, &span)?;
633 c!(SpecialRegister::Ctaid { axis })
634 }
635 base if base.starts_with("envreg") => {
636 ensure_no_axis(axis_suffix, span)?;
637 let digits = base.strip_prefix("envreg").unwrap();
638 let index = parse_index_suffix(digits, 31, "envreg", span)?;
639 c!(SpecialRegister::Envreg { index })
640 }
641 base if base.starts_with("pm") && base.ends_with("_64") => {
642 ensure_no_axis(axis_suffix, span)?;
643 let digits = base
644 .strip_prefix("pm")
645 .and_then(|rest| rest.strip_suffix("_64"))
646 .unwrap();
647 let index = parse_index_suffix(digits, 7, "pm64", span)?;
648 c!(SpecialRegister::Pm64 { index })
649 }
650 base if base.starts_with("pm") => {
651 ensure_no_axis(axis_suffix, span)?;
652 let digits = base.strip_prefix("pm").unwrap();
653 let index = parse_index_suffix(digits, 7, "pm", span)?;
654 c!(SpecialRegister::Pm { index })
655 }
656 base if base.starts_with("reserved_smem_offset_") => {
657 ensure_no_axis(axis_suffix, span)?;
658 let digits = base.strip_prefix("reserved_smem_offset_").unwrap();
659 let index = parse_index_suffix(digits, 1, "reserved_smem_offset", span)?;
660 c!(SpecialRegister::ReservedSmemOffset { index })
661 }
662 _ => {
663 return err!(ParseErrorKind::InvalidLiteral(format!(
664 "unknown special register: {name}"
665 )));
666 }
667 };
668
669 node.set_span(span);
670 Ok(node)
671 })
672 }
673}
674
675impl PtxParser for Immediate {
676 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
677 mapc!(literal_p(), Immediate { value })
678 }
679}
680
681impl PtxParser for AddressBase {
682 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
683 alt(
684 mapc!(RegisterOperand::parse(), AddressBase::Register { operand }),
685 mapc!(VariableSymbol::parse(), AddressBase::Variable { symbol }),
686 )
687 }
688}
689
690impl PtxParser for AddressOffset {
691 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
692 alt(
693 mapc!(
694 seq(plus_p(), RegisterOperand::parse()),
695 AddressOffset::Register { _, operand }
696 ),
697 map(
698 seq_n!(
699 map(plus_p(), |_, span| span),
700 optional(map(minus_p(), |_, span| span)),
701 Immediate::parse(),
702 ),
703 |(plus_span, minus_span, value), span| {
704 let sign = minus_span.map_or(Sign::Positive { span: plus_span }, |span| {
708 Sign::Negative { span }
709 });
710 c!(AddressOffset::Immediate { sign, value })
711 },
712 ),
713 )
714 }
715}
716
717impl PtxParser for AddressOperand {
718 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
719 alt!(
720 mapc!(
721 seq(
722 VariableSymbol::parse(),
723 between(lbracket_p(), rbracket_p(), Immediate::parse()),
724 ),
725 AddressOperand::Array { base, index }
726 ),
727 mapc!(
728 between(
729 lbracket_p(),
730 rbracket_p(),
731 seq(AddressBase::parse(), optional(AddressOffset::parse())),
732 ),
733 AddressOperand::Offset { base, offset }
734 ),
735 map(
736 between(
737 lbracket_p(),
738 rbracket_p(),
739 seq(optional(Sign::parse()), Immediate::parse()),
740 ),
741 |(sign, mut addr), span| {
742 if matches!(sign, Some(Sign::Negative { .. })) && !addr.value.starts_with('-') {
743 addr.value = format!("-{}", addr.value);
744 }
745 c!(AddressOperand::ImmediateAddress { addr })
746 },
747 ),
748 )
749 }
750}
751
752fn split_axis_suffix(raw: &str) -> Result<(&str, Option<char>), &'static str> {
753 if let Some(idx) = raw.rfind('.') {
754 let (base, suffix) = raw.split_at(idx);
755 if suffix.len() != 2 {
756 return Err("invalid axis suffix");
757 }
758 let axis_char = suffix.chars().nth(1).unwrap();
759 Ok((base, Some(axis_char)))
760 } else {
761 Ok((raw, None))
762 }
763}
764
765fn axis_from_suffix(axis: Option<char>, span: Span) -> Result<Axis, PtxParseError> {
766 match axis.map(|c| c.to_ascii_lowercase()) {
767 None => Ok(Axis::None { span }),
768 Some('x') => Ok(Axis::X { span }),
769 Some('y') => Ok(Axis::Y { span }),
770 Some('z') => Ok(Axis::Z { span }),
771 Some(other) => Err(PtxParseError {
772 kind: ParseErrorKind::InvalidLiteral(format!(
773 "invalid axis '.{}' for special register",
774 other
775 )),
776 span,
777 }),
778 }
779}
780
781fn axis_with_span(axis: Option<char>, span: &Span) -> Result<Axis, PtxParseError> {
782 axis_from_suffix(axis, *span)
783}
784
785fn ensure_no_axis(axis: Option<char>, span: Span) -> Result<(), PtxParseError> {
786 if let Some(ch) = axis {
787 Err(PtxParseError {
788 kind: ParseErrorKind::InvalidLiteral(format!(
789 "register does not accept axis '.{}'",
790 ch
791 )),
792 span,
793 })
794 } else {
795 Ok(())
796 }
797}