Skip to content

Commit 8fe50d8

Browse files
committed
Macro-ify udivmod
1 parent 1e27c3f commit 8fe50d8

File tree

3 files changed

+154
-132
lines changed

3 files changed

+154
-132
lines changed

src/int/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
macro_rules! hty {
2+
($ty:ty) => {
3+
<$ty as LargeInt>::HighHalf
4+
}
5+
}
6+
7+
macro_rules! os_ty {
8+
($ty:ty) => {
9+
<$ty as Int>::OtherSign
10+
}
11+
}
112

213
pub mod mul;
314
pub mod sdiv;
@@ -6,18 +17,22 @@ pub mod udiv;
617

718
/// Trait for some basic operations on integers
819
pub trait Int {
20+
/// Type with the same width but other signedness
21+
type OtherSign;
922
/// Returns the bitwidth of the int type
1023
fn bits() -> u32;
1124
}
1225

1326
macro_rules! int_impl {
1427
($ity:ty, $sty:ty, $bits:expr) => {
1528
impl Int for $ity {
29+
type OtherSign = $sty;
1630
fn bits() -> u32 {
1731
$bits
1832
}
1933
}
2034
impl Int for $sty {
35+
type OtherSign = $ity;
2136
fn bits() -> u32 {
2237
$bits
2338
}

src/int/mul.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use int::LargeInt;
22
use int::Int;
33

44
macro_rules! mul {
5-
($intrinsic:ident: $ty:ty, $tyh:ty) => {
5+
($intrinsic:ident: $ty:ty) => {
66
/// Returns `a * b`
77
#[cfg_attr(not(test), no_mangle)]
88
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
@@ -13,15 +13,15 @@ macro_rules! mul {
1313
low &= lower_mask;
1414
t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask);
1515
low += (t & lower_mask) << half_bits;
16-
let mut high = (t >> half_bits) as $tyh;
16+
let mut high = (t >> half_bits) as hty!($ty);
1717
t = low >> half_bits;
1818
low &= lower_mask;
1919
t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask);
2020
low += (t & lower_mask) << half_bits;
21-
high += (t >> half_bits) as $tyh;
22-
high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as $tyh;
23-
high = high.wrapping_add(a.high().wrapping_mul(b.low() as $tyh))
24-
.wrapping_add((a.low() as $tyh).wrapping_mul(b.high()));
21+
high += (t >> half_bits) as hty!($ty);
22+
high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as hty!($ty);
23+
high = high.wrapping_add(a.high().wrapping_mul(b.low() as hty!($ty)))
24+
.wrapping_add((a.low() as hty!($ty)).wrapping_mul(b.high()));
2525
<$ty>::from_parts(low, high)
2626
}
2727
}
@@ -73,9 +73,9 @@ macro_rules! mulo {
7373
}
7474

7575
#[cfg(not(all(feature = "c", target_arch = "x86")))]
76-
mul!(__muldi3: u64, u32);
76+
mul!(__muldi3: u64);
7777

78-
mul!(__multi3: i128, i64);
78+
mul!(__multi3: i128);
7979

8080
mulo!(__mulosi4: i32);
8181
mulo!(__mulodi4: i64);

src/int/udiv.rs

Lines changed: 131 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -114,152 +114,159 @@ pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 {
114114
rem
115115
}
116116

117-
/// Returns `n / d` and sets `*rem = n % d`
118-
#[cfg_attr(not(test), no_mangle)]
119-
pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
120-
// NOTE X is unknown, K != 0
121-
if n.high() == 0 {
122-
if d.high() == 0 {
123-
// 0 X
124-
// ---
125-
// 0 X
117+
macro_rules! udivmod_inner {
118+
($n:expr, $d:expr, $rem:expr, $ty:ty) => {{
119+
let (n, d, rem) = ($n, $d, $rem);
120+
// NOTE X is unknown, K != 0
121+
if n.high() == 0 {
122+
if d.high() == 0 {
123+
// 0 X
124+
// ---
125+
// 0 X
126+
127+
if let Some(rem) = rem {
128+
*rem = <$ty>::from(urem!(n.low(), d.low()));
129+
}
130+
return <$ty>::from(udiv!(n.low(), d.low()));
131+
} else {
132+
// 0 X
133+
// ---
134+
// K X
135+
if let Some(rem) = rem {
136+
*rem = n;
137+
}
138+
return 0;
139+
};
140+
}
126141

127-
if let Some(rem) = rem {
128-
*rem = u64::from(urem!(n.low(), d.low()));
142+
let mut sr;
143+
let mut q;
144+
let mut r;
145+
146+
if d.low() == 0 {
147+
if d.high() == 0 {
148+
// K X
149+
// ---
150+
// 0 0
151+
// NOTE This should be unreachable in safe Rust because the program will panic before
152+
// this intrinsic is called
153+
unsafe {
154+
intrinsics::abort()
155+
}
129156
}
130-
return u64::from(udiv!(n.low(), d.low()));
131-
} else {
132-
// 0 X
133-
// ---
134-
// K X
135-
if let Some(rem) = rem {
136-
*rem = n;
137-
}
138-
return 0;
139-
};
140-
}
141-
142-
let mut sr;
143-
let mut q;
144-
let mut r;
145157

146-
if d.low() == 0 {
147-
if d.high() == 0 {
148-
// K X
149-
// ---
150-
// 0 0
151-
// NOTE This should be unreachable in safe Rust because the program will panic before
152-
// this intrinsic is called
153-
unsafe {
154-
intrinsics::abort()
158+
if n.low() == 0 {
159+
// K 0
160+
// ---
161+
// K 0
162+
if let Some(rem) = rem {
163+
*rem = <$ty>::from_parts(0, urem!(n.high(), d.high()));
164+
}
165+
return <$ty>::from(udiv!(n.high(), d.high()));
155166
}
156-
}
157167

158-
if n.low() == 0 {
159-
// K 0
168+
// K K
160169
// ---
161170
// K 0
162-
if let Some(rem) = rem {
163-
*rem = u64::from_parts(0, urem!(n.high(), d.high()));
171+
172+
if d.high().is_power_of_two() {
173+
if let Some(rem) = rem {
174+
*rem = <$ty>::from_parts(n.low(), n.high() & (d.high() - 1));
175+
}
176+
return <$ty>::from(n.high() >> d.high().trailing_zeros());
164177
}
165-
return u64::from(udiv!(n.high(), d.high()));
166-
}
167178

168-
// K K
169-
// ---
170-
// K 0
179+
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
171180

172-
if d.high().is_power_of_two() {
173-
if let Some(rem) = rem {
174-
*rem = u64::from_parts(n.low(), n.high() & (d.high() - 1));
181+
// D > N
182+
if sr > <hty!($ty)>::bits() - 2 {
183+
if let Some(rem) = rem {
184+
*rem = n;
185+
}
186+
return 0;
175187
}
176-
return u64::from(n.high() >> d.high().trailing_zeros());
177-
}
178188

179-
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
189+
sr += 1;
180190

181-
// D > N
182-
if sr > u32::bits() - 2 {
183-
if let Some(rem) = rem {
184-
*rem = n;
191+
// 1 <= sr <= <hty!($ty)>::bits() - 1
192+
q = n << (<$ty>::bits() - sr);
193+
r = n >> sr;
194+
} else if d.high() == 0 {
195+
// K X
196+
// ---
197+
// 0 K
198+
if d.low().is_power_of_two() {
199+
if let Some(rem) = rem {
200+
*rem = <$ty>::from(n.low() & (d.low() - 1));
201+
}
202+
203+
if d.low() == 1 {
204+
return n;
205+
} else {
206+
let sr = d.low().trailing_zeros();
207+
return n >> sr;
208+
};
185209
}
186-
return 0;
187-
}
188210

189-
sr += 1;
190-
191-
// 1 <= sr <= u32::bits() - 1
192-
q = n << (u64::bits() - sr);
193-
r = n >> sr;
194-
} else if d.high() == 0 {
195-
// K X
196-
// ---
197-
// 0 K
198-
if d.low().is_power_of_two() {
199-
if let Some(rem) = rem {
200-
*rem = u64::from(n.low() & (d.low() - 1));
201-
}
211+
sr = 1 + <hty!($ty)>::bits() + d.low().leading_zeros() - n.high().leading_zeros();
202212

203-
if d.low() == 1 {
204-
return n;
205-
} else {
206-
let sr = d.low().trailing_zeros();
207-
return n >> sr;
208-
};
209-
}
210-
211-
sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros();
212-
213-
// 2 <= sr <= u64::bits() - 1
214-
q = n << (u64::bits() - sr);
215-
r = n >> sr;
216-
} else {
217-
// K X
218-
// ---
219-
// K K
220-
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
221-
222-
// D > N
223-
if sr > u32::bits() - 1 {
224-
if let Some(rem) = rem {
225-
*rem = n;
213+
// 2 <= sr <= u64::bits() - 1
214+
q = n << (<$ty>::bits() - sr);
215+
r = n >> sr;
216+
} else {
217+
// K X
218+
// ---
219+
// K K
220+
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
221+
222+
// D > N
223+
if sr > <hty!($ty)>::bits() - 1 {
224+
if let Some(rem) = rem {
225+
*rem = n;
226+
}
227+
return 0;
226228
}
227-
return 0;
228-
}
229229

230-
sr += 1;
230+
sr += 1;
231231

232-
// 1 <= sr <= u32::bits()
233-
q = n << (u64::bits() - sr);
234-
r = n >> sr;
235-
}
236-
237-
// Not a special case
238-
// q and r are initialized with
239-
// q = n << (u64::bits() - sr)
240-
// r = n >> sr
241-
// 1 <= sr <= u64::bits() - 1
242-
let mut carry = 0;
232+
// 1 <= sr <= <hty!($ty)>::bits()
233+
q = n << (<$ty>::bits() - sr);
234+
r = n >> sr;
235+
}
243236

244-
for _ in 0..sr {
245-
// r:q = ((r:q) << 1) | carry
246-
r = (r << 1) | (q >> (u64::bits() - 1));
247-
q = (q << 1) | carry as u64;
237+
// Not a special case
238+
// q and r are initialized with
239+
// q = n << (u64::bits() - sr)
240+
// r = n >> sr
241+
// 1 <= sr <= u64::bits() - 1
242+
let mut carry = 0;
243+
244+
for _ in 0..sr {
245+
// r:q = ((r:q) << 1) | carry
246+
r = (r << 1) | (q >> (<$ty>::bits() - 1));
247+
q = (q << 1) | carry as $ty;
248+
249+
// carry = 0
250+
// if r >= d {
251+
// r -= d;
252+
// carry = 1;
253+
// }
254+
let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::bits() - 1);
255+
carry = (s & 1) as hty!($ty);
256+
r -= d & s as $ty;
257+
}
248258

249-
// carry = 0
250-
// if r >= d {
251-
// r -= d;
252-
// carry = 1;
253-
// }
254-
let s = (d.wrapping_sub(r).wrapping_sub(1)) as i64 >> (u64::bits() - 1);
255-
carry = (s & 1) as u32;
256-
r -= d & s as u64;
257-
}
259+
if let Some(rem) = rem {
260+
*rem = r;
261+
}
262+
(q << 1) | carry as $ty
263+
}}
264+
}
258265

259-
if let Some(rem) = rem {
260-
*rem = r;
261-
}
262-
(q << 1) | carry as u64
266+
/// Returns `n / d` and sets `*rem = n % d`
267+
#[cfg_attr(not(test), no_mangle)]
268+
pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
269+
udivmod_inner!(n, d, rem, u64)
263270
}
264271

265272
#[cfg(test)]

0 commit comments

Comments
 (0)