@@ -5,17 +5,18 @@ use std::time::Duration;
55
66use log:: trace;
77
8+ use rustc_apfloat:: ieee:: { Double , Single } ;
89use rustc_hir:: def:: { DefKind , Namespace } ;
910use rustc_hir:: def_id:: { DefId , CRATE_DEF_INDEX } ;
1011use rustc_index:: IndexVec ;
1112use rustc_middle:: mir;
1213use rustc_middle:: ty:: {
1314 self ,
14- layout:: { IntegerExt as _ , LayoutOf , TyAndLayout } ,
15- IntTy , Ty , TyCtxt , UintTy ,
15+ layout:: { LayoutOf , TyAndLayout } ,
16+ FloatTy , IntTy , Ty , TyCtxt , UintTy ,
1617} ;
1718use rustc_span:: { def_id:: CrateNum , sym, Span , Symbol } ;
18- use rustc_target:: abi:: { Align , FieldIdx , FieldsShape , Integer , Size , Variants } ;
19+ use rustc_target:: abi:: { Align , FieldIdx , FieldsShape , Size , Variants } ;
1920use rustc_target:: spec:: abi:: Abi ;
2021
2122use rand:: RngCore ;
@@ -986,65 +987,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
986987 }
987988 }
988989
989- /// Converts `f` to integer type `dest_ty` after rounding with mode `round`.
990+ /// Converts `src` from floating point to integer type `dest_ty`
991+ /// after rounding with mode `round`.
990992 /// Returns `None` if `f` is NaN or out of range.
991- fn float_to_int_checked < F > (
993+ fn float_to_int_checked (
992994 & self ,
993- f : F ,
995+ src : & ImmTy < ' tcx , Provenance > ,
994996 cast_to : TyAndLayout < ' tcx > ,
995997 round : rustc_apfloat:: Round ,
996- ) -> Option < ImmTy < ' tcx , Provenance > >
997- where
998- F : rustc_apfloat:: Float + Into < Scalar < Provenance > > ,
999- {
998+ ) -> InterpResult < ' tcx , Option < ImmTy < ' tcx , Provenance > > > {
1000999 let this = self . eval_context_ref ( ) ;
10011000
1002- let val = match cast_to. ty . kind ( ) {
1003- // Unsigned
1004- ty:: Uint ( t) => {
1005- let size = Integer :: from_uint_ty ( this, * t) . size ( ) ;
1006- let res = f. to_u128_r ( size. bits_usize ( ) , round, & mut false ) ;
1007- if res. status . intersects (
1008- rustc_apfloat:: Status :: INVALID_OP
1009- | rustc_apfloat:: Status :: OVERFLOW
1010- | rustc_apfloat:: Status :: UNDERFLOW ,
1011- ) {
1012- // Floating point value is NaN (flagged with INVALID_OP) or outside the range
1013- // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1014- return None ;
1015- } else {
1016- // Floating point value can be represented by the integer type after rounding.
1017- // The INEXACT flag is ignored on purpose to allow rounding.
1018- Scalar :: from_uint ( res. value , size)
1001+ fn float_to_int_inner < ' tcx , F : rustc_apfloat:: Float > (
1002+ this : & MiriInterpCx < ' _ , ' tcx > ,
1003+ src : F ,
1004+ cast_to : TyAndLayout < ' tcx > ,
1005+ round : rustc_apfloat:: Round ,
1006+ ) -> ( Scalar < Provenance > , rustc_apfloat:: Status ) {
1007+ let int_size = cast_to. layout . size ;
1008+ match cast_to. ty . kind ( ) {
1009+ // Unsigned
1010+ ty:: Uint ( _) => {
1011+ let res = src. to_u128_r ( int_size. bits_usize ( ) , round, & mut false ) ;
1012+ ( Scalar :: from_uint ( res. value , int_size) , res. status )
10191013 }
1020- }
1021- // Signed
1022- ty:: Int ( t) => {
1023- let size = Integer :: from_int_ty ( this, * t) . size ( ) ;
1024- let res = f. to_i128_r ( size. bits_usize ( ) , round, & mut false ) ;
1025- if res. status . intersects (
1026- rustc_apfloat:: Status :: INVALID_OP
1027- | rustc_apfloat:: Status :: OVERFLOW
1028- | rustc_apfloat:: Status :: UNDERFLOW ,
1029- ) {
1030- // Floating point value is NaN (flagged with INVALID_OP) or outside the range
1031- // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1032- return None ;
1033- } else {
1034- // Floating point value can be represented by the integer type after rounding.
1035- // The INEXACT flag is ignored on purpose to allow rounding.
1036- Scalar :: from_int ( res. value , size)
1014+ // Signed
1015+ ty:: Int ( _) => {
1016+ let res = src. to_i128_r ( int_size. bits_usize ( ) , round, & mut false ) ;
1017+ ( Scalar :: from_int ( res. value , int_size) , res. status )
10371018 }
1019+ // Nothing else
1020+ _ =>
1021+ span_bug ! (
1022+ this. cur_span( ) ,
1023+ "attempted float-to-int conversion with non-int output type {}" ,
1024+ cast_to. ty,
1025+ ) ,
10381026 }
1027+ }
1028+
1029+ let ( val, status) = match src. layout . ty . kind ( ) {
1030+ // f32
1031+ ty:: Float ( FloatTy :: F32 ) =>
1032+ float_to_int_inner :: < Single > ( this, src. to_scalar ( ) . to_f32 ( ) ?, cast_to, round) ,
1033+ // f64
1034+ ty:: Float ( FloatTy :: F64 ) =>
1035+ float_to_int_inner :: < Double > ( this, src. to_scalar ( ) . to_f64 ( ) ?, cast_to, round) ,
10391036 // Nothing else
10401037 _ =>
10411038 span_bug ! (
10421039 this. cur_span( ) ,
1043- "attempted float-to-int conversion with non-int output type {}" ,
1044- cast_to . ty,
1040+ "attempted float-to-int conversion with non-float input type {}" ,
1041+ src . layout . ty,
10451042 ) ,
10461043 } ;
1047- Some ( ImmTy :: from_scalar ( val, cast_to) )
1044+
1045+ if status. intersects (
1046+ rustc_apfloat:: Status :: INVALID_OP
1047+ | rustc_apfloat:: Status :: OVERFLOW
1048+ | rustc_apfloat:: Status :: UNDERFLOW ,
1049+ ) {
1050+ // Floating point value is NaN (flagged with INVALID_OP) or outside the range
1051+ // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1052+ Ok ( None )
1053+ } else {
1054+ // Floating point value can be represented by the integer type after rounding.
1055+ // The INEXACT flag is ignored on purpose to allow rounding.
1056+ Ok ( Some ( ImmTy :: from_scalar ( val, cast_to) ) )
1057+ }
10481058 }
10491059
10501060 /// Returns an integer type that is twice wide as `ty`
0 commit comments