|
@@ -18,8 +18,6 @@ pub mod arm;
|
|
#[cfg(test)]
|
|
#[cfg(test)]
|
|
mod test;
|
|
mod test;
|
|
|
|
|
|
-use core::mem;
|
|
|
|
-
|
|
|
|
/// Trait for some basic operations on integers
|
|
/// Trait for some basic operations on integers
|
|
trait Int {
|
|
trait Int {
|
|
fn bits() -> usize;
|
|
fn bits() -> usize;
|
|
@@ -27,16 +25,24 @@ trait Int {
|
|
|
|
|
|
// TODO: Once i128/u128 support lands, we'll want to add impls for those as well
|
|
// TODO: Once i128/u128 support lands, we'll want to add impls for those as well
|
|
impl Int for u32 {
|
|
impl Int for u32 {
|
|
- fn bits() -> usize { 32 }
|
|
|
|
|
|
+ fn bits() -> usize {
|
|
|
|
+ 32
|
|
|
|
+ }
|
|
}
|
|
}
|
|
impl Int for i32 {
|
|
impl Int for i32 {
|
|
- fn bits() -> usize { 32 }
|
|
|
|
|
|
+ fn bits() -> usize {
|
|
|
|
+ 32
|
|
|
|
+ }
|
|
}
|
|
}
|
|
impl Int for u64 {
|
|
impl Int for u64 {
|
|
- fn bits() -> usize { 64 }
|
|
|
|
|
|
+ fn bits() -> usize {
|
|
|
|
+ 64
|
|
|
|
+ }
|
|
}
|
|
}
|
|
impl Int for i64 {
|
|
impl Int for i64 {
|
|
- fn bits() -> usize { 64 }
|
|
|
|
|
|
+ fn bits() -> usize {
|
|
|
|
+ 64
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/// Trait to convert an integer to/from smaller parts
|
|
/// Trait to convert an integer to/from smaller parts
|
|
@@ -99,131 +105,124 @@ absv_i2!(__absvdi2: i64);
|
|
// TODO(rust-lang/35118)?
|
|
// TODO(rust-lang/35118)?
|
|
// absv_i2!(__absvti2, i128);
|
|
// absv_i2!(__absvti2, i128);
|
|
|
|
|
|
|
|
+/// Return `n / d` and `*rem = n % d`
|
|
#[no_mangle]
|
|
#[no_mangle]
|
|
-pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 {
|
|
|
|
|
|
+pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
|
|
|
+ use core::ops::{Index, IndexMut, RangeFull};
|
|
|
|
+
|
|
#[cfg(target_endian = "little")]
|
|
#[cfg(target_endian = "little")]
|
|
#[repr(C)]
|
|
#[repr(C)]
|
|
- #[derive(Debug)]
|
|
|
|
- struct words {
|
|
|
|
|
|
+ struct U64 {
|
|
low: u32,
|
|
low: u32,
|
|
high: u32,
|
|
high: u32,
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(target_endian = "big")]
|
|
#[cfg(target_endian = "big")]
|
|
#[repr(C)]
|
|
#[repr(C)]
|
|
- #[derive(Debug)]
|
|
|
|
- struct words {
|
|
|
|
|
|
+ struct U64 {
|
|
high: u32,
|
|
high: u32,
|
|
low: u32,
|
|
low: u32,
|
|
}
|
|
}
|
|
|
|
|
|
- impl words {
|
|
|
|
- fn all(&mut self) -> &mut u64 {
|
|
|
|
- unsafe { mem::transmute(self) }
|
|
|
|
- }
|
|
|
|
|
|
+ impl Index<RangeFull> for U64 {
|
|
|
|
+ type Output = u64;
|
|
|
|
|
|
- fn u64(&self) -> u64 {
|
|
|
|
- unsafe { *(self as *const _ as *const u64) }
|
|
|
|
|
|
+ fn index(&self, _: RangeFull) -> &u64 {
|
|
|
|
+ unsafe { &*(self as *const _ as *const u64) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- impl From<u64> for words {
|
|
|
|
- fn from(x: u64) -> words {
|
|
|
|
- unsafe { mem::transmute(x) }
|
|
|
|
|
|
+ impl IndexMut<RangeFull> for U64 {
|
|
|
|
+ fn index_mut(&mut self, _: RangeFull) -> &mut u64 {
|
|
|
|
+ unsafe { &mut *(self as *const _ as *mut u64) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
let u32_bits = u32::bits() as u32;
|
|
let u32_bits = u32::bits() as u32;
|
|
let u64_bits = u64::bits() as u32;
|
|
let u64_bits = u64::bits() as u32;
|
|
|
|
|
|
- let n = words::from(a);
|
|
|
|
- let d = words::from(b);
|
|
|
|
-
|
|
|
|
// NOTE X is unknown, K != 0
|
|
// NOTE X is unknown, K != 0
|
|
- if n.high == 0 {
|
|
|
|
- if d.high == 0 {
|
|
|
|
|
|
+ if n.high() == 0 {
|
|
|
|
+ if d.high() == 0 {
|
|
// 0 X
|
|
// 0 X
|
|
// ---
|
|
// ---
|
|
// 0 X
|
|
// 0 X
|
|
|
|
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = u64::from(n.low % d.low);
|
|
|
|
|
|
+ *rem = u64::from(n.low() % d.low());
|
|
}
|
|
}
|
|
- return u64::from(n.low / d.low);
|
|
|
|
|
|
+ return u64::from(n.low() / d.low());
|
|
} else
|
|
} else
|
|
- // d.high != 0
|
|
|
|
- {
|
|
|
|
|
|
+ // d.high() != 0
|
|
|
|
+ {
|
|
// 0 X
|
|
// 0 X
|
|
// ---
|
|
// ---
|
|
// K X
|
|
// K X
|
|
|
|
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = u64::from(n.low);
|
|
|
|
|
|
+ *rem = u64::from(n.low());
|
|
}
|
|
}
|
|
return 0;
|
|
return 0;
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
let mut sr;
|
|
let mut sr;
|
|
- // NOTE IMO it should be possible to leave these "uninitialized" (just declare them here)
|
|
|
|
- // because these variables get initialized below, but if I do that the compiler complains about
|
|
|
|
- // them being used before being initialized.
|
|
|
|
- let mut q = words { low: 0, high: 0 };
|
|
|
|
- let mut r = words { low: 0, high: 0 };
|
|
|
|
-
|
|
|
|
- // n.high != 0
|
|
|
|
- if d.low == 0 {
|
|
|
|
- if d.high == 0 {
|
|
|
|
|
|
+ let mut q = U64 { low: 0, high: 0 };
|
|
|
|
+ let mut r = U64 { low: 0, high: 0 };
|
|
|
|
+
|
|
|
|
+ // n.high() != 0
|
|
|
|
+ if d.low() == 0 {
|
|
|
|
+ if d.high() == 0 {
|
|
// K X
|
|
// K X
|
|
// ---
|
|
// ---
|
|
// 0 0
|
|
// 0 0
|
|
|
|
|
|
- // NOTE copied verbatim from compiler-rt, but does division by zero even make sense?
|
|
|
|
|
|
+ // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to
|
|
|
|
+ // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable
|
|
|
|
+ // from safe code.
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = u64::from(n.high % d.low);
|
|
|
|
|
|
+ *rem = u64::from(n.high() % d.low());
|
|
}
|
|
}
|
|
- return u64::from(n.high / d.low);
|
|
|
|
|
|
+ return u64::from(n.high() / d.low());
|
|
}
|
|
}
|
|
|
|
|
|
- // d.high != 0
|
|
|
|
- if n.low == 0 {
|
|
|
|
|
|
+ // d.high() != 0
|
|
|
|
+ if n.low() == 0 {
|
|
// K 0
|
|
// K 0
|
|
// ---
|
|
// ---
|
|
// K 0
|
|
// K 0
|
|
|
|
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = words {
|
|
|
|
- low: 0,
|
|
|
|
- high: n.high % d.high,
|
|
|
|
- }
|
|
|
|
- .u64();
|
|
|
|
|
|
+ *rem = U64 {
|
|
|
|
+ low: 0,
|
|
|
|
+ high: n.high() % d.high(),
|
|
|
|
+ }[..];
|
|
}
|
|
}
|
|
- return u64::from(n.high / d.high);
|
|
|
|
|
|
+ return u64::from(n.high() / d.high());
|
|
}
|
|
}
|
|
|
|
|
|
- // n.low != 0
|
|
|
|
|
|
+ // n.low() != 0
|
|
// K K
|
|
// K K
|
|
// ---
|
|
// ---
|
|
// K 0
|
|
// K 0
|
|
|
|
|
|
- if d.high.is_power_of_two() {
|
|
|
|
|
|
+ if d.high().is_power_of_two() {
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = words {
|
|
|
|
- low: n.low,
|
|
|
|
- high: n.high & (d.high - 1),
|
|
|
|
- }
|
|
|
|
- .u64()
|
|
|
|
|
|
+ *rem = U64 {
|
|
|
|
+ low: n.low(),
|
|
|
|
+ high: n.high() & (d.high() - 1),
|
|
|
|
+ }[..];
|
|
}
|
|
}
|
|
|
|
|
|
- return u64::from(n.high >> d.high.trailing_zeros());
|
|
|
|
|
|
+ return u64::from(n.high() >> d.high().trailing_zeros());
|
|
}
|
|
}
|
|
|
|
|
|
- sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros());
|
|
|
|
|
|
+ sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
|
|
|
|
|
// D > N
|
|
// D > N
|
|
if sr > u32_bits - 2 {
|
|
if sr > u32_bits - 2 {
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = n.u64();
|
|
|
|
|
|
+ *rem = n;
|
|
}
|
|
}
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -231,75 +230,74 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 {
|
|
sr = sr + 1;
|
|
sr = sr + 1;
|
|
|
|
|
|
// 1 <= sr <= u32_bits - 1
|
|
// 1 <= sr <= u32_bits - 1
|
|
- // *q.all() = n.u64() << (u64_bits - sr);
|
|
|
|
|
|
+ // q = n << (u64_bits - sr);
|
|
q.low = 0;
|
|
q.low = 0;
|
|
- q.high = n.low << (u32_bits - sr);
|
|
|
|
- // *r.all() = n.u64() >> sr
|
|
|
|
- r.high = n.high >> sr;
|
|
|
|
- r.low = (n.high << (u32_bits - sr)) | (n.low >> sr);
|
|
|
|
|
|
+ q.high = n.low() << (u32_bits - sr);
|
|
|
|
+ // r = n >> sr
|
|
|
|
+ r.high = n.high() >> sr;
|
|
|
|
+ r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
|
|
} else
|
|
} else
|
|
- // d.low != 0
|
|
|
|
|
|
+ // d.low() != 0
|
|
{
|
|
{
|
|
- if d.high == 0 {
|
|
|
|
|
|
+ if d.high() == 0 {
|
|
// K X
|
|
// K X
|
|
// ---
|
|
// ---
|
|
// 0 K
|
|
// 0 K
|
|
- if d.low.is_power_of_two() {
|
|
|
|
|
|
+ if d.low().is_power_of_two() {
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = u64::from(n.low & (d.low - 1));
|
|
|
|
|
|
+ *rem = u64::from(n.low() & (d.low() - 1));
|
|
}
|
|
}
|
|
|
|
|
|
- return if d.low == 1 {
|
|
|
|
- n.u64()
|
|
|
|
|
|
+ if d.low() == 1 {
|
|
|
|
+ return n;
|
|
} else {
|
|
} else {
|
|
- let sr = d.low.trailing_zeros();
|
|
|
|
- words {
|
|
|
|
- low: (n.high << (u32_bits - sr)) | (n.low >> sr),
|
|
|
|
- high: n.high >> sr,
|
|
|
|
- }
|
|
|
|
- .u64()
|
|
|
|
|
|
+ let sr = d.low().trailing_zeros();
|
|
|
|
+ return U64 {
|
|
|
|
+ low: (n.high() << (u32_bits - sr)) | (n.low() >> sr),
|
|
|
|
+ high: n.high() >> sr,
|
|
|
|
+ }[..];
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
- sr = 1 + u32_bits + d.low.leading_zeros() - n.high.leading_zeros();
|
|
|
|
|
|
+ sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros();
|
|
|
|
|
|
// 2 <= sr <= u64_bits - 1
|
|
// 2 <= sr <= u64_bits - 1
|
|
- // *q.all() = n.u64() << (u64_bits - sr)
|
|
|
|
- // *r.all() = n.u64() >> sr;
|
|
|
|
|
|
+ // q = n << (u64_bits - sr)
|
|
|
|
+ // r = n >> sr;
|
|
if sr == u32_bits {
|
|
if sr == u32_bits {
|
|
q.low = 0;
|
|
q.low = 0;
|
|
- q.high = n.low;
|
|
|
|
|
|
+ q.high = n.low();
|
|
r.high = 0;
|
|
r.high = 0;
|
|
- r.low = n.high;
|
|
|
|
|
|
+ r.low = n.high();
|
|
} else if sr < u32_bits
|
|
} else if sr < u32_bits
|
|
// 2 <= sr <= u32_bits - 1
|
|
// 2 <= sr <= u32_bits - 1
|
|
{
|
|
{
|
|
q.low = 0;
|
|
q.low = 0;
|
|
- q.high = n.low << (u32_bits - sr);
|
|
|
|
- r.high = n.high >> sr;
|
|
|
|
- r.low = (n.high << (u32_bits - sr)) | (n.low >> sr);
|
|
|
|
|
|
+ q.high = n.low() << (u32_bits - sr);
|
|
|
|
+ r.high = n.high() >> sr;
|
|
|
|
+ r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
|
|
} else
|
|
} else
|
|
// u32_bits + 1 <= sr <= u64_bits - 1
|
|
// u32_bits + 1 <= sr <= u64_bits - 1
|
|
{
|
|
{
|
|
- q.low = n.low << (u64_bits - sr);
|
|
|
|
- q.high = (n.high << (u64_bits - sr)) | (n.low >> (sr - u32_bits));
|
|
|
|
|
|
+ q.low = n.low() << (u64_bits - sr);
|
|
|
|
+ q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits));
|
|
r.high = 0;
|
|
r.high = 0;
|
|
- r.low = n.high >> (sr - u32_bits);
|
|
|
|
|
|
+ r.low = n.high() >> (sr - u32_bits);
|
|
}
|
|
}
|
|
|
|
|
|
} else
|
|
} else
|
|
- // d.high != 0
|
|
|
|
|
|
+ // d.high() != 0
|
|
{
|
|
{
|
|
// K X
|
|
// K X
|
|
// ---
|
|
// ---
|
|
// K K
|
|
// K K
|
|
|
|
|
|
- sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros());
|
|
|
|
|
|
+ sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
|
|
|
|
|
// D > N
|
|
// D > N
|
|
if sr > u32_bits - 1 {
|
|
if sr > u32_bits - 1 {
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = a;
|
|
|
|
|
|
+ *rem = n;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -307,61 +305,61 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 {
|
|
sr += 1;
|
|
sr += 1;
|
|
|
|
|
|
// 1 <= sr <= u32_bits
|
|
// 1 <= sr <= u32_bits
|
|
- // *q.all() = n.u64() << (u64_bits - sr)
|
|
|
|
|
|
+ // q = n << (u64_bits - sr)
|
|
q.low = 0;
|
|
q.low = 0;
|
|
if sr == u32_bits {
|
|
if sr == u32_bits {
|
|
- q.high = n.low;
|
|
|
|
|
|
+ q.high = n.low();
|
|
r.high = 0;
|
|
r.high = 0;
|
|
- r.low = n.high;
|
|
|
|
|
|
+ r.low = n.high();
|
|
} else {
|
|
} else {
|
|
- q.high = n.low << (u32_bits - sr);
|
|
|
|
- r.high = n.high >> sr;
|
|
|
|
- r.low = (n.high << (u32_bits - sr)) | (n.low >> sr);
|
|
|
|
|
|
+ q.high = n.low() << (u32_bits - sr);
|
|
|
|
+ r.high = n.high() >> sr;
|
|
|
|
+ r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Not a special case
|
|
// Not a special case
|
|
// q and r are initialized with
|
|
// q and r are initialized with
|
|
- // *q.all() = n.u64() << (u64_bits - sr)
|
|
|
|
- // *.r.all() = n.u64() >> sr
|
|
|
|
|
|
+ // q = n << (u64_bits - sr)
|
|
|
|
+ // r = n >> sr
|
|
// 1 <= sr <= u64_bits - 1
|
|
// 1 <= sr <= u64_bits - 1
|
|
let mut carry = 0;
|
|
let mut carry = 0;
|
|
|
|
|
|
for _ in 0..sr {
|
|
for _ in 0..sr {
|
|
// r:q = ((r:q) << 1) | carry
|
|
// r:q = ((r:q) << 1) | carry
|
|
- r.high = (r.high << 1) | (r.low >> (u32_bits - 1));
|
|
|
|
- r.low = (r.low << 1) | (q.high >> (u32_bits - 1));
|
|
|
|
- q.high = (q.high << 1) | (q.low >> (u32_bits - 1));
|
|
|
|
- q.low = (q.low << 1) | carry;
|
|
|
|
|
|
+ r[..] = (r[..] << 1) | (q[..] >> 63);
|
|
|
|
+ q[..] = (q[..] << 1) | carry as u64;
|
|
|
|
|
|
// carry = 0
|
|
// carry = 0
|
|
- // if r.u64() >= d.u64() {
|
|
|
|
- // *r.all() -= d.u64();
|
|
|
|
|
|
+ // if r >= d {
|
|
|
|
+ // r -= d;
|
|
// carry = 1;
|
|
// carry = 1;
|
|
// }
|
|
// }
|
|
|
|
|
|
- let s = (d.u64().wrapping_sub(r.u64()).wrapping_sub(1)) as i64 >> (u64_bits - 1);
|
|
|
|
|
|
+ let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1);
|
|
carry = (s & 1) as u32;
|
|
carry = (s & 1) as u32;
|
|
- *r.all() -= d.u64() & s as u64;
|
|
|
|
|
|
+ r[..] -= d & s as u64;
|
|
}
|
|
}
|
|
|
|
|
|
- *q.all() = (q.u64() << 1) | carry as u64;
|
|
|
|
|
|
+ q[..] = (q[..] << 1) | carry as u64;
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = r.u64();
|
|
|
|
|
|
+ *rem = r[..];
|
|
}
|
|
}
|
|
- q.u64()
|
|
|
|
|
|
+ q[..]
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/// Return `n / d` and `*rem = n % d`
|
|
#[no_mangle]
|
|
#[no_mangle]
|
|
pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 {
|
|
pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 {
|
|
let d = __udivsi3(a, b);
|
|
let d = __udivsi3(a, b);
|
|
if let Some(rem) = rem {
|
|
if let Some(rem) = rem {
|
|
- *rem = a - (d*b);
|
|
|
|
|
|
+ *rem = a - (d * b);
|
|
}
|
|
}
|
|
return d;
|
|
return d;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/// Return `n / d`
|
|
#[no_mangle]
|
|
#[no_mangle]
|
|
pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
|
|
pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
|
|
let u32_bits = u32::bits() as u32;
|
|
let u32_bits = u32::bits() as u32;
|