--- /dev/null
+use crate::{OverflowFlags, TestDivInput, TestDivResult};
+
+pub fn divdeo(inputs: TestDivInput) -> TestDivResult {
+ let dividend = i128::from(inputs.dividend as i64) << 64;
+ let divisor = i128::from(inputs.divisor as i64);
+ let overflow;
+ let result;
+ if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
+ result = 0;
+ overflow = true;
+ } else {
+ let result128 = dividend / divisor;
+ result = result128 as u64;
+ overflow = result128 as i64 as i128 != result128;
+ }
+ TestDivResult {
+ result,
+ overflow: Some(OverflowFlags {
+ overflow,
+ overflow32: overflow,
+ }),
+ }
+}
+
+pub fn divdeuo(inputs: TestDivInput) -> TestDivResult {
+ let dividend = u128::from(inputs.dividend) << 64;
+ let divisor = u128::from(inputs.divisor);
+ let overflow;
+ let result;
+ if divisor == 0 {
+ result = 0;
+ overflow = true;
+ } else {
+ let resultu128 = dividend / divisor;
+ result = resultu128 as u64;
+ overflow = resultu128 > u128::from(u64::max_value());
+ }
+ TestDivResult {
+ result,
+ overflow: Some(OverflowFlags {
+ overflow,
+ overflow32: overflow,
+ }),
+ }
+}
+
+pub fn divdo(inputs: TestDivInput) -> TestDivResult {
+ let dividend = inputs.dividend as i64;
+ let divisor = inputs.divisor as i64;
+ let overflow;
+ let result;
+ if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
+ result = 0;
+ overflow = true;
+ } else {
+ result = (dividend / divisor) as u64;
+ overflow = false;
+ }
+ TestDivResult {
+ result,
+ overflow: Some(OverflowFlags {
+ overflow,
+ overflow32: overflow,
+ }),
+ }
+}
+
+pub fn divduo(inputs: TestDivInput) -> TestDivResult {
+ let dividend: u64 = inputs.dividend;
+ let divisor: u64 = inputs.divisor;
+ let overflow;
+ let result;
+ if divisor == 0 {
+ result = 0;
+ overflow = true;
+ } else {
+ result = dividend / divisor;
+ overflow = false;
+ }
+ TestDivResult {
+ result,
+ overflow: Some(OverflowFlags {
+ overflow,
+ overflow32: overflow,
+ }),
+ }
+}
+
+pub fn divweo(inputs: TestDivInput) -> TestDivResult {
+ let dividend = i64::from(inputs.dividend as i32) << 32;
+ let divisor = i64::from(inputs.divisor as i32);
+ let overflow;
+ let result;
+ if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
+ result = 0;
+ overflow = true;
+ } else {
+ let result64 = dividend / divisor;
+ result = result64 as u32 as u64;
+ overflow = result64 as i32 as i64 != result64;
+ }
+ TestDivResult {
+ result,
+ overflow: Some(OverflowFlags {
+ overflow,
+ overflow32: overflow,
+ }),
+ }
+}
+
+pub fn divweuo(inputs: TestDivInput) -> TestDivResult {
+ let dividend = u64::from(inputs.dividend) << 32;
+ let divisor = u64::from(inputs.divisor);
+ let overflow;
+ let result;
+ if divisor == 0 {
+ result = 0;
+ overflow = true;
+ } else {
+ let resultu64 = dividend / divisor;
+ result = resultu64 as u32 as u64;
+ overflow = resultu64 > u64::from(u32::max_value());
+ }
+ TestDivResult {
+ result,
+ overflow: Some(OverflowFlags {
+ overflow,
+ overflow32: overflow,
+ }),
+ }
+}
+
+pub fn divwo(inputs: TestDivInput) -> TestDivResult {
+ let dividend = inputs.dividend as i32;
+ let divisor = inputs.divisor as i32;
+ let overflow;
+ let result;
+ if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
+ result = 0;
+ overflow = true;
+ } else {
+ result = (dividend / divisor) as u32 as u64;
+ overflow = false;
+ }
+ TestDivResult {
+ result,
+ overflow: Some(OverflowFlags {
+ overflow,
+ overflow32: overflow,
+ }),
+ }
+}
+
+pub fn divwuo(inputs: TestDivInput) -> TestDivResult {
+ let dividend = inputs.dividend as u32;
+ let divisor = inputs.divisor as u32;
+ let overflow;
+ let result;
+ if divisor == 0 {
+ result = 0;
+ overflow = true;
+ } else {
+ result = (dividend / divisor) as u64;
+ overflow = false;
+ }
+ TestDivResult {
+ result,
+ overflow: Some(OverflowFlags {
+ overflow,
+ overflow32: overflow,
+ }),
+ }
+}
+
+pub fn modsd(inputs: TestDivInput) -> TestDivResult {
+ let dividend = inputs.dividend as i64;
+ let divisor = inputs.divisor as i64;
+ let result;
+ if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
+ result = 0;
+ } else {
+ result = (dividend % divisor) as u64;
+ }
+ TestDivResult {
+ result,
+ overflow: None,
+ }
+}
+
+pub fn modud(inputs: TestDivInput) -> TestDivResult {
+ let dividend: u64 = inputs.dividend;
+ let divisor: u64 = inputs.divisor;
+ let result;
+ if divisor == 0 {
+ result = 0;
+ } else {
+ result = dividend % divisor;
+ }
+ TestDivResult {
+ result,
+ overflow: None,
+ }
+}
+
+pub fn modsw(inputs: TestDivInput) -> TestDivResult {
+ let dividend = inputs.dividend as i32;
+ let divisor = inputs.divisor as i32;
+ let result;
+ if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
+ result = 0;
+ } else {
+ result = (dividend % divisor) as u32 as u64;
+ }
+ TestDivResult {
+ result,
+ overflow: None,
+ }
+}
+
+pub fn moduw(inputs: TestDivInput) -> TestDivResult {
+ let dividend = inputs.dividend as u32;
+ let divisor = inputs.divisor as u32;
+ let result;
+ if divisor == 0 {
+ result = 0;
+ } else {
+ result = (dividend % divisor) as u64;
+ }
+ TestDivResult {
+ result,
+ overflow: None,
+ }
+}
// SPDX-License-Identifier: LGPL-2.1-or-later
// See Notices.txt for copyright information
-#![feature(llvm_asm)]
+#![cfg_attr(feature = "native_instrs", feature(llvm_asm))]
+mod instr_models;
mod serde_hex;
use serde::{Deserialize, Serialize};
-#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
+#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct OverflowFlags {
pub overflow: bool,
pub overflow32: bool,
}
}
-#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
+#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct TestDivResult {
#[serde(with = "serde_hex::SerdeHex")]
pub result: u64,
pub result_prev: u64,
}
+fn is_false(v: &bool) -> bool {
+ !v
+}
+
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct TestDivCase {
pub instr: TestDivInstr,
#[serde(flatten)]
pub inputs: TestDivInput,
- #[serde(flatten)]
- pub outputs: TestDivResult,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub native_outputs: Option<TestDivResult>,
+ pub model_outputs: TestDivResult,
+ #[serde(default, skip_serializing_if = "is_false")]
+ pub model_mismatch: bool,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct WholeTest {
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub test_div_cases: Vec<TestDivCase>,
+ pub any_model_mismatch: bool,
}
macro_rules! make_div_functions {
}
impl TestDivInstr {
- pub fn get_fn(self) -> fn(TestDivInput) -> TestDivResult {
+ #[cfg(feature = "native_instrs")]
+ pub fn get_native_fn(self) -> fn(TestDivInput) -> TestDivResult {
match self {
$(
- Self::$div_enum => TestDivInput::$div_fn,
+ Self::$div_enum => native_instrs::$div_fn,
)+
$(
- Self::$rem_enum => TestDivInput::$rem_fn,
+ Self::$rem_enum => native_instrs::$rem_fn,
+ )+
+ }
+ }
+ pub fn get_model_fn(self) -> fn(TestDivInput) -> TestDivResult {
+ match self {
+ $(
+ Self::$div_enum => instr_models::$div_fn,
+ )+
+ $(
+ Self::$rem_enum => instr_models::$rem_fn,
)+
}
}
];
}
- impl TestDivInput {
+ #[cfg(feature = "native_instrs")]
+ mod native_instrs {
+ use super::*;
+
$(
- pub fn $div_fn(self) -> TestDivResult {
- let Self {
+ pub fn $div_fn(inputs: TestDivInput) -> TestDivResult {
+ let TestDivInput {
dividend,
divisor,
result_prev,
- } = self;
+ } = inputs;
let result: u64;
let xer: u64;
unsafe {
}
)+
$(
- pub fn $rem_fn(self) -> TestDivResult {
- let Self {
+ pub fn $rem_fn(inputs: TestDivInput) -> TestDivResult {
+ let TestDivInput {
dividend,
divisor,
result_prev,
- } = self;
+ } = inputs;
let result: u64;
unsafe {
llvm_asm!(
make_div_functions! {
#[div]
{
- DivDE = divde("divdeo"),
- DivDEU = divdeu("divdeuo"),
- DivD = divd("divdo"),
- DivDU = divdu("divduo"),
- DivWE = divwe("divweo"),
- DivWEU = divweu("divweuo"),
- DivW = divw("divwo"),
- DivWU = divwu("divwuo"),
+ DivDEO = divdeo("divdeo"),
+ DivDEUO = divdeuo("divdeuo"),
+ DivDO = divdo("divdo"),
+ DivDUO = divduo("divduo"),
+ DivWEO = divweo("divweo"),
+ DivWEUO = divweuo("divweuo"),
+ DivWO = divwo("divwo"),
+ DivWUO = divwuo("divwuo"),
}
#[rem]
{
];
fn main() {
- let mut cases = Vec::new();
+ let mut test_div_cases = Vec::new();
+ let mut any_model_mismatch = false;
for &instr in TestDivInstr::VALUES {
for ÷nd in TEST_VALUES {
for &divisor in TEST_VALUES {
divisor,
result_prev: 0xFECD_BA98_7654_3210,
};
- let outputs = instr.get_fn()(inputs);
- cases.push(TestDivCase {
+ let model_outputs = instr.get_model_fn()(inputs);
+ #[cfg(feature = "native_instrs")]
+ let native_outputs = Some(instr.get_native_fn()(inputs));
+ #[cfg(not(feature = "native_instrs"))]
+ let native_outputs = None;
+ let model_mismatch = match native_outputs {
+ Some(native_outputs) if native_outputs != model_outputs => true,
+ _ => false,
+ };
+ any_model_mismatch |= model_mismatch;
+ test_div_cases.push(TestDivCase {
instr,
inputs,
- outputs,
+ native_outputs,
+ model_outputs,
+ model_mismatch,
});
}
}
}
- serde_json::to_writer_pretty(std::io::stdout().lock(), &cases).unwrap();
+ let whole_test = WholeTest {
+ test_div_cases,
+ any_model_mismatch,
+ };
+ serde_json::to_writer_pretty(std::io::stdout().lock(), &whole_test).unwrap();
println!();
}