diff options
Diffstat (limited to 'compiler/rustc_const_eval/src')
4 files changed, 99 insertions, 19 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 30b5a8d70bc..1def3d08328 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -334,19 +334,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { { use rustc_type_ir::TyKind::*; - fn adjust_nan< - 'tcx, - M: Machine<'tcx>, - F1: rustc_apfloat::Float + FloatConvert<F2>, - F2: rustc_apfloat::Float, - >( - ecx: &InterpCx<'tcx, M>, - f1: F1, - f2: F2, - ) -> F2 { - if f2.is_nan() { M::generate_nan(ecx, &[f1]) } else { f2 } - } - match *dest_ty.kind() { // float -> uint Uint(t) => { @@ -367,11 +354,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // float -> float Float(fty) => match fty { - FloatTy::F16 => Scalar::from_f16(adjust_nan(self, f, f.convert(&mut false).value)), - FloatTy::F32 => Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value)), - FloatTy::F64 => Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value)), + FloatTy::F16 => { + Scalar::from_f16(self.adjust_nan(f.convert(&mut false).value, &[f])) + } + FloatTy::F32 => { + Scalar::from_f32(self.adjust_nan(f.convert(&mut false).value, &[f])) + } + FloatTy::F64 => { + Scalar::from_f64(self.adjust_nan(f.convert(&mut false).value, &[f])) + } FloatTy::F128 => { - Scalar::from_f128(adjust_nan(self, f, f.convert(&mut false).value)) + Scalar::from_f128(self.adjust_nan(f.convert(&mut false).value, &[f])) } }, // That's it. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 5165f95afd5..02dd7821ef6 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -599,6 +599,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> { Frame::generate_stacktrace_from_stack(self.stack()) } + + pub fn adjust_nan<F1, F2>(&self, f: F2, inputs: &[F1]) -> F2 + where + F1: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F2>, + F2: rustc_apfloat::Float, + { + if f.is_nan() { M::generate_nan(self, inputs) } else { f } + } } #[doc(hidden)] diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 52780cc6a3a..540898ec645 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -4,6 +4,7 @@ use std::assert_matches::assert_matches; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_hir::def_id::DefId; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout, ValidityRequirement}; @@ -438,6 +439,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?; } + sym::minnumf16 => self.float_min_intrinsic::<Half>(args, dest)?, + sym::minnumf32 => self.float_min_intrinsic::<Single>(args, dest)?, + sym::minnumf64 => self.float_min_intrinsic::<Double>(args, dest)?, + sym::minnumf128 => self.float_min_intrinsic::<Quad>(args, dest)?, + + sym::maxnumf16 => self.float_max_intrinsic::<Half>(args, dest)?, + sym::maxnumf32 => self.float_max_intrinsic::<Single>(args, dest)?, + sym::maxnumf64 => self.float_max_intrinsic::<Double>(args, dest)?, + sym::maxnumf128 => self.float_max_intrinsic::<Quad>(args, dest)?, + + sym::copysignf16 => self.float_copysign_intrinsic::<Half>(args, dest)?, + sym::copysignf32 => self.float_copysign_intrinsic::<Single>(args, dest)?, + sym::copysignf64 => self.float_copysign_intrinsic::<Double>(args, dest)?, + sym::copysignf128 => self.float_copysign_intrinsic::<Quad>(args, dest)?, + + sym::fabsf16 => self.float_abs_intrinsic::<Half>(args, dest)?, + sym::fabsf32 => self.float_abs_intrinsic::<Single>(args, dest)?, + sym::fabsf64 => self.float_abs_intrinsic::<Double>(args, dest)?, + sym::fabsf128 => self.float_abs_intrinsic::<Quad>(args, dest)?, + // Unsupported intrinsic: skip the return_to_block below. _ => return interp_ok(false), } @@ -697,4 +718,63 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let rhs_bytes = get_bytes(self, rhs)?; interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) } + + fn float_min_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 a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let res = self.adjust_nan(a.min(b), &[a, b]); + self.write_scalar(res, dest)?; + interp_ok(()) + } + + fn float_max_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 a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let res = self.adjust_nan(a.max(b), &[a, b]); + self.write_scalar(res, dest)?; + interp_ok(()) + } + + fn float_copysign_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 a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + // bitwise, no NaN adjustments + self.write_scalar(a.copy_sign(b), 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(()) + } } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 52cd9b898bb..b28ac68ac54 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -64,8 +64,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { use rustc_middle::mir::BinOp::*; // Performs appropriate non-deterministic adjustments of NaN results. - let adjust_nan = - |f: F| -> F { if f.is_nan() { M::generate_nan(self, &[l, r]) } else { f } }; + let adjust_nan = |f: F| -> F { self.adjust_nan(f, &[l, r]) }; match bin_op { Eq => ImmTy::from_bool(l == r, *self.tcx), |
