1use crate::{read_u64, write_u64};
11
12pub(crate) const BINARY_U64_CASES: &[(u64, u64)] = &[
16 (0, 0),
17 (1, 2),
18 (1, 1),
19 (u64::MAX, 1),
20 (u64::MAX, u64::MAX),
21 (0xDEAD_BEEF_DEAD_BEEF, 0x0123_4567_89AB_CDEF),
22 (0x8000_0000_0000_0000, 0x8000_0000_0000_0000),
23];
24
25pub(crate) const DIV_U64_CASES: &[(u64, u64)] = &[
28 (10, 3),
29 (u64::MAX, 1),
30 (u64::MAX, 2),
31 (100, 0),
32 (0, 7),
33 (i64::MIN as u64, (-1i64) as u64),
34];
35
36pub(crate) fn run_binary_u64(cases: &[(u64, u64)], op: fn(&[u8], &mut [u8]) -> usize) -> u64 {
38 let mut acc = 0u64;
39 let mut input = [0u8; 16];
40 let mut output = [0u8; 8];
41 for (a, b) in cases {
42 input[0..8].copy_from_slice(&a.to_le_bytes());
43 input[8..16].copy_from_slice(&b.to_le_bytes());
44 let len = op(&input, &mut output);
45 debug_assert!(len == 8);
46 acc ^= u64::from_le_bytes(output);
47 }
48 acc
49}
50
51pub fn add_u64(input: &[u8], output: &mut [u8]) -> usize {
54 let (mut off, mut out) = (0, 0);
55 let a = read_u64(input, &mut off);
56 let b = read_u64(input, &mut off);
57 write_u64(output, &mut out, a.wrapping_add(b));
58 out
59}
60
61pub fn sub_u64(input: &[u8], output: &mut [u8]) -> usize {
62 let (mut off, mut out) = (0, 0);
63 let a = read_u64(input, &mut off);
64 let b = read_u64(input, &mut off);
65 write_u64(output, &mut out, a.wrapping_sub(b));
66 out
67}
68
69pub fn mul_u64(input: &[u8], output: &mut [u8]) -> usize {
70 let (mut off, mut out) = (0, 0);
71 let a = read_u64(input, &mut off);
72 let b = read_u64(input, &mut off);
73 write_u64(output, &mut out, a.wrapping_mul(b));
74 out
75}
76
77pub fn mul_upper_uu(input: &[u8], output: &mut [u8]) -> usize {
78 let (mut off, mut out) = (0, 0);
79 let a = read_u64(input, &mut off);
80 let b = read_u64(input, &mut off);
81 let hi = ((a as u128).wrapping_mul(b as u128) >> 64) as u64;
82 write_u64(output, &mut out, hi);
83 out
84}
85
86pub fn mul_upper_ss(input: &[u8], output: &mut [u8]) -> usize {
87 let (mut off, mut out) = (0, 0);
88 let a = read_u64(input, &mut off) as i64;
89 let b = read_u64(input, &mut off) as i64;
90 let hi = ((a as i128).wrapping_mul(b as i128) >> 64) as u64;
91 write_u64(output, &mut out, hi);
92 out
93}
94
95pub fn div_u64(input: &[u8], output: &mut [u8]) -> usize {
96 let (mut off, mut out) = (0, 0);
97 let a = read_u64(input, &mut off);
98 let b = read_u64(input, &mut off);
99 let result = a.checked_div(b).unwrap_or(u64::MAX);
100 write_u64(output, &mut out, result);
101 out
102}
103
104pub fn rem_u64(input: &[u8], output: &mut [u8]) -> usize {
105 let (mut off, mut out) = (0, 0);
106 let a = read_u64(input, &mut off);
107 let b = read_u64(input, &mut off);
108 let result = if b == 0 { a } else { a % b };
109 write_u64(output, &mut out, result);
110 out
111}
112
113pub fn div_s64(input: &[u8], output: &mut [u8]) -> usize {
114 let (mut off, mut out) = (0, 0);
115 let a = read_u64(input, &mut off) as i64;
116 let b = read_u64(input, &mut off) as i64;
117 let result = if b == 0 {
118 -1i64 as u64
119 } else if a == i64::MIN && b == -1 {
120 a as u64 } else {
122 (a / b) as u64
123 };
124 write_u64(output, &mut out, result);
125 out
126}
127
128pub fn rem_s64(input: &[u8], output: &mut [u8]) -> usize {
129 let (mut off, mut out) = (0, 0);
130 let a = read_u64(input, &mut off) as i64;
131 let b = read_u64(input, &mut off) as i64;
132 let result = if b == 0 {
133 a as u64
134 } else if a == i64::MIN && b == -1 {
135 0u64
136 } else {
137 (a % b) as u64
138 };
139 write_u64(output, &mut out, result);
140 out
141}
142
143pub fn add_u64_suite() -> u64 {
146 run_binary_u64(BINARY_U64_CASES, add_u64)
147}
148pub fn sub_u64_suite() -> u64 {
149 run_binary_u64(BINARY_U64_CASES, sub_u64)
150}
151pub fn mul_u64_suite() -> u64 {
152 run_binary_u64(BINARY_U64_CASES, mul_u64)
153}
154pub fn mul_upper_uu_suite() -> u64 {
155 run_binary_u64(BINARY_U64_CASES, mul_upper_uu)
156}
157pub fn mul_upper_ss_suite() -> u64 {
158 run_binary_u64(BINARY_U64_CASES, mul_upper_ss)
159}
160pub fn div_u64_suite() -> u64 {
161 run_binary_u64(DIV_U64_CASES, div_u64)
162}
163pub fn rem_u64_suite() -> u64 {
164 run_binary_u64(DIV_U64_CASES, rem_u64)
165}
166pub fn div_s64_suite() -> u64 {
167 run_binary_u64(DIV_U64_CASES, div_s64)
168}
169pub fn rem_s64_suite() -> u64 {
170 run_binary_u64(DIV_U64_CASES, rem_s64)
171}