change loop order
[power-instruction-analyzer.git] / src / main.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
3
4 #![feature(llvm_asm)]
5 use std::fmt;
6
7 #[derive(Copy, Clone, Debug)]
8 struct OverflowFlags {
9 overflow: bool,
10 overflow32: bool,
11 }
12
13 impl OverflowFlags {
14 fn from_xer(xer: u64) -> Self {
15 Self {
16 overflow: (xer & 0x4000_0000) != 0,
17 overflow32: (xer & 0x8_0000) != 0,
18 }
19 }
20 }
21
22 impl fmt::Display for OverflowFlags {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 let Self {
25 overflow,
26 overflow32,
27 } = *self;
28 write!(
29 f,
30 "OV:{overflow}, OV32:{overflow32}",
31 overflow = overflow as i32,
32 overflow32 = overflow32 as i32,
33 )
34 }
35 }
36
37 #[derive(Copy, Clone, Debug)]
38 struct TestDivResult {
39 result: u64,
40 overflow: Option<OverflowFlags>,
41 }
42
43 impl fmt::Display for TestDivResult {
44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 let Self { result, overflow } = *self;
46 write!(f, "{:#X}", result)?;
47 if let Some(overflow) = overflow {
48 write!(f, ", {}", overflow)?;
49 }
50 Ok(())
51 }
52 }
53
54 #[derive(Copy, Clone, Debug)]
55 struct TestDivInput {
56 dividend: u64,
57 divisor: u64,
58 result_prev: u64,
59 }
60
61 impl fmt::Display for TestDivInput {
62 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63 let Self {
64 dividend,
65 divisor,
66 result_prev,
67 } = *self;
68 write!(
69 f,
70 "{:#X} div {:#X} (result_prev:{:#X})",
71 dividend, divisor, result_prev,
72 )
73 }
74 }
75
76 macro_rules! make_div_functions {
77 (
78 #[div]
79 {
80 $($div_name:ident;)+
81 }
82 #[rem]
83 {
84 $($rem_name:ident;)+
85 }
86 ) => {
87 impl TestDivInput {
88 $(
89 #[inline(never)]
90 pub fn $div_name(self) -> TestDivResult {
91 let Self {
92 dividend,
93 divisor,
94 result_prev,
95 } = self;
96 let result: u64;
97 let xer: u64;
98 unsafe {
99 llvm_asm!(
100 concat!(
101 stringify!($div_name),
102 " $0, $3, $4\n",
103 "mfxer $1"
104 )
105 : "=&r"(result), "=&r"(xer)
106 : "0"(result_prev), "r"(dividend), "r"(divisor)
107 : "xer");
108 }
109 TestDivResult {
110 result,
111 overflow: Some(OverflowFlags::from_xer(xer)),
112 }
113 }
114 )+
115 $(
116 #[inline(never)]
117 pub fn $rem_name(self) -> TestDivResult {
118 let Self {
119 dividend,
120 divisor,
121 result_prev,
122 } = self;
123 let result: u64;
124 unsafe {
125 llvm_asm!(
126 concat!(
127 stringify!($rem_name),
128 " $0, $2, $3"
129 )
130 : "=&r"(result)
131 : "0"(result_prev), "r"(dividend), "r"(divisor));
132 }
133 TestDivResult {
134 result,
135 overflow: None,
136 }
137 }
138 )+
139 pub const FUNCTIONS: &'static [(fn(TestDivInput) -> TestDivResult, &'static str)] = &[
140 $((Self::$div_name, stringify!($div_name)),)+
141 $((Self::$rem_name, stringify!($rem_name)),)+
142 ];
143 }
144 };
145 }
146
147 make_div_functions! {
148 #[div]
149 {divdeo; divdeuo; divdo; divduo; divweo; divweuo; divwo; divwuo;}
150 #[rem]
151 {modsd; modud; modsw; moduw;}
152 }
153
154 const TEST_VALUES: &[u64] = &[
155 0x0,
156 0xFFFF_FFFF_FFFF_FFFF,
157 0x7FFF_FFFF_FFFF_FFFF,
158 0x8000_0000_0000_0000,
159 0x1234_5678_0000_0000,
160 0x1234_5678_8000_0000,
161 0x1234_5678_FFFF_FFFF,
162 0x1234_5678_7FFF_FFFF,
163 ];
164
165 fn main() {
166 for &(f, name) in TestDivInput::FUNCTIONS {
167 for &dividend in TEST_VALUES {
168 for &divisor in TEST_VALUES {
169 let inputs = TestDivInput {
170 dividend,
171 divisor,
172 result_prev: 0xFECD_BA98_7654_3210,
173 };
174 let outputs = f(inputs);
175 println!("{}: {} -> {}", name, inputs, outputs);
176 }
177 }
178 }
179 }