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