/target
+__pycache__
+*.pyc
\ No newline at end of file
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "cloudabi"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "ctor"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39858aa5bac06462d4dd4b9164848eb81ffc4aa5c479746393598fd193afa227"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "ghost"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "indoc"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
+dependencies = [
+ "indoc-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "indoc-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unindent",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
+
+[[package]]
+name = "inventory"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "621b50c176968fd3b0bd71f821a28a0ea98db2b5aea966b2fbb8bd1b7d310328"
+dependencies = [
+ "ctor",
+ "ghost",
+ "inventory-impl",
+]
+
+[[package]]
+name = "inventory-impl"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f99a4111304bade76468d05beab3487c226e4fe4c4de1c4e8f006e815762db73"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "itoa"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
+[[package]]
+name = "libc"
+version = "0.2.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
+
+[[package]]
+name = "lock_api"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733"
+dependencies = [
+ "instant",
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
+dependencies = [
+ "cfg-if",
+ "cloudabi",
+ "instant",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "winapi",
+]
+
+[[package]]
+name = "paste"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
+dependencies = [
+ "paste-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "paste-impl"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
+dependencies = [
+ "proc-macro-hack",
+]
+
[[package]]
name = "power-instruction-analyzer"
version = "0.1.0"
dependencies = [
+ "pyo3",
"serde",
"serde_json",
]
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
+
[[package]]
name = "proc-macro2"
version = "1.0.17"
"unicode-xid",
]
+[[package]]
+name = "pyo3"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ca8710ffa8211c9a62a8a3863c4267c710dc42a82a7fd29c97de465d7ea6b7d"
+dependencies = [
+ "ctor",
+ "indoc",
+ "inventory",
+ "libc",
+ "parking_lot",
+ "paste",
+ "pyo3cls",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-derive-backend"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58ad070bf6967b0d29ea74931ffcf9c6bbe8402a726e9afbeafadc0a287cc2b3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pyo3cls"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3fa17e1ea569d0bf3b7c00f2a9eea831ca05e55dd76f1794c541abba1c64baa"
+dependencies = [
+ "pyo3-derive-backend",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "quote"
version = "1.0.6"
"proc-macro2",
]
+[[package]]
+name = "redox_syscall"
+version = "0.1.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+
[[package]]
name = "ryu"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
[[package]]
name = "serde"
version = "1.0.110"
"serde",
]
+[[package]]
+name = "smallvec"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
+
[[package]]
name = "syn"
version = "1.0.27"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+
+[[package]]
+name = "unindent"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af41d708427f8fd0e915dcebb2cae0f0e6acb2a939b2d399c265c39a38a18942"
+
+[[package]]
+name = "winapi"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[features]
native_instrs = []
-default = ["native_instrs"]
+python = ["pyo3"]
+python-extension = ["python", "pyo3/extension-module"]
+
+[lib]
+name = "power_instruction_analyzer"
+crate-type = ["rlib", "cdylib"]
[dependencies]
serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
\ No newline at end of file
+serde_json = "1.0"
+pyo3 = { version = "0.11", optional = true }
\ No newline at end of file
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# See Notices.txt for copyright information
+[build-system]
+requires = ["maturin"]
+build-backend = "maturin"
+
+[tool.maturin]
+bindings = "pyo3"
+cargo-extra-args = "--features python-extension"
-use crate::{OverflowFlags, TestDivInput, TestDivResult};
+use crate::{DivInput, DivResult, OverflowFlags};
-pub fn divdeo(inputs: TestDivInput) -> TestDivResult {
+pub fn divdeo(inputs: DivInput) -> DivResult {
let dividend = i128::from(inputs.dividend as i64) << 64;
let divisor = i128::from(inputs.divisor as i64);
let overflow;
overflow = false;
}
}
- TestDivResult {
+ DivResult {
result,
overflow: Some(OverflowFlags {
overflow,
}
}
-pub fn divdeuo(inputs: TestDivInput) -> TestDivResult {
+pub fn divdeuo(inputs: DivInput) -> DivResult {
let dividend = u128::from(inputs.dividend) << 64;
let divisor = u128::from(inputs.divisor);
let overflow;
overflow = false;
}
}
- TestDivResult {
+ DivResult {
result,
overflow: Some(OverflowFlags {
overflow,
}
}
-pub fn divdo(inputs: TestDivInput) -> TestDivResult {
+pub fn divdo(inputs: DivInput) -> DivResult {
let dividend = inputs.dividend as i64;
let divisor = inputs.divisor as i64;
let overflow;
result = (dividend / divisor) as u64;
overflow = false;
}
- TestDivResult {
+ DivResult {
result,
overflow: Some(OverflowFlags {
overflow,
}
}
-pub fn divduo(inputs: TestDivInput) -> TestDivResult {
+pub fn divduo(inputs: DivInput) -> DivResult {
let dividend: u64 = inputs.dividend;
let divisor: u64 = inputs.divisor;
let overflow;
result = dividend / divisor;
overflow = false;
}
- TestDivResult {
+ DivResult {
result,
overflow: Some(OverflowFlags {
overflow,
}
}
-pub fn divweo(inputs: TestDivInput) -> TestDivResult {
+pub fn divweo(inputs: DivInput) -> DivResult {
let dividend = i64::from(inputs.dividend as i32) << 32;
let divisor = i64::from(inputs.divisor as i32);
let overflow;
overflow = false;
}
}
- TestDivResult {
+ DivResult {
result,
overflow: Some(OverflowFlags {
overflow,
}
}
-pub fn divweuo(inputs: TestDivInput) -> TestDivResult {
+pub fn divweuo(inputs: DivInput) -> DivResult {
let dividend = u64::from(inputs.dividend as u32) << 32;
let divisor = u64::from(inputs.divisor as u32);
let overflow;
overflow = false;
}
}
- TestDivResult {
+ DivResult {
result,
overflow: Some(OverflowFlags {
overflow,
}
}
-pub fn divwo(inputs: TestDivInput) -> TestDivResult {
+pub fn divwo(inputs: DivInput) -> DivResult {
let dividend = inputs.dividend as i32;
let divisor = inputs.divisor as i32;
let overflow;
result = (dividend / divisor) as u32 as u64;
overflow = false;
}
- TestDivResult {
+ DivResult {
result,
overflow: Some(OverflowFlags {
overflow,
}
}
-pub fn divwuo(inputs: TestDivInput) -> TestDivResult {
+pub fn divwuo(inputs: DivInput) -> DivResult {
let dividend = inputs.dividend as u32;
let divisor = inputs.divisor as u32;
let overflow;
result = (dividend / divisor) as u64;
overflow = false;
}
- TestDivResult {
+ DivResult {
result,
overflow: Some(OverflowFlags {
overflow,
}
}
-pub fn modsd(inputs: TestDivInput) -> TestDivResult {
+pub fn modsd(inputs: DivInput) -> DivResult {
let dividend = inputs.dividend as i64;
let divisor = inputs.divisor as i64;
let result;
} else {
result = (dividend % divisor) as u64;
}
- TestDivResult {
+ DivResult {
result,
overflow: None,
}
}
-pub fn modud(inputs: TestDivInput) -> TestDivResult {
+pub fn modud(inputs: DivInput) -> DivResult {
let dividend: u64 = inputs.dividend;
let divisor: u64 = inputs.divisor;
let result;
} else {
result = dividend % divisor;
}
- TestDivResult {
+ DivResult {
result,
overflow: None,
}
}
-pub fn modsw(inputs: TestDivInput) -> TestDivResult {
+pub fn modsw(inputs: DivInput) -> DivResult {
let dividend = inputs.dividend as i32;
let divisor = inputs.divisor as i32;
let result;
} else {
result = (dividend % divisor) as u64;
}
- TestDivResult {
+ DivResult {
result,
overflow: None,
}
}
-pub fn moduw(inputs: TestDivInput) -> TestDivResult {
+pub fn moduw(inputs: DivInput) -> DivResult {
let dividend = inputs.dividend as u32;
let divisor = inputs.divisor as u32;
let result;
} else {
result = (dividend % divisor) as u64;
}
- TestDivResult {
+ DivResult {
result,
overflow: None,
}
--- /dev/null
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// See Notices.txt for copyright information
+
+#![cfg_attr(feature = "native_instrs", feature(llvm_asm))]
+
+#[cfg(all(feature = "native_instrs", not(target_arch = "powerpc64")))]
+compile_error!("native_instrs feature requires target_arch to be powerpc64");
+
+pub mod instr_models;
+mod python;
+mod serde_hex;
+
+use serde::{Deserialize, Serialize};
+
+#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct OverflowFlags {
+ pub overflow: bool,
+ pub overflow32: bool,
+}
+
+impl OverflowFlags {
+ pub fn from_xer(xer: u64) -> Self {
+ Self {
+ overflow: (xer & 0x4000_0000) != 0,
+ overflow32: (xer & 0x8_0000) != 0,
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct DivResult {
+ #[serde(with = "serde_hex::SerdeHex")]
+ pub result: u64,
+ #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
+ pub overflow: Option<OverflowFlags>,
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
+pub struct DivInput {
+ #[serde(with = "serde_hex::SerdeHex")]
+ pub dividend: u64,
+ #[serde(with = "serde_hex::SerdeHex")]
+ pub divisor: u64,
+ #[serde(default, with = "serde_hex::SerdeHex")]
+ pub result_prev: u64,
+}
+
+fn is_false(v: &bool) -> bool {
+ !v
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
+pub struct TestDivCase {
+ pub instr: DivInstr,
+ #[serde(flatten)]
+ pub inputs: DivInput,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub native_outputs: Option<DivResult>,
+ pub model_outputs: DivResult,
+ #[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 {
+ (
+ #[div]
+ {
+ $($div_enum:ident = $div_fn:ident ($div_instr:literal),)+
+ }
+ #[rem]
+ {
+ $($rem_enum:ident = $rem_fn:ident ($rem_instr:literal),)+
+ }
+ ) => {
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
+ pub enum DivInstr {
+ $(
+ #[serde(rename = $div_instr)]
+ $div_enum,
+ )+
+ $(
+ #[serde(rename = $rem_instr)]
+ $rem_enum,
+ )+
+ }
+
+ impl DivInstr {
+ #[cfg(feature = "native_instrs")]
+ pub fn get_native_fn(self) -> fn(DivInput) -> DivResult {
+ match self {
+ $(
+ Self::$div_enum => native_instrs::$div_fn,
+ )+
+ $(
+ Self::$rem_enum => native_instrs::$rem_fn,
+ )+
+ }
+ }
+ pub fn get_model_fn(self) -> fn(DivInput) -> DivResult {
+ match self {
+ $(
+ Self::$div_enum => instr_models::$div_fn,
+ )+
+ $(
+ Self::$rem_enum => instr_models::$rem_fn,
+ )+
+ }
+ }
+ pub fn name(self) -> &'static str {
+ match self {
+ $(
+ Self::$div_enum => $div_instr,
+ )+
+ $(
+ Self::$rem_enum => $rem_instr,
+ )+
+ }
+ }
+ pub const VALUES: &'static [Self] = &[
+ $(
+ Self::$div_enum,
+ )+
+ $(
+ Self::$rem_enum,
+ )+
+ ];
+ }
+
+ #[cfg(feature = "native_instrs")]
+ pub mod native_instrs {
+ use super::*;
+
+ $(
+ pub fn $div_fn(inputs: DivInput) -> DivResult {
+ let DivInput {
+ dividend,
+ divisor,
+ result_prev,
+ } = inputs;
+ let result: u64;
+ let xer: u64;
+ unsafe {
+ llvm_asm!(
+ concat!(
+ $div_instr,
+ " $0, $3, $4\n",
+ "mfxer $1"
+ )
+ : "=&r"(result), "=&r"(xer)
+ : "0"(result_prev), "r"(dividend), "r"(divisor)
+ : "xer");
+ }
+ DivResult {
+ result,
+ overflow: Some(OverflowFlags::from_xer(xer)),
+ }
+ }
+ )+
+ $(
+ pub fn $rem_fn(inputs: DivInput) -> DivResult {
+ let DivInput {
+ dividend,
+ divisor,
+ result_prev,
+ } = inputs;
+ let result: u64;
+ unsafe {
+ llvm_asm!(
+ concat!(
+ $rem_instr,
+ " $0, $2, $3"
+ )
+ : "=&r"(result)
+ : "0"(result_prev), "r"(dividend), "r"(divisor));
+ }
+ DivResult {
+ result,
+ overflow: None,
+ }
+ }
+ )+
+ }
+ };
+}
+
+make_div_functions! {
+ #[div]
+ {
+ 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]
+ {
+ ModSD = modsd("modsd"),
+ ModUD = modud("modud"),
+ ModSW = modsw("modsw"),
+ ModUW = moduw("moduw"),
+ }
+}
// SPDX-License-Identifier: LGPL-2.1-or-later
// See Notices.txt for copyright information
-#![cfg_attr(feature = "native_instrs", feature(llvm_asm))]
-
-mod instr_models;
-mod serde_hex;
-
-use serde::{Deserialize, Serialize};
-
-#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct OverflowFlags {
- pub overflow: bool,
- pub overflow32: bool,
-}
-
-impl OverflowFlags {
- pub fn from_xer(xer: u64) -> Self {
- Self {
- overflow: (xer & 0x4000_0000) != 0,
- overflow32: (xer & 0x8_0000) != 0,
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct TestDivResult {
- #[serde(with = "serde_hex::SerdeHex")]
- pub result: u64,
- #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
- pub overflow: Option<OverflowFlags>,
-}
-
-#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
-pub struct TestDivInput {
- #[serde(with = "serde_hex::SerdeHex")]
- pub dividend: u64,
- #[serde(with = "serde_hex::SerdeHex")]
- pub divisor: u64,
- #[serde(with = "serde_hex::SerdeHex")]
- 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(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 {
- (
- #[div]
- {
- $($div_enum:ident = $div_fn:ident ($div_instr:literal),)+
- }
- #[rem]
- {
- $($rem_enum:ident = $rem_fn:ident ($rem_instr:literal),)+
- }
- ) => {
- #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
- pub enum TestDivInstr {
- $(
- #[serde(rename = $div_instr)]
- $div_enum,
- )+
- $(
- #[serde(rename = $rem_instr)]
- $rem_enum,
- )+
- }
-
- impl TestDivInstr {
- #[cfg(feature = "native_instrs")]
- pub fn get_native_fn(self) -> fn(TestDivInput) -> TestDivResult {
- match self {
- $(
- Self::$div_enum => native_instrs::$div_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,
- )+
- }
- }
- pub fn name(self) -> &'static str {
- match self {
- $(
- Self::$div_enum => $div_instr,
- )+
- $(
- Self::$rem_enum => $rem_instr,
- )+
- }
- }
- pub const VALUES: &'static [Self] = &[
- $(
- Self::$div_enum,
- )+
- $(
- Self::$rem_enum,
- )+
- ];
- }
-
- #[cfg(feature = "native_instrs")]
- mod native_instrs {
- use super::*;
-
- $(
- pub fn $div_fn(inputs: TestDivInput) -> TestDivResult {
- let TestDivInput {
- dividend,
- divisor,
- result_prev,
- } = inputs;
- let result: u64;
- let xer: u64;
- unsafe {
- llvm_asm!(
- concat!(
- $div_instr,
- " $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)),
- }
- }
- )+
- $(
- pub fn $rem_fn(inputs: TestDivInput) -> TestDivResult {
- let TestDivInput {
- dividend,
- divisor,
- result_prev,
- } = inputs;
- let result: u64;
- unsafe {
- llvm_asm!(
- concat!(
- $rem_instr,
- " $0, $2, $3"
- )
- : "=&r"(result)
- : "0"(result_prev), "r"(dividend), "r"(divisor));
- }
- TestDivResult {
- result,
- overflow: None,
- }
- }
- )+
- }
- };
-}
-
-make_div_functions! {
- #[div]
- {
- 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]
- {
- ModSD = modsd("modsd"),
- ModUD = modud("modud"),
- ModSW = modsw("modsw"),
- ModUW = moduw("moduw"),
- }
-}
+use power_instruction_analyzer::{DivInput, DivInstr, TestDivCase, WholeTest};
const TEST_VALUES: &[u64] = &[
0x0,
fn main() {
let mut test_div_cases = Vec::new();
let mut any_model_mismatch = false;
- for &instr in TestDivInstr::VALUES {
+ for &instr in DivInstr::VALUES {
for ÷nd in TEST_VALUES {
for &divisor in TEST_VALUES {
- let inputs = TestDivInput {
+ let inputs = DivInput {
dividend,
divisor,
result_prev: 0xFECD_BA98_7654_3210,
--- /dev/null
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// See Notices.txt for copyright information
+
+#![cfg(feature = "python")]
+
+use crate::{DivInput, DivResult, OverflowFlags};
+use pyo3::{prelude::*, wrap_pyfunction, PyObjectProtocol};
+use std::{borrow::Cow, cell::RefCell, fmt};
+
+trait ToPythonRepr {
+ fn to_python_repr(&self) -> Cow<str> {
+ struct Helper<T>(RefCell<Option<T>>);
+
+ impl<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Display for Helper<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.borrow_mut().take().unwrap()(f)
+ }
+ }
+
+ impl<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result> Helper<T> {
+ fn new(f: T) -> Self {
+ Helper(RefCell::new(Some(f)))
+ }
+ }
+ Cow::Owned(format!(
+ "{}",
+ Helper::new(|f: &mut fmt::Formatter<'_>| -> fmt::Result { self.write(f) })
+ ))
+ }
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(&self.to_python_repr())
+ }
+}
+
+fn write_list_body_to_python_repr<I: IntoIterator<Item = T>, T: ToPythonRepr>(
+ list: I,
+ f: &mut fmt::Formatter<'_>,
+ separator: &str,
+) -> fmt::Result {
+ let mut first = true;
+ for i in list {
+ if first {
+ first = false;
+ } else {
+ f.write_str(separator)?;
+ }
+ i.write(f)?;
+ }
+ Ok(())
+}
+
+struct NamedArgPythonRepr<'a> {
+ name: &'a str,
+ value: &'a (dyn ToPythonRepr + 'a),
+}
+
+impl ToPythonRepr for NamedArgPythonRepr<'_> {
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.name)?;
+ f.write_str("=")?;
+ self.value.write(f)
+ }
+}
+
+impl<T: ToPythonRepr> ToPythonRepr for &'_ T {
+ fn to_python_repr(&self) -> Cow<str> {
+ (**self).to_python_repr()
+ }
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (**self).write(f)
+ }
+}
+
+impl ToPythonRepr for bool {
+ fn to_python_repr(&self) -> Cow<str> {
+ Cow::Borrowed(match self {
+ true => "True",
+ false => "False",
+ })
+ }
+}
+
+impl<T: ToPythonRepr> ToPythonRepr for Option<T> {
+ fn to_python_repr(&self) -> Cow<str> {
+ match self {
+ Some(v) => v.to_python_repr(),
+ None => Cow::Borrowed("None"),
+ }
+ }
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Some(v) => v.write(f),
+ None => f.write_str("None"),
+ }
+ }
+}
+
+impl<T: ToPythonRepr> ToPythonRepr for Vec<T> {
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("[")?;
+ write_list_body_to_python_repr(self, f, ", ")?;
+ f.write_str("]")
+ }
+}
+
+macro_rules! impl_int_to_python_repr {
+ ($($int:ident,)*) => {
+ $(
+ impl ToPythonRepr for $int {
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self)
+ }
+ }
+ )*
+ };
+}
+
+impl_int_to_python_repr! {u8, u16, u32, u64, u128, i8, i16, i32, i64, i128,}
+
+macro_rules! wrap_type {
+ (
+ #[pymodule($m:expr)]
+ // use tt to work around PyO3 bug fixed in PyO3#832
+ #[pyclass $($pyclass_args:tt)?]
+ #[wrapped($value:ident: $wrapped:ident)]
+ $(#[$meta:meta])*
+ struct $wrapper:ident {
+ $(
+ #[set=$setter_name:ident]
+ $(#[$field_meta:meta])*
+ $field_name:ident:$field_type:ty,
+ )*
+ }
+ ) => {
+ #[pyclass $($pyclass_args)?]
+ $(#[$meta])*
+ #[derive(Clone)]
+ struct $wrapper {
+ $value: $wrapped,
+ }
+
+ impl<'source> FromPyObject<'source> for $wrapped {
+ fn extract(ob: &'source PyAny) -> PyResult<Self> {
+ Ok(ob.extract::<$wrapper>()?.$value)
+ }
+ }
+
+ impl IntoPy<PyObject> for $wrapped {
+ fn into_py(self, py: Python) -> PyObject {
+ $wrapper { $value: self }.into_py(py)
+ }
+ }
+
+ #[pymethods]
+ impl $wrapper {
+ #[new]
+ fn new($($field_name:$field_type),*) -> Self {
+ Self {
+ $value: $wrapped {
+ $($field_name),*
+ }
+ }
+ }
+ $(
+ #[getter]
+ $(#[$field_meta:meta])*
+ fn $field_name(&self) -> $field_type {
+ self.$value.$field_name
+ }
+ #[setter]
+ fn $setter_name(&mut self, $field_name: $field_type) {
+ self.$value.$field_name = $field_name;
+ }
+ )*
+ }
+
+ impl ToPythonRepr for $wrapped {
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(concat!(stringify!($wrapped), "("))?;
+ write_list_body_to_python_repr(&[
+ $(
+ NamedArgPythonRepr {
+ name: stringify!($field_name),
+ value: &self.$field_name,
+ },
+ )*
+ ], f, ", ")?;
+ f.write_str(")")
+ }
+ }
+
+ #[pyproto]
+ impl PyObjectProtocol for $wrapper {
+ fn __str__(&self) -> String {
+ serde_json::to_string(&self.$value).unwrap()
+ }
+ fn __repr__(&self) -> String {
+ self.$value.to_python_repr().into_owned()
+ }
+ }
+
+ $m.add_class::<$wrapper>()?;
+ };
+}
+
+macro_rules! wrap_instr_fns {
+ (
+ #![pymodule($m:ident)]
+ $(
+ // use tt to work around PyO3 bug fixed in PyO3#832
+ $(#[pyfunction $pyfunction_args:tt])?
+ $(#[$meta:meta])*
+ fn $name:ident(inputs: $inputs:ty) -> $result:ty;
+ )*
+ ) => {
+ $(
+ {
+ #[pyfunction $($pyfunction_args)?]
+ #[text_signature = "(inputs)"]
+ $(#[$meta])*
+ fn $name(inputs: $inputs) -> $result {
+ $crate::instr_models::$name(inputs)
+ }
+
+ $m.add_wrapped(wrap_pyfunction!($name))?;
+ }
+ )*
+ };
+}
+
+#[pymodule]
+fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
+ wrap_type! {
+ #[pymodule(m)]
+ #[pyclass(name = OverflowFlags)]
+ #[wrapped(value: OverflowFlags)]
+ #[text_signature = "(overflow, overflow32)"]
+ struct PyOverflowFlags {
+ #[set = set_overflow]
+ overflow: bool,
+ #[set = set_overflow32]
+ overflow32: bool,
+ }
+ }
+
+ wrap_type! {
+ #[pymodule(m)]
+ #[pyclass(name = DivInput)]
+ #[wrapped(value: DivInput)]
+ #[text_signature = "(dividend, divisor, result_prev)"]
+ struct PyDivInput {
+ #[set = set_dividend]
+ dividend: u64,
+ #[set = set_divisor]
+ divisor: u64,
+ #[set = set_result_prev]
+ result_prev: u64,
+ }
+ }
+
+ wrap_type! {
+ #[pymodule(m)]
+ #[pyclass(name = DivResult)]
+ #[wrapped(value: DivResult)]
+ #[text_signature = "(result, overflow)"]
+ struct PyDivResult {
+ #[set = set_result]
+ result: u64,
+ #[set = set_overflow]
+ overflow: Option<OverflowFlags>,
+ }
+ }
+ wrap_instr_fns! {
+ #![pymodule(m)]
+
+ fn divdeo(inputs: DivInput) -> DivResult;
+ fn divdeuo(inputs: DivInput) -> DivResult;
+ fn divdo(inputs: DivInput) -> DivResult;
+ fn divduo(inputs: DivInput) -> DivResult;
+ fn divweo(inputs: DivInput) -> DivResult;
+ fn divweuo(inputs: DivInput) -> DivResult;
+ fn divwo(inputs: DivInput) -> DivResult;
+ fn divwuo(inputs: DivInput) -> DivResult;
+ fn modsd(inputs: DivInput) -> DivResult;
+ fn modud(inputs: DivInput) -> DivResult;
+ fn modsw(inputs: DivInput) -> DivResult;
+ fn moduw(inputs: DivInput) -> DivResult;
+ }
+ Ok(())
+}
// SPDX-License-Identifier: LGPL-2.1-or-later
// See Notices.txt for copyright information
-use serde::{Deserialize, Deserializer, Serializer};
+use serde::{de, Deserialize, Deserializer, Serializer};
pub(crate) trait SerdeHex {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
Self: Sized;
}
-impl SerdeHex for u64 {
- fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
- serializer.serialize_str(&format!("{:#X}", self))
- }
- fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
- let _text: &str = Deserialize::deserialize(deserializer)?;
- todo!("parse text as 0x<HEXDIGITS>")
- }
+macro_rules! impl_hex_for_uint {
+ ($ty:ty) => {
+ impl SerdeHex for $ty {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ serializer.serialize_str(&format!("{:#X}", self))
+ }
+ fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
+ let text: &str = Deserialize::deserialize(deserializer)?;
+ const PREFIX: &str = "0x";
+ if text.starts_with(PREFIX) {
+ let hex_digits = &text[PREFIX.len()..];
+ Self::from_str_radix(hex_digits, 16).map_err(de::Error::custom)
+ } else {
+ Err(de::Error::custom("hexadecimal field must start with 0x"))
+ }
+ }
+ }
+ };
}
+
+impl_hex_for_uint!(u8);
+impl_hex_for_uint!(u16);
+impl_hex_for_uint!(u32);
+impl_hex_for_uint!(u64);
+impl_hex_for_uint!(u128);
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# See Notices.txt for copyright information
+
+import unittest
+import power_instruction_analyzer as pia
+
+
+class TestOverflowFlags(unittest.TestCase):
+ def test_text_signature(self):
+ self.assertEqual(pia.OverflowFlags.__text_signature__,
+ "(overflow, overflow32)")
+
+ def test_fields(self):
+ v = pia.OverflowFlags(overflow=False, overflow32=True)
+ self.assertEqual(v.overflow, False)
+ self.assertEqual(v.overflow32, True)
+ v.overflow = True
+ self.assertEqual(v.overflow, True)
+ v.overflow32 = False
+ self.assertEqual(v.overflow32, False)
+
+ def test_str_repr(self):
+ v = pia.OverflowFlags(overflow=False, overflow32=True)
+ self.assertEqual(str(v),
+ '{"overflow":false,"overflow32":true}')
+ self.assertEqual(repr(v),
+ "OverflowFlags(overflow=False, overflow32=True)")
+
+
+class TestDivInput(unittest.TestCase):
+ def test_text_signature(self):
+ self.assertEqual(pia.DivInput.__text_signature__,
+ "(dividend, divisor, result_prev)")
+
+ def test_fields(self):
+ v = pia.DivInput(dividend=123, divisor=456, result_prev=789)
+ self.assertEqual(v.dividend, 123)
+ self.assertEqual(v.divisor, 456)
+ self.assertEqual(v.result_prev, 789)
+ v.dividend = 1234
+ self.assertEqual(v.dividend, 1234)
+ v.divisor = 4567
+ self.assertEqual(v.divisor, 4567)
+ v.result_prev = 7890
+ self.assertEqual(v.result_prev, 7890)
+
+ def test_str_repr(self):
+ v = pia.DivInput(dividend=123, divisor=456, result_prev=789)
+ self.assertEqual(str(v),
+ '{"dividend":"0x7B","divisor":"0x1C8","result_prev":"0x315"}')
+ self.assertEqual(repr(v),
+ "DivInput(dividend=123, divisor=456, result_prev=789)")
+
+
+class TestDivResult(unittest.TestCase):
+ def test_text_signature(self):
+ self.assertEqual(pia.DivResult.__text_signature__,
+ "(result, overflow)")
+
+ def test_fields(self):
+ v = pia.DivResult(result=1234,
+ overflow=pia.OverflowFlags(overflow=False, overflow32=True))
+ self.assertEqual(v.result, 1234)
+ self.assertIsNotNone(v.overflow)
+ self.assertEqual(v.overflow.overflow, False)
+ self.assertEqual(v.overflow.overflow32, True)
+ v.result = 123
+ self.assertEqual(v.result, 123)
+ v.overflow = None
+ self.assertIsNone(v.overflow)
+
+ def test_str_repr(self):
+ v = pia.DivResult(result=1234,
+ overflow=pia.OverflowFlags(overflow=False, overflow32=True))
+ self.assertEqual(str(v),
+ '{"result":"0x4D2","overflow":false,"overflow32":true}')
+ self.assertEqual(repr(v),
+ "DivResult(result=1234, overflow=OverflowFlags(overflow=False, overflow32=True))")
+
+
+class TestDivInstrs(unittest.TestCase):
+ cases = [
+ ("divdeo", '{"result":"0x0","overflow":true,"overflow32":true}'),
+ ("divdeuo", '{"result":"0x0","overflow":true,"overflow32":true}'),
+ ("divdo", '{"result":"0x36","overflow":false,"overflow32":false}'),
+ ("divduo", '{"result":"0x36","overflow":false,"overflow32":false}'),
+ ("divweo", '{"result":"0x0","overflow":true,"overflow32":true}'),
+ ("divweuo", '{"result":"0x0","overflow":true,"overflow32":true}'),
+ ("divwo", '{"result":"0x36","overflow":false,"overflow32":false}'),
+ ("divwuo", '{"result":"0x36","overflow":false,"overflow32":false}'),
+ ("modsd", '{"result":"0x10"}'),
+ ("modud", '{"result":"0x10"}'),
+ ("modsw", '{"result":"0x10"}'),
+ ("moduw", '{"result":"0x10"}'),
+ ]
+
+ def test(self):
+ v = pia.DivInput(dividend=0x1234, divisor=0x56, result_prev=0x789)
+ for fn_name, expected in self.cases:
+ with self.subTest(fn_name=fn_name):
+ fn = getattr(pia, fn_name)
+ results = fn(v)
+ self.assertEqual(str(results), expected)
+
+
+if __name__ == "__main__":
+ unittest.main()