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 alt(
136 map(directive_exact_p("managed"), |_, span| {
137 c!(AttributeDirective::Managed)
138 }),
139 mapc!(
140 skip_first(
141 directive_exact_p("unified"),
142 between(
143 lparen_p(),
144 rparen_p(),
145 seq_n!(u64_p(), skip_first(comma_p(), u64_p()))
146 ),
147 ),
148 AttributeDirective::Unified { uuid1, uuid2 }
149 ),
150 )
151 }
152}
153
154impl PtxParser for Sign {
155 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
156 alt(
157 map(plus_p(), |_, span| c!(Sign::Positive)),
158 map(minus_p(), |_, span| c!(Sign::Negative)),
159 )
160 }
161}
162
163impl PtxParser for RegisterOperand {
164 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
165 try_map(register_p(), |mut raw, span| {
166 let component = if let Some(idx) = raw.rfind('.') {
167 if idx + 1 >= raw.len() {
168 return err!(ParseErrorKind::InvalidLiteral(
169 "register component missing after '.'".into(),
170 ));
171 }
172 let suffix = raw[idx + 1..].to_string();
173 raw.truncate(idx);
174 Some(suffix)
175 } else {
176 None
177 };
178 let name = raw;
179 ok!(RegisterOperand { name, component })
180 })
181 }
182}
183
184impl PtxParser for VariableSymbol {
185 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
186 map(identifier_p(), |val, span| c!(VariableSymbol { val }))
187 }
188}
189
190impl PtxParser for FunctionSymbol {
191 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
192 map(identifier_p(), |val, span| c!(FunctionSymbol { val }))
193 }
194}
195
196impl PtxParser for Label {
197 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
198 alt(
199 map(identifier_p(), |val, span| c!(Label { val })),
200 map(directive_p(), |name, span| {
201 c!(Label {
202 val = format!(".{name}")
203 })
204 }),
205 )
206 }
207}
208
209impl PtxParser for PredicateRegister {
210 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
211 try_map(register_p(), |name, span| {
212 if name.starts_with("%p") {
213 ok!(PredicateRegister { name })
214 } else {
215 err!(ParseErrorKind::InvalidLiteral(
216 "expected predicate register (%pX)".into(),
217 ))
218 }
219 })
220 }
221}
222
223impl PtxParser for Predicate {
224 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
225 try_map(
226 seq_n!(at_p(), optional(exclamation_p()), Operand::parse()),
227 |(_, negation, operand), span| {
228 let negated = negation.is_some();
229 ok!(Predicate { negated, operand })
230 },
231 )
232 }
233}
234
235impl PtxParser for Instruction {
236 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
237 use crate::r#type::instruction::Inst;
238
239 try_map(
240 seq(optional(Predicate::parse()), Inst::parse()),
241 |(predicate, inst), span| ok!(Instruction { predicate, inst }),
242 )
243 }
244}
245
246impl PtxParser for ParamStateSpace {
247 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
248 alt!(
249 map(directive_exact_p("const"), |_, span| {
250 c!(ParamStateSpace::Const)
251 }),
252 map(directive_exact_p("global"), |_, span| {
253 c!(ParamStateSpace::Global)
254 }),
255 map(directive_exact_p("local"), |_, span| {
256 c!(ParamStateSpace::Local)
257 }),
258 map(directive_exact_p("shared"), |_, span| {
259 c!(ParamStateSpace::Shared)
260 }),
261 )
262 }
263}
264
265impl PtxParser for Operand {
266 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
267 let register = mapc!(RegisterOperand::parse(), Operand::Register { operand });
268 let immediate = map(
269 seq(optional(Sign::parse()), Immediate::parse()),
270 |(sign, mut operand), span| {
271 if matches!(sign, Some(Sign::Negative { .. })) && !operand.value.starts_with('-') {
272 operand.value = format!("-{}", operand.value);
273 }
274 c!(Operand::Immediate { operand })
275 },
276 );
277 let symbol_offset = map(
278 seq_n!(identifier_p(), plus_p(), Immediate::parse()),
279 |(symbol, _, offset), span| c!(Operand::SymbolOffset { symbol, offset }),
280 );
281 let symbol = mapc!(identifier_p(), Operand::Symbol { name });
282 alt!(register, immediate, symbol_offset, symbol)
283 }
284}
285
286impl PtxParser for VectorOperand {
287 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
288 try_map(
289 between(lbrace_p(), rbrace_p(), sep_by1(Operand::parse(), comma_p())),
290 |operands, span| match operands.len() {
291 1 => {
292 let mut iter = operands.into_iter();
293 let operand = iter.next().unwrap();
294 ok!(VectorOperand::Vector1 { operand })
295 }
296 2 => {
297 let mut iter = operands.into_iter();
298 let operands = [iter.next().unwrap(), iter.next().unwrap()];
299 ok!(VectorOperand::Vector2 { operands })
300 }
301 3 => {
302 let mut iter = operands.into_iter();
303 let operands = [
304 iter.next().unwrap(),
305 iter.next().unwrap(),
306 iter.next().unwrap(),
307 ];
308 ok!(VectorOperand::Vector3 { operands })
309 }
310 4 => {
311 let mut iter = operands.into_iter();
312 let operands = [
313 iter.next().unwrap(),
314 iter.next().unwrap(),
315 iter.next().unwrap(),
316 iter.next().unwrap(),
317 ];
318 ok!(VectorOperand::Vector4 { operands })
319 }
320 8 => {
321 let mut iter = operands.into_iter();
322 let operands = [
323 iter.next().unwrap(),
324 iter.next().unwrap(),
325 iter.next().unwrap(),
326 iter.next().unwrap(),
327 iter.next().unwrap(),
328 iter.next().unwrap(),
329 iter.next().unwrap(),
330 iter.next().unwrap(),
331 ];
332 ok!(VectorOperand::Vector8 { operands })
333 }
334 _ => {
335 let span = operands.first().map(Spanned::span).unwrap_or(span!(0..0));
336 Err(PtxParseError {
337 kind: ParseErrorKind::UnexpectedToken {
338 expected: vec!["vector with 1,2,3,4, or 8 operands".into()],
339 found: format!("vector with {} operands", operands.len()),
340 },
341 span,
342 })
343 }
344 },
345 )
346 }
347}
348
349impl PtxParser for GeneralOperand {
350 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
351 alt(
352 mapc!(VectorOperand::parse(), GeneralOperand::Vec { operand }),
353 mapc!(Operand::parse(), GeneralOperand::Single { operand }),
354 )
355 }
356}
357
358fn handler_len_error(ty: &str, expected: &str, found: usize) -> PtxParseError {
359 PtxParseError {
360 kind: ParseErrorKind::InvalidLiteral(format!("{ty} expects {expected}, found {found}")),
361 span: Span::new(0, 0),
362 }
363}
364
365fn tex_operands()
366-> impl Fn(&mut PtxTokenStream) -> Result<(Vec<GeneralOperand>, Span), PtxParseError> {
367 between(
368 lbracket_p(),
369 rbracket_p(),
370 sep_by1(GeneralOperand::parse(), comma_p()),
371 )
372}
373
374impl PtxParser for TexHandler2 {
375 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
376 try_map(tex_operands(), |operands, span| {
377 if operands.len() != 2 {
378 return Err(handler_len_error(
379 "TexHandler2",
380 "exactly 2 operands",
381 operands.len(),
382 ));
383 }
384 let mut iter = operands.into_iter();
385 let first = iter.next().unwrap();
386 let second = iter.next().unwrap();
387 let operands = [first, second];
388 ok!(TexHandler2 { operands })
389 })
390 }
391}
392
393impl PtxParser for TexHandler3 {
394 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
395 try_map(tex_operands(), |operands, span| {
396 if operands.len() != 3 {
397 return Err(handler_len_error(
398 "TexHandler3",
399 "exactly 3 operands",
400 operands.len(),
401 ));
402 }
403 let mut iter = operands.into_iter();
404 let handle = iter.next().unwrap();
405 let sampler = iter.next().unwrap();
406 let coords = iter.next().unwrap();
407 ok!(TexHandler3 {
408 handle,
409 sampler,
410 coords
411 })
412 })
413 }
414}
415
416impl PtxParser for TexHandler3Optional {
417 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
418 try_map(tex_operands(), |operands, span| match operands.len() {
419 2 => {
420 let mut iter = operands.into_iter();
421 let handle = iter.next().unwrap();
422 let coords = iter.next().unwrap();
423 let sampler = None;
424 ok!(TexHandler3Optional {
425 handle,
426 sampler,
427 coords
428 })
429 }
430 3 => {
431 let mut iter = operands.into_iter();
432 let handle = iter.next().unwrap();
433 let sampler = Some(iter.next().unwrap());
434 let coords = iter.next().unwrap();
435 ok!(TexHandler3Optional {
436 handle,
437 sampler,
438 coords
439 })
440 }
441 other => Err(handler_len_error(
442 "TexHandler3Optional",
443 "2 or 3 operands",
444 other,
445 )),
446 })
447 }
448}
449
450impl PtxParser for SpecialRegister {
451 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
452 try_map(register_p(), |name, span| {
453 let raw = name.strip_prefix('%').ok_or_else(|| PtxParseError {
454 kind: ParseErrorKind::InvalidLiteral("expected % prefix".into()),
455 span,
456 })?;
457
458 let (base, axis_suffix) = split_axis_suffix(raw).map_err(|msg| PtxParseError {
459 kind: ParseErrorKind::InvalidLiteral(msg.into()),
460 span,
461 })?;
462 let base_lower = base.to_ascii_lowercase();
463
464 let mut node = match base_lower.as_str() {
465 "aggr_smem_size" => {
466 ensure_no_axis(axis_suffix, span)?;
467 c!(SpecialRegister::AggrSmemSize)
468 }
469 "dynamic_smem_size" => {
470 ensure_no_axis(axis_suffix, span)?;
471 c!(SpecialRegister::DynamicSmemSize)
472 }
473 "lanemask_gt" => {
474 ensure_no_axis(axis_suffix, span)?;
475 c!(SpecialRegister::LanemaskGt)
476 }
477 "reserved_smem_offset_begin" => {
478 ensure_no_axis(axis_suffix, span)?;
479 c!(SpecialRegister::ReservedSmemOffsetBegin)
480 }
481 "clock" => {
482 ensure_no_axis(axis_suffix, span)?;
483 c!(SpecialRegister::Clock)
484 }
485 "lanemask_le" => {
486 ensure_no_axis(axis_suffix, span)?;
487 c!(SpecialRegister::LanemaskLe)
488 }
489 "reserved_smem_offset_cap" => {
490 ensure_no_axis(axis_suffix, span)?;
491 c!(SpecialRegister::ReservedSmemOffsetCap)
492 }
493 "clock64" => {
494 ensure_no_axis(axis_suffix, span)?;
495 c!(SpecialRegister::Clock64)
496 }
497 "globaltimer" => {
498 ensure_no_axis(axis_suffix, span)?;
499 c!(SpecialRegister::Globaltimer)
500 }
501 "lanemask_lt" => {
502 ensure_no_axis(axis_suffix, span)?;
503 c!(SpecialRegister::LanemaskLt)
504 }
505 "reserved_smem_offset_end" => {
506 ensure_no_axis(axis_suffix, span)?;
507 c!(SpecialRegister::ReservedSmemOffsetEnd)
508 }
509 "globaltimer_hi" => {
510 ensure_no_axis(axis_suffix, span)?;
511 c!(SpecialRegister::GlobaltimerHi)
512 }
513 "nclusterid" => {
514 ensure_no_axis(axis_suffix, span)?;
515 c!(SpecialRegister::Nclusterid)
516 }
517 "smid" => {
518 ensure_no_axis(axis_suffix, span)?;
519 c!(SpecialRegister::Smid)
520 }
521 "globaltimer_lo" => {
522 ensure_no_axis(axis_suffix, span)?;
523 c!(SpecialRegister::GlobaltimerLo)
524 }
525 "gridid" => {
526 ensure_no_axis(axis_suffix, span)?;
527 c!(SpecialRegister::Gridid)
528 }
529 "nsmid" => {
530 ensure_no_axis(axis_suffix, span)?;
531 c!(SpecialRegister::Nsmid)
532 }
533 "total_smem_size" => {
534 ensure_no_axis(axis_suffix, span)?;
535 c!(SpecialRegister::TotalSmemSize)
536 }
537 "is_explicit_cluster" => {
538 ensure_no_axis(axis_suffix, span)?;
539 c!(SpecialRegister::IsExplicitCluster)
540 }
541 "warpid" => {
542 ensure_no_axis(axis_suffix, span)?;
543 c!(SpecialRegister::Warpid)
544 }
545 "clusterid" => {
546 ensure_no_axis(axis_suffix, span)?;
547 c!(SpecialRegister::Clusterid)
548 }
549 "laneid" => {
550 ensure_no_axis(axis_suffix, span)?;
551 c!(SpecialRegister::Laneid)
552 }
553 "nwarpid" => {
554 ensure_no_axis(axis_suffix, span)?;
555 c!(SpecialRegister::Nwarpid)
556 }
557 "warpsz" => {
558 ensure_no_axis(axis_suffix, span)?;
559 c!(SpecialRegister::WARPSZ)
560 }
561 "lanemask_eq" => {
562 ensure_no_axis(axis_suffix, span)?;
563 c!(SpecialRegister::LanemaskEq)
564 }
565 "current_graph_exec" => {
566 ensure_no_axis(axis_suffix, span)?;
567 c!(SpecialRegister::CurrentGraphExec)
568 }
569 "lanemask_ge" => {
570 ensure_no_axis(axis_suffix, span)?;
571 c!(SpecialRegister::LanemaskGe)
572 }
573 "cluster_ctaid" => {
574 let axis = axis_with_span(axis_suffix, &span)?;
575 c!(SpecialRegister::ClusterCtaid { axis })
576 }
577 "cluster_ctarank" => {
578 let axis = axis_with_span(axis_suffix, &span)?;
579 c!(SpecialRegister::ClusterCtarank { axis })
580 }
581 "nctaid" => {
582 let axis = axis_with_span(axis_suffix, &span)?;
583 c!(SpecialRegister::Nctaid { axis })
584 }
585 "tid" => {
586 let axis = axis_with_span(axis_suffix, &span)?;
587 c!(SpecialRegister::Tid { axis })
588 }
589 "cluster_nctaid" => {
590 let axis = axis_with_span(axis_suffix, &span)?;
591 c!(SpecialRegister::ClusterNctaid { axis })
592 }
593 "cluster_nctarank" => {
594 let axis = axis_with_span(axis_suffix, &span)?;
595 c!(SpecialRegister::ClusterNctarank { axis })
596 }
597 "ntid" => {
598 let axis = axis_with_span(axis_suffix, &span)?;
599 c!(SpecialRegister::Ntid { axis })
600 }
601 "ctaid" => {
602 let axis = axis_with_span(axis_suffix, &span)?;
603 c!(SpecialRegister::Ctaid { axis })
604 }
605 base if base.starts_with("envreg") => {
606 ensure_no_axis(axis_suffix, span)?;
607 let digits = base.strip_prefix("envreg").unwrap();
608 let index = parse_index_suffix(digits, 31, "envreg", span)?;
609 c!(SpecialRegister::Envreg { index })
610 }
611 base if base.starts_with("pm") && base.ends_with("_64") => {
612 ensure_no_axis(axis_suffix, span)?;
613 let digits = base
614 .strip_prefix("pm")
615 .and_then(|rest| rest.strip_suffix("_64"))
616 .unwrap();
617 let index = parse_index_suffix(digits, 7, "pm64", span)?;
618 c!(SpecialRegister::Pm64 { index })
619 }
620 base if base.starts_with("pm") => {
621 ensure_no_axis(axis_suffix, span)?;
622 let digits = base.strip_prefix("pm").unwrap();
623 let index = parse_index_suffix(digits, 7, "pm", span)?;
624 c!(SpecialRegister::Pm { index })
625 }
626 base if base.starts_with("reserved_smem_offset_") => {
627 ensure_no_axis(axis_suffix, span)?;
628 let digits = base.strip_prefix("reserved_smem_offset_").unwrap();
629 let index = parse_index_suffix(digits, 1, "reserved_smem_offset", span)?;
630 c!(SpecialRegister::ReservedSmemOffset { index })
631 }
632 _ => {
633 return err!(ParseErrorKind::InvalidLiteral(format!(
634 "unknown special register: {name}"
635 )));
636 }
637 };
638
639 node.set_span(span);
640 Ok(node)
641 })
642 }
643}
644
645impl PtxParser for Immediate {
646 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
647 mapc!(literal_p(), Immediate { value })
648 }
649}
650
651impl PtxParser for AddressBase {
652 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
653 alt(
654 mapc!(RegisterOperand::parse(), AddressBase::Register { operand }),
655 mapc!(VariableSymbol::parse(), AddressBase::Variable { symbol }),
656 )
657 }
658}
659
660impl PtxParser for AddressOffset {
661 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
662 alt(
663 mapc!(
664 seq(plus_p(), RegisterOperand::parse()),
665 AddressOffset::Register { _, operand }
666 ),
667 mapc!(
668 seq(Sign::parse(), Immediate::parse()),
669 AddressOffset::Immediate { sign, value }
670 ),
671 )
672 }
673}
674
675impl PtxParser for AddressOperand {
676 fn parse() -> impl Fn(&mut PtxTokenStream) -> Result<(Self, Span), PtxParseError> {
677 alt!(
678 mapc!(
679 seq(
680 VariableSymbol::parse(),
681 between(lbracket_p(), rbracket_p(), Immediate::parse()),
682 ),
683 AddressOperand::Array { base, index }
684 ),
685 mapc!(
686 between(
687 lbracket_p(),
688 rbracket_p(),
689 seq(AddressBase::parse(), optional(AddressOffset::parse())),
690 ),
691 AddressOperand::Offset { base, offset }
692 ),
693 map(
694 between(
695 lbracket_p(),
696 rbracket_p(),
697 seq(optional(Sign::parse()), Immediate::parse()),
698 ),
699 |(sign, mut addr), span| {
700 if matches!(sign, Some(Sign::Negative { .. })) && !addr.value.starts_with('-') {
701 addr.value = format!("-{}", addr.value);
702 }
703 c!(AddressOperand::ImmediateAddress { addr })
704 },
705 ),
706 )
707 }
708}
709
710fn split_axis_suffix(raw: &str) -> Result<(&str, Option<char>), &'static str> {
711 if let Some(idx) = raw.rfind('.') {
712 let (base, suffix) = raw.split_at(idx);
713 if suffix.len() != 2 {
714 return Err("invalid axis suffix");
715 }
716 let axis_char = suffix.chars().nth(1).unwrap();
717 Ok((base, Some(axis_char)))
718 } else {
719 Ok((raw, None))
720 }
721}
722
723fn axis_from_suffix(axis: Option<char>, span: Span) -> Result<Axis, PtxParseError> {
724 match axis.map(|c| c.to_ascii_lowercase()) {
725 None => Ok(Axis::None { span }),
726 Some('x') => Ok(Axis::X { span }),
727 Some('y') => Ok(Axis::Y { span }),
728 Some('z') => Ok(Axis::Z { span }),
729 Some(other) => Err(PtxParseError {
730 kind: ParseErrorKind::InvalidLiteral(format!(
731 "invalid axis '.{}' for special register",
732 other
733 )),
734 span,
735 }),
736 }
737}
738
739fn axis_with_span(axis: Option<char>, span: &Span) -> Result<Axis, PtxParseError> {
740 axis_from_suffix(axis, *span)
741}
742
743fn ensure_no_axis(axis: Option<char>, span: Span) -> Result<(), PtxParseError> {
744 if let Some(ch) = axis {
745 Err(PtxParseError {
746 kind: ParseErrorKind::InvalidLiteral(format!(
747 "register does not accept axis '.{}'",
748 ch
749 )),
750 span,
751 })
752 } else {
753 Ok(())
754 }
755}