power_instruction_analyzer/
lib.rs

1// SPDX-License-Identifier: LGPL-2.1-or-later
2// See Notices.txt for copyright information
3
4#![cfg_attr(feature = "native_instrs", feature(llvm_asm))]
5
6#[cfg(all(feature = "native_instrs", not(target_arch = "powerpc64")))]
7compile_error!("native_instrs feature requires target_arch to be powerpc64");
8
9pub mod instr_models;
10mod serde_hex;
11
12use power_instruction_analyzer_proc_macro::instructions;
13use serde::{Deserialize, Serialize};
14use serde_plain::forward_display_to_serde;
15use std::{cmp::Ordering, fmt};
16
17// powerpc bit numbers count from MSB to LSB
18const fn get_xer_bit_mask(powerpc_bit_num: usize) -> u64 {
19    (1 << 63) >> powerpc_bit_num
20}
21
22macro_rules! xer_subset {
23    (
24        $struct_vis:vis struct $struct_name:ident {
25            $(
26                #[bit($powerpc_bit_num:expr, $mask_name:ident)]
27                $field_vis:vis $field_name:ident: bool,
28            )+
29        }
30    ) => {
31        #[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
32        $struct_vis struct $struct_name {
33            $(
34                $field_vis $field_name: bool,
35            )+
36        }
37
38        impl $struct_name {
39            $(
40                $field_vis const $mask_name: u64 = get_xer_bit_mask($powerpc_bit_num);
41            )+
42            $struct_vis const XER_MASK: u64 = $(Self::$mask_name)|+;
43            pub const fn from_xer(xer: u64) -> Self {
44                Self {
45                    $(
46                        $field_name: (xer & Self::$mask_name) != 0,
47                    )+
48                }
49            }
50            pub const fn to_xer(self) -> u64 {
51                let mut retval = 0u64;
52                $(
53                    if self.$field_name {
54                        retval |= Self::$mask_name;
55                    }
56                )+
57                retval
58            }
59        }
60    };
61}
62
63xer_subset! {
64    pub struct OverflowFlags {
65        #[bit(32, XER_SO_MASK)]
66        pub so: bool,
67        #[bit(33, XER_OV_MASK)]
68        pub ov: bool,
69        #[bit(44, XER_OV32_MASK)]
70        pub ov32: bool,
71    }
72}
73
74impl OverflowFlags {
75    pub const fn from_overflow(overflow: bool) -> Self {
76        Self {
77            so: overflow,
78            ov: overflow,
79            ov32: overflow,
80        }
81    }
82}
83
84xer_subset! {
85    pub struct CarryFlags {
86        #[bit(34, XER_CA_MASK)]
87        pub ca: bool,
88        #[bit(45, XER_CA32_MASK)]
89        pub ca32: bool,
90    }
91}
92
93#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
94pub struct ConditionRegister {
95    pub lt: bool,
96    pub gt: bool,
97    pub eq: bool,
98    pub so: bool,
99}
100
101impl ConditionRegister {
102    pub const fn from_4_bits(bits: u8) -> Self {
103        // assert bits is 4-bits long
104        // can switch to using assert! once rustc feature const_panic is stabilized
105        [0; 0x10][bits as usize];
106
107        Self {
108            lt: (bits & 8) != 0,
109            gt: (bits & 4) != 0,
110            eq: (bits & 2) != 0,
111            so: (bits & 1) != 0,
112        }
113    }
114    pub const CR_FIELD_COUNT: usize = 8;
115    pub const fn from_cr_field(cr: u32, field_index: usize) -> Self {
116        // assert field_index is less than CR_FIELD_COUNT
117        // can switch to using assert! once rustc feature const_panic is stabilized
118        [0; Self::CR_FIELD_COUNT][field_index];
119
120        let reversed_field_index = Self::CR_FIELD_COUNT - field_index - 1;
121        let bits = (cr >> (4 * reversed_field_index)) & 0xF;
122        Self::from_4_bits(bits as u8)
123    }
124    pub fn from_signed_int<T: Ord + Default>(value: T, so: bool) -> Self {
125        let ordering = value.cmp(&T::default());
126        Self {
127            lt: ordering == Ordering::Less,
128            gt: ordering == Ordering::Greater,
129            eq: ordering == Ordering::Equal,
130            so,
131        }
132    }
133    pub fn from_ordering(ordering: Ordering, so: bool) -> Self {
134        Self {
135            lt: ordering == Ordering::Less,
136            gt: ordering == Ordering::Greater,
137            eq: ordering == Ordering::Equal,
138            so,
139        }
140    }
141}
142
143#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
144pub struct InstructionOutput {
145    #[serde(
146        default,
147        skip_serializing_if = "Option::is_none",
148        with = "serde_hex::SerdeHex"
149    )]
150    pub rt: Option<u64>,
151    #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
152    pub overflow: Option<OverflowFlags>,
153    #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
154    pub carry: Option<CarryFlags>,
155    #[serde(default, skip_serializing_if = "Option::is_none")]
156    pub cr0: Option<ConditionRegister>,
157    #[serde(default, skip_serializing_if = "Option::is_none")]
158    pub cr1: Option<ConditionRegister>,
159    #[serde(default, skip_serializing_if = "Option::is_none")]
160    pub cr2: Option<ConditionRegister>,
161    #[serde(default, skip_serializing_if = "Option::is_none")]
162    pub cr3: Option<ConditionRegister>,
163    #[serde(default, skip_serializing_if = "Option::is_none")]
164    pub cr4: Option<ConditionRegister>,
165    #[serde(default, skip_serializing_if = "Option::is_none")]
166    pub cr5: Option<ConditionRegister>,
167    #[serde(default, skip_serializing_if = "Option::is_none")]
168    pub cr6: Option<ConditionRegister>,
169    #[serde(default, skip_serializing_if = "Option::is_none")]
170    pub cr7: Option<ConditionRegister>,
171}
172
173#[derive(Debug)]
174pub struct MissingInstructionInput {
175    pub input: InstructionInputRegister,
176}
177
178impl fmt::Display for MissingInstructionInput {
179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180        write!(f, "missing instruction input: {}", self.input)
181    }
182}
183
184impl std::error::Error for MissingInstructionInput {}
185
186pub type InstructionResult = Result<InstructionOutput, MissingInstructionInput>;
187
188#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
189pub enum InstructionInputRegister {
190    #[serde(rename = "ra")]
191    Ra,
192    #[serde(rename = "rb")]
193    Rb,
194    #[serde(rename = "rc")]
195    Rc,
196    #[serde(rename = "carry")]
197    Carry,
198    #[serde(rename = "overflow")]
199    Overflow,
200    #[serde(rename = "immediate_s16")]
201    ImmediateS16,
202    #[serde(rename = "immediate_u16")]
203    ImmediateU16,
204}
205
206forward_display_to_serde!(InstructionInputRegister);
207
208#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
209pub struct InstructionInput {
210    #[serde(
211        default,
212        skip_serializing_if = "Option::is_none",
213        with = "serde_hex::SerdeHex"
214    )]
215    pub ra: Option<u64>,
216    #[serde(
217        default,
218        skip_serializing_if = "Option::is_none",
219        with = "serde_hex::SerdeHex"
220    )]
221    pub rb: Option<u64>,
222    #[serde(
223        default,
224        skip_serializing_if = "Option::is_none",
225        with = "serde_hex::SerdeHex"
226    )]
227    pub rc: Option<u64>,
228    #[serde(
229        default,
230        skip_serializing_if = "Option::is_none",
231        with = "serde_hex::SerdeHex"
232    )]
233    pub immediate: Option<u64>,
234    #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
235    pub carry: Option<CarryFlags>,
236    #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
237    pub overflow: Option<OverflowFlags>,
238}
239
240macro_rules! impl_instr_try_get {
241    (
242        $(
243            $vis:vis fn $fn:ident -> $return_type:ty { .$field:ident else $error_enum:ident }
244        )+
245    ) => {
246        impl InstructionInput {
247            $(
248                $vis fn $fn(self) -> Result<$return_type, MissingInstructionInput> {
249                    self.$field.ok_or(MissingInstructionInput {
250                        input: InstructionInputRegister::$error_enum,
251                    })
252                }
253            )+
254        }
255    };
256}
257
258impl_instr_try_get! {
259    pub fn try_get_ra -> u64 {
260        .ra else Ra
261    }
262    pub fn try_get_rb -> u64 {
263        .rb else Rb
264    }
265    pub fn try_get_rc -> u64 {
266        .rc else Rc
267    }
268    pub fn try_get_carry -> CarryFlags {
269        .carry else Carry
270    }
271    pub fn try_get_overflow -> OverflowFlags {
272        .overflow else Overflow
273    }
274}
275
276impl InstructionInput {
277    fn try_get_immediate(
278        self,
279        input: InstructionInputRegister,
280    ) -> Result<u64, MissingInstructionInput> {
281        self.immediate.ok_or(MissingInstructionInput { input })
282    }
283    pub fn try_get_immediate_u16(self) -> Result<u16, MissingInstructionInput> {
284        Ok(self.try_get_immediate(InstructionInputRegister::ImmediateU16)? as u16)
285    }
286    pub fn try_get_immediate_s16(self) -> Result<i16, MissingInstructionInput> {
287        Ok(self.try_get_immediate(InstructionInputRegister::ImmediateS16)? as i16)
288    }
289}
290
291fn is_false(v: &bool) -> bool {
292    !v
293}
294
295#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
296pub struct TestCase {
297    pub instr: Instr,
298    #[serde(flatten)]
299    pub inputs: InstructionInput,
300    #[serde(default, skip_serializing_if = "Option::is_none")]
301    pub native_outputs: Option<InstructionOutput>,
302    pub model_outputs: InstructionOutput,
303    #[serde(default, skip_serializing_if = "is_false")]
304    pub model_mismatch: bool,
305}
306
307#[derive(Clone, Debug, Serialize, Deserialize)]
308pub struct WholeTest {
309    #[serde(default, skip_serializing_if = "Vec::is_empty")]
310    pub test_cases: Vec<TestCase>,
311    pub any_model_mismatch: bool,
312}
313
314instructions! {
315    #[enumerant = AddI]
316    fn addi(Ra, ImmediateS16) -> (Rt) {
317        "addi"
318    }
319
320    #[enumerant = AddIS]
321    fn addis(Ra, ImmediateS16) -> (Rt) {
322        "addis"
323    }
324
325    // add
326    #[enumerant = Add]
327    fn add(Ra, Rb) -> (Rt) {
328        "add"
329    }
330    #[enumerant = AddO]
331    fn addo(Ra, Rb, Overflow) -> (Rt, Overflow) {
332        "addo"
333    }
334    #[enumerant = Add_]
335    fn add_(Ra, Rb, Overflow) -> (Rt, CR0) {
336        "add."
337    }
338    #[enumerant = AddO_]
339    fn addo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
340        "addo."
341    }
342
343    // addic
344    #[enumerant = AddIC]
345    fn addic(Ra, ImmediateS16) -> (Rt, Carry) {
346        "addic"
347    }
348    #[enumerant = AddIC_]
349    fn addic_(Ra, ImmediateS16, Overflow) -> (Rt, Carry, CR0) {
350        "addic."
351    }
352
353    // subf
354    #[enumerant = SubF]
355    fn subf(Ra, Rb) -> (Rt) {
356        "subf"
357    }
358    #[enumerant = SubFO]
359    fn subfo(Ra, Rb, Overflow) -> (Rt, Overflow) {
360        "subfo"
361    }
362    #[enumerant = SubF_]
363    fn subf_(Ra, Rb, Overflow) -> (Rt, CR0) {
364        "subf."
365    }
366    #[enumerant = SubFO_]
367    fn subfo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
368        "subfo."
369    }
370
371    #[enumerant = SubFIC]
372    fn subfic(Ra, ImmediateS16) -> (Rt, Carry) {
373        "subfic"
374    }
375
376    // addc
377    #[enumerant = AddC]
378    fn addc(Ra, Rb) -> (Rt, Carry) {
379        "addc"
380    }
381    #[enumerant = AddCO]
382    fn addco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
383        "addco"
384    }
385    #[enumerant = AddC_]
386    fn addc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
387        "addc."
388    }
389    #[enumerant = AddCO_]
390    fn addco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
391        "addco."
392    }
393
394    // subfc
395    #[enumerant = SubFC]
396    fn subfc(Ra, Rb) -> (Rt, Carry) {
397        "subfc"
398    }
399    #[enumerant = SubFCO]
400    fn subfco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
401        "subfco"
402    }
403    #[enumerant = SubFC_]
404    fn subfc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
405        "subfc."
406    }
407    #[enumerant = SubFCO_]
408    fn subfco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
409        "subfco."
410    }
411
412    // adde
413    #[enumerant = AddE]
414    fn adde(Ra, Rb, Carry) -> (Rt, Carry) {
415        "adde"
416    }
417    #[enumerant = AddEO]
418    fn addeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
419        "addeo"
420    }
421    #[enumerant = AddE_]
422    fn adde_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
423        "adde."
424    }
425    #[enumerant = AddEO_]
426    fn addeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
427        "addeo."
428    }
429
430    // subfe
431    #[enumerant = SubFE]
432    fn subfe(Ra, Rb, Carry) -> (Rt, Carry) {
433        "subfe"
434    }
435    #[enumerant = SubFEO]
436    fn subfeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
437        "subfeo"
438    }
439    #[enumerant = SubFE_]
440    fn subfe_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
441        "subfe."
442    }
443    #[enumerant = SubFEO_]
444    fn subfeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
445        "subfeo."
446    }
447
448    // addme
449    #[enumerant = AddME]
450    fn addme(Ra, Carry) -> (Rt, Carry) {
451        "addme"
452    }
453    #[enumerant = AddMEO]
454    fn addmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
455        "addmeo"
456    }
457    #[enumerant = AddME_]
458    fn addme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
459        "addme."
460    }
461    #[enumerant = AddMEO_]
462    fn addmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
463        "addmeo."
464    }
465
466    // subfme
467    #[enumerant = SubFME]
468    fn subfme(Ra, Carry) -> (Rt, Carry) {
469        "subfme"
470    }
471    #[enumerant = SubFMEO]
472    fn subfmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
473        "subfmeo"
474    }
475    #[enumerant = SubFME_]
476    fn subfme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
477        "subfme."
478    }
479    #[enumerant = SubFMEO_]
480    fn subfmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
481        "subfmeo."
482    }
483
484    // addze
485    #[enumerant = AddZE]
486    fn addze(Ra, Carry) -> (Rt, Carry) {
487        "addze"
488    }
489    #[enumerant = AddZEO]
490    fn addzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
491        "addzeo"
492    }
493    #[enumerant = AddZE_]
494    fn addze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
495        "addze."
496    }
497    #[enumerant = AddZEO_]
498    fn addzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
499        "addzeo."
500    }
501
502    // subfze
503    #[enumerant = SubFZE]
504    fn subfze(Ra, Carry) -> (Rt, Carry) {
505        "subfze"
506    }
507    #[enumerant = SubFZEO]
508    fn subfzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
509        "subfzeo"
510    }
511    #[enumerant = SubFZE_]
512    fn subfze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
513        "subfze."
514    }
515    #[enumerant = SubFZEO_]
516    fn subfzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
517        "subfzeo."
518    }
519
520    #[enumerant = AddEX]
521    fn addex(Ra("r3"), Rb("r4"), Overflow) -> (Rt("r5"), Overflow) {
522        // work around LLVM not supporting addex instruction:
523        "addex" : ".long 0x7CA32154 # addex r5, r3, r4, 0"
524    }
525
526    // neg
527    #[enumerant = Neg]
528    fn neg(Ra) -> (Rt) {
529        "neg"
530    }
531    #[enumerant = NegO]
532    fn nego(Ra, Overflow) -> (Rt, Overflow) {
533        "nego"
534    }
535    #[enumerant = Neg_]
536    fn neg_(Ra, Overflow) -> (Rt, CR0) {
537        "neg."
538    }
539    #[enumerant = NegO_]
540    fn nego_(Ra, Overflow) -> (Rt, Overflow, CR0) {
541        "nego."
542    }
543
544    // divde
545    #[enumerant = DivDE]
546    fn divde(Ra, Rb) -> (Rt) {
547        "divde"
548    }
549    #[enumerant = DivDEO]
550    fn divdeo(Ra, Rb, Overflow) -> (Rt, Overflow) {
551        "divdeo"
552    }
553    #[enumerant = DivDE_]
554    fn divde_(Ra, Rb, Overflow) -> (Rt, CR0) {
555        "divde."
556    }
557    #[enumerant = DivDEO_]
558    fn divdeo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
559        "divdeo."
560    }
561
562    // divdeu
563    #[enumerant = DivDEU]
564    fn divdeu(Ra, Rb) -> (Rt) {
565        "divdeu"
566    }
567    #[enumerant = DivDEUO]
568    fn divdeuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
569        "divdeuo"
570    }
571    #[enumerant = DivDEU_]
572    fn divdeu_(Ra, Rb, Overflow) -> (Rt, CR0) {
573        "divdeu."
574    }
575    #[enumerant = DivDEUO_]
576    fn divdeuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
577        "divdeuo."
578    }
579
580    // divd
581    #[enumerant = DivD]
582    fn divd(Ra, Rb) -> (Rt) {
583        "divd"
584    }
585    #[enumerant = DivDO]
586    fn divdo(Ra, Rb, Overflow) -> (Rt, Overflow) {
587        "divdo"
588    }
589    #[enumerant = DivD_]
590    fn divd_(Ra, Rb, Overflow) -> (Rt, CR0) {
591        "divd."
592    }
593    #[enumerant = DivDO_]
594    fn divdo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
595        "divdo."
596    }
597
598    // divdu
599    #[enumerant = DivDU]
600    fn divdu(Ra, Rb) -> (Rt) {
601        "divdu"
602    }
603    #[enumerant = DivDUO]
604    fn divduo(Ra, Rb, Overflow) -> (Rt, Overflow) {
605        "divduo"
606    }
607    #[enumerant = DivDU_]
608    fn divdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
609        "divdu."
610    }
611    #[enumerant = DivDUO_]
612    fn divduo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
613        "divduo."
614    }
615
616    // divwe
617    #[enumerant = DivWE]
618    fn divwe(Ra, Rb) -> (Rt) {
619        "divwe"
620    }
621    #[enumerant = DivWEO]
622    fn divweo(Ra, Rb, Overflow) -> (Rt, Overflow) {
623        "divweo"
624    }
625    #[enumerant = DivWE_]
626    fn divwe_(Ra, Rb, Overflow) -> (Rt, CR0) {
627        "divwe."
628    }
629    #[enumerant = DivWEO_]
630    fn divweo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
631        "divweo."
632    }
633
634    // divweu
635    #[enumerant = DivWEU]
636    fn divweu(Ra, Rb) -> (Rt) {
637        "divweu"
638    }
639    #[enumerant = DivWEUO]
640    fn divweuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
641        "divweuo"
642    }
643    #[enumerant = DivWEU_]
644    fn divweu_(Ra, Rb, Overflow) -> (Rt, CR0) {
645        "divweu."
646    }
647    #[enumerant = DivWEUO_]
648    fn divweuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
649        "divweuo."
650    }
651
652    // divw
653    #[enumerant = DivW]
654    fn divw(Ra, Rb) -> (Rt) {
655        "divw"
656    }
657    #[enumerant = DivWO]
658    fn divwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
659        "divwo"
660    }
661    #[enumerant = DivW_]
662    fn divw_(Ra, Rb, Overflow) -> (Rt, CR0) {
663        "divw."
664    }
665    #[enumerant = DivWO_]
666    fn divwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
667        "divwo."
668    }
669
670    // divwu
671    #[enumerant = DivWU]
672    fn divwu(Ra, Rb) -> (Rt) {
673        "divwu"
674    }
675    #[enumerant = DivWUO]
676    fn divwuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
677        "divwuo"
678    }
679    #[enumerant = DivWU_]
680    fn divwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
681        "divwu."
682    }
683    #[enumerant = DivWUO_]
684    fn divwuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
685        "divwuo."
686    }
687
688    // mod*
689    #[enumerant = ModSD]
690    fn modsd(Ra, Rb) -> (Rt) {
691        "modsd"
692    }
693    #[enumerant = ModUD]
694    fn modud(Ra, Rb) -> (Rt) {
695        "modud"
696    }
697    #[enumerant = ModSW]
698    fn modsw(Ra, Rb) -> (Rt) {
699        "modsw"
700    }
701    #[enumerant = ModUW]
702    fn moduw(Ra, Rb) -> (Rt) {
703        "moduw"
704    }
705
706    #[enumerant = MulLI]
707    fn mulli(Ra, ImmediateS16) -> (Rt) {
708        "mulli"
709    }
710
711    // mullw
712    #[enumerant = MulLW]
713    fn mullw(Ra, Rb) -> (Rt) {
714        "mullw"
715    }
716    #[enumerant = MulLWO]
717    fn mullwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
718        "mullwo"
719    }
720    #[enumerant = MulLW_]
721    fn mullw_(Ra, Rb, Overflow) -> (Rt, CR0) {
722        "mullw."
723    }
724    #[enumerant = MulLWO_]
725    fn mullwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
726        "mullwo."
727    }
728
729    // mulhw
730    #[enumerant = MulHW]
731    fn mulhw(Ra, Rb) -> (Rt) {
732        "mulhw"
733    }
734    #[enumerant = MulHW_]
735    fn mulhw_(Ra, Rb, Overflow) -> (Rt, CR0) {
736        "mulhw."
737    }
738
739    // mulhwu
740    #[enumerant = MulHWU]
741    fn mulhwu(Ra, Rb) -> (Rt) {
742        "mulhwu"
743    }
744    #[enumerant = MulHWU_]
745    fn mulhwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
746        "mulhwu."
747    }
748
749    // mulld
750    #[enumerant = MulLD]
751    fn mulld(Ra, Rb) -> (Rt) {
752        "mulld"
753    }
754    #[enumerant = MulLDO]
755    fn mulldo(Ra, Rb, Overflow) -> (Rt, Overflow) {
756        "mulldo"
757    }
758    #[enumerant = MulLD_]
759    fn mulld_(Ra, Rb, Overflow) -> (Rt, CR0) {
760        "mulld."
761    }
762    #[enumerant = MulLDO_]
763    fn mulldo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
764        "mulldo."
765    }
766
767    // mulhd
768    #[enumerant = MulHD]
769    fn mulhd(Ra, Rb) -> (Rt) {
770        "mulhd"
771    }
772    #[enumerant = MulHD_]
773    fn mulhd_(Ra, Rb, Overflow) -> (Rt, CR0) {
774        "mulhd."
775    }
776
777    // mulhdu
778    #[enumerant = MulHDU]
779    fn mulhdu(Ra, Rb) -> (Rt) {
780        "mulhdu"
781    }
782    #[enumerant = MulHDU_]
783    fn mulhdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
784        "mulhdu."
785    }
786
787    // madd*
788    #[enumerant = MAddHD]
789    fn maddhd(Ra, Rb, Rc) -> (Rt) {
790        "maddhd"
791    }
792    #[enumerant = MAddHDU]
793    fn maddhdu(Ra, Rb, Rc) -> (Rt) {
794        "maddhdu"
795    }
796    #[enumerant = MAddLD]
797    fn maddld(Ra, Rb, Rc) -> (Rt) {
798        "maddld"
799    }
800
801    // cmpi
802    #[enumerant = CmpDI]
803    fn cmpdi(Ra, ImmediateS16, Overflow) -> (CR0) {
804        "cmpdi"
805    }
806    #[enumerant = CmpWI]
807    fn cmpwi(Ra, ImmediateS16, Overflow) -> (CR0) {
808        "cmpwi"
809    }
810
811    // cmpli
812    #[enumerant = CmpLDI]
813    fn cmpldi(Ra, ImmediateU16, Overflow) -> (CR0) {
814        "cmpldi"
815    }
816    #[enumerant = CmpLWI]
817    fn cmplwi(Ra, ImmediateU16, Overflow) -> (CR0) {
818        "cmplwi"
819    }
820
821    // cmp
822    #[enumerant = CmpD]
823    fn cmpd(Ra, Rb, Overflow) -> (CR0) {
824        "cmpd"
825    }
826    #[enumerant = CmpW]
827    fn cmpw(Ra, Rb, Overflow) -> (CR0) {
828        "cmpw"
829    }
830
831    // cmpl
832    #[enumerant = CmpLD]
833    fn cmpld(Ra, Rb, Overflow) -> (CR0) {
834        "cmpld"
835    }
836    #[enumerant = CmpLW]
837    fn cmplw(Ra, Rb, Overflow) -> (CR0) {
838        "cmplw"
839    }
840
841    // cmprb 0, 0, ..., ...
842    #[enumerant = CmpRB0]
843    fn cmprb_0(Ra("r3"), Rb("r4")) -> (CR0) {
844        "cmprb_0" : "cmprb 0, 0, 3, 4"
845    }
846}
847
848// must be after instrs macro call since it uses a macro definition
849mod python;