Skip to content

Commit d335ea9

Browse files
committed
Refactor implementation of float minmax intrinsics
1 parent c4d6b0b commit d335ea9

File tree

2 files changed

+80
-107
lines changed

2 files changed

+80
-107
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 65 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,26 @@ enum MulAddType {
3434
Nondeterministic,
3535
}
3636

37+
#[derive(Copy, Clone)]
38+
pub(crate) enum MinMax {
39+
/// The IEEE `Minimum` operation - see `f32::minimum` etc
40+
/// In particular, `-0.0` is considered smaller than `+0.0` and
41+
/// if either input is NaN, the result is NaN.
42+
Minimum,
43+
/// The IEEE `MinNum` operation - see `f32::min` etc
44+
/// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic,
45+
/// and is one argument is NaN, the other one is returned.
46+
MinNum,
47+
/// The IEEE `Maximum` operation - see `f32::maximum` etc
48+
/// In particular, `-0.0` is considered smaller than `+0.0` and
49+
/// if either input is NaN, the result is NaN.
50+
Maximum,
51+
/// The IEEE `MaxNum` operation - see `f32::max` etc
52+
/// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic,
53+
/// and is one argument is NaN, the other one is returned.
54+
MaxNum,
55+
}
56+
3757
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
3858
pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId, u64) {
3959
let path = crate::util::type_name(tcx, ty);
@@ -513,25 +533,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
513533
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
514534
}
515535

516-
sym::minnumf16 => self.float_min_intrinsic::<Half>(args, dest)?,
517-
sym::minnumf32 => self.float_min_intrinsic::<Single>(args, dest)?,
518-
sym::minnumf64 => self.float_min_intrinsic::<Double>(args, dest)?,
519-
sym::minnumf128 => self.float_min_intrinsic::<Quad>(args, dest)?,
536+
sym::minnumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::MinNum, dest)?,
537+
sym::minnumf32 => self.float_minmax_intrinsic::<Single>(args, MinMax::MinNum, dest)?,
538+
sym::minnumf64 => self.float_minmax_intrinsic::<Double>(args, MinMax::MinNum, dest)?,
539+
sym::minnumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::MinNum, dest)?,
520540

521-
sym::minimumf16 => self.float_minimum_intrinsic::<Half>(args, dest)?,
522-
sym::minimumf32 => self.float_minimum_intrinsic::<Single>(args, dest)?,
523-
sym::minimumf64 => self.float_minimum_intrinsic::<Double>(args, dest)?,
524-
sym::minimumf128 => self.float_minimum_intrinsic::<Quad>(args, dest)?,
541+
sym::minimumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Minimum, dest)?,
542+
sym::minimumf32 => {
543+
self.float_minmax_intrinsic::<Single>(args, MinMax::Minimum, dest)?
544+
}
545+
sym::minimumf64 => {
546+
self.float_minmax_intrinsic::<Double>(args, MinMax::Minimum, dest)?
547+
}
548+
sym::minimumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Minimum, dest)?,
525549

526-
sym::maxnumf16 => self.float_max_intrinsic::<Half>(args, dest)?,
527-
sym::maxnumf32 => self.float_max_intrinsic::<Single>(args, dest)?,
528-
sym::maxnumf64 => self.float_max_intrinsic::<Double>(args, dest)?,
529-
sym::maxnumf128 => self.float_max_intrinsic::<Quad>(args, dest)?,
550+
sym::maxnumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::MaxNum, dest)?,
551+
sym::maxnumf32 => self.float_minmax_intrinsic::<Single>(args, MinMax::MaxNum, dest)?,
552+
sym::maxnumf64 => self.float_minmax_intrinsic::<Double>(args, MinMax::MaxNum, dest)?,
553+
sym::maxnumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::MaxNum, dest)?,
530554

531-
sym::maximumf16 => self.float_maximum_intrinsic::<Half>(args, dest)?,
532-
sym::maximumf32 => self.float_maximum_intrinsic::<Single>(args, dest)?,
533-
sym::maximumf64 => self.float_maximum_intrinsic::<Double>(args, dest)?,
534-
sym::maximumf128 => self.float_maximum_intrinsic::<Quad>(args, dest)?,
555+
sym::maximumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Maximum, dest)?,
556+
sym::maximumf32 => {
557+
self.float_minmax_intrinsic::<Single>(args, MinMax::Maximum, dest)?
558+
}
559+
sym::maximumf64 => {
560+
self.float_minmax_intrinsic::<Double>(args, MinMax::Maximum, dest)?
561+
}
562+
sym::maximumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Maximum, dest)?,
535563

536564
sym::copysignf16 => self.float_copysign_intrinsic::<Half>(args, dest)?,
537565
sym::copysignf32 => self.float_copysign_intrinsic::<Single>(args, dest)?,
@@ -936,76 +964,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
936964
interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
937965
}
938966

939-
fn float_min_intrinsic<F>(
940-
&mut self,
941-
args: &[OpTy<'tcx, M::Provenance>],
942-
dest: &PlaceTy<'tcx, M::Provenance>,
943-
) -> InterpResult<'tcx, ()>
944-
where
945-
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
946-
{
947-
let a: F = self.read_scalar(&args[0])?.to_float()?;
948-
let b: F = self.read_scalar(&args[1])?.to_float()?;
949-
let res = if a == b {
950-
// They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
951-
// Let the machine decide which one to return.
952-
M::equal_float_min_max(self, a, b)
953-
} else {
954-
self.adjust_nan(a.min(b), &[a, b])
955-
};
956-
self.write_scalar(res, dest)?;
957-
interp_ok(())
958-
}
959-
960-
fn float_max_intrinsic<F>(
961-
&mut self,
962-
args: &[OpTy<'tcx, M::Provenance>],
963-
dest: &PlaceTy<'tcx, M::Provenance>,
964-
) -> InterpResult<'tcx, ()>
967+
fn float_minmax<F>(
968+
&self,
969+
a: Scalar<M::Provenance>,
970+
b: Scalar<M::Provenance>,
971+
op: MinMax,
972+
) -> InterpResult<'tcx, Scalar<M::Provenance>>
965973
where
966974
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
967975
{
968-
let a: F = self.read_scalar(&args[0])?.to_float()?;
969-
let b: F = self.read_scalar(&args[1])?.to_float()?;
970-
let res = if a == b {
976+
let a: F = a.to_float()?;
977+
let b: F = b.to_float()?;
978+
let res = if matches!(op, MinMax::MinNum | MinMax::MaxNum) && a == b {
971979
// They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
972980
// Let the machine decide which one to return.
973981
M::equal_float_min_max(self, a, b)
974982
} else {
975-
self.adjust_nan(a.max(b), &[a, b])
983+
let result = match op {
984+
MinMax::Minimum => a.minimum(b),
985+
MinMax::MinNum => a.min(b),
986+
MinMax::Maximum => a.maximum(b),
987+
MinMax::MaxNum => a.max(b),
988+
};
989+
self.adjust_nan(result, &[a, b])
976990
};
977-
self.write_scalar(res, dest)?;
978-
interp_ok(())
979-
}
980991

981-
fn float_minimum_intrinsic<F>(
982-
&mut self,
983-
args: &[OpTy<'tcx, M::Provenance>],
984-
dest: &PlaceTy<'tcx, M::Provenance>,
985-
) -> InterpResult<'tcx, ()>
986-
where
987-
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
988-
{
989-
let a: F = self.read_scalar(&args[0])?.to_float()?;
990-
let b: F = self.read_scalar(&args[1])?.to_float()?;
991-
let res = a.minimum(b);
992-
let res = self.adjust_nan(res, &[a, b]);
993-
self.write_scalar(res, dest)?;
994-
interp_ok(())
992+
interp_ok(res.into())
995993
}
996994

997-
fn float_maximum_intrinsic<F>(
995+
fn float_minmax_intrinsic<F>(
998996
&mut self,
999997
args: &[OpTy<'tcx, M::Provenance>],
998+
op: MinMax,
1000999
dest: &PlaceTy<'tcx, M::Provenance>,
10011000
) -> InterpResult<'tcx, ()>
10021001
where
10031002
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
10041003
{
1005-
let a: F = self.read_scalar(&args[0])?.to_float()?;
1006-
let b: F = self.read_scalar(&args[1])?.to_float()?;
1007-
let res = a.maximum(b);
1008-
let res = self.adjust_nan(res, &[a, b]);
1004+
let res =
1005+
self.float_minmax::<F>(self.read_scalar(&args[0])?, self.read_scalar(&args[1])?, op)?;
10091006
self.write_scalar(res, dest)?;
10101007
interp_ok(())
10111008
}

compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs

Lines changed: 15 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,11 @@ use rustc_span::{Symbol, sym};
99
use tracing::trace;
1010

1111
use super::{
12-
ImmTy, InterpCx, InterpResult, Machine, MulAddType, OpTy, PlaceTy, Provenance, Scalar, Size,
13-
interp_ok, throw_ub_format,
12+
ImmTy, InterpCx, InterpResult, Machine, MinMax, MulAddType, OpTy, PlaceTy, Provenance, Scalar,
13+
Size, interp_ok, throw_ub_format,
1414
};
1515
use crate::interpret::Writeable;
1616

17-
#[derive(Copy, Clone)]
18-
pub(crate) enum MinMax {
19-
Min,
20-
Max,
21-
}
22-
2317
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
2418
/// Returns `true` if emulation happened.
2519
/// Here we implement the intrinsics that are common to all CTFE instances; individual machines can add their own
@@ -217,8 +211,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
217211
sym::simd_le => Op::MirOp(BinOp::Le),
218212
sym::simd_gt => Op::MirOp(BinOp::Gt),
219213
sym::simd_ge => Op::MirOp(BinOp::Ge),
220-
sym::simd_fmax => Op::FMinMax(MinMax::Max),
221-
sym::simd_fmin => Op::FMinMax(MinMax::Min),
214+
sym::simd_fmax => Op::FMinMax(MinMax::MaxNum),
215+
sym::simd_fmin => Op::FMinMax(MinMax::MinNum),
222216
sym::simd_saturating_add => Op::SaturatingOp(BinOp::Add),
223217
sym::simd_saturating_sub => Op::SaturatingOp(BinOp::Sub),
224218
sym::simd_arith_offset => Op::WrappingOffset,
@@ -310,8 +304,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
310304
sym::simd_reduce_xor => Op::MirOp(BinOp::BitXor),
311305
sym::simd_reduce_any => Op::MirOpBool(BinOp::BitOr),
312306
sym::simd_reduce_all => Op::MirOpBool(BinOp::BitAnd),
313-
sym::simd_reduce_max => Op::MinMax(MinMax::Max),
314-
sym::simd_reduce_min => Op::MinMax(MinMax::Min),
307+
sym::simd_reduce_max => Op::MinMax(MinMax::MaxNum),
308+
sym::simd_reduce_min => Op::MinMax(MinMax::MinNum),
315309
_ => unreachable!(),
316310
};
317311

@@ -333,10 +327,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
333327
if matches!(res.layout.ty.kind(), ty::Float(_)) {
334328
ImmTy::from_scalar(self.fminmax_op(mmop, &res, &op)?, res.layout)
335329
} else {
336-
// Just boring integers, so NaNs to worry about
330+
// Just boring integers, no NaNs to worry about.
337331
let mirop = match mmop {
338-
MinMax::Min => BinOp::Le,
339-
MinMax::Max => BinOp::Ge,
332+
MinMax::MinNum | MinMax::Minimum => BinOp::Le,
333+
MinMax::MaxNum | MinMax::Maximum => BinOp::Ge,
340334
};
341335
if self.binary_op(mirop, &res, &op)?.to_scalar().to_bool()? {
342336
res
@@ -749,12 +743,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
749743
interp_ok(true)
750744
}
751745

752-
fn fminmax_op<Prov: Provenance>(
746+
fn fminmax_op(
753747
&self,
754748
op: MinMax,
755-
left: &ImmTy<'tcx, Prov>,
756-
right: &ImmTy<'tcx, Prov>,
757-
) -> InterpResult<'tcx, Scalar<Prov>> {
749+
left: &ImmTy<'tcx, M::Provenance>,
750+
right: &ImmTy<'tcx, M::Provenance>,
751+
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
758752
assert_eq!(left.layout.ty, right.layout.ty);
759753
let ty::Float(float_ty) = left.layout.ty.kind() else {
760754
bug!("fmax operand is not a float")
@@ -763,26 +757,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
763757
let right = right.to_scalar();
764758
interp_ok(match float_ty {
765759
FloatTy::F16 => unimplemented!("f16_f128"),
766-
FloatTy::F32 => {
767-
let left = left.to_f32()?;
768-
let right = right.to_f32()?;
769-
let res = match op {
770-
MinMax::Min => left.min(right),
771-
MinMax::Max => left.max(right),
772-
};
773-
let res = self.adjust_nan(res, &[left, right]);
774-
Scalar::from_f32(res)
775-
}
776-
FloatTy::F64 => {
777-
let left = left.to_f64()?;
778-
let right = right.to_f64()?;
779-
let res = match op {
780-
MinMax::Min => left.min(right),
781-
MinMax::Max => left.max(right),
782-
};
783-
let res = self.adjust_nan(res, &[left, right]);
784-
Scalar::from_f64(res)
785-
}
760+
FloatTy::F32 => self.float_minmax::<Single>(left, right, op)?,
761+
FloatTy::F64 => self.float_minmax::<Double>(left, right, op)?,
786762
FloatTy::F128 => unimplemented!("f16_f128"),
787763
})
788764
}

0 commit comments

Comments
 (0)