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 serde::{Deserialize, Serialize};
15 ops::{Index, IndexMut},
18 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
19 pub struct OverflowFlags {
26 pub const fn from_xer(xer: u64) -> Self {
28 so: (xer & 0x8000_0000) != 0,
29 ov: (xer & 0x4000_0000) != 0,
30 ov32: (xer & 0x8_0000) != 0,
33 pub const fn from_overflow(overflow: bool) -> Self {
42 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
43 pub struct ConditionRegister {
50 impl ConditionRegister {
51 pub const fn from_4_bits(bits: u8) -> Self {
52 // assert bits is 4-bits long
53 // can switch to using assert! once rustc feature const_panic is stabilized
54 [0; 0x10][bits as usize];
63 pub const CR_FIELD_COUNT: usize = 8;
64 pub const fn from_cr_field(cr: u32, field_index: usize) -> Self {
65 // assert field_index is less than CR_FIELD_COUNT
66 // can switch to using assert! once rustc feature const_panic is stabilized
67 [0; Self::CR_FIELD_COUNT][field_index];
69 let reversed_field_index = Self::CR_FIELD_COUNT - field_index - 1;
70 let bits = (cr >> (4 * reversed_field_index)) & 0xF;
71 Self::from_4_bits(bits as u8)
73 pub fn from_signed_int<T: Ord + Default>(value: T, so: bool) -> Self {
74 let ordering = value.cmp(&T::default());
76 lt: ordering == Ordering::Less,
77 gt: ordering == Ordering::Greater,
78 eq: ordering == Ordering::Equal,
84 #[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
85 pub struct InstructionResult {
88 skip_serializing_if = "Option::is_none",
89 with = "serde_hex::SerdeHex"
92 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
93 pub overflow: Option<OverflowFlags>,
94 #[serde(default, skip_serializing_if = "Option::is_none")]
95 pub cr0: Option<ConditionRegister>,
96 #[serde(default, skip_serializing_if = "Option::is_none")]
97 pub cr1: Option<ConditionRegister>,
98 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub cr2: Option<ConditionRegister>,
100 #[serde(default, skip_serializing_if = "Option::is_none")]
101 pub cr3: Option<ConditionRegister>,
102 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub cr4: Option<ConditionRegister>,
104 #[serde(default, skip_serializing_if = "Option::is_none")]
105 pub cr5: Option<ConditionRegister>,
106 #[serde(default, skip_serializing_if = "Option::is_none")]
107 pub cr6: Option<ConditionRegister>,
108 #[serde(default, skip_serializing_if = "Option::is_none")]
109 pub cr7: Option<ConditionRegister>,
112 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
113 pub enum InstructionInputRegister {
114 #[serde(rename = "ra")]
116 #[serde(rename = "rb")]
118 #[serde(rename = "rc")]
122 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
123 pub struct InstructionInput {
124 #[serde(with = "serde_hex::SerdeHex")]
126 #[serde(with = "serde_hex::SerdeHex")]
128 #[serde(with = "serde_hex::SerdeHex")]
132 impl Index<InstructionInputRegister> for InstructionInput {
134 fn index(&self, index: InstructionInputRegister) -> &Self::Output {
136 InstructionInputRegister::Ra => &self.ra,
137 InstructionInputRegister::Rb => &self.rb,
138 InstructionInputRegister::Rc => &self.rc,
143 impl IndexMut<InstructionInputRegister> for InstructionInput {
144 fn index_mut(&mut self, index: InstructionInputRegister) -> &mut Self::Output {
146 InstructionInputRegister::Ra => &mut self.ra,
147 InstructionInputRegister::Rb => &mut self.rb,
148 InstructionInputRegister::Rc => &mut self.rc,
153 fn is_false(v: &bool) -> bool {
157 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
158 pub struct TestCase {
161 pub inputs: InstructionInput,
162 #[serde(default, skip_serializing_if = "Option::is_none")]
163 pub native_outputs: Option<InstructionResult>,
164 pub model_outputs: InstructionResult,
165 #[serde(default, skip_serializing_if = "is_false")]
166 pub model_mismatch: bool,
169 #[derive(Clone, Debug, Serialize, Deserialize)]
170 pub struct WholeTest {
171 #[serde(default, skip_serializing_if = "Vec::is_empty")]
172 pub test_cases: Vec<TestCase>,
173 pub any_model_mismatch: bool,
176 #[cfg(feature = "native_instrs")]
177 macro_rules! map_instr_asm_args {
181 ([], [], [$string0:literal $($strings:literal)*]) => {
182 concat!(" ", $string0, $(", ", $strings),*)
184 ([$($args:ident)*], [rt $($results:ident)*], [$($strings:literal)*]) => {
185 map_instr_asm_args!([$($args)*], [$($results)*], ["$0" $($strings)*])
187 ([ra $($args:ident)*], [$($results:ident)*], [$($strings:literal)*]) => {
188 map_instr_asm_args!([$($args)*], [$($results)*], ["$3" $($strings)*])
190 ([rb $($args:ident)*], [$($results:ident)*], [$($strings:literal)*]) => {
191 map_instr_asm_args!([$($args)*], [$($results)*], ["$4" $($strings)*])
193 ([rc $($args:ident)*], [$($results:ident)*], [$($strings:literal)*]) => {
194 map_instr_asm_args!([$($args)*], [$($results)*], ["$5" $($strings)*])
196 ([$($args:ident)*], [ov $($results:ident)*], [$($strings:literal)*]) => {
197 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
199 ([$($args:ident)*], [cr0 $($results:ident)*], [$($strings:literal)*]) => {
200 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
202 ([$($args:ident)*], [cr1 $($results:ident)*], [$($strings:literal)*]) => {
203 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
205 ([$($args:ident)*], [cr2 $($results:ident)*], [$($strings:literal)*]) => {
206 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
208 ([$($args:ident)*], [cr3 $($results:ident)*], [$($strings:literal)*]) => {
209 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
211 ([$($args:ident)*], [cr4 $($results:ident)*], [$($strings:literal)*]) => {
212 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
214 ([$($args:ident)*], [cr5 $($results:ident)*], [$($strings:literal)*]) => {
215 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
217 ([$($args:ident)*], [cr6 $($results:ident)*], [$($strings:literal)*]) => {
218 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
220 ([$($args:ident)*], [cr7 $($results:ident)*], [$($strings:literal)*]) => {
221 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
225 macro_rules! map_instr_input_registers {
226 ([], [$($reg:expr,)*]) => {
229 ([ra $($args:ident)*], [$($reg:expr,)*]) => {
230 map_instr_input_registers!([$($args)*], [InstructionInputRegister::Ra, $($reg,)*])
232 ([rb $($args:ident)*], [$($reg:expr,)*]) => {
233 map_instr_input_registers!([$($args)*], [InstructionInputRegister::Rb, $($reg,)*])
235 ([rc $($args:ident)*], [$($reg:expr,)*]) => {
236 map_instr_input_registers!([$($args)*], [InstructionInputRegister::Rc, $($reg,)*])
240 #[cfg(feature = "native_instrs")]
241 macro_rules! map_instr_results {
242 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, []) => {};
243 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [rt $($args:ident)*]) => {
244 $retval.rt = Some($rt);
245 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
247 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [ov $($args:ident)*]) => {
248 $retval.overflow = Some(OverflowFlags::from_xer($xer));
249 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
251 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr0 $($args:ident)*]) => {
252 $retval.cr0 = Some(ConditionRegister::from_cr_field($cr, 0));
253 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
255 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr1 $($args:ident)*]) => {
256 $retval.cr1 = Some(ConditionRegister::from_cr_field($cr, 1));
257 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
259 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr2 $($args:ident)*]) => {
260 $retval.cr2 = Some(ConditionRegister::from_cr_field($cr, 2));
261 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
263 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr3 $($args:ident)*]) => {
264 $retval.cr3 = Some(ConditionRegister::from_cr_field($cr, 3));
265 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
267 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr4 $($args:ident)*]) => {
268 $retval.cr4 = Some(ConditionRegister::from_cr_field($cr, 4));
269 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
271 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr5 $($args:ident)*]) => {
272 $retval.cr5 = Some(ConditionRegister::from_cr_field($cr, 5));
273 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
275 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr6 $($args:ident)*]) => {
276 $retval.cr6 = Some(ConditionRegister::from_cr_field($cr, 6));
277 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
279 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr7 $($args:ident)*]) => {
280 $retval.cr7 = Some(ConditionRegister::from_cr_field($cr, 7));
281 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
285 #[cfg(feature = "native_instrs")]
288 #[enumerant = $enumerant:ident]
289 fn $fn:ident($($args:ident),*) -> ($($results:ident),*) {
293 pub fn $fn(inputs: InstructionInput) -> InstructionResult {
294 #![allow(unused_variables, unused_assignments)]
295 let InstructionInput {
310 map_instr_asm_args!([$($args)*], [$($results)*], []),
315 : "=&r"(rt), "=&r"(xer), "=&r"(cr)
316 : "r"(ra), "r"(rb), "r"(rc), "r"(0u64), "r"(!0x8000_0000u64)
319 let mut retval = InstructionResult::default();
320 map_instr_results!(rt, xer, cr, retval, [$($results)*]);
326 macro_rules! instrs {
329 #[enumerant = $enumerant:ident]
330 fn $fn:ident($($args:ident),*) -> ($($results:ident),*) {
335 #[cfg(feature = "python")]
336 macro_rules! wrap_all_instr_fns {
341 $(fn $fn(inputs: InstructionInput) -> InstructionResult;)*
346 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
349 #[serde(rename = $instr)]
355 #[cfg(feature = "native_instrs")]
356 pub fn get_native_fn(self) -> fn(InstructionInput) -> InstructionResult {
359 Self::$enumerant => native_instrs::$fn,
363 pub fn get_model_fn(self) -> fn(InstructionInput) -> InstructionResult {
366 Self::$enumerant => instr_models::$fn,
370 pub fn get_used_input_registers(self) -> &'static [InstructionInputRegister] {
373 Self::$enumerant => &map_instr_input_registers!([$($args)*], []),
377 pub fn name(self) -> &'static str {
380 Self::$enumerant => $instr,
384 pub const VALUES: &'static [Self] = &[
391 #[cfg(feature = "native_instrs")]
392 pub mod native_instrs {
397 #[enumerant = $enumerant]
398 fn $fn($($args),*) -> ($($results),*) {
410 fn divde(ra, rb) -> (rt) {
413 #[enumerant = DivDEO]
414 fn divdeo(ra, rb) -> (rt, ov) {
417 #[enumerant = DivDE_]
418 fn divde_(ra, rb) -> (rt, cr0) {
421 #[enumerant = DivDEO_]
422 fn divdeo_(ra, rb) -> (rt, ov, cr0) {
427 #[enumerant = DivDEU]
428 fn divdeu(ra, rb) -> (rt) {
431 #[enumerant = DivDEUO]
432 fn divdeuo(ra, rb) -> (rt, ov) {
435 #[enumerant = DivDEU_]
436 fn divdeu_(ra, rb) -> (rt, cr0) {
439 #[enumerant = DivDEUO_]
440 fn divdeuo_(ra, rb) -> (rt, ov, cr0) {
446 fn divd(ra, rb) -> (rt) {
450 fn divdo(ra, rb) -> (rt, ov) {
454 fn divd_(ra, rb) -> (rt, cr0) {
457 #[enumerant = DivDO_]
458 fn divdo_(ra, rb) -> (rt, ov, cr0) {
464 fn divdu(ra, rb) -> (rt) {
467 #[enumerant = DivDUO]
468 fn divduo(ra, rb) -> (rt, ov) {
471 #[enumerant = DivDU_]
472 fn divdu_(ra, rb) -> (rt, cr0) {
475 #[enumerant = DivDUO_]
476 fn divduo_(ra, rb) -> (rt, ov, cr0) {
482 fn divwe(ra, rb) -> (rt) {
485 #[enumerant = DivWEO]
486 fn divweo(ra, rb) -> (rt, ov) {
489 #[enumerant = DivWE_]
490 fn divwe_(ra, rb) -> (rt, cr0) {
493 #[enumerant = DivWEO_]
494 fn divweo_(ra, rb) -> (rt, ov, cr0) {
499 #[enumerant = DivWEU]
500 fn divweu(ra, rb) -> (rt) {
503 #[enumerant = DivWEUO]
504 fn divweuo(ra, rb) -> (rt, ov) {
507 #[enumerant = DivWEU_]
508 fn divweu_(ra, rb) -> (rt, cr0) {
511 #[enumerant = DivWEUO_]
512 fn divweuo_(ra, rb) -> (rt, ov, cr0) {
518 fn divw(ra, rb) -> (rt) {
522 fn divwo(ra, rb) -> (rt, ov) {
526 fn divw_(ra, rb) -> (rt, cr0) {
529 #[enumerant = DivWO_]
530 fn divwo_(ra, rb) -> (rt, ov, cr0) {
536 fn divwu(ra, rb) -> (rt) {
539 #[enumerant = DivWUO]
540 fn divwuo(ra, rb) -> (rt, ov) {
543 #[enumerant = DivWU_]
544 fn divwu_(ra, rb) -> (rt, cr0) {
547 #[enumerant = DivWUO_]
548 fn divwuo_(ra, rb) -> (rt, ov, cr0) {
554 fn modsd(ra, rb) -> (rt) {
558 fn modud(ra, rb) -> (rt) {
562 fn modsw(ra, rb) -> (rt) {
566 fn moduw(ra, rb) -> (rt) {
572 fn mullw(ra, rb) -> (rt) {
575 #[enumerant = MulLWO]
576 fn mullwo(ra, rb) -> (rt, ov) {
579 #[enumerant = MulLW_]
580 fn mullw_(ra, rb) -> (rt, cr0) {
583 #[enumerant = MulLWO_]
584 fn mullwo_(ra, rb) -> (rt, ov, cr0) {
590 fn mulhw(ra, rb) -> (rt) {
593 #[enumerant = MulHW_]
594 fn mulhw_(ra, rb) -> (rt, cr0) {
599 #[enumerant = MulHWU]
600 fn mulhwu(ra, rb) -> (rt) {
603 #[enumerant = MulHWU_]
604 fn mulhwu_(ra, rb) -> (rt, cr0) {
610 fn mulld(ra, rb) -> (rt) {
613 #[enumerant = MulLDO]
614 fn mulldo(ra, rb) -> (rt, ov) {
617 #[enumerant = MulLD_]
618 fn mulld_(ra, rb) -> (rt, cr0) {
621 #[enumerant = MulLDO_]
622 fn mulldo_(ra, rb) -> (rt, ov, cr0) {
628 fn mulhd(ra, rb) -> (rt) {
631 #[enumerant = MulHD_]
632 fn mulhd_(ra, rb) -> (rt, cr0) {
637 #[enumerant = MulHDU]
638 fn mulhdu(ra, rb) -> (rt) {
641 #[enumerant = MulHDU_]
642 fn mulhdu_(ra, rb) -> (rt, cr0) {
647 #[enumerant = MAddHD]
648 fn maddhd(ra, rb, rc) -> (rt) {
651 #[enumerant = MAddHDU]
652 fn maddhdu(ra, rb, rc) -> (rt) {
655 #[enumerant = MAddLD]
656 fn maddld(ra, rb, rc) -> (rt) {
661 // must be after instrs macro call since it uses a macro definition