add more instructions and test cases
authorJacob Lifshay <programmerjake@gmail.com>
Tue, 26 May 2020 03:24:23 +0000 (20:24 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Tue, 26 May 2020 03:24:23 +0000 (20:24 -0700)
src/main.rs

index bfcb86b58aa7e7dc2352ff15b5347a4b7735d396..220991a5bc90eceba7cd0ca71b37b960d0ab0108 100644 (file)
 // See Notices.txt for copyright information
 
 #![feature(llvm_asm)]
+use std::fmt;
 
 #[derive(Copy, Clone, Debug)]
-struct TestDivResult {
-    result: u64,
+struct OverflowFlags {
     overflow: bool,
     overflow32: bool,
 }
 
-impl TestDivResult {
-    fn from_result_xer(result: u64, xer: u64) -> Self {
-        TestDivResult {
-            result,
+impl OverflowFlags {
+    fn from_xer(xer: u64) -> Self {
+        Self {
             overflow: (xer & 0x4000_0000) != 0,
             overflow32: (xer & 0x8_0000) != 0,
         }
     }
 }
 
+impl fmt::Display for OverflowFlags {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let Self {
+            overflow,
+            overflow32,
+        } = *self;
+        write!(
+            f,
+            "OV:{overflow}, OV32:{overflow32}",
+            overflow = overflow as i32,
+            overflow32 = overflow32 as i32,
+        )
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+struct TestDivResult {
+    result: u64,
+    overflow: Option<OverflowFlags>,
+}
+
+impl fmt::Display for TestDivResult {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let Self { result, overflow } = *self;
+        write!(f, "{:#X}", result)?;
+        if let Some(overflow) = overflow {
+            write!(f, ", {}", overflow)?;
+        }
+        Ok(())
+    }
+}
+
 #[derive(Copy, Clone, Debug)]
 struct TestDivInput {
-    divisor: u64,
     dividend: u64,
+    divisor: u64,
     result_prev: u64,
 }
 
-macro_rules! make_div_fn {
-    ($name:ident) => {
+impl fmt::Display for TestDivInput {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let Self {
+            dividend,
+            divisor,
+            result_prev,
+        } = *self;
+        write!(
+            f,
+            "{:#X} div {:#X} (result_prev:{:#X})",
+            dividend, divisor, result_prev,
+        )
+    }
+}
+
+macro_rules! make_div_functions {
+    (
+        #[div]
+        {
+            $($div_name:ident;)+
+        }
+        #[rem]
+        {
+            $($rem_name:ident;)+
+        }
+    ) => {
         impl TestDivInput {
-            fn $name(self) -> TestDivResult {
-                let Self {
-                    divisor,
-                    dividend,
-                    result_prev,
-                } = self;
-                let result: u64;
-                let xer: u64;
-                unsafe {
-                    llvm_asm!(
-                        concat!(
-                            stringify!($name),
-                            " $0, $3, $4\n",
-                            "mfxer $1"
-                        )
-                        : "=&r"(result), "=&r"(xer)
-                        : "0"(result_prev), "r"(dividend), "r"(divisor)
-                        : "xer");
+            $(
+                #[inline(never)]
+                pub fn $div_name(self) -> TestDivResult {
+                    let Self {
+                        dividend,
+                        divisor,
+                        result_prev,
+                    } = self;
+                    let result: u64;
+                    let xer: u64;
+                    unsafe {
+                        llvm_asm!(
+                            concat!(
+                                stringify!($div_name),
+                                " $0, $3, $4\n",
+                                "mfxer $1"
+                            )
+                            : "=&r"(result), "=&r"(xer)
+                            : "0"(result_prev), "r"(dividend), "r"(divisor)
+                            : "xer");
+                    }
+                    TestDivResult {
+                        result,
+                        overflow: Some(OverflowFlags::from_xer(xer)),
+                    }
                 }
-                TestDivResult::from_result_xer(result, xer)
-            }
+            )+
+            $(
+                #[inline(never)]
+                pub fn $rem_name(self) -> TestDivResult {
+                    let Self {
+                        dividend,
+                        divisor,
+                        result_prev,
+                    } = self;
+                    let result: u64;
+                    unsafe {
+                        llvm_asm!(
+                            concat!(
+                                stringify!($rem_name),
+                                " $0, $2, $3"
+                            )
+                            : "=&r"(result)
+                            : "0"(result_prev), "r"(dividend), "r"(divisor));
+                    }
+                    TestDivResult {
+                        result,
+                        overflow: None,
+                    }
+                }
+            )+
+            pub const FUNCTIONS: &'static [(fn(TestDivInput) -> TestDivResult, &'static str)] = &[
+                $((Self::$div_name, stringify!($div_name)),)+
+                $((Self::$rem_name, stringify!($rem_name)),)+
+            ];
         }
     };
 }
 
-make_div_fn!(divdo);
+make_div_functions! {
+    #[div]
+    {divdeo; divdeuo; divdo; divduo; divweo; divweuo; divwo; divwuo;}
+    #[rem]
+    {modsd; modud; modsw; moduw;}
+}
+
+const TEST_VALUES: &[u64] = &[
+    0x0,
+    0xFFFF_FFFF_FFFF_FFFF,
+    0x7FFF_FFFF_FFFF_FFFF,
+    0x8000_0000_0000_0000,
+    0x1234_5678_0000_0000,
+    0x1234_5678_8000_0000,
+    0x1234_5678_FFFF_FFFF,
+    0x1234_5678_7FFF_FFFF,
+];
 
 fn main() {
-    let inputs = TestDivInput {
-        divisor: 0,
-        dividend: 0,
-        result_prev: 0x123456789ABCDEF,
-    };
-    dbg!(inputs);
-    let outputs = inputs.divdo();
-    dbg!(outputs);
+    for &dividend in TEST_VALUES {
+        for &divisor in TEST_VALUES {
+            for &(f, name) in TestDivInput::FUNCTIONS {
+                let inputs = TestDivInput {
+                    dividend,
+                    divisor,
+                    result_prev: 0xFECD_BA98_7654_3210,
+                };
+                let outputs = f(inputs);
+                println!("{}: {} -> {}", name, inputs, outputs);
+            }
+        }
+    }
 }