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))]
9 use serde::{Deserialize, Serialize};
11 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
12 pub struct OverflowFlags {
18 pub fn from_xer(xer: u64) -> Self {
20 overflow: (xer & 0x4000_0000) != 0,
21 overflow32: (xer & 0x8_0000) != 0,
26 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
27 pub struct TestDivResult {
28 #[serde(with = "serde_hex::SerdeHex")]
30 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
31 pub overflow: Option<OverflowFlags>,
34 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
35 pub struct TestDivInput {
36 #[serde(with = "serde_hex::SerdeHex")]
38 #[serde(with = "serde_hex::SerdeHex")]
40 #[serde(with = "serde_hex::SerdeHex")]
44 fn is_false(v: &bool) -> bool {
48 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
49 pub struct TestDivCase {
50 pub instr: TestDivInstr,
52 pub inputs: TestDivInput,
53 #[serde(default, skip_serializing_if = "Option::is_none")]
54 pub native_outputs: Option<TestDivResult>,
55 pub model_outputs: TestDivResult,
56 #[serde(default, skip_serializing_if = "is_false")]
57 pub model_mismatch: bool,
60 #[derive(Clone, Debug, Serialize, Deserialize)]
61 pub struct WholeTest {
62 #[serde(default, skip_serializing_if = "Vec::is_empty")]
63 pub test_div_cases: Vec<TestDivCase>,
64 pub any_model_mismatch: bool,
67 macro_rules! make_div_functions {
71 $($div_enum:ident = $div_fn:ident ($div_instr:literal),)+
75 $($rem_enum:ident = $rem_fn:ident ($rem_instr:literal),)+
78 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
79 pub enum TestDivInstr {
81 #[serde(rename = $div_instr)]
85 #[serde(rename = $rem_instr)]
91 #[cfg(feature = "native_instrs")]
92 pub fn get_native_fn(self) -> fn(TestDivInput) -> TestDivResult {
95 Self::$div_enum => native_instrs::$div_fn,
98 Self::$rem_enum => native_instrs::$rem_fn,
102 pub fn get_model_fn(self) -> fn(TestDivInput) -> TestDivResult {
105 Self::$div_enum => instr_models::$div_fn,
108 Self::$rem_enum => instr_models::$rem_fn,
112 pub fn name(self) -> &'static str {
115 Self::$div_enum => $div_instr,
118 Self::$rem_enum => $rem_instr,
122 pub const VALUES: &'static [Self] = &[
132 #[cfg(feature = "native_instrs")]
137 pub fn $div_fn(inputs: TestDivInput) -> TestDivResult {
152 : "=&r"(result), "=&r"(xer)
153 : "0"(result_prev), "r"(dividend), "r"(divisor)
158 overflow: Some(OverflowFlags::from_xer(xer)),
163 pub fn $rem_fn(inputs: TestDivInput) -> TestDivResult {
177 : "0"(result_prev), "r"(dividend), "r"(divisor));
189 make_div_functions! {
192 DivDEO = divdeo("divdeo"),
193 DivDEUO = divdeuo("divdeuo"),
194 DivDO = divdo("divdo"),
195 DivDUO = divduo("divduo"),
196 DivWEO = divweo("divweo"),
197 DivWEUO = divweuo("divweuo"),
198 DivWO = divwo("divwo"),
199 DivWUO = divwuo("divwuo"),
203 ModSD = modsd("modsd"),
204 ModUD = modud("modud"),
205 ModSW = modsw("modsw"),
206 ModUW = moduw("moduw"),
210 const TEST_VALUES: &[u64] = &[
214 0xFFFF_FFFF_FFFF_FFFF,
215 0xFFFF_FFFF_FFFF_FFFE,
216 0x7FFF_FFFF_FFFF_FFFF,
217 0x8000_0000_0000_0000,
218 0x1234_5678_0000_0000,
219 0x1234_5678_8000_0000,
220 0x1234_5678_FFFF_FFFF,
221 0x1234_5678_7FFF_FFFF,
225 let mut test_div_cases = Vec::new();
226 let mut any_model_mismatch = false;
227 for &instr in TestDivInstr::VALUES {
228 for ÷nd in TEST_VALUES {
229 for &divisor in TEST_VALUES {
230 let inputs = TestDivInput {
233 result_prev: 0xFECD_BA98_7654_3210,
235 let model_outputs = instr.get_model_fn()(inputs);
236 #[cfg(feature = "native_instrs")]
237 let native_outputs = Some(instr.get_native_fn()(inputs));
238 #[cfg(not(feature = "native_instrs"))]
239 let native_outputs = None;
240 let model_mismatch = match native_outputs {
241 Some(native_outputs) if native_outputs != model_outputs => true,
244 any_model_mismatch |= model_mismatch;
245 test_div_cases.push(TestDivCase {
255 let whole_test = WholeTest {
259 serde_json::to_writer_pretty(std::io::stdout().lock(), &whole_test).unwrap();