@@ -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 ;
@@ -565,10 +566,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
565566 /// is part of the UNIX family. It panics showing a message with the `name` of the foreign function
566567 /// if this is not the case.
567568 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" )
572574 }
573575
574576 /// 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> {
985987 }
986988 }
987989
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`.
989992 /// Returns `None` if `f` is NaN or out of range.
990- fn float_to_int_checked < F > (
993+ fn float_to_int_checked (
991994 & self ,
992- f : F ,
995+ src : & ImmTy < ' tcx , Provenance > ,
993996 cast_to : TyAndLayout < ' tcx > ,
994997 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 > > > {
999999 let this = self . eval_context_ref ( ) ;
10001000
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 )
10181013 }
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 )
10361018 }
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+ ) ,
10371026 }
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) ,
10381036 // Nothing else
10391037 _ =>
10401038 span_bug ! (
10411039 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,
10441042 ) ,
10451043 } ;
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+ }
10471058 }
10481059
10491060 /// Returns an integer type that is twice wide as `ty`
@@ -1063,6 +1074,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10631074 _ => span_bug ! ( this. cur_span( ) , "unexpected type: {ty:?}" ) ,
10641075 }
10651076 }
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+ }
10661095}
10671096
10681097impl < ' mir , ' tcx > MiriMachine < ' mir , ' tcx > {
@@ -1143,12 +1172,6 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
11431172 local_crates
11441173}
11451174
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-
11521175pub ( crate ) fn bool_to_simd_element ( b : bool , size : Size ) -> Scalar < Provenance > {
11531176 // SIMD uses all-1 as pattern for "true". In two's complement,
11541177 // -1 has all its bits set to one and `from_int` will truncate or
0 commit comments