about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-02-03 21:29:41 +0100
committerGitHub <noreply@github.com>2024-02-03 21:29:41 +0100
commit977945d2854fa066614c68a9e407c2a079ecf66f (patch)
tree5f46ba0b4d6741d813082277d913aa9aad1e72ea
parent98d0d4595e2552ef75f9785605c48d5749cf8cfe (diff)
parent6ac035df442a27cf9e99ab4ec25bb6147a700902 (diff)
downloadrust-977945d2854fa066614c68a9e407c2a079ecf66f.tar.gz
rust-977945d2854fa066614c68a9e407c2a079ecf66f.zip
Rollup merge of #120562 - oli-obk:revert_stuff, r=cuviper
Revert unsound libcore changes

fixes #120537

these were introduced in #119911
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/num/int_macros.rs284
-rw-r--r--library/core/src/num/uint_macros.rs249
-rw-r--r--tests/codegen/pow_of_two.rs55
4 files changed, 149 insertions, 440 deletions
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 2af242d4b50..ead8cbe0e2f 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -200,7 +200,6 @@
 //
 // Language features:
 // tidy-alphabetical-start
-#![cfg_attr(not(bootstrap), feature(is_val_statically_known))]
 #![feature(abi_unadjusted)]
 #![feature(adt_const_params)]
 #![feature(allow_internal_unsafe)]
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index bb35b6128ea..d052dcc3e6e 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1374,59 +1374,26 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
-            // SAFETY: This path has the same behavior as the other.
-            if unsafe { intrinsics::is_val_statically_known(self) }
-                && self.unsigned_abs().is_power_of_two()
-            {
-                if self == 1 { // Avoid divide by zero
-                    return Some(1);
-                }
-                if self == -1 { // Avoid divide by zero
-                    return Some(if exp & 1 != 0 { -1 } else { 1 });
-                }
-                // SAFETY: We just checked this is a power of two. and above zero.
-                let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
-                if exp > Self::BITS / power_used { return None; } // Division of constants is free
-
-                // SAFETY: exp <= Self::BITS / power_used
-                let res = unsafe { intrinsics::unchecked_shl(
-                    1 as Self,
-                    intrinsics::unchecked_mul(power_used, exp) as Self
-                )};
-                // LLVM doesn't always optimize out the checks
-                // at the ir level.
-
-                let sign = self.is_negative() && exp & 1 != 0;
-                if !sign && res == Self::MIN  {
-                    None
-                } else if sign {
-                    Some(res.wrapping_neg())
-                } else {
-                    Some(res)
-                }
-            } else {
-                if exp == 0 {
-                    return Some(1);
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = try_opt!(acc.checked_mul(base));
-                    }
-                    exp /= 2;
-                    base = try_opt!(base.checked_mul(base));
+            if exp == 0 {
+                return Some(1);
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
+
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = try_opt!(acc.checked_mul(base));
                 }
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                acc.checked_mul(base)
+                exp /= 2;
+                base = try_opt!(base.checked_mul(base));
             }
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            acc.checked_mul(base)
         }
 
         /// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@@ -2091,58 +2058,27 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn wrapping_pow(self, mut exp: u32) -> Self {
-            // SAFETY: This path has the same behavior as the other.
-            if unsafe { intrinsics::is_val_statically_known(self) }
-                && self.unsigned_abs().is_power_of_two()
-            {
-                if self == 1 { // Avoid divide by zero
-                    return 1;
-                }
-                if self == -1 { // Avoid divide by zero
-                    return if exp & 1 != 0 { -1 } else { 1 };
-                }
-                // SAFETY: We just checked this is a power of two. and above zero.
-                let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
-                if exp > Self::BITS / power_used { return 0; } // Division of constants is free
-
-                // SAFETY: exp <= Self::BITS / power_used
-                let res = unsafe { intrinsics::unchecked_shl(
-                    1 as Self,
-                    intrinsics::unchecked_mul(power_used, exp) as Self
-                )};
-                // LLVM doesn't always optimize out the checks
-                // at the ir level.
-
-                let sign = self.is_negative() && exp & 1 != 0;
-                if sign {
-                    res.wrapping_neg()
-                } else {
-                    res
-                }
-            } else {
-                if exp == 0 {
-                    return 1;
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = acc.wrapping_mul(base);
-                    }
-                    exp /= 2;
-                    base = base.wrapping_mul(base);
-                }
+            if exp == 0 {
+                return 1;
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
 
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                acc.wrapping_mul(base)
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = acc.wrapping_mul(base);
+                }
+                exp /= 2;
+                base = base.wrapping_mul(base);
             }
+
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            acc.wrapping_mul(base)
         }
 
         /// Calculates `self` + `rhs`
@@ -2625,68 +2561,36 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
-            // SAFETY: This path has the same behavior as the other.
-            if unsafe { intrinsics::is_val_statically_known(self) }
-                && self.unsigned_abs().is_power_of_two()
-            {
-                if self == 1 { // Avoid divide by zero
-                    return (1, false);
-                }
-                if self == -1 { // Avoid divide by zero
-                    return (if exp & 1 != 0 { -1 } else { 1 }, false);
-                }
-                // SAFETY: We just checked this is a power of two. and above zero.
-                let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
-                if exp > Self::BITS / power_used { return (0, true); } // Division of constants is free
-
-                // SAFETY: exp <= Self::BITS / power_used
-                let res = unsafe { intrinsics::unchecked_shl(
-                    1 as Self,
-                    intrinsics::unchecked_mul(power_used, exp) as Self
-                )};
-                // LLVM doesn't always optimize out the checks
-                // at the ir level.
-
-                let sign = self.is_negative() && exp & 1 != 0;
-                let overflow = res == Self::MIN;
-                if sign {
-                    (res.wrapping_neg(), overflow)
-                } else {
-                    (res, overflow)
-                }
-            } else {
-                if exp == 0 {
-                    return (1,false);
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-                let mut overflown = false;
-                // Scratch space for storing results of overflowing_mul.
-                let mut r;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        r = acc.overflowing_mul(base);
-                        acc = r.0;
-                        overflown |= r.1;
-                    }
-                    exp /= 2;
-                    r = base.overflowing_mul(base);
-                    base = r.0;
+            if exp == 0 {
+                return (1,false);
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
+            let mut overflown = false;
+            // Scratch space for storing results of overflowing_mul.
+            let mut r;
+
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    r = acc.overflowing_mul(base);
+                    acc = r.0;
                     overflown |= r.1;
                 }
-
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                r = acc.overflowing_mul(base);
-                r.1 |= overflown;
-                r
+                exp /= 2;
+                r = base.overflowing_mul(base);
+                base = r.0;
+                overflown |= r.1;
             }
+
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            r = acc.overflowing_mul(base);
+            r.1 |= overflown;
+            r
         }
 
         /// Raises self to the power of `exp`, using exponentiation by squaring.
@@ -2704,68 +2608,28 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         #[rustc_inherit_overflow_checks]
-        #[track_caller] // Hides the hackish overflow check for powers of two.
         pub const fn pow(self, mut exp: u32) -> Self {
-            // SAFETY: This path has the same behavior as the other.
-            if unsafe { intrinsics::is_val_statically_known(self) }
-                && self.unsigned_abs().is_power_of_two()
-            {
-                if self == 1 { // Avoid divide by zero
-                    return 1;
-                }
-                if self == -1 { // Avoid divide by zero
-                    return if exp & 1 != 0 { -1 } else { 1 };
-                }
-                // SAFETY: We just checked this is a power of two. and above zero.
-                let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
-                if exp > Self::BITS / power_used { // Division of constants is free
-                    #[allow(arithmetic_overflow)]
-                    return Self::MAX * Self::MAX * 0;
-                }
+            if exp == 0 {
+                return 1;
+            }
+            let mut base = self;
+            let mut acc = 1;
 
-                // SAFETY: exp <= Self::BITS / power_used
-                let res = unsafe { intrinsics::unchecked_shl(
-                    1 as Self,
-                    intrinsics::unchecked_mul(power_used, exp) as Self
-                )};
-                // LLVM doesn't always optimize out the checks
-                // at the ir level.
-
-                let sign = self.is_negative() && exp & 1 != 0;
-                #[allow(arithmetic_overflow)]
-                if !sign && res == Self::MIN  {
-                    // So it panics.
-                    _ = Self::MAX * Self::MAX;
-                }
-                if sign {
-                    res.wrapping_neg()
-                } else {
-                    res
-                }
-            } else {
-                if exp == 0 {
-                    return 1;
-                }
-                let mut base = self;
-                let mut acc = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = acc * base;
-                    }
-                    exp /= 2;
-                    base = base * base;
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = acc * base;
                 }
-
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                acc * base
+                exp /= 2;
+                base = base * base;
             }
+
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            acc * base
         }
 
         /// Returns the square root of the number, rounded down.
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index d450c68a5b2..a217c2e259d 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1364,49 +1364,28 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
-            // SAFETY: This path has the same behavior as the other.
-            if unsafe { intrinsics::is_val_statically_known(self) }
-                && self.is_power_of_two()
-            {
-                if self == 1 { // Avoid divide by zero
-                    return Some(1);
-                }
-                // SAFETY: We just checked this is a power of two. and above zero.
-                let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
-                if exp > Self::BITS / power_used { return None; } // Division of constants is free
-
-                // SAFETY: exp <= Self::BITS / power_used
-                unsafe { Some(intrinsics::unchecked_shl(
-                    1 as Self,
-                    intrinsics::unchecked_mul(power_used, exp) as Self
-                )) }
-                // LLVM doesn't always optimize out the checks
-                // at the ir level.
-            } else {
-                if exp == 0 {
-                    return Some(1);
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = try_opt!(acc.checked_mul(base));
-                    }
-                    exp /= 2;
-                    base = try_opt!(base.checked_mul(base));
+            if exp == 0 {
+                return Some(1);
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
+
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = try_opt!(acc.checked_mul(base));
                 }
+                exp /= 2;
+                base = try_opt!(base.checked_mul(base));
+            }
 
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
 
-                acc.checked_mul(base)
-            }
+            acc.checked_mul(base)
         }
 
         /// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@@ -1908,48 +1887,27 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn wrapping_pow(self, mut exp: u32) -> Self {
-            // SAFETY: This path has the same behavior as the other.
-            if unsafe { intrinsics::is_val_statically_known(self) }
-                && self.is_power_of_two()
-            {
-                if self == 1 { // Avoid divide by zero
-                    return 1;
-                }
-                // SAFETY: We just checked this is a power of two. and above zero.
-                let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
-                if exp > Self::BITS / power_used {  return 0; } // Division of constants is free
-
-                // SAFETY: exp <= Self::BITS / power_used
-                unsafe { intrinsics::unchecked_shl(
-                    1 as Self,
-                    intrinsics::unchecked_mul(power_used, exp) as Self
-                )}
-                // LLVM doesn't always optimize out the checks
-                // at the ir level.
-            } else {
-                if exp == 0 {
-                    return 1;
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = acc.wrapping_mul(base);
-                    }
-                    exp /= 2;
-                    base = base.wrapping_mul(base);
-                }
+            if exp == 0 {
+                return 1;
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
 
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                acc.wrapping_mul(base)
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = acc.wrapping_mul(base);
+                }
+                exp /= 2;
+                base = base.wrapping_mul(base);
             }
+
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            acc.wrapping_mul(base)
         }
 
         /// Calculates `self` + `rhs`
@@ -2383,58 +2341,37 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
-            // SAFETY: This path has the same behavior as the other.
-            if unsafe { intrinsics::is_val_statically_known(self) }
-                && self.is_power_of_two()
-            {
-                if self == 1 { // Avoid divide by zero
-                    return (1, false);
-                }
-                // SAFETY: We just checked this is a power of two. and above zero.
-                let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
-                if exp > Self::BITS / power_used {  return (0, true); } // Division of constants is free
-
-                // SAFETY: exp <= Self::BITS / power_used
-                unsafe { (intrinsics::unchecked_shl(
-                    1 as Self,
-                    intrinsics::unchecked_mul(power_used, exp) as Self
-                ), false) }
-                // LLVM doesn't always optimize out the checks
-                // at the ir level.
-            } else {
-                if exp == 0{
-                    return (1,false);
-                }
-                let mut base = self;
-                let mut acc: Self = 1;
-                let mut overflown = false;
-                // Scratch space for storing results of overflowing_mul.
-                let mut r;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        r = acc.overflowing_mul(base);
-                        acc = r.0;
-                        overflown |= r.1;
-                    }
-                    exp /= 2;
-                    r = base.overflowing_mul(base);
-                    base = r.0;
+            if exp == 0{
+                return (1,false);
+            }
+            let mut base = self;
+            let mut acc: Self = 1;
+            let mut overflown = false;
+            // Scratch space for storing results of overflowing_mul.
+            let mut r;
+
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    r = acc.overflowing_mul(base);
+                    acc = r.0;
                     overflown |= r.1;
                 }
+                exp /= 2;
+                r = base.overflowing_mul(base);
+                base = r.0;
+                overflown |= r.1;
+            }
 
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                r = acc.overflowing_mul(base);
-                r.1 |= overflown;
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            r = acc.overflowing_mul(base);
+            r.1 |= overflown;
 
-                r
-            }
+            r
         }
 
         /// Raises self to the power of `exp`, using exponentiation by squaring.
@@ -2450,64 +2387,28 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         #[rustc_inherit_overflow_checks]
-        #[track_caller] // Hides the hackish overflow check for powers of two.
         pub const fn pow(self, mut exp: u32) -> Self {
-            // LLVM now knows that `self` is a constant value, but not a
-            // constant in Rust. This allows us to compute the power used at
-            // compile-time.
-            //
-            // This will likely add a branch in debug builds, but this should
-            // be ok.
-            //
-            // This is a massive performance boost in release builds as you can
-            // get the power of a power of two and the exponent through a `shl`
-            // instruction, but we must add a couple more checks for parity with
-            // our own `pow`.
-            // SAFETY: This path has the same behavior as the other.
-            if unsafe { intrinsics::is_val_statically_known(self) }
-                && self.is_power_of_two()
-            {
-                if self == 1 { // Avoid divide by zero
-                    return 1;
-                }
-                // SAFETY: We just checked this is a power of two. and above zero.
-                let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
-                if exp > Self::BITS / power_used { // Division of constants is free
-                    #[allow(arithmetic_overflow)]
-                    return Self::MAX * Self::MAX * 0;
-                }
+            if exp == 0 {
+                return 1;
+            }
+            let mut base = self;
+            let mut acc = 1;
 
-                // SAFETY: exp <= Self::BITS / power_used
-                unsafe { intrinsics::unchecked_shl(
-                    1 as Self,
-                    intrinsics::unchecked_mul(power_used, exp) as Self
-                )}
-                // LLVM doesn't always optimize out the checks
-                // at the ir level.
-            } else {
-                if exp == 0 {
-                    return 1;
-                }
-                let mut base = self;
-                let mut acc = 1;
-
-                while exp > 1 {
-                    if (exp & 1) == 1 {
-                        acc = acc * base;
-                    }
-                    exp /= 2;
-                    base = base * base;
+            while exp > 1 {
+                if (exp & 1) == 1 {
+                    acc = acc * base;
                 }
-
-                // since exp!=0, finally the exp must be 1.
-                // Deal with the final bit of the exponent separately, since
-                // squaring the base afterwards is not necessary and may cause a
-                // needless overflow.
-                acc * base
+                exp /= 2;
+                base = base * base;
             }
+
+            // since exp!=0, finally the exp must be 1.
+            // Deal with the final bit of the exponent separately, since
+            // squaring the base afterwards is not necessary and may cause a
+            // needless overflow.
+            acc * base
         }
 
         /// Returns the square root of the number, rounded down.
diff --git a/tests/codegen/pow_of_two.rs b/tests/codegen/pow_of_two.rs
deleted file mode 100644
index 372360dfd12..00000000000
--- a/tests/codegen/pow_of_two.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-// compile-flags: --crate-type=lib -Zmerge-functions=disabled -O -C overflow-checks=false
-
-// CHECK-LABEL: @a(
-#[no_mangle]
-pub fn a(exp: u32) -> u64 {
-    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64
-    // CHECK: %{{[^ ]+}} = zext{{( nneg)?}} i32 %exp to i64
-    // CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}}
-    // CHECK: ret i64 %{{[^ ]+}}
-    2u64.pow(exp)
-}
-
-// CHECK-LABEL: @b(
-#[no_mangle]
-pub fn b(exp: u32) -> i64 {
-    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64
-    // CHECK: %{{[^ ]+}} = zext{{( nneg)?}} i32 %exp to i64
-    // CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}}
-    // CHECK: ret i64 %{{[^ ]+}}
-    2i64.pow(exp)
-}
-
-// CHECK-LABEL: @c(
-#[no_mangle]
-pub fn c(exp: u32) -> u32 {
-    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 16
-    // CHECK: %{{[^ ]+}} = shl nuw nsw i32 %exp, 1
-    // CHECK: %{{[^ ]+}} = shl nuw i32 1, %{{[^ ]+}}
-    // CHECK: %{{[^ ]+}} = select i1 %{{[^ ]+}}, i32 0, i32 %{{[^ ]+}}
-    // CHECK: ret i32 %{{[^ ]+}}
-    4u32.pow(exp)
-}
-
-// CHECK-LABEL: @d(
-#[no_mangle]
-pub fn d(exp: u32) -> u32 {
-    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6
-    // CHECK: %{{[^ ]+}} = mul nuw nsw i32 %exp, 5
-    // CHECK: %{{[^ ]+}} = shl nuw nsw i32 1, %{{[^ ]+}}
-    // CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}}
-    // CHECK: ret i32 %{{[^ ]+}}
-    32u32.pow(exp)
-}
-
-// CHECK-LABEL: @e(
-#[no_mangle]
-pub fn e(exp: u32) -> i32 {
-    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6
-    // CHECK: %{{[^ ]+}} = mul nuw {{(nsw )?}}i32 %exp, 5
-    // CHECK: %{{[^ ]+}} = shl nuw {{(nsw )?}}i32 1, %{{[^ ]+}}
-    // CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}}
-    // CHECK: ret i32 %{{[^ ]+}}
-    32i32.pow(exp)
-}
-// note: d and e are expected to yield the same IR