working on adding instruction models
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 28 May 2020 06:13:50 +0000 (23:13 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 28 May 2020 06:13:50 +0000 (23:13 -0700)
Cargo.toml
src/instr_models.rs [new file with mode: 0644]
src/main.rs

index 8992fa9fd037c80cc999147ffa8f3390c8ccf020..14461b00c2226dddeb0f49faf561d114f3bb3f6d 100644 (file)
@@ -7,6 +7,10 @@ authors = ["Jacob Lifshay <programmerjake@gmail.com>"]
 edition = "2018"
 license = "LGPL-2.1-or-later"
 
+[features]
+native_instrs = []
+default = ["native_instrs"]
+
 [dependencies]
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
\ No newline at end of file
diff --git a/src/instr_models.rs b/src/instr_models.rs
new file mode 100644 (file)
index 0000000..a609bcb
--- /dev/null
@@ -0,0 +1,233 @@
+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,
+    }
+}
index 657466b7e213bc69f649d87b857893eef5a0f831..aa9bda748b4ec0fc87d8790932d72b9f5c64e338 100644 (file)
@@ -1,13 +1,14 @@
 // 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,
@@ -22,7 +23,7 @@ impl OverflowFlags {
     }
 }
 
-#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
+#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
 pub struct TestDivResult {
     #[serde(with = "serde_hex::SerdeHex")]
     pub result: u64,
@@ -40,13 +41,27 @@ pub struct TestDivInput {
     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 {
@@ -73,13 +88,24 @@ 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,
                     )+
                 }
             }
@@ -103,14 +129,17 @@ macro_rules! make_div_functions {
             ];
         }
 
-        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 {
@@ -131,12 +160,12 @@ macro_rules! make_div_functions {
                 }
             )+
             $(
-                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!(
@@ -160,14 +189,14 @@ macro_rules! make_div_functions {
 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]
     {
@@ -190,7 +219,8 @@ const TEST_VALUES: &[u64] = &[
 ];
 
 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 &dividend in TEST_VALUES {
             for &divisor in TEST_VALUES {
@@ -199,15 +229,30 @@ fn main() {
                     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!();
 }