1 //! AArch64 ISA definitions: instruction arguments.
2 
3 use crate::ir::types::*;
4 use crate::isa::aarch64::inst::*;
5 
6 //=============================================================================
7 // Instruction sub-components: shift and extend descriptors
8 
9 /// A shift operator for a register or immediate.
10 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
11 #[repr(u8)]
12 pub enum ShiftOp {
13     /// Logical shift left.
14     LSL = 0b00,
15     /// Logical shift right.
16     LSR = 0b01,
17     /// Arithmetic shift right.
18     ASR = 0b10,
19     /// Rotate right.
20     ROR = 0b11,
21 }
22 
23 impl ShiftOp {
24     /// Get the encoding of this shift op.
25     pub fn bits(self) -> u8 {
26         self as u8
27     }
28 }
29 
30 /// A shift operator amount.
31 #[derive(Clone, Copy, Debug)]
32 pub struct ShiftOpShiftImm(u8);
33 
34 impl ShiftOpShiftImm {
35     /// Maximum shift for shifted-register operands.
36     pub const MAX_SHIFT: u64 = 63;
37 
38     /// Create a new shiftop shift amount, if possible.
39     pub fn maybe_from_shift(shift: u64) -> Option<ShiftOpShiftImm> {
40         if shift <= Self::MAX_SHIFT {
41             Some(ShiftOpShiftImm(shift as u8))
42         } else {
43             None
44         }
45     }
46 
47     /// Return the shift amount.
48     pub fn value(self) -> u8 {
49         self.0
50     }
51 
52     /// Mask down to a given number of bits.
53     pub fn mask(self, bits: u8) -> ShiftOpShiftImm {
54         ShiftOpShiftImm(self.0 & (bits - 1))
55     }
56 }
57 
58 /// A shift operator with an amount, guaranteed to be within range.
59 #[derive(Copy, Clone, Debug)]
60 pub struct ShiftOpAndAmt {
61     /// The shift operator.
62     op: ShiftOp,
63     /// The shift operator amount.
64     shift: ShiftOpShiftImm,
65 }
66 
67 impl ShiftOpAndAmt {
68     /// Create a new shift operator with an amount.
69     pub fn new(op: ShiftOp, shift: ShiftOpShiftImm) -> ShiftOpAndAmt {
70         ShiftOpAndAmt { op, shift }
71     }
72 
73     /// Get the shift op.
74     pub fn op(&self) -> ShiftOp {
75         self.op
76     }
77 
78     /// Get the shift amount.
79     pub fn amt(&self) -> ShiftOpShiftImm {
80         self.shift
81     }
82 }
83 
84 /// An extend operator for a register.
85 #[derive(Clone, Copy, Debug)]
86 #[repr(u8)]
87 pub enum ExtendOp {
88     /// Unsigned extend byte.
89     UXTB = 0b000,
90     /// Unsigned extend halfword.
91     UXTH = 0b001,
92     /// Unsigned extend word.
93     UXTW = 0b010,
94     /// Unsigned extend doubleword.
95     UXTX = 0b011,
96     /// Signed extend byte.
97     SXTB = 0b100,
98     /// Signed extend halfword.
99     SXTH = 0b101,
100     /// Signed extend word.
101     SXTW = 0b110,
102     /// Signed extend doubleword.
103     SXTX = 0b111,
104 }
105 
106 impl ExtendOp {
107     /// Encoding of this op.
108     pub fn bits(self) -> u8 {
109         self as u8
110     }
111 }
112 
113 //=============================================================================
114 // Instruction sub-components (memory addresses): definitions
115 
116 /// A reference to some memory address.
117 #[derive(Clone, Debug)]
118 pub enum MemLabel {
119     /// An address in the code, a constant pool or jumptable, with relative
120     /// offset from this instruction. This form must be used at emission time;
121     /// see `memlabel_finalize()` for how other forms are lowered to this one.
122     PCRel(i32),
123     /// An address that refers to a label within a `MachBuffer`, for example a
124     /// constant that lives in the pool at the end of the function.
125     Mach(MachLabel),
126 }
127 
128 impl AMode {
129     /// Memory reference using an address in a register.
130     pub fn reg(reg: Reg) -> AMode {
131         // Use UnsignedOffset rather than Unscaled to use ldr rather than ldur.
132         // This also does not use PostIndexed / PreIndexed as they update the register.
133         AMode::UnsignedOffset {
134             rn: reg,
135             uimm12: UImm12Scaled::zero(I64),
136         }
137     }
138 
139     /// Memory reference using `reg1 + sizeof(ty) * reg2` as an address, with `reg2` sign- or
140     /// zero-extended as per `op`.
141     pub fn reg_plus_reg_scaled_extended(reg1: Reg, reg2: Reg, op: ExtendOp) -> AMode {
142         AMode::RegScaledExtended {
143             rn: reg1,
144             rm: reg2,
145             extendop: op,
146         }
147     }
148 }
149 
150 pub use crate::isa::aarch64::lower::isle::generated_code::PairAMode;
151 
152 //=============================================================================
153 // Instruction sub-components (conditions, branches and branch targets):
154 // definitions
155 
156 /// Condition for conditional branches.
157 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
158 #[repr(u8)]
159 pub enum Cond {
160     /// Equal.
161     Eq = 0,
162     /// Not equal.
163     Ne = 1,
164     /// Unsigned greater than or equal to.
165     Hs = 2,
166     /// Unsigned less than.
167     Lo = 3,
168     /// Minus, negative.
169     Mi = 4,
170     /// Positive or zero.
171     Pl = 5,
172     /// Signed overflow.
173     Vs = 6,
174     /// No signed overflow.
175     Vc = 7,
176     /// Unsigned greater than.
177     Hi = 8,
178     /// Unsigned less than or equal to.
179     Ls = 9,
180     /// Signed greater or equal to.
181     Ge = 10,
182     /// Signed less than.
183     Lt = 11,
184     /// Signed greater than.
185     Gt = 12,
186     /// Signed less than or equal.
187     Le = 13,
188     /// Always executed.
189     Al = 14,
190     /// Always executed.
191     Nv = 15,
192 }
193 
194 impl Cond {
195     /// Return the inverted condition.
196     pub fn invert(self) -> Cond {
197         match self {
198             Cond::Eq => Cond::Ne,
199             Cond::Ne => Cond::Eq,
200 
201             Cond::Hs => Cond::Lo,
202             Cond::Lo => Cond::Hs,
203 
204             Cond::Mi => Cond::Pl,
205             Cond::Pl => Cond::Mi,
206 
207             Cond::Vs => Cond::Vc,
208             Cond::Vc => Cond::Vs,
209 
210             Cond::Hi => Cond::Ls,
211             Cond::Ls => Cond::Hi,
212 
213             Cond::Ge => Cond::Lt,
214             Cond::Lt => Cond::Ge,
215 
216             Cond::Gt => Cond::Le,
217             Cond::Le => Cond::Gt,
218 
219             Cond::Al => Cond::Nv,
220             Cond::Nv => Cond::Al,
221         }
222     }
223 
224     /// Return the machine encoding of this condition.
225     pub fn bits(self) -> u32 {
226         self as u32
227     }
228 }
229 
230 /// The kind of conditional branch: the common-case-optimized "reg-is-zero" /
231 /// "reg-is-nonzero" variants, or the generic one that tests the machine
232 /// condition codes.
233 #[derive(Clone, Copy, Debug)]
234 pub enum CondBrKind {
235     /// Condition: given register is zero.
236     Zero(Reg, OperandSize),
237     /// Condition: given register is nonzero.
238     NotZero(Reg, OperandSize),
239     /// Condition: the given condition-code test is true.
240     Cond(Cond),
241 }
242 
243 impl CondBrKind {
244     /// Return the inverted branch condition.
245     pub fn invert(self) -> CondBrKind {
246         match self {
247             CondBrKind::Zero(reg, size) => CondBrKind::NotZero(reg, size),
248             CondBrKind::NotZero(reg, size) => CondBrKind::Zero(reg, size),
249             CondBrKind::Cond(c) => CondBrKind::Cond(c.invert()),
250         }
251     }
252 }
253 
254 /// A branch target. Either unresolved (basic-block index) or resolved (offset
255 /// from end of current instruction).
256 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
257 pub enum BranchTarget {
258     /// An unresolved reference to a Label, as passed into
259     /// `lower_branch_group()`.
260     Label(MachLabel),
261     /// A fixed PC offset.
262     ResolvedOffset(i32),
263 }
264 
265 impl BranchTarget {
266     /// Return the target's label, if it is a label-based target.
267     pub fn as_label(self) -> Option<MachLabel> {
268         match self {
269             BranchTarget::Label(l) => Some(l),
270             _ => None,
271         }
272     }
273 
274     /// Return the target's offset, if specified, or zero if label-based.
275     pub fn as_offset14_or_zero(self) -> u32 {
276         self.as_offset_bounded(14)
277     }
278 
279     /// Return the target's offset, if specified, or zero if label-based.
280     pub fn as_offset19_or_zero(self) -> u32 {
281         self.as_offset_bounded(19)
282     }
283 
284     /// Return the target's offset, if specified, or zero if label-based.
285     pub fn as_offset26_or_zero(self) -> u32 {
286         self.as_offset_bounded(26)
287     }
288 
289     fn as_offset_bounded(self, bits: u32) -> u32 {
290         let off = match self {
291             BranchTarget::ResolvedOffset(off) => off >> 2,
292             _ => 0,
293         };
294         let hi = (1 << (bits - 1)) - 1;
295         let lo = -(1 << bits - 1);
296         assert!(off <= hi);
297         assert!(off >= lo);
298         (off as u32) & ((1 << bits) - 1)
299     }
300 }
301 
302 impl PrettyPrint for ShiftOpAndAmt {
303     fn pretty_print(&self, _: u8) -> String {
304         format!("{:?} {}", self.op(), self.amt().value())
305     }
306 }
307 
308 impl PrettyPrint for ExtendOp {
309     fn pretty_print(&self, _: u8) -> String {
310         format!("{self:?}")
311     }
312 }
313 
314 impl PrettyPrint for MemLabel {
315     fn pretty_print(&self, _: u8) -> String {
316         match self {
317             MemLabel::PCRel(off) => format!("pc+{off}"),
318             MemLabel::Mach(off) => format!("label({})", off.as_u32()),
319         }
320     }
321 }
322 
323 fn shift_for_type(size_bytes: u8) -> usize {
324     match size_bytes {
325         1 => 0,
326         2 => 1,
327         4 => 2,
328         8 => 3,
329         16 => 4,
330         _ => panic!("unknown type size: {size_bytes}"),
331     }
332 }
333 
334 impl PrettyPrint for AMode {
335     fn pretty_print(&self, size_bytes: u8) -> String {
336         debug_assert!(size_bytes != 0);
337         match self {
338             &AMode::Unscaled { rn, simm9 } => {
339                 let reg = pretty_print_reg(rn);
340                 if simm9.value != 0 {
341                     let simm9 = simm9.pretty_print(8);
342                     format!("[{reg}, {simm9}]")
343                 } else {
344                     format!("[{reg}]")
345                 }
346             }
347             &AMode::UnsignedOffset { rn, uimm12 } => {
348                 let reg = pretty_print_reg(rn);
349                 if uimm12.value() != 0 {
350                     let uimm12 = uimm12.pretty_print(8);
351                     format!("[{reg}, {uimm12}]")
352                 } else {
353                     format!("[{reg}]")
354                 }
355             }
356             &AMode::RegReg { rn, rm } => {
357                 let r1 = pretty_print_reg(rn);
358                 let r2 = pretty_print_reg(rm);
359                 format!("[{r1}, {r2}]")
360             }
361             &AMode::RegScaled { rn, rm } => {
362                 let r1 = pretty_print_reg(rn);
363                 let r2 = pretty_print_reg(rm);
364                 let shift = shift_for_type(size_bytes);
365                 format!("[{r1}, {r2}, LSL #{shift}]")
366             }
367             &AMode::RegScaledExtended { rn, rm, extendop } => {
368                 let shift = shift_for_type(size_bytes);
369                 let size = match extendop {
370                     ExtendOp::SXTW | ExtendOp::UXTW => OperandSize::Size32,
371                     _ => OperandSize::Size64,
372                 };
373                 let r1 = pretty_print_reg(rn);
374                 let r2 = pretty_print_ireg(rm, size);
375                 let op = extendop.pretty_print(0);
376                 format!("[{r1}, {r2}, {op} #{shift}]")
377             }
378             &AMode::RegExtended { rn, rm, extendop } => {
379                 let size = match extendop {
380                     ExtendOp::SXTW | ExtendOp::UXTW => OperandSize::Size32,
381                     _ => OperandSize::Size64,
382                 };
383                 let r1 = pretty_print_reg(rn);
384                 let r2 = pretty_print_ireg(rm, size);
385                 let op = extendop.pretty_print(0);
386                 format!("[{r1}, {r2}, {op}]")
387             }
388             &AMode::Label { ref label } => label.pretty_print(0),
389             &AMode::SPPreIndexed { simm9 } => {
390                 let simm9 = simm9.pretty_print(8);
391                 format!("[sp, {simm9}]!")
392             }
393             &AMode::SPPostIndexed { simm9 } => {
394                 let simm9 = simm9.pretty_print(8);
395                 format!("[sp], {simm9}")
396             }
397             AMode::Const { addr } => format!("[const({})]", addr.as_u32()),
398 
399             // Eliminated by `mem_finalize()`.
400             &AMode::SPOffset { .. }
401             | &AMode::FPOffset { .. }
402             | &AMode::IncomingArg { .. }
403             | &AMode::SlotOffset { .. }
404             | &AMode::RegOffset { .. } => {
405                 panic!("Unexpected pseudo mem-arg mode: {self:?}")
406             }
407         }
408     }
409 }
410 
411 impl PrettyPrint for PairAMode {
412     fn pretty_print(&self, _: u8) -> String {
413         match self {
414             &PairAMode::SignedOffset { reg, simm7 } => {
415                 let reg = pretty_print_reg(reg);
416                 if simm7.value != 0 {
417                     let simm7 = simm7.pretty_print(8);
418                     format!("[{reg}, {simm7}]")
419                 } else {
420                     format!("[{reg}]")
421                 }
422             }
423             &PairAMode::SPPreIndexed { simm7 } => {
424                 let simm7 = simm7.pretty_print(8);
425                 format!("[sp, {simm7}]!")
426             }
427             &PairAMode::SPPostIndexed { simm7 } => {
428                 let simm7 = simm7.pretty_print(8);
429                 format!("[sp], {simm7}")
430             }
431         }
432     }
433 }
434 
435 impl PrettyPrint for Cond {
436     fn pretty_print(&self, _: u8) -> String {
437         let mut s = format!("{self:?}");
438         s.make_ascii_lowercase();
439         s
440     }
441 }
442 
443 impl PrettyPrint for BranchTarget {
444     fn pretty_print(&self, _: u8) -> String {
445         match self {
446             &BranchTarget::Label(label) => format!("label{:?}", label.as_u32()),
447             &BranchTarget::ResolvedOffset(off) => format!("{off}"),
448         }
449     }
450 }
451 
452 /// Type used to communicate the operand size of a machine instruction, as AArch64 has 32- and
453 /// 64-bit variants of many instructions (and integer registers).
454 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
455 pub enum OperandSize {
456     /// 32-bit.
457     Size32,
458     /// 64-bit.
459     Size64,
460 }
461 
462 impl OperandSize {
463     /// 32-bit case?
464     pub fn is32(self) -> bool {
465         self == OperandSize::Size32
466     }
467 
468     /// 64-bit case?
469     pub fn is64(self) -> bool {
470         self == OperandSize::Size64
471     }
472 
473     /// Convert from a needed width to the smallest size that fits.
474     pub fn from_bits<I: Into<usize>>(bits: I) -> OperandSize {
475         let bits: usize = bits.into();
476         assert!(bits <= 64);
477         if bits <= 32 {
478             OperandSize::Size32
479         } else {
480             OperandSize::Size64
481         }
482     }
483 
484     /// Return the operand size in bits.
485     pub fn bits(&self) -> u8 {
486         match self {
487             OperandSize::Size32 => 32,
488             OperandSize::Size64 => 64,
489         }
490     }
491 
492     /// Convert from an integer type into the smallest size that fits.
493     pub fn from_ty(ty: Type) -> OperandSize {
494         debug_assert!(!ty.is_vector());
495 
496         Self::from_bits(ty_bits(ty))
497     }
498 
499     /// Convert to I32, I64, or I128.
500     pub fn to_ty(self) -> Type {
501         match self {
502             OperandSize::Size32 => I32,
503             OperandSize::Size64 => I64,
504         }
505     }
506 
507     /// Register interpretation bit.
508     /// When 0, the register is interpreted as the 32-bit version.
509     /// When 1, the register is interpreted as the 64-bit version.
510     pub fn sf_bit(&self) -> u32 {
511         match self {
512             OperandSize::Size32 => 0,
513             OperandSize::Size64 => 1,
514         }
515     }
516 
517     /// The maximum unsigned value representable in a value of this size.
518     pub fn max_value(&self) -> u64 {
519         match self {
520             OperandSize::Size32 => u32::MAX as u64,
521             OperandSize::Size64 => u64::MAX,
522         }
523     }
524 }
525 
526 /// Type used to communicate the size of a scalar SIMD & FP operand.
527 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
528 pub enum ScalarSize {
529     /// 8-bit.
530     Size8,
531     /// 16-bit.
532     Size16,
533     /// 32-bit.
534     Size32,
535     /// 64-bit.
536     Size64,
537     /// 128-bit.
538     Size128,
539 }
540 
541 impl ScalarSize {
542     /// Convert to an integer operand size.
543     pub fn operand_size(&self) -> OperandSize {
544         match self {
545             ScalarSize::Size8 | ScalarSize::Size16 | ScalarSize::Size32 => OperandSize::Size32,
546             ScalarSize::Size64 => OperandSize::Size64,
547             _ => panic!("Unexpected operand_size request for: {self:?}"),
548         }
549     }
550 
551     /// Return the encoding bits that are used by some scalar FP instructions
552     /// for a particular operand size.
553     pub fn ftype(&self) -> u32 {
554         match self {
555             ScalarSize::Size16 => 0b11,
556             ScalarSize::Size32 => 0b00,
557             ScalarSize::Size64 => 0b01,
558             _ => panic!("Unexpected scalar FP operand size: {self:?}"),
559         }
560     }
561 
562     /// Return the widened version of the scalar size.
563     pub fn widen(&self) -> ScalarSize {
564         match self {
565             ScalarSize::Size8 => ScalarSize::Size16,
566             ScalarSize::Size16 => ScalarSize::Size32,
567             ScalarSize::Size32 => ScalarSize::Size64,
568             ScalarSize::Size64 => ScalarSize::Size128,
569             ScalarSize::Size128 => panic!("can't widen 128-bits"),
570         }
571     }
572 
573     /// Return the narrowed version of the scalar size.
574     pub fn narrow(&self) -> ScalarSize {
575         match self {
576             ScalarSize::Size8 => panic!("can't narrow 8-bits"),
577             ScalarSize::Size16 => ScalarSize::Size8,
578             ScalarSize::Size32 => ScalarSize::Size16,
579             ScalarSize::Size64 => ScalarSize::Size32,
580             ScalarSize::Size128 => ScalarSize::Size64,
581         }
582     }
583 
584     /// Return a type with the same size as this scalar.
585     pub fn ty(&self) -> Type {
586         match self {
587             ScalarSize::Size8 => I8,
588             ScalarSize::Size16 => I16,
589             ScalarSize::Size32 => I32,
590             ScalarSize::Size64 => I64,
591             ScalarSize::Size128 => I128,
592         }
593     }
594 }
595 
596 /// Type used to communicate the size of a vector operand.
597 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
598 pub enum VectorSize {
599     /// 8-bit, 8 lanes.
600     Size8x8,
601     /// 8 bit, 16 lanes.
602     Size8x16,
603     /// 16-bit, 4 lanes.
604     Size16x4,
605     /// 16-bit, 8 lanes.
606     Size16x8,
607     /// 32-bit, 2 lanes.
608     Size32x2,
609     /// 32-bit, 4 lanes.
610     Size32x4,
611     /// 64-bit, 2 lanes.
612     Size64x2,
613 }
614 
615 impl VectorSize {
616     /// Get the vector operand of the same size but with 8-bit lane size.
617     pub fn as_scalar8_vector(&self) -> VectorSize {
618         match self {
619             // 64-bit vector
620             VectorSize::Size8x8 | VectorSize::Size16x4 | VectorSize::Size32x2 => {
621                 VectorSize::Size8x8
622             }
623             // 128-bit vector
624             VectorSize::Size8x16
625             | VectorSize::Size16x8
626             | VectorSize::Size32x4
627             | VectorSize::Size64x2 => VectorSize::Size8x16,
628         }
629     }
630 
631     /// Get the vector operand size with the given scalar size as lane size.
632     pub fn from_lane_size(size: ScalarSize, is_128bit: bool) -> VectorSize {
633         match (size, is_128bit) {
634             (ScalarSize::Size8, false) => VectorSize::Size8x8,
635             (ScalarSize::Size8, true) => VectorSize::Size8x16,
636             (ScalarSize::Size16, false) => VectorSize::Size16x4,
637             (ScalarSize::Size16, true) => VectorSize::Size16x8,
638             (ScalarSize::Size32, false) => VectorSize::Size32x2,
639             (ScalarSize::Size32, true) => VectorSize::Size32x4,
640             (ScalarSize::Size64, true) => VectorSize::Size64x2,
641             _ => panic!("Unexpected scalar FP operand size: {size:?}"),
642         }
643     }
644 
645     /// Get the integer operand size that corresponds to a lane of a vector with a certain size.
646     pub fn operand_size(&self) -> OperandSize {
647         match self {
648             VectorSize::Size64x2 => OperandSize::Size64,
649             _ => OperandSize::Size32,
650         }
651     }
652 
653     /// Get the scalar operand size that corresponds to a lane of a vector with a certain size.
654     pub fn lane_size(&self) -> ScalarSize {
655         match self {
656             VectorSize::Size8x8 | VectorSize::Size8x16 => ScalarSize::Size8,
657             VectorSize::Size16x4 | VectorSize::Size16x8 => ScalarSize::Size16,
658             VectorSize::Size32x2 | VectorSize::Size32x4 => ScalarSize::Size32,
659             VectorSize::Size64x2 => ScalarSize::Size64,
660         }
661     }
662 
663     /// Returns true if the VectorSize is 128-bits.
664     pub fn is_128bits(&self) -> bool {
665         match self {
666             VectorSize::Size8x8 => false,
667             VectorSize::Size8x16 => true,
668             VectorSize::Size16x4 => false,
669             VectorSize::Size16x8 => true,
670             VectorSize::Size32x2 => false,
671             VectorSize::Size32x4 => true,
672             VectorSize::Size64x2 => true,
673         }
674     }
675 
676     /// Return the encoding bits that are used by some SIMD instructions
677     /// for a particular operand size.
678     pub fn enc_size(&self) -> (u32, u32) {
679         let q = self.is_128bits() as u32;
680         let size = match self.lane_size() {
681             ScalarSize::Size8 => 0b00,
682             ScalarSize::Size16 => 0b01,
683             ScalarSize::Size32 => 0b10,
684             ScalarSize::Size64 => 0b11,
685             _ => unreachable!(),
686         };
687 
688         (q, size)
689     }
690 
691     /// Return the encoding bit that is used by some floating-point SIMD
692     /// instructions for a particular operand size.
693     pub fn enc_float_size(&self) -> u32 {
694         match self.lane_size() {
695             ScalarSize::Size32 => 0b0,
696             ScalarSize::Size64 => 0b1,
697             size => panic!("Unsupported floating-point size for vector op: {size:?}"),
698         }
699     }
700 }
701 
702 impl APIKey {
703     /// Returns the encoding of the `auti{key}` instruction used to decrypt the
704     /// `lr` register.
705     pub fn enc_auti_hint(&self) -> u32 {
706         let (crm, op2) = match self {
707             APIKey::AZ => (0b0011, 0b100),
708             APIKey::ASP => (0b0011, 0b101),
709             APIKey::BZ => (0b0011, 0b110),
710             APIKey::BSP => (0b0011, 0b111),
711         };
712         0xd503201f | (crm << 8) | (op2 << 5)
713     }
714 }
715 
716 pub use crate::isa::aarch64::lower::isle::generated_code::TestBitAndBranchKind;
717 
718 impl TestBitAndBranchKind {
719     /// Complements this branch condition to act on the opposite result.
720     pub fn complement(&self) -> TestBitAndBranchKind {
721         match self {
722             TestBitAndBranchKind::Z => TestBitAndBranchKind::NZ,
723             TestBitAndBranchKind::NZ => TestBitAndBranchKind::Z,
724         }
725     }
726 }
727