Skip to content

Commit c1878f3

Browse files
committed
Refactor implementation of float minmax intrinsics
1 parent effe469 commit c1878f3

File tree

2 files changed

+74
-109
lines changed

2 files changed

+74
-109
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 58 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ 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+
Minimum,
41+
/// The IEEE `MinNum` operation - see `f32::min` etc
42+
Minnum,
43+
/// The IEEE `Maximum` operation - see `f32::maximum` etc
44+
Maximum,
45+
/// The IEEE `MaxNum` operation - see `f32::max` etc
46+
Maxnum,
47+
}
48+
3749
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
3850
pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId, u64) {
3951
let path = crate::util::type_name(tcx, ty);
@@ -495,25 +507,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
495507
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
496508
}
497509

498-
sym::minnumf16 => self.float_min_intrinsic::<Half>(args, dest)?,
499-
sym::minnumf32 => self.float_min_intrinsic::<Single>(args, dest)?,
500-
sym::minnumf64 => self.float_min_intrinsic::<Double>(args, dest)?,
501-
sym::minnumf128 => self.float_min_intrinsic::<Quad>(args, dest)?,
510+
sym::minnumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Minnum, dest)?,
511+
sym::minnumf32 => self.float_minmax_intrinsic::<Single>(args, MinMax::Minnum, dest)?,
512+
sym::minnumf64 => self.float_minmax_intrinsic::<Double>(args, MinMax::Minnum, dest)?,
513+
sym::minnumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Minnum, dest)?,
502514

503-
sym::minimumf16 => self.float_minimum_intrinsic::<Half>(args, dest)?,
504-
sym::minimumf32 => self.float_minimum_intrinsic::<Single>(args, dest)?,
505-
sym::minimumf64 => self.float_minimum_intrinsic::<Double>(args, dest)?,
506-
sym::minimumf128 => self.float_minimum_intrinsic::<Quad>(args, dest)?,
515+
sym::minimumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Minimum, dest)?,
516+
sym::minimumf32 => {
517+
self.float_minmax_intrinsic::<Single>(args, MinMax::Minimum, dest)?
518+
}
519+
sym::minimumf64 => {
520+
self.float_minmax_intrinsic::<Double>(args, MinMax::Minimum, dest)?
521+
}
522+
sym::minimumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Minimum, dest)?,
507523

508-
sym::maxnumf16 => self.float_max_intrinsic::<Half>(args, dest)?,
509-
sym::maxnumf32 => self.float_max_intrinsic::<Single>(args, dest)?,
510-
sym::maxnumf64 => self.float_max_intrinsic::<Double>(args, dest)?,
511-
sym::maxnumf128 => self.float_max_intrinsic::<Quad>(args, dest)?,
524+
sym::maxnumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Maxnum, dest)?,
525+
sym::maxnumf32 => self.float_minmax_intrinsic::<Single>(args, MinMax::Maxnum, dest)?,
526+
sym::maxnumf64 => self.float_minmax_intrinsic::<Double>(args, MinMax::Maxnum, dest)?,
527+
sym::maxnumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Maxnum, dest)?,
512528

513-
sym::maximumf16 => self.float_maximum_intrinsic::<Half>(args, dest)?,
514-
sym::maximumf32 => self.float_maximum_intrinsic::<Single>(args, dest)?,
515-
sym::maximumf64 => self.float_maximum_intrinsic::<Double>(args, dest)?,
516-
sym::maximumf128 => self.float_maximum_intrinsic::<Quad>(args, dest)?,
529+
sym::maximumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Maximum, dest)?,
530+
sym::maximumf32 => {
531+
self.float_minmax_intrinsic::<Single>(args, MinMax::Maximum, dest)?
532+
}
533+
sym::maximumf64 => {
534+
self.float_minmax_intrinsic::<Double>(args, MinMax::Maximum, dest)?
535+
}
536+
sym::maximumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Maximum, dest)?,
517537

518538
sym::copysignf16 => self.float_copysign_intrinsic::<Half>(args, dest)?,
519539
sym::copysignf32 => self.float_copysign_intrinsic::<Single>(args, dest)?,
@@ -918,76 +938,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
918938
interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
919939
}
920940

921-
fn float_min_intrinsic<F>(
922-
&mut self,
923-
args: &[OpTy<'tcx, M::Provenance>],
924-
dest: &PlaceTy<'tcx, M::Provenance>,
925-
) -> InterpResult<'tcx, ()>
926-
where
927-
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
928-
{
929-
let a: F = self.read_scalar(&args[0])?.to_float()?;
930-
let b: F = self.read_scalar(&args[1])?.to_float()?;
931-
let res = if a == b {
932-
// They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
933-
// Let the machine decide which one to return.
934-
M::equal_float_min_max(self, a, b)
935-
} else {
936-
self.adjust_nan(a.min(b), &[a, b])
937-
};
938-
self.write_scalar(res, dest)?;
939-
interp_ok(())
940-
}
941-
942-
fn float_max_intrinsic<F>(
943-
&mut self,
944-
args: &[OpTy<'tcx, M::Provenance>],
945-
dest: &PlaceTy<'tcx, M::Provenance>,
946-
) -> InterpResult<'tcx, ()>
941+
fn float_minmax<F>(
942+
&self,
943+
a: Scalar<M::Provenance>,
944+
b: Scalar<M::Provenance>,
945+
op: MinMax,
946+
) -> InterpResult<'tcx, F>
947947
where
948-
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
948+
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F>,
949949
{
950-
let a: F = self.read_scalar(&args[0])?.to_float()?;
951-
let b: F = self.read_scalar(&args[1])?.to_float()?;
952-
let res = if a == b {
950+
let a: F = a.to_float()?;
951+
let b: F = b.to_float()?;
952+
let res = if matches!(op, MinMax::Minnum | MinMax::Maxnum) && a == b {
953953
// They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
954954
// Let the machine decide which one to return.
955955
M::equal_float_min_max(self, a, b)
956956
} else {
957-
self.adjust_nan(a.max(b), &[a, b])
957+
let result = match op {
958+
MinMax::Minimum => a.minimum(b),
959+
MinMax::Minnum => a.min(b),
960+
MinMax::Maximum => a.maximum(b),
961+
MinMax::Maxnum => a.max(b),
962+
};
963+
self.adjust_nan(result, &[a, b])
958964
};
959-
self.write_scalar(res, dest)?;
960-
interp_ok(())
961-
}
962965

963-
fn float_minimum_intrinsic<F>(
964-
&mut self,
965-
args: &[OpTy<'tcx, M::Provenance>],
966-
dest: &PlaceTy<'tcx, M::Provenance>,
967-
) -> InterpResult<'tcx, ()>
968-
where
969-
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
970-
{
971-
let a: F = self.read_scalar(&args[0])?.to_float()?;
972-
let b: F = self.read_scalar(&args[1])?.to_float()?;
973-
let res = a.minimum(b);
974-
let res = self.adjust_nan(res, &[a, b]);
975-
self.write_scalar(res, dest)?;
976-
interp_ok(())
966+
interp_ok(res)
977967
}
978968

979-
fn float_maximum_intrinsic<F>(
969+
fn float_minmax_intrinsic<F>(
980970
&mut self,
981971
args: &[OpTy<'tcx, M::Provenance>],
972+
op: MinMax,
982973
dest: &PlaceTy<'tcx, M::Provenance>,
983974
) -> InterpResult<'tcx, ()>
984975
where
985976
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
986977
{
987-
let a: F = self.read_scalar(&args[0])?.to_float()?;
988-
let b: F = self.read_scalar(&args[1])?.to_float()?;
989-
let res = a.maximum(b);
990-
let res = self.adjust_nan(res, &[a, b]);
978+
let res =
979+
self.float_minmax::<F>(self.read_scalar(&args[0])?, self.read_scalar(&args[1])?, op)?;
991980
self.write_scalar(res, dest)?;
992981
interp_ok(())
993982
}

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

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,11 @@ use rustc_span::{Symbol, sym};
88
use tracing::trace;
99

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

16-
#[derive(Copy, Clone)]
17-
pub(crate) enum MinMax {
18-
Min,
19-
Max,
20-
}
21-
2216
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
2317
/// Returns `true` if emulation happened.
2418
/// Here we implement the intrinsics that are common to all CTFE instances; individual machines can add their own
@@ -216,8 +210,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
216210
sym::simd_le => Op::MirOp(BinOp::Le),
217211
sym::simd_gt => Op::MirOp(BinOp::Gt),
218212
sym::simd_ge => Op::MirOp(BinOp::Ge),
219-
sym::simd_fmax => Op::FMinMax(MinMax::Max),
220-
sym::simd_fmin => Op::FMinMax(MinMax::Min),
213+
sym::simd_fmax => Op::FMinMax(MinMax::Maxnum),
214+
sym::simd_fmin => Op::FMinMax(MinMax::Minnum),
221215
sym::simd_saturating_add => Op::SaturatingOp(BinOp::Add),
222216
sym::simd_saturating_sub => Op::SaturatingOp(BinOp::Sub),
223217
sym::simd_arith_offset => Op::WrappingOffset,
@@ -309,8 +303,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
309303
sym::simd_reduce_xor => Op::MirOp(BinOp::BitXor),
310304
sym::simd_reduce_any => Op::MirOpBool(BinOp::BitOr),
311305
sym::simd_reduce_all => Op::MirOpBool(BinOp::BitAnd),
312-
sym::simd_reduce_max => Op::MinMax(MinMax::Max),
313-
sym::simd_reduce_min => Op::MinMax(MinMax::Min),
306+
sym::simd_reduce_max => Op::MinMax(MinMax::Maxnum),
307+
sym::simd_reduce_min => Op::MinMax(MinMax::Minnum),
314308
_ => unreachable!(),
315309
};
316310

@@ -334,8 +328,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
334328
} else {
335329
// Just boring integers, so NaNs to worry about
336330
let mirop = match mmop {
337-
MinMax::Min => BinOp::Le,
338-
MinMax::Max => BinOp::Ge,
331+
MinMax::Minnum | MinMax::Minimum => BinOp::Le,
332+
MinMax::Maxnum | MinMax::Maximum => BinOp::Ge,
339333
};
340334
if self.binary_op(mirop, &res, &op)?.to_scalar().to_bool()? {
341335
res
@@ -748,41 +742,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
748742
interp_ok(true)
749743
}
750744

751-
fn fminmax_op<Prov: Provenance>(
745+
fn fminmax_op(
752746
&self,
753747
op: MinMax,
754-
left: &ImmTy<'tcx, Prov>,
755-
right: &ImmTy<'tcx, Prov>,
756-
) -> InterpResult<'tcx, Scalar<Prov>> {
748+
left: &ImmTy<'tcx, M::Provenance>,
749+
right: &ImmTy<'tcx, M::Provenance>,
750+
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
757751
assert_eq!(left.layout.ty, right.layout.ty);
758752
let ty::Float(float_ty) = left.layout.ty.kind() else {
759753
bug!("fmax operand is not a float")
760754
};
761755
let left = left.to_scalar();
762756
let right = right.to_scalar();
763757
interp_ok(match float_ty {
764-
FloatTy::F16 => unimplemented!("f16_f128"),
765-
FloatTy::F32 => {
766-
let left = left.to_f32()?;
767-
let right = right.to_f32()?;
768-
let res = match op {
769-
MinMax::Min => left.min(right),
770-
MinMax::Max => left.max(right),
771-
};
772-
let res = self.adjust_nan(res, &[left, right]);
773-
Scalar::from_f32(res)
774-
}
775-
FloatTy::F64 => {
776-
let left = left.to_f64()?;
777-
let right = right.to_f64()?;
778-
let res = match op {
779-
MinMax::Min => left.min(right),
780-
MinMax::Max => left.max(right),
781-
};
782-
let res = self.adjust_nan(res, &[left, right]);
783-
Scalar::from_f64(res)
784-
}
785-
FloatTy::F128 => unimplemented!("f16_f128"),
758+
FloatTy::F16 => Scalar::from_f16(self.float_minmax(left, right, op)?),
759+
FloatTy::F32 => Scalar::from_f32(self.float_minmax(left, right, op)?),
760+
FloatTy::F64 => Scalar::from_f64(self.float_minmax(left, right, op)?),
761+
FloatTy::F128 => Scalar::from_f128(self.float_minmax(left, right, op)?),
786762
})
787763
}
788764
}

0 commit comments

Comments
 (0)