Skip to content

Commit

Permalink
Make float abs, copysign and signum const too
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardosm committed Oct 5, 2024
1 parent fa312ed commit 593f644
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 137 deletions.
89 changes: 73 additions & 16 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
})
}

enum FloatBinIntrinsic {
Min,
Max,
Copysign,
}

impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Returns `true` if emulation happened.
/// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
Expand Down Expand Up @@ -438,21 +444,54 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
}

sym::minnumf16 | sym::maxnumf16 => {
let is_max = intrinsic_name == sym::maxnumf16;
self.float_min_max_intrinsic::<rustc_apfloat::ieee::Half>(is_max, args, dest)?;
sym::minnumf16 | sym::maxnumf16 | sym::copysignf16 => {
let op = match intrinsic_name {
sym::minnumf16 => FloatBinIntrinsic::Min,
sym::maxnumf16 => FloatBinIntrinsic::Max,
sym::copysignf16 => FloatBinIntrinsic::Copysign,
_ => bug!(),
};
self.float_bin_op_intrinsic::<rustc_apfloat::ieee::Half>(op, args, dest)?;
}
sym::minnumf32 | sym::maxnumf32 | sym::copysignf32 => {
let op = match intrinsic_name {
sym::minnumf32 => FloatBinIntrinsic::Min,
sym::maxnumf32 => FloatBinIntrinsic::Max,
sym::copysignf32 => FloatBinIntrinsic::Copysign,
_ => bug!(),
};
self.float_bin_op_intrinsic::<rustc_apfloat::ieee::Single>(op, args, dest)?;
}
sym::minnumf64 | sym::maxnumf64 | sym::copysignf64 => {
let op = match intrinsic_name {
sym::minnumf64 => FloatBinIntrinsic::Min,
sym::maxnumf64 => FloatBinIntrinsic::Max,
sym::copysignf64 => FloatBinIntrinsic::Copysign,
_ => bug!(),
};
self.float_bin_op_intrinsic::<rustc_apfloat::ieee::Double>(op, args, dest)?;
}
sym::minnumf128 | sym::maxnumf128 | sym::copysignf128 => {
let op = match intrinsic_name {
sym::minnumf128 => FloatBinIntrinsic::Min,
sym::maxnumf128 => FloatBinIntrinsic::Max,
sym::copysignf128 => FloatBinIntrinsic::Copysign,
_ => bug!(),
};
self.float_bin_op_intrinsic::<rustc_apfloat::ieee::Quad>(op, args, dest)?;
}

sym::fabsf16 => {
self.float_abs_intrinsic::<rustc_apfloat::ieee::Half>(args, dest)?;
}
sym::minnumf32 | sym::maxnumf32 => {
let is_max = intrinsic_name == sym::maxnumf32;
self.float_min_max_intrinsic::<rustc_apfloat::ieee::Single>(is_max, args, dest)?;
sym::fabsf32 => {
self.float_abs_intrinsic::<rustc_apfloat::ieee::Single>(args, dest)?;
}
sym::minnumf64 | sym::maxnumf64 => {
let is_max = intrinsic_name == sym::maxnumf64;
self.float_min_max_intrinsic::<rustc_apfloat::ieee::Double>(is_max, args, dest)?;
sym::fabsf64 => {
self.float_abs_intrinsic::<rustc_apfloat::ieee::Double>(args, dest)?;
}
sym::minnumf128 | sym::maxnumf128 => {
let is_max = intrinsic_name == sym::maxnumf128;
self.float_min_max_intrinsic::<rustc_apfloat::ieee::Quad>(is_max, args, dest)?;
sym::fabsf128 => {
self.float_abs_intrinsic::<rustc_apfloat::ieee::Quad>(args, dest)?;
}

// Unsupported intrinsic: skip the return_to_block below.
Expand Down Expand Up @@ -715,9 +754,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
}

fn float_min_max_intrinsic<F>(
fn float_bin_op_intrinsic<F>(
&mut self,
is_max: bool,
op: FloatBinIntrinsic,
args: &[OpTy<'tcx, M::Provenance>],
dest: &MPlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ()>
Expand All @@ -726,8 +765,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
{
let a: F = self.read_scalar(&args[0])?.to_float()?;
let b: F = self.read_scalar(&args[1])?.to_float()?;
let res = if is_max { a.max(b) } else { a.min(b) };
self.write_scalar(adjust_nan(self, res, &[a, b]), dest)?;
let res = match op {
FloatBinIntrinsic::Min => adjust_nan(self, a.min(b), &[a, b]),
FloatBinIntrinsic::Max => adjust_nan(self, a.max(b), &[a, b]),
FloatBinIntrinsic::Copysign => a.copy_sign(b), // bitwise, no NaN adjustments
};
self.write_scalar(res, dest)?;
interp_ok(())
}

fn float_abs_intrinsic<F>(
&mut self,
args: &[OpTy<'tcx, M::Provenance>],
dest: &MPlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ()>
where
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
{
let x: F = self.read_scalar(&args[0])?.to_float()?;
// bitwise, no NaN adjustments
self.write_scalar(x.abs(), dest)?;
interp_ok(())
}
}
Expand Down
149 changes: 99 additions & 50 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1795,56 +1795,6 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
pub fn fmaf128(a: f128, b: f128, c: f128) -> f128;

/// Returns the absolute value of an `f16`.
///
/// The stabilized version of this intrinsic is
/// [`f16::abs`](../../std/primitive.f16.html#method.abs)
#[rustc_nounwind]
pub fn fabsf16(x: f16) -> f16;
/// Returns the absolute value of an `f32`.
///
/// The stabilized version of this intrinsic is
/// [`f32::abs`](../../std/primitive.f32.html#method.abs)
#[rustc_nounwind]
pub fn fabsf32(x: f32) -> f32;
/// Returns the absolute value of an `f64`.
///
/// The stabilized version of this intrinsic is
/// [`f64::abs`](../../std/primitive.f64.html#method.abs)
#[rustc_nounwind]
pub fn fabsf64(x: f64) -> f64;
/// Returns the absolute value of an `f128`.
///
/// The stabilized version of this intrinsic is
/// [`f128::abs`](../../std/primitive.f128.html#method.abs)
#[rustc_nounwind]
pub fn fabsf128(x: f128) -> f128;

/// Copies the sign from `y` to `x` for `f16` values.
///
/// The stabilized version of this intrinsic is
/// [`f16::copysign`](../../std/primitive.f16.html#method.copysign)
#[rustc_nounwind]
pub fn copysignf16(x: f16, y: f16) -> f16;
/// Copies the sign from `y` to `x` for `f32` values.
///
/// The stabilized version of this intrinsic is
/// [`f32::copysign`](../../std/primitive.f32.html#method.copysign)
#[rustc_nounwind]
pub fn copysignf32(x: f32, y: f32) -> f32;
/// Copies the sign from `y` to `x` for `f64` values.
///
/// The stabilized version of this intrinsic is
/// [`f64::copysign`](../../std/primitive.f64.html#method.copysign)
#[rustc_nounwind]
pub fn copysignf64(x: f64, y: f64) -> f64;
/// Copies the sign from `y` to `x` for `f128` values.
///
/// The stabilized version of this intrinsic is
/// [`f128::copysign`](../../std/primitive.f128.html#method.copysign)
#[rustc_nounwind]
pub fn copysignf128(x: f128, y: f128) -> f128;

/// Returns the largest integer less than or equal to an `f16`.
///
/// The stabilized version of this intrinsic is
Expand Down Expand Up @@ -3539,6 +3489,105 @@ pub const fn maxnumf128(_x: f128, _y: f128) -> f128 {
unimplemented!();
}

/// Returns the absolute value of an `f16`.
///
/// The stabilized version of this intrinsic is
/// [`f16::abs`](../../std/primitive.f16.html#method.abs)
#[rustc_nounwind]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const unsafe fn fabsf16(_x: f16) -> f16 {
unimplemented!();
}

/// Returns the absolute value of an `f32`.
///
/// The stabilized version of this intrinsic is
/// [`f32::abs`](../../std/primitive.f32.html#method.abs)
#[rustc_nounwind]
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const unsafe fn fabsf32(_x: f32) -> f32 {
unimplemented!();
}

/// Returns the absolute value of an `f64`.
///
/// The stabilized version of this intrinsic is
/// [`f64::abs`](../../std/primitive.f64.html#method.abs)
#[rustc_nounwind]
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const unsafe fn fabsf64(_x: f64) -> f64 {
unimplemented!();
}

/// Returns the absolute value of an `f128`.
///
/// The stabilized version of this intrinsic is
/// [`f128::abs`](../../std/primitive.f128.html#method.abs)
#[rustc_nounwind]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const unsafe fn fabsf128(_x: f128) -> f128 {
unimplemented!();
}

/// Copies the sign from `y` to `x` for `f16` values.
///
/// The stabilized version of this intrinsic is
/// [`f16::copysign`](../../std/primitive.f16.html#method.copysign)
#[rustc_nounwind]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 {
unimplemented!();
}

/// Copies the sign from `y` to `x` for `f32` values.
///
/// The stabilized version of this intrinsic is
/// [`f32::copysign`](../../std/primitive.f32.html#method.copysign)
#[rustc_nounwind]
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 {
unimplemented!();
}
/// Copies the sign from `y` to `x` for `f64` values.
///
/// The stabilized version of this intrinsic is
/// [`f64::copysign`](../../std/primitive.f64.html#method.copysign)
#[rustc_nounwind]
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 {
unimplemented!();
}

/// Copies the sign from `y` to `x` for `f128` values.
///
/// The stabilized version of this intrinsic is
/// [`f128::copysign`](../../std/primitive.f128.html#method.copysign)
#[rustc_nounwind]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 {
unimplemented!();
}

/// Inform Miri that a given pointer definitely has a certain alignment.
#[cfg(miri)]
pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) {
Expand Down
12 changes: 9 additions & 3 deletions library/std/src/f128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,10 @@ impl f128 {
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f128", issue = "116909")]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn abs(self) -> Self {
pub const fn abs(self) -> Self {
// FIXME(f16_f128): replace with `intrinsics::fabsf128` when available
// We don't do this now because LLVM has lowering bugs for f128 math.
Self::from_bits(self.to_bits() & !(1 << 127))
Expand Down Expand Up @@ -240,8 +242,10 @@ impl f128 {
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f128", issue = "116909")]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn signum(self) -> f128 {
pub const fn signum(self) -> f128 {
if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) }
}

Expand Down Expand Up @@ -278,8 +282,10 @@ impl f128 {
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f128", issue = "116909")]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn copysign(self, sign: f128) -> f128 {
pub const fn copysign(self, sign: f128) -> f128 {
unsafe { intrinsics::copysignf128(self, sign) }
}

Expand Down
12 changes: 9 additions & 3 deletions library/std/src/f16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,10 @@ impl f16 {
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f16", issue = "116909")]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn abs(self) -> Self {
pub const fn abs(self) -> Self {
// FIXME(f16_f128): replace with `intrinsics::fabsf16` when available
Self::from_bits(self.to_bits() & !(1 << 15))
}
Expand Down Expand Up @@ -239,8 +241,10 @@ impl f16 {
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f16", issue = "116909")]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn signum(self) -> f16 {
pub const fn signum(self) -> f16 {
if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) }
}

Expand Down Expand Up @@ -277,8 +281,10 @@ impl f16 {
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f16", issue = "116909")]
// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn copysign(self, sign: f16) -> f16 {
pub const fn copysign(self, sign: f16) -> f16 {
unsafe { intrinsics::copysignf16(self, sign) }
}

Expand Down
9 changes: 6 additions & 3 deletions library/std/src/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,9 @@ impl f32 {
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[inline]
pub fn abs(self) -> f32 {
pub const fn abs(self) -> f32 {
unsafe { intrinsics::fabsf32(self) }
}

Expand All @@ -218,8 +219,9 @@ impl f32 {
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
#[inline]
pub fn signum(self) -> f32 {
pub const fn signum(self) -> f32 {
if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) }
}

Expand Down Expand Up @@ -253,7 +255,8 @@ impl f32 {
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
#[stable(feature = "copysign", since = "1.35.0")]
pub fn copysign(self, sign: f32) -> f32 {
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
pub const fn copysign(self, sign: f32) -> f32 {
unsafe { intrinsics::copysignf32(self, sign) }
}

Expand Down
Loading

0 comments on commit 593f644

Please sign in to comment.