Always const-eval the gcd in slice::align_to_offsets
This commit is contained in:
parent
333b920fee
commit
b5ee324d79
@ -3474,44 +3474,13 @@ fn align_to_offsets<U>(&self) -> (usize, usize) {
|
||||
// Ts = size_of::<U> / gcd(size_of::<T>, size_of::<U>)
|
||||
//
|
||||
// Luckily since all this is constant-evaluated... performance here matters not!
|
||||
#[inline]
|
||||
fn gcd(a: usize, b: usize) -> usize {
|
||||
use crate::intrinsics;
|
||||
// iterative stein’s algorithm
|
||||
// We should still make this `const fn` (and revert to recursive algorithm if we do)
|
||||
// because relying on llvm to consteval all this is… well, it makes me uncomfortable.
|
||||
|
||||
// SAFETY: `a` and `b` are checked to be non-zero values.
|
||||
let (ctz_a, mut ctz_b) = unsafe {
|
||||
if a == 0 {
|
||||
return b;
|
||||
}
|
||||
if b == 0 {
|
||||
return a;
|
||||
}
|
||||
(intrinsics::cttz_nonzero(a), intrinsics::cttz_nonzero(b))
|
||||
};
|
||||
let k = ctz_a.min(ctz_b);
|
||||
let mut a = a >> ctz_a;
|
||||
let mut b = b;
|
||||
loop {
|
||||
// remove all factors of 2 from b
|
||||
b >>= ctz_b;
|
||||
if a > b {
|
||||
mem::swap(&mut a, &mut b);
|
||||
}
|
||||
b = b - a;
|
||||
// SAFETY: `b` is checked to be non-zero.
|
||||
unsafe {
|
||||
if b == 0 {
|
||||
break;
|
||||
}
|
||||
ctz_b = intrinsics::cttz_nonzero(b);
|
||||
}
|
||||
}
|
||||
a << k
|
||||
const fn gcd(a: usize, b: usize) -> usize {
|
||||
if b == 0 { a } else { gcd(b, a % b) }
|
||||
}
|
||||
let gcd: usize = gcd(mem::size_of::<T>(), mem::size_of::<U>());
|
||||
|
||||
// Explicitly wrap the function call in a const block so it gets
|
||||
// constant-evaluated even in debug mode.
|
||||
let gcd: usize = const { gcd(mem::size_of::<T>(), mem::size_of::<U>()) };
|
||||
let ts: usize = mem::size_of::<U>() / gcd;
|
||||
let us: usize = mem::size_of::<T>() / gcd;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user