1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
4 #![cfg_attr(feature = "native_instrs", feature(asm))]
6 #[cfg(all(feature = "native_instrs", not(target_arch = "powerpc64")))]
7 compile_error!("native_instrs feature requires target_arch to be powerpc64");
12 use power_instruction_analyzer_proc_macro::instructions;
13 use serde::{Deserialize, Serialize};
14 use serde_plain::forward_display_to_serde;
15 use std::{cmp::Ordering, fmt};
17 // powerpc bit numbers count from MSB to LSB
18 const fn get_xer_bit_mask(powerpc_bit_num: usize) -> u64 {
19 (1 << 63) >> powerpc_bit_num
22 macro_rules! xer_subset {
24 $struct_vis:vis struct $struct_name:ident {
26 #[bit($powerpc_bit_num:expr, $mask_name:ident)]
27 $field_vis:vis $field_name:ident: bool,
31 #[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
32 $struct_vis struct $struct_name {
34 $field_vis $field_name: bool,
40 $field_vis const $mask_name: u64 = get_xer_bit_mask($powerpc_bit_num);
42 $struct_vis const XER_MASK: u64 = $(Self::$mask_name)|+;
43 pub const fn from_xer(xer: u64) -> Self {
46 $field_name: (xer & Self::$mask_name) != 0,
50 pub const fn to_xer(self) -> u64 {
51 let mut retval = 0u64;
54 retval |= Self::$mask_name;
64 pub struct OverflowFlags {
65 #[bit(32, XER_SO_MASK)]
67 #[bit(33, XER_OV_MASK)]
69 #[bit(44, XER_OV32_MASK)]
75 pub const fn from_overflow(overflow: bool) -> Self {
85 pub struct CarryFlags {
86 #[bit(34, XER_CA_MASK)]
88 #[bit(45, XER_CA32_MASK)]
93 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
94 pub struct ConditionRegister {
101 impl 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];
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];
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)
124 pub fn from_signed_int<T: Ord + Default>(value: T, so: bool) -> Self {
125 let ordering = value.cmp(&T::default());
127 lt: ordering == Ordering::Less,
128 gt: ordering == Ordering::Greater,
129 eq: ordering == Ordering::Equal,
133 pub fn from_ordering(ordering: Ordering, so: bool) -> Self {
135 lt: ordering == Ordering::Less,
136 gt: ordering == Ordering::Greater,
137 eq: ordering == Ordering::Equal,
143 #[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
144 pub struct InstructionOutput {
147 skip_serializing_if = "Option::is_none",
148 with = "serde_hex::SerdeHex"
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>,
174 pub struct MissingInstructionInput {
175 pub input: InstructionInputRegister,
178 impl fmt::Display for MissingInstructionInput {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 write!(f, "missing instruction input: {}", self.input)
184 impl std::error::Error for MissingInstructionInput {}
186 pub type InstructionResult = Result<InstructionOutput, MissingInstructionInput>;
188 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
189 pub enum InstructionInputRegister {
190 #[serde(rename = "ra")]
192 #[serde(rename = "rb")]
194 #[serde(rename = "rc")]
196 #[serde(rename = "carry")]
198 #[serde(rename = "overflow")]
200 #[serde(rename = "immediate_s16")]
202 #[serde(rename = "immediate_u16")]
206 forward_display_to_serde!(InstructionInputRegister);
208 #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
209 pub struct InstructionInput {
212 skip_serializing_if = "Option::is_none",
213 with = "serde_hex::SerdeHex"
218 skip_serializing_if = "Option::is_none",
219 with = "serde_hex::SerdeHex"
224 skip_serializing_if = "Option::is_none",
225 with = "serde_hex::SerdeHex"
230 skip_serializing_if = "Option::is_none",
231 with = "serde_hex::SerdeHex"
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>,
240 macro_rules! impl_instr_try_get {
243 $vis:vis fn $fn:ident -> $return_type:ty { .$field:ident else $error_enum:ident }
246 impl InstructionInput {
248 $vis fn $fn(self) -> Result<$return_type, MissingInstructionInput> {
249 self.$field.ok_or(MissingInstructionInput {
250 input: InstructionInputRegister::$error_enum,
258 impl_instr_try_get! {
259 pub fn try_get_ra -> u64 {
262 pub fn try_get_rb -> u64 {
265 pub fn try_get_rc -> u64 {
268 pub fn try_get_carry -> CarryFlags {
271 pub fn try_get_overflow -> OverflowFlags {
272 .overflow else Overflow
276 impl InstructionInput {
277 fn try_get_immediate(
279 input: InstructionInputRegister,
280 ) -> Result<u64, MissingInstructionInput> {
281 self.immediate.ok_or(MissingInstructionInput { input })
283 pub fn try_get_immediate_u16(self) -> Result<u16, MissingInstructionInput> {
284 Ok(self.try_get_immediate(InstructionInputRegister::ImmediateU16)? as u16)
286 pub fn try_get_immediate_s16(self) -> Result<i16, MissingInstructionInput> {
287 Ok(self.try_get_immediate(InstructionInputRegister::ImmediateS16)? as i16)
291 fn is_false(v: &bool) -> bool {
295 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
296 pub struct TestCase {
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,
307 #[derive(Clone, Debug, Serialize, Deserialize)]
308 pub struct WholeTest {
309 #[serde(default, skip_serializing_if = "Vec::is_empty")]
310 pub test_cases: Vec<TestCase>,
311 pub any_model_mismatch: bool,
316 fn addi(Ra, ImmediateS16) -> (Rt) {
321 fn addis(Ra, ImmediateS16) -> (Rt) {
327 fn add(Ra, Rb) -> (Rt) {
331 fn addo(Ra, Rb, Overflow) -> (Rt, Overflow) {
335 fn add_(Ra, Rb, Overflow) -> (Rt, CR0) {
339 fn addo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
345 fn addic(Ra, ImmediateS16) -> (Rt, Carry) {
348 #[enumerant = AddIC_]
349 fn addic_(Ra, ImmediateS16, Overflow) -> (Rt, Carry, CR0) {
355 fn subf(Ra, Rb) -> (Rt) {
359 fn subfo(Ra, Rb, Overflow) -> (Rt, Overflow) {
363 fn subf_(Ra, Rb, Overflow) -> (Rt, CR0) {
366 #[enumerant = SubFO_]
367 fn subfo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
371 #[enumerant = SubFIC]
372 fn subfic(Ra, ImmediateS16) -> (Rt, Carry) {
378 fn addc(Ra, Rb) -> (Rt, Carry) {
382 fn addco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
386 fn addc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
389 #[enumerant = AddCO_]
390 fn addco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
396 fn subfc(Ra, Rb) -> (Rt, Carry) {
399 #[enumerant = SubFCO]
400 fn subfco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
403 #[enumerant = SubFC_]
404 fn subfc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
407 #[enumerant = SubFCO_]
408 fn subfco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
414 fn adde(Ra, Rb, Carry) -> (Rt, Carry) {
418 fn addeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
422 fn adde_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
425 #[enumerant = AddEO_]
426 fn addeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
432 fn subfe(Ra, Rb, Carry) -> (Rt, Carry) {
435 #[enumerant = SubFEO]
436 fn subfeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
439 #[enumerant = SubFE_]
440 fn subfe_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
443 #[enumerant = SubFEO_]
444 fn subfeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
450 fn addme(Ra, Carry) -> (Rt, Carry) {
453 #[enumerant = AddMEO]
454 fn addmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
457 #[enumerant = AddME_]
458 fn addme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
461 #[enumerant = AddMEO_]
462 fn addmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
467 #[enumerant = SubFME]
468 fn subfme(Ra, Carry) -> (Rt, Carry) {
471 #[enumerant = SubFMEO]
472 fn subfmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
475 #[enumerant = SubFME_]
476 fn subfme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
479 #[enumerant = SubFMEO_]
480 fn subfmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
486 fn addze(Ra, Carry) -> (Rt, Carry) {
489 #[enumerant = AddZEO]
490 fn addzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
493 #[enumerant = AddZE_]
494 fn addze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
497 #[enumerant = AddZEO_]
498 fn addzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
503 #[enumerant = SubFZE]
504 fn subfze(Ra, Carry) -> (Rt, Carry) {
507 #[enumerant = SubFZEO]
508 fn subfzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
511 #[enumerant = SubFZE_]
512 fn subfze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
515 #[enumerant = SubFZEO_]
516 fn subfzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
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"
532 fn nego(Ra, Overflow) -> (Rt, Overflow) {
536 fn neg_(Ra, Overflow) -> (Rt, CR0) {
540 fn nego_(Ra, Overflow) -> (Rt, Overflow, CR0) {
546 fn divde(Ra, Rb) -> (Rt) {
549 #[enumerant = DivDEO]
550 fn divdeo(Ra, Rb, Overflow) -> (Rt, Overflow) {
553 #[enumerant = DivDE_]
554 fn divde_(Ra, Rb, Overflow) -> (Rt, CR0) {
557 #[enumerant = DivDEO_]
558 fn divdeo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
563 #[enumerant = DivDEU]
564 fn divdeu(Ra, Rb) -> (Rt) {
567 #[enumerant = DivDEUO]
568 fn divdeuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
571 #[enumerant = DivDEU_]
572 fn divdeu_(Ra, Rb, Overflow) -> (Rt, CR0) {
575 #[enumerant = DivDEUO_]
576 fn divdeuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
582 fn divd(Ra, Rb) -> (Rt) {
586 fn divdo(Ra, Rb, Overflow) -> (Rt, Overflow) {
590 fn divd_(Ra, Rb, Overflow) -> (Rt, CR0) {
593 #[enumerant = DivDO_]
594 fn divdo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
600 fn divdu(Ra, Rb) -> (Rt) {
603 #[enumerant = DivDUO]
604 fn divduo(Ra, Rb, Overflow) -> (Rt, Overflow) {
607 #[enumerant = DivDU_]
608 fn divdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
611 #[enumerant = DivDUO_]
612 fn divduo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
618 fn divwe(Ra, Rb) -> (Rt) {
621 #[enumerant = DivWEO]
622 fn divweo(Ra, Rb, Overflow) -> (Rt, Overflow) {
625 #[enumerant = DivWE_]
626 fn divwe_(Ra, Rb, Overflow) -> (Rt, CR0) {
629 #[enumerant = DivWEO_]
630 fn divweo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
635 #[enumerant = DivWEU]
636 fn divweu(Ra, Rb) -> (Rt) {
639 #[enumerant = DivWEUO]
640 fn divweuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
643 #[enumerant = DivWEU_]
644 fn divweu_(Ra, Rb, Overflow) -> (Rt, CR0) {
647 #[enumerant = DivWEUO_]
648 fn divweuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
654 fn divw(Ra, Rb) -> (Rt) {
658 fn divwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
662 fn divw_(Ra, Rb, Overflow) -> (Rt, CR0) {
665 #[enumerant = DivWO_]
666 fn divwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
672 fn divwu(Ra, Rb) -> (Rt) {
675 #[enumerant = DivWUO]
676 fn divwuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
679 #[enumerant = DivWU_]
680 fn divwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
683 #[enumerant = DivWUO_]
684 fn divwuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
690 fn modsd(Ra, Rb) -> (Rt) {
694 fn modud(Ra, Rb) -> (Rt) {
698 fn modsw(Ra, Rb) -> (Rt) {
702 fn moduw(Ra, Rb) -> (Rt) {
707 fn mulli(Ra, ImmediateS16) -> (Rt) {
713 fn mullw(Ra, Rb) -> (Rt) {
716 #[enumerant = MulLWO]
717 fn mullwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
720 #[enumerant = MulLW_]
721 fn mullw_(Ra, Rb, Overflow) -> (Rt, CR0) {
724 #[enumerant = MulLWO_]
725 fn mullwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
731 fn mulhw(Ra, Rb) -> (Rt) {
734 #[enumerant = MulHW_]
735 fn mulhw_(Ra, Rb, Overflow) -> (Rt, CR0) {
740 #[enumerant = MulHWU]
741 fn mulhwu(Ra, Rb) -> (Rt) {
744 #[enumerant = MulHWU_]
745 fn mulhwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
751 fn mulld(Ra, Rb) -> (Rt) {
754 #[enumerant = MulLDO]
755 fn mulldo(Ra, Rb, Overflow) -> (Rt, Overflow) {
758 #[enumerant = MulLD_]
759 fn mulld_(Ra, Rb, Overflow) -> (Rt, CR0) {
762 #[enumerant = MulLDO_]
763 fn mulldo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
769 fn mulhd(Ra, Rb) -> (Rt) {
772 #[enumerant = MulHD_]
773 fn mulhd_(Ra, Rb, Overflow) -> (Rt, CR0) {
778 #[enumerant = MulHDU]
779 fn mulhdu(Ra, Rb) -> (Rt) {
782 #[enumerant = MulHDU_]
783 fn mulhdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
788 #[enumerant = MAddHD]
789 fn maddhd(Ra, Rb, Rc) -> (Rt) {
792 #[enumerant = MAddHDU]
793 fn maddhdu(Ra, Rb, Rc) -> (Rt) {
796 #[enumerant = MAddLD]
797 fn maddld(Ra, Rb, Rc) -> (Rt) {
803 fn cmpdi(Ra, ImmediateS16, Overflow) -> (CR0) {
807 fn cmpwi(Ra, ImmediateS16, Overflow) -> (CR0) {
812 #[enumerant = CmpLDI]
813 fn cmpldi(Ra, ImmediateU16, Overflow) -> (CR0) {
816 #[enumerant = CmpLWI]
817 fn cmplwi(Ra, ImmediateU16, Overflow) -> (CR0) {
823 fn cmpd(Ra, Rb, Overflow) -> (CR0) {
827 fn cmpw(Ra, Rb, Overflow) -> (CR0) {
833 fn cmpld(Ra, Rb, Overflow) -> (CR0) {
837 fn cmplw(Ra, Rb, Overflow) -> (CR0) {
841 // cmprb 0, 0, ..., ...
842 #[enumerant = CmpRB0]
843 fn cmprb_0(Ra("r3"), Rb("r4")) -> (CR0) {
844 "cmprb_0" : "cmprb 0, 0, 3, 4"
847 #[enumerant = CDTBcd]
848 fn cdtbcd(Ra("r3")) -> (Rt("r4")) {
849 // work around LLVM not supporting cdtbcd instruction:
850 "cdtbcd" : ".long 0x7C640234 # cdtbcd r4, r3"
853 #[enumerant = CBcdTD]
854 fn cbcdtd(Ra("r3")) -> (Rt("r4")) {
855 // work around LLVM not supporting cbcdtd instruction:
856 "cbcdtd" : ".long 0x7C640274 # cbcdtd r4, r3"
859 #[enumerant = AddG6s]
860 fn addg6s(Ra("r3"), Rb("r4")) -> (Rt("r5")) {
861 // work around LLVM not supporting addg6s instruction:
862 "addg6s" : ".long 0x7CA32094 # addg6s r5, r3, r4"
866 // must be after instrs macro call since it uses a macro definition