|
2 | 2 | //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
|
3 | 3 | //! and miri.
|
4 | 4 |
|
| 5 | +mod simd; |
| 6 | + |
5 | 7 | use std::assert_matches::assert_matches;
|
6 | 8 |
|
7 | 9 | use rustc_abi::{FieldIdx, HasDataLayout, Size};
|
8 | 10 | use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
9 | 11 | use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
|
10 | 12 | use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
|
11 | 13 | use rustc_middle::ty::layout::TyAndLayout;
|
12 |
| -use rustc_middle::ty::{Ty, TyCtxt}; |
13 |
| -use rustc_middle::{bug, ty}; |
| 14 | +use rustc_middle::ty::{FloatTy, Ty, TyCtxt}; |
| 15 | +use rustc_middle::{bug, span_bug, ty}; |
14 | 16 | use rustc_span::{Symbol, sym};
|
15 | 17 | use tracing::trace;
|
16 | 18 |
|
@@ -121,6 +123,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
121 | 123 | ) -> InterpResult<'tcx, bool> {
|
122 | 124 | let instance_args = instance.args;
|
123 | 125 | let intrinsic_name = self.tcx.item_name(instance.def_id());
|
| 126 | + |
| 127 | + if intrinsic_name.as_str().starts_with("simd_") { |
| 128 | + return self.eval_simd_intrinsic(intrinsic_name, instance_args, args, dest, ret); |
| 129 | + } |
| 130 | + |
124 | 131 | let tcx = self.tcx.tcx;
|
125 | 132 |
|
126 | 133 | match intrinsic_name {
|
@@ -454,37 +461,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
454 | 461 | self.exact_div(&val, &size, dest)?;
|
455 | 462 | }
|
456 | 463 |
|
457 |
| - sym::simd_insert => { |
458 |
| - let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); |
459 |
| - let elem = &args[2]; |
460 |
| - let (input, input_len) = self.project_to_simd(&args[0])?; |
461 |
| - let (dest, dest_len) = self.project_to_simd(dest)?; |
462 |
| - assert_eq!(input_len, dest_len, "Return vector length must match input length"); |
463 |
| - // Bounds are not checked by typeck so we have to do it ourselves. |
464 |
| - if index >= input_len { |
465 |
| - throw_ub_format!( |
466 |
| - "`simd_insert` index {index} is out-of-bounds of vector with length {input_len}" |
467 |
| - ); |
468 |
| - } |
469 |
| - |
470 |
| - for i in 0..dest_len { |
471 |
| - let place = self.project_index(&dest, i)?; |
472 |
| - let value = |
473 |
| - if i == index { elem.clone() } else { self.project_index(&input, i)? }; |
474 |
| - self.copy_op(&value, &place)?; |
475 |
| - } |
476 |
| - } |
477 |
| - sym::simd_extract => { |
478 |
| - let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); |
479 |
| - let (input, input_len) = self.project_to_simd(&args[0])?; |
480 |
| - // Bounds are not checked by typeck so we have to do it ourselves. |
481 |
| - if index >= input_len { |
482 |
| - throw_ub_format!( |
483 |
| - "`simd_extract` index {index} is out-of-bounds of vector with length {input_len}" |
484 |
| - ); |
485 |
| - } |
486 |
| - self.copy_op(&self.project_index(&input, index)?, dest)?; |
487 |
| - } |
488 | 464 | sym::black_box => {
|
489 | 465 | // These just return their argument
|
490 | 466 | self.copy_op(&args[0], dest)?;
|
@@ -1035,4 +1011,66 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
1035 | 1011 | self.write_scalar(res, dest)?;
|
1036 | 1012 | interp_ok(())
|
1037 | 1013 | }
|
| 1014 | + |
| 1015 | + /// Converts `src` from floating point to integer type `dest_ty` |
| 1016 | + /// after rounding with mode `round`. |
| 1017 | + /// Returns `None` if `f` is NaN or out of range. |
| 1018 | + pub fn float_to_int_checked( |
| 1019 | + &self, |
| 1020 | + src: &ImmTy<'tcx, M::Provenance>, |
| 1021 | + cast_to: TyAndLayout<'tcx>, |
| 1022 | + round: rustc_apfloat::Round, |
| 1023 | + ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::Provenance>>> { |
| 1024 | + fn float_to_int_inner<'tcx, F: rustc_apfloat::Float, M: Machine<'tcx>>( |
| 1025 | + ecx: &InterpCx<'tcx, M>, |
| 1026 | + src: F, |
| 1027 | + cast_to: TyAndLayout<'tcx>, |
| 1028 | + round: rustc_apfloat::Round, |
| 1029 | + ) -> (Scalar<M::Provenance>, rustc_apfloat::Status) { |
| 1030 | + let int_size = cast_to.layout.size; |
| 1031 | + match cast_to.ty.kind() { |
| 1032 | + // Unsigned |
| 1033 | + ty::Uint(_) => { |
| 1034 | + let res = src.to_u128_r(int_size.bits_usize(), round, &mut false); |
| 1035 | + (Scalar::from_uint(res.value, int_size), res.status) |
| 1036 | + } |
| 1037 | + // Signed |
| 1038 | + ty::Int(_) => { |
| 1039 | + let res = src.to_i128_r(int_size.bits_usize(), round, &mut false); |
| 1040 | + (Scalar::from_int(res.value, int_size), res.status) |
| 1041 | + } |
| 1042 | + // Nothing else |
| 1043 | + _ => span_bug!( |
| 1044 | + ecx.cur_span(), |
| 1045 | + "attempted float-to-int conversion with non-int output type {}", |
| 1046 | + cast_to.ty, |
| 1047 | + ), |
| 1048 | + } |
| 1049 | + } |
| 1050 | + |
| 1051 | + let ty::Float(fty) = src.layout.ty.kind() else { |
| 1052 | + bug!("float_to_int_checked: non-float input type {}", src.layout.ty) |
| 1053 | + }; |
| 1054 | + |
| 1055 | + let (val, status) = match fty { |
| 1056 | + FloatTy::F16 => float_to_int_inner(self, src.to_scalar().to_f16()?, cast_to, round), |
| 1057 | + FloatTy::F32 => float_to_int_inner(self, src.to_scalar().to_f32()?, cast_to, round), |
| 1058 | + FloatTy::F64 => float_to_int_inner(self, src.to_scalar().to_f64()?, cast_to, round), |
| 1059 | + FloatTy::F128 => float_to_int_inner(self, src.to_scalar().to_f128()?, cast_to, round), |
| 1060 | + }; |
| 1061 | + |
| 1062 | + if status.intersects( |
| 1063 | + rustc_apfloat::Status::INVALID_OP |
| 1064 | + | rustc_apfloat::Status::OVERFLOW |
| 1065 | + | rustc_apfloat::Status::UNDERFLOW, |
| 1066 | + ) { |
| 1067 | + // Floating point value is NaN (flagged with INVALID_OP) or outside the range |
| 1068 | + // of values of the integer type (flagged with OVERFLOW or UNDERFLOW). |
| 1069 | + interp_ok(None) |
| 1070 | + } else { |
| 1071 | + // Floating point value can be represented by the integer type after rounding. |
| 1072 | + // The INEXACT flag is ignored on purpose to allow rounding. |
| 1073 | + interp_ok(Some(ImmTy::from_scalar(val, cast_to))) |
| 1074 | + } |
| 1075 | + } |
1038 | 1076 | }
|
0 commit comments