about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarkus Everling <markuseverling@gmail.com>2023-05-06 17:31:51 +0000
committerMarkus Everling <markuseverling@gmail.com>2023-05-06 17:31:51 +0000
commitb5ee324d79b310761b98173825895b16b859361b (patch)
treebf9627fbace077fb46c6340cad3b10751720f4e7
parent333b920feeb136d35fac804d51310df1a35c399e (diff)
downloadrust-b5ee324d79b310761b98173825895b16b859361b.tar.gz
rust-b5ee324d79b310761b98173825895b16b859361b.zip
Always const-eval the gcd in `slice::align_to_offsets`
-rw-r--r--library/core/src/slice/mod.rs43
1 files changed, 6 insertions, 37 deletions
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index d4981af90d1..28a6c05c383 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -3474,44 +3474,13 @@ impl<T> [T] {
         // 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;