Skip to content

Commit a67261b

Browse files
committed
Refactor implementation of float minmax intrinsics
1 parent a382c74 commit a67261b

File tree

2 files changed

+70
-109
lines changed

2 files changed

+70
-109
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 54 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ use super::{
2525
};
2626
use crate::fluent_generated as fluent;
2727

28+
#[derive(Copy, Clone)]
29+
pub(crate) enum MinMax {
30+
Minimum,
31+
Minnum,
32+
Maximum,
33+
Maxnum,
34+
}
35+
2836
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
2937
pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId, u64) {
3038
let path = crate::util::type_name(tcx, ty);
@@ -486,25 +494,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
486494
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
487495
}
488496

489-
sym::minnumf16 => self.float_min_intrinsic::<Half>(args, dest)?,
490-
sym::minnumf32 => self.float_min_intrinsic::<Single>(args, dest)?,
491-
sym::minnumf64 => self.float_min_intrinsic::<Double>(args, dest)?,
492-
sym::minnumf128 => self.float_min_intrinsic::<Quad>(args, dest)?,
497+
sym::minnumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Minnum, dest)?,
498+
sym::minnumf32 => self.float_minmax_intrinsic::<Single>(args, MinMax::Minnum, dest)?,
499+
sym::minnumf64 => self.float_minmax_intrinsic::<Double>(args, MinMax::Minnum, dest)?,
500+
sym::minnumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Minnum, dest)?,
493501

494-
sym::minimumf16 => self.float_minimum_intrinsic::<Half>(args, dest)?,
495-
sym::minimumf32 => self.float_minimum_intrinsic::<Single>(args, dest)?,
496-
sym::minimumf64 => self.float_minimum_intrinsic::<Double>(args, dest)?,
497-
sym::minimumf128 => self.float_minimum_intrinsic::<Quad>(args, dest)?,
502+
sym::minimumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Minimum, dest)?,
503+
sym::minimumf32 => {
504+
self.float_minmax_intrinsic::<Single>(args, MinMax::Minimum, dest)?
505+
}
506+
sym::minimumf64 => {
507+
self.float_minmax_intrinsic::<Double>(args, MinMax::Minimum, dest)?
508+
}
509+
sym::minimumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Minimum, dest)?,
498510

499-
sym::maxnumf16 => self.float_max_intrinsic::<Half>(args, dest)?,
500-
sym::maxnumf32 => self.float_max_intrinsic::<Single>(args, dest)?,
501-
sym::maxnumf64 => self.float_max_intrinsic::<Double>(args, dest)?,
502-
sym::maxnumf128 => self.float_max_intrinsic::<Quad>(args, dest)?,
511+
sym::maxnumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Maxnum, dest)?,
512+
sym::maxnumf32 => self.float_minmax_intrinsic::<Single>(args, MinMax::Maxnum, dest)?,
513+
sym::maxnumf64 => self.float_minmax_intrinsic::<Double>(args, MinMax::Maxnum, dest)?,
514+
sym::maxnumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Maxnum, dest)?,
503515

504-
sym::maximumf16 => self.float_maximum_intrinsic::<Half>(args, dest)?,
505-
sym::maximumf32 => self.float_maximum_intrinsic::<Single>(args, dest)?,
506-
sym::maximumf64 => self.float_maximum_intrinsic::<Double>(args, dest)?,
507-
sym::maximumf128 => self.float_maximum_intrinsic::<Quad>(args, dest)?,
516+
sym::maximumf16 => self.float_minmax_intrinsic::<Half>(args, MinMax::Maximum, dest)?,
517+
sym::maximumf32 => {
518+
self.float_minmax_intrinsic::<Single>(args, MinMax::Maximum, dest)?
519+
}
520+
sym::maximumf64 => {
521+
self.float_minmax_intrinsic::<Double>(args, MinMax::Maximum, dest)?
522+
}
523+
sym::maximumf128 => self.float_minmax_intrinsic::<Quad>(args, MinMax::Maximum, dest)?,
508524

509525
sym::copysignf16 => self.float_copysign_intrinsic::<Half>(args, dest)?,
510526
sym::copysignf32 => self.float_copysign_intrinsic::<Single>(args, dest)?,
@@ -901,76 +917,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
901917
interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
902918
}
903919

904-
fn float_min_intrinsic<F>(
905-
&mut self,
906-
args: &[OpTy<'tcx, M::Provenance>],
907-
dest: &PlaceTy<'tcx, M::Provenance>,
908-
) -> InterpResult<'tcx, ()>
909-
where
910-
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
911-
{
912-
let a: F = self.read_scalar(&args[0])?.to_float()?;
913-
let b: F = self.read_scalar(&args[1])?.to_float()?;
914-
let res = if a == b {
915-
// They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
916-
// Let the machine decide which one to return.
917-
M::equal_float_min_max(self, a, b)
918-
} else {
919-
self.adjust_nan(a.min(b), &[a, b])
920-
};
921-
self.write_scalar(res, dest)?;
922-
interp_ok(())
923-
}
924-
925-
fn float_max_intrinsic<F>(
926-
&mut self,
927-
args: &[OpTy<'tcx, M::Provenance>],
928-
dest: &PlaceTy<'tcx, M::Provenance>,
929-
) -> InterpResult<'tcx, ()>
920+
fn float_minmax<F>(
921+
&self,
922+
a: Scalar<M::Provenance>,
923+
b: Scalar<M::Provenance>,
924+
op: MinMax,
925+
) -> InterpResult<'tcx, F>
930926
where
931-
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
927+
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F>,
932928
{
933-
let a: F = self.read_scalar(&args[0])?.to_float()?;
934-
let b: F = self.read_scalar(&args[1])?.to_float()?;
935-
let res = if a == b {
929+
let a: F = a.to_float()?;
930+
let b: F = b.to_float()?;
931+
let res = if matches!(op, MinMax::Minnum | MinMax::Maxnum) && a == b {
936932
// They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
937933
// Let the machine decide which one to return.
938934
M::equal_float_min_max(self, a, b)
939935
} else {
940-
self.adjust_nan(a.max(b), &[a, b])
936+
let result = match op {
937+
MinMax::Minimum => a.minimum(b),
938+
MinMax::Minnum => a.min(b),
939+
MinMax::Maximum => a.maximum(b),
940+
MinMax::Maxnum => a.max(b),
941+
};
942+
self.adjust_nan(result, &[a, b])
941943
};
942-
self.write_scalar(res, dest)?;
943-
interp_ok(())
944-
}
945944

946-
fn float_minimum_intrinsic<F>(
947-
&mut self,
948-
args: &[OpTy<'tcx, M::Provenance>],
949-
dest: &PlaceTy<'tcx, M::Provenance>,
950-
) -> InterpResult<'tcx, ()>
951-
where
952-
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
953-
{
954-
let a: F = self.read_scalar(&args[0])?.to_float()?;
955-
let b: F = self.read_scalar(&args[1])?.to_float()?;
956-
let res = a.minimum(b);
957-
let res = self.adjust_nan(res, &[a, b]);
958-
self.write_scalar(res, dest)?;
959-
interp_ok(())
945+
interp_ok(res)
960946
}
961947

962-
fn float_maximum_intrinsic<F>(
948+
fn float_minmax_intrinsic<F>(
963949
&mut self,
964950
args: &[OpTy<'tcx, M::Provenance>],
951+
op: MinMax,
965952
dest: &PlaceTy<'tcx, M::Provenance>,
966953
) -> InterpResult<'tcx, ()>
967954
where
968955
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
969956
{
970-
let a: F = self.read_scalar(&args[0])?.to_float()?;
971-
let b: F = self.read_scalar(&args[1])?.to_float()?;
972-
let res = a.maximum(b);
973-
let res = self.adjust_nan(res, &[a, b]);
957+
let res =
958+
self.float_minmax::<F>(self.read_scalar(&args[0])?, self.read_scalar(&args[1])?, op)?;
974959
self.write_scalar(res, dest)?;
975960
interp_ok(())
976961
}

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, OpTy, PlaceTy, Provenance, Scalar, Size, interp_ok,
12-
throw_ub_format,
11+
ImmTy, InterpCx, InterpResult, Machine, MinMax, OpTy, PlaceTy, Provenance, Scalar, Size,
12+
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)