1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
4 #![cfg_attr(feature = "native_instrs", feature(llvm_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,
135 #[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
136 pub struct InstructionOutput {
139 skip_serializing_if = "Option::is_none",
140 with = "serde_hex::SerdeHex"
143 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
144 pub overflow: Option<OverflowFlags>,
145 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
146 pub carry: Option<CarryFlags>,
147 #[serde(default, skip_serializing_if = "Option::is_none")]
148 pub cr0: Option<ConditionRegister>,
149 #[serde(default, skip_serializing_if = "Option::is_none")]
150 pub cr1: Option<ConditionRegister>,
151 #[serde(default, skip_serializing_if = "Option::is_none")]
152 pub cr2: Option<ConditionRegister>,
153 #[serde(default, skip_serializing_if = "Option::is_none")]
154 pub cr3: Option<ConditionRegister>,
155 #[serde(default, skip_serializing_if = "Option::is_none")]
156 pub cr4: Option<ConditionRegister>,
157 #[serde(default, skip_serializing_if = "Option::is_none")]
158 pub cr5: Option<ConditionRegister>,
159 #[serde(default, skip_serializing_if = "Option::is_none")]
160 pub cr6: Option<ConditionRegister>,
161 #[serde(default, skip_serializing_if = "Option::is_none")]
162 pub cr7: Option<ConditionRegister>,
166 pub struct MissingInstructionInput {
167 pub input: InstructionInputRegister,
170 impl fmt::Display for MissingInstructionInput {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 write!(f, "missing instruction input: {}", self.input)
176 impl std::error::Error for MissingInstructionInput {}
178 pub type InstructionResult = Result<InstructionOutput, MissingInstructionInput>;
180 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
181 pub enum InstructionInputRegister {
182 #[serde(rename = "ra")]
184 #[serde(rename = "rb")]
186 #[serde(rename = "rc")]
188 #[serde(rename = "carry")]
190 #[serde(rename = "overflow")]
194 forward_display_to_serde!(InstructionInputRegister);
196 #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
197 pub struct InstructionInput {
200 skip_serializing_if = "Option::is_none",
201 with = "serde_hex::SerdeHex"
206 skip_serializing_if = "Option::is_none",
207 with = "serde_hex::SerdeHex"
212 skip_serializing_if = "Option::is_none",
213 with = "serde_hex::SerdeHex"
216 #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
217 pub carry: Option<CarryFlags>,
218 #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
219 pub overflow: Option<OverflowFlags>,
222 macro_rules! impl_instr_try_get {
225 $vis:vis fn $fn:ident -> $return_type:ty { .$field:ident else $error_enum:ident }
228 impl InstructionInput {
230 $vis fn $fn(self) -> Result<$return_type, MissingInstructionInput> {
231 self.$field.ok_or(MissingInstructionInput {
232 input: InstructionInputRegister::$error_enum,
240 impl_instr_try_get! {
241 pub fn try_get_ra -> u64 {
244 pub fn try_get_rb -> u64 {
247 pub fn try_get_rc -> u64 {
250 pub fn try_get_carry -> CarryFlags {
253 pub fn try_get_overflow -> OverflowFlags {
254 .overflow else Overflow
258 fn is_false(v: &bool) -> bool {
262 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
263 pub struct TestCase {
266 pub inputs: InstructionInput,
267 #[serde(default, skip_serializing_if = "Option::is_none")]
268 pub native_outputs: Option<InstructionOutput>,
269 pub model_outputs: InstructionOutput,
270 #[serde(default, skip_serializing_if = "is_false")]
271 pub model_mismatch: bool,
274 #[derive(Clone, Debug, Serialize, Deserialize)]
275 pub struct WholeTest {
276 #[serde(default, skip_serializing_if = "Vec::is_empty")]
277 pub test_cases: Vec<TestCase>,
278 pub any_model_mismatch: bool,
284 fn add(Ra, Rb) -> (Rt) {
288 fn addo(Ra, Rb, Overflow) -> (Rt, Overflow) {
292 fn add_(Ra, Rb, Overflow) -> (Rt, CR0) {
296 fn addo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
302 fn subf(Ra, Rb) -> (Rt) {
306 fn subfo(Ra, Rb, Overflow) -> (Rt, Overflow) {
310 fn subf_(Ra, Rb, Overflow) -> (Rt, CR0) {
313 #[enumerant = SubFO_]
314 fn subfo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
320 fn addc(Ra, Rb) -> (Rt, Carry) {
324 fn addco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
328 fn addc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
331 #[enumerant = AddCO_]
332 fn addco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
338 fn subfc(Ra, Rb) -> (Rt, Carry) {
341 #[enumerant = SubFCO]
342 fn subfco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
345 #[enumerant = SubFC_]
346 fn subfc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
349 #[enumerant = SubFCO_]
350 fn subfco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
356 fn adde(Ra, Rb, Carry) -> (Rt, Carry) {
360 fn addeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
364 fn adde_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
367 #[enumerant = AddEO_]
368 fn addeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
374 fn subfe(Ra, Rb, Carry) -> (Rt, Carry) {
377 #[enumerant = SubFEO]
378 fn subfeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
381 #[enumerant = SubFE_]
382 fn subfe_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
385 #[enumerant = SubFEO_]
386 fn subfeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
392 fn addme(Ra, Carry) -> (Rt, Carry) {
395 #[enumerant = AddMEO]
396 fn addmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
399 #[enumerant = AddME_]
400 fn addme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
403 #[enumerant = AddMEO_]
404 fn addmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
409 #[enumerant = SubFME]
410 fn subfme(Ra, Carry) -> (Rt, Carry) {
413 #[enumerant = SubFMEO]
414 fn subfmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
417 #[enumerant = SubFME_]
418 fn subfme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
421 #[enumerant = SubFMEO_]
422 fn subfmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
428 fn addze(Ra, Carry) -> (Rt, Carry) {
431 #[enumerant = AddZEO]
432 fn addzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
435 #[enumerant = AddZE_]
436 fn addze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
439 #[enumerant = AddZEO_]
440 fn addzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
445 #[enumerant = SubFZE]
446 fn subfze(Ra, Carry) -> (Rt, Carry) {
449 #[enumerant = SubFZEO]
450 fn subfzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
453 #[enumerant = SubFZE_]
454 fn subfze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
457 #[enumerant = SubFZEO_]
458 fn subfzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
464 fn divde(Ra, Rb) -> (Rt) {
467 #[enumerant = DivDEO]
468 fn divdeo(Ra, Rb, Overflow) -> (Rt, Overflow) {
471 #[enumerant = DivDE_]
472 fn divde_(Ra, Rb, Overflow) -> (Rt, CR0) {
475 #[enumerant = DivDEO_]
476 fn divdeo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
481 #[enumerant = DivDEU]
482 fn divdeu(Ra, Rb) -> (Rt) {
485 #[enumerant = DivDEUO]
486 fn divdeuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
489 #[enumerant = DivDEU_]
490 fn divdeu_(Ra, Rb, Overflow) -> (Rt, CR0) {
493 #[enumerant = DivDEUO_]
494 fn divdeuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
500 fn divd(Ra, Rb) -> (Rt) {
504 fn divdo(Ra, Rb, Overflow) -> (Rt, Overflow) {
508 fn divd_(Ra, Rb, Overflow) -> (Rt, CR0) {
511 #[enumerant = DivDO_]
512 fn divdo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
518 fn divdu(Ra, Rb) -> (Rt) {
521 #[enumerant = DivDUO]
522 fn divduo(Ra, Rb, Overflow) -> (Rt, Overflow) {
525 #[enumerant = DivDU_]
526 fn divdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
529 #[enumerant = DivDUO_]
530 fn divduo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
536 fn divwe(Ra, Rb) -> (Rt) {
539 #[enumerant = DivWEO]
540 fn divweo(Ra, Rb, Overflow) -> (Rt, Overflow) {
543 #[enumerant = DivWE_]
544 fn divwe_(Ra, Rb, Overflow) -> (Rt, CR0) {
547 #[enumerant = DivWEO_]
548 fn divweo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
553 #[enumerant = DivWEU]
554 fn divweu(Ra, Rb) -> (Rt) {
557 #[enumerant = DivWEUO]
558 fn divweuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
561 #[enumerant = DivWEU_]
562 fn divweu_(Ra, Rb, Overflow) -> (Rt, CR0) {
565 #[enumerant = DivWEUO_]
566 fn divweuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
572 fn divw(Ra, Rb) -> (Rt) {
576 fn divwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
580 fn divw_(Ra, Rb, Overflow) -> (Rt, CR0) {
583 #[enumerant = DivWO_]
584 fn divwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
590 fn divwu(Ra, Rb) -> (Rt) {
593 #[enumerant = DivWUO]
594 fn divwuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
597 #[enumerant = DivWU_]
598 fn divwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
601 #[enumerant = DivWUO_]
602 fn divwuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
608 fn modsd(Ra, Rb) -> (Rt) {
612 fn modud(Ra, Rb) -> (Rt) {
616 fn modsw(Ra, Rb) -> (Rt) {
620 fn moduw(Ra, Rb) -> (Rt) {
626 fn mullw(Ra, Rb) -> (Rt) {
629 #[enumerant = MulLWO]
630 fn mullwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
633 #[enumerant = MulLW_]
634 fn mullw_(Ra, Rb, Overflow) -> (Rt, CR0) {
637 #[enumerant = MulLWO_]
638 fn mullwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
644 fn mulhw(Ra, Rb) -> (Rt) {
647 #[enumerant = MulHW_]
648 fn mulhw_(Ra, Rb, Overflow) -> (Rt, CR0) {
653 #[enumerant = MulHWU]
654 fn mulhwu(Ra, Rb) -> (Rt) {
657 #[enumerant = MulHWU_]
658 fn mulhwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
664 fn mulld(Ra, Rb) -> (Rt) {
667 #[enumerant = MulLDO]
668 fn mulldo(Ra, Rb, Overflow) -> (Rt, Overflow) {
671 #[enumerant = MulLD_]
672 fn mulld_(Ra, Rb, Overflow) -> (Rt, CR0) {
675 #[enumerant = MulLDO_]
676 fn mulldo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
682 fn mulhd(Ra, Rb) -> (Rt) {
685 #[enumerant = MulHD_]
686 fn mulhd_(Ra, Rb, Overflow) -> (Rt, CR0) {
691 #[enumerant = MulHDU]
692 fn mulhdu(Ra, Rb) -> (Rt) {
695 #[enumerant = MulHDU_]
696 fn mulhdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
701 #[enumerant = MAddHD]
702 fn maddhd(Ra, Rb, Rc) -> (Rt) {
705 #[enumerant = MAddHDU]
706 fn maddhdu(Ra, Rb, Rc) -> (Rt) {
709 #[enumerant = MAddLD]
710 fn maddld(Ra, Rb, Rc) -> (Rt) {
715 // must be after instrs macro call since it uses a macro definition