@@ -5,17 +5,18 @@ use std::time::Duration;
5
5
6
6
use log:: trace;
7
7
8
+ use rustc_apfloat:: ieee:: { Double , Single } ;
8
9
use rustc_hir:: def:: { DefKind , Namespace } ;
9
10
use rustc_hir:: def_id:: { DefId , CRATE_DEF_INDEX } ;
10
11
use rustc_index:: IndexVec ;
11
12
use rustc_middle:: mir;
12
13
use rustc_middle:: ty:: {
13
14
self ,
14
- layout:: { IntegerExt as _ , LayoutOf , TyAndLayout } ,
15
- IntTy , Ty , TyCtxt , UintTy ,
15
+ layout:: { LayoutOf , TyAndLayout } ,
16
+ FloatTy , IntTy , Ty , TyCtxt , UintTy ,
16
17
} ;
17
18
use 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 } ;
19
20
use rustc_target:: spec:: abi:: Abi ;
20
21
21
22
use rand:: RngCore ;
@@ -565,10 +566,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
565
566
/// is part of the UNIX family. It panics showing a message with the `name` of the foreign function
566
567
/// if this is not the case.
567
568
fn assert_target_os_is_unix ( & self , name : & str ) {
568
- assert ! (
569
- target_os_is_unix( self . eval_context_ref( ) . tcx. sess. target. os. as_ref( ) ) ,
570
- "`{name}` is only available for supported UNIX family targets" ,
571
- ) ;
569
+ assert ! ( self . target_os_is_unix( ) , "`{name}` is only available for unix targets" , ) ;
570
+ }
571
+
572
+ fn target_os_is_unix ( & self ) -> bool {
573
+ self . eval_context_ref ( ) . tcx . sess . target . families . iter ( ) . any ( |f| f == "unix" )
572
574
}
573
575
574
576
/// Get last error variable as a place, lazily allocating thread-local storage for it if
@@ -985,65 +987,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
985
987
}
986
988
}
987
989
988
- /// 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`.
989
992
/// Returns `None` if `f` is NaN or out of range.
990
- fn float_to_int_checked < F > (
993
+ fn float_to_int_checked (
991
994
& self ,
992
- f : F ,
995
+ src : & ImmTy < ' tcx , Provenance > ,
993
996
cast_to : TyAndLayout < ' tcx > ,
994
997
round : rustc_apfloat:: Round ,
995
- ) -> Option < ImmTy < ' tcx , Provenance > >
996
- where
997
- F : rustc_apfloat:: Float + Into < Scalar < Provenance > > ,
998
- {
998
+ ) -> InterpResult < ' tcx , Option < ImmTy < ' tcx , Provenance > > > {
999
999
let this = self . eval_context_ref ( ) ;
1000
1000
1001
- let val = match cast_to. ty . kind ( ) {
1002
- // Unsigned
1003
- ty:: Uint ( t) => {
1004
- let size = Integer :: from_uint_ty ( this, * t) . size ( ) ;
1005
- let res = f. to_u128_r ( size. bits_usize ( ) , round, & mut false ) ;
1006
- if res. status . intersects (
1007
- rustc_apfloat:: Status :: INVALID_OP
1008
- | rustc_apfloat:: Status :: OVERFLOW
1009
- | rustc_apfloat:: Status :: UNDERFLOW ,
1010
- ) {
1011
- // Floating point value is NaN (flagged with INVALID_OP) or outside the range
1012
- // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1013
- return None ;
1014
- } else {
1015
- // Floating point value can be represented by the integer type after rounding.
1016
- // The INEXACT flag is ignored on purpose to allow rounding.
1017
- 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 )
1018
1013
}
1019
- }
1020
- // Signed
1021
- ty:: Int ( t) => {
1022
- let size = Integer :: from_int_ty ( this, * t) . size ( ) ;
1023
- let res = f. to_i128_r ( size. bits_usize ( ) , round, & mut false ) ;
1024
- if res. status . intersects (
1025
- rustc_apfloat:: Status :: INVALID_OP
1026
- | rustc_apfloat:: Status :: OVERFLOW
1027
- | rustc_apfloat:: Status :: UNDERFLOW ,
1028
- ) {
1029
- // Floating point value is NaN (flagged with INVALID_OP) or outside the range
1030
- // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1031
- return None ;
1032
- } else {
1033
- // Floating point value can be represented by the integer type after rounding.
1034
- // The INEXACT flag is ignored on purpose to allow rounding.
1035
- 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 )
1036
1018
}
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
+ ) ,
1037
1026
}
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) ,
1038
1036
// Nothing else
1039
1037
_ =>
1040
1038
span_bug ! (
1041
1039
this. cur_span( ) ,
1042
- "attempted float-to-int conversion with non-int output type {}" ,
1043
- cast_to . ty,
1040
+ "attempted float-to-int conversion with non-float input type {}" ,
1041
+ src . layout . ty,
1044
1042
) ,
1045
1043
} ;
1046
- 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
+ }
1047
1058
}
1048
1059
1049
1060
/// Returns an integer type that is twice wide as `ty`
@@ -1063,6 +1074,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
1063
1074
_ => span_bug ! ( this. cur_span( ) , "unexpected type: {ty:?}" ) ,
1064
1075
}
1065
1076
}
1077
+
1078
+ /// Checks that target feature `target_feature` is enabled.
1079
+ ///
1080
+ /// If not enabled, emits an UB error that states that the feature is
1081
+ /// required by `intrinsic`.
1082
+ fn expect_target_feature_for_intrinsic (
1083
+ & self ,
1084
+ intrinsic : Symbol ,
1085
+ target_feature : & str ,
1086
+ ) -> InterpResult < ' tcx , ( ) > {
1087
+ let this = self . eval_context_ref ( ) ;
1088
+ if !this. tcx . sess . unstable_target_features . contains ( & Symbol :: intern ( target_feature) ) {
1089
+ throw_ub_format ! (
1090
+ "attempted to call intrinsic `{intrinsic}` that requires missing target feature {target_feature}"
1091
+ ) ;
1092
+ }
1093
+ Ok ( ( ) )
1094
+ }
1066
1095
}
1067
1096
1068
1097
impl < ' mir , ' tcx > MiriMachine < ' mir , ' tcx > {
@@ -1143,12 +1172,6 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
1143
1172
local_crates
1144
1173
}
1145
1174
1146
- /// Helper function used inside the shims of foreign functions to check that
1147
- /// `target_os` is a supported UNIX OS.
1148
- pub fn target_os_is_unix ( target_os : & str ) -> bool {
1149
- matches ! ( target_os, "linux" | "macos" | "freebsd" | "android" )
1150
- }
1151
-
1152
1175
pub ( crate ) fn bool_to_simd_element ( b : bool , size : Size ) -> Scalar < Provenance > {
1153
1176
// SIMD uses all-1 as pattern for "true". In two's complement,
1154
1177
// -1 has all its bits set to one and `from_int` will truncate or
0 commit comments