@@ -9,8 +9,8 @@ use rustc_apfloat::ieee::{Double, Half, Quad, Single};
9
9
use rustc_middle:: mir:: interpret:: { CTFE_ALLOC_SALT , read_target_uint, write_target_uint} ;
10
10
use rustc_middle:: mir:: { self , BinOp , ConstValue , NonDivergingIntrinsic } ;
11
11
use rustc_middle:: ty:: layout:: TyAndLayout ;
12
- use rustc_middle:: ty:: { Ty , TyCtxt } ;
13
- use rustc_middle:: { bug, ty} ;
12
+ use rustc_middle:: ty:: { FloatTy , Ty , TyCtxt } ;
13
+ use rustc_middle:: { bug, span_bug , ty} ;
14
14
use rustc_span:: { Symbol , sym} ;
15
15
use tracing:: trace;
16
16
@@ -22,6 +22,15 @@ use super::{
22
22
throw_ub_custom, throw_ub_format,
23
23
} ;
24
24
use crate :: fluent_generated as fluent;
25
+ use crate :: interpret:: Projectable ;
26
+
27
+ #[ derive( Copy , Clone ) ]
28
+ pub ( super ) enum MinMax {
29
+ MinNum ,
30
+ MaxNum ,
31
+ Minimum ,
32
+ Maximum ,
33
+ }
25
34
26
35
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
27
36
pub ( crate ) fn alloc_type_name < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> ( AllocId , u64 ) {
@@ -123,6 +132,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
123
132
let intrinsic_name = self . tcx . item_name ( instance. def_id ( ) ) ;
124
133
let tcx = self . tcx . tcx ;
125
134
135
+ if intrinsic_name. as_str ( ) . starts_with ( "simd_" ) {
136
+ return self . eval_simd_intrinsic ( intrinsic_name, instance, args, dest, ret) ;
137
+ }
138
+
126
139
match intrinsic_name {
127
140
sym:: type_name => {
128
141
let tp_ty = instance. args . type_at ( 0 ) ;
@@ -453,38 +466,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
453
466
let size = ImmTy :: from_int ( pointee_layout. size . bytes ( ) , ret_layout) ;
454
467
self . exact_div ( & val, & size, dest) ?;
455
468
}
456
-
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
469
sym:: black_box => {
489
470
// These just return their argument
490
471
self . copy_op ( & args[ 0 ] , dest) ?;
@@ -510,25 +491,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
510
491
self . write_scalar ( Scalar :: from_target_usize ( align. bytes ( ) , self ) , dest) ?;
511
492
}
512
493
513
- sym:: minnumf16 => self . float_min_intrinsic :: < Half > ( args, dest) ?,
514
- sym:: minnumf32 => self . float_min_intrinsic :: < Single > ( args, dest) ?,
515
- sym:: minnumf64 => self . float_min_intrinsic :: < Double > ( args, dest) ?,
516
- sym:: minnumf128 => self . float_min_intrinsic :: < Quad > ( args, dest) ?,
494
+ sym:: minnumf16 => self . float_minmax_intrinsic :: < Half > ( args, dest, MinMax :: MinNum ) ?,
495
+ sym:: minnumf32 => self . float_minmax_intrinsic :: < Single > ( args, dest, MinMax :: MinNum ) ?,
496
+ sym:: minnumf64 => self . float_minmax_intrinsic :: < Double > ( args, dest, MinMax :: MinNum ) ?,
497
+ sym:: minnumf128 => self . float_minmax_intrinsic :: < Quad > ( args, dest, MinMax :: MinNum ) ?,
517
498
518
- sym:: minimumf16 => self . float_minimum_intrinsic :: < Half > ( args, dest) ?,
519
- sym:: minimumf32 => self . float_minimum_intrinsic :: < Single > ( args, dest) ?,
520
- sym:: minimumf64 => self . float_minimum_intrinsic :: < Double > ( args, dest) ?,
521
- sym:: minimumf128 => self . float_minimum_intrinsic :: < Quad > ( args, dest) ?,
499
+ sym:: minimumf16 => self . float_minmax_intrinsic :: < Half > ( args, dest, MinMax :: Minimum ) ?,
500
+ sym:: minimumf32 => {
501
+ self . float_minmax_intrinsic :: < Single > ( args, dest, MinMax :: Minimum ) ?
502
+ }
503
+ sym:: minimumf64 => {
504
+ self . float_minmax_intrinsic :: < Double > ( args, dest, MinMax :: Minimum ) ?
505
+ }
506
+ sym:: minimumf128 => self . float_minmax_intrinsic :: < Quad > ( args, dest, MinMax :: Minimum ) ?,
522
507
523
- sym:: maxnumf16 => self . float_max_intrinsic :: < Half > ( args, dest) ?,
524
- sym:: maxnumf32 => self . float_max_intrinsic :: < Single > ( args, dest) ?,
525
- sym:: maxnumf64 => self . float_max_intrinsic :: < Double > ( args, dest) ?,
526
- sym:: maxnumf128 => self . float_max_intrinsic :: < Quad > ( args, dest) ?,
508
+ sym:: maxnumf16 => self . float_minmax_intrinsic :: < Half > ( args, dest, MinMax :: MaxNum ) ?,
509
+ sym:: maxnumf32 => self . float_minmax_intrinsic :: < Single > ( args, dest, MinMax :: MaxNum ) ?,
510
+ sym:: maxnumf64 => self . float_minmax_intrinsic :: < Double > ( args, dest, MinMax :: MaxNum ) ?,
511
+ sym:: maxnumf128 => self . float_minmax_intrinsic :: < Quad > ( args, dest, MinMax :: MaxNum ) ?,
527
512
528
- sym:: maximumf16 => self . float_maximum_intrinsic :: < Half > ( args, dest) ?,
529
- sym:: maximumf32 => self . float_maximum_intrinsic :: < Single > ( args, dest) ?,
530
- sym:: maximumf64 => self . float_maximum_intrinsic :: < Double > ( args, dest) ?,
531
- sym:: maximumf128 => self . float_maximum_intrinsic :: < Quad > ( args, dest) ?,
513
+ sym:: maximumf16 => self . float_minmax_intrinsic :: < Half > ( args, dest, MinMax :: Maximum ) ?,
514
+ sym:: maximumf32 => {
515
+ self . float_minmax_intrinsic :: < Single > ( args, dest, MinMax :: Maximum ) ?
516
+ }
517
+ sym:: maximumf64 => {
518
+ self . float_minmax_intrinsic :: < Double > ( args, dest, MinMax :: Maximum ) ?
519
+ }
520
+ sym:: maximumf128 => self . float_minmax_intrinsic :: < Quad > ( args, dest, MinMax :: Maximum ) ?,
532
521
533
522
sym:: copysignf16 => self . float_copysign_intrinsic :: < Half > ( args, dest) ?,
534
523
sym:: copysignf32 => self . float_copysign_intrinsic :: < Single > ( args, dest) ?,
@@ -917,78 +906,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
917
906
interp_ok ( Scalar :: from_bool ( lhs_bytes == rhs_bytes) )
918
907
}
919
908
920
- fn float_min_intrinsic < F > (
909
+ fn float_minmax_intrinsic < F > (
921
910
& mut self ,
922
911
args : & [ OpTy < ' tcx , M :: Provenance > ] ,
923
912
dest : & PlaceTy < ' tcx , M :: Provenance > ,
913
+ op : MinMax ,
924
914
) -> InterpResult < ' tcx , ( ) >
925
915
where
926
916
F : rustc_apfloat:: Float + rustc_apfloat:: FloatConvert < F > + Into < Scalar < M :: Provenance > > ,
927
917
{
928
- let a: F = self . read_scalar ( & args[ 0 ] ) ?. to_float ( ) ?;
929
- let b: F = self . read_scalar ( & args[ 1 ] ) ?. to_float ( ) ?;
930
- let res = if a == b {
931
- // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
932
- // Let the machine decide which one to return.
933
- M :: equal_float_min_max ( self , a, b)
934
- } else {
935
- self . adjust_nan ( a. min ( b) , & [ a, b] )
936
- } ;
918
+ let res = self . float_minmax :: < F > ( & args[ 0 ] , & args[ 1 ] , op) ?;
937
919
self . write_scalar ( res, dest) ?;
938
920
interp_ok ( ( ) )
939
921
}
940
922
941
- fn float_max_intrinsic < F > (
942
- & mut self ,
943
- args : & [ OpTy < ' tcx , M :: Provenance > ] ,
944
- dest : & PlaceTy < ' tcx , M :: Provenance > ,
945
- ) -> InterpResult < ' tcx , ( ) >
923
+ pub ( super ) fn float_minmax < F > (
924
+ & self ,
925
+ a : & impl Projectable < ' tcx , M :: Provenance > ,
926
+ b : & impl Projectable < ' tcx , M :: Provenance > ,
927
+ op : MinMax ,
928
+ ) -> InterpResult < ' tcx , Scalar < M :: Provenance > >
946
929
where
947
930
F : rustc_apfloat:: Float + rustc_apfloat:: FloatConvert < F > + Into < Scalar < M :: Provenance > > ,
948
931
{
949
- let a: F = self . read_scalar ( & args [ 0 ] ) ?. to_float ( ) ?;
950
- let b: F = self . read_scalar ( & args [ 1 ] ) ?. to_float ( ) ?;
951
- let res = if a == b {
932
+ let a: F = self . read_scalar ( a ) ?. to_float ( ) ?;
933
+ let b: F = self . read_scalar ( b ) ?. to_float ( ) ?;
934
+ let res = if matches ! ( op , MinMax :: MaxNum | MinMax :: MinNum ) && a == b {
952
935
// They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
953
936
// Let the machine decide which one to return.
954
937
M :: equal_float_min_max ( self , a, b)
955
938
} else {
956
- self . adjust_nan ( a. max ( b) , & [ a, b] )
939
+ let res = match op {
940
+ MinMax :: MinNum => a. min ( b) ,
941
+ MinMax :: MaxNum => a. max ( b) ,
942
+ MinMax :: Minimum => a. minimum ( b) ,
943
+ MinMax :: Maximum => a. maximum ( b) ,
944
+ } ;
945
+ self . adjust_nan ( res, & [ a, b] )
957
946
} ;
958
- self . write_scalar ( res, dest) ?;
959
- interp_ok ( ( ) )
960
- }
961
-
962
- fn float_minimum_intrinsic < F > (
963
- & mut self ,
964
- args : & [ OpTy < ' tcx , M :: Provenance > ] ,
965
- dest : & PlaceTy < ' tcx , M :: Provenance > ,
966
- ) -> InterpResult < ' tcx , ( ) >
967
- where
968
- F : rustc_apfloat:: Float + rustc_apfloat:: FloatConvert < F > + Into < Scalar < M :: Provenance > > ,
969
- {
970
- let a: F = self . read_scalar ( & args[ 0 ] ) ?. to_float ( ) ?;
971
- let b: F = self . read_scalar ( & args[ 1 ] ) ?. to_float ( ) ?;
972
- let res = a. minimum ( b) ;
973
- let res = self . adjust_nan ( res, & [ a, b] ) ;
974
- self . write_scalar ( res, dest) ?;
975
- interp_ok ( ( ) )
976
- }
977
-
978
- fn float_maximum_intrinsic < F > (
979
- & mut self ,
980
- args : & [ OpTy < ' tcx , M :: Provenance > ] ,
981
- dest : & PlaceTy < ' tcx , M :: Provenance > ,
982
- ) -> InterpResult < ' tcx , ( ) >
983
- where
984
- F : rustc_apfloat:: Float + rustc_apfloat:: FloatConvert < F > + Into < Scalar < M :: Provenance > > ,
985
- {
986
- let a: F = self . read_scalar ( & args[ 0 ] ) ?. to_float ( ) ?;
987
- let b: F = self . read_scalar ( & args[ 1 ] ) ?. to_float ( ) ?;
988
- let res = a. maximum ( b) ;
989
- let res = self . adjust_nan ( res, & [ a, b] ) ;
990
- self . write_scalar ( res, dest) ?;
991
- interp_ok ( ( ) )
947
+ interp_ok ( res. into ( ) )
992
948
}
993
949
994
950
fn float_copysign_intrinsic < F > (
@@ -1035,4 +991,66 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
1035
991
self . write_scalar ( res, dest) ?;
1036
992
interp_ok ( ( ) )
1037
993
}
994
+
995
+ fn float_to_int_inner < F : rustc_apfloat:: Float > (
996
+ & self ,
997
+ src : F ,
998
+ cast_to : TyAndLayout < ' tcx > ,
999
+ round : rustc_apfloat:: Round ,
1000
+ ) -> ( Scalar < M :: Provenance > , rustc_apfloat:: Status ) {
1001
+ let int_size = cast_to. layout . size ;
1002
+ match cast_to. ty . kind ( ) {
1003
+ // Unsigned
1004
+ ty:: Uint ( _) => {
1005
+ let res = src. to_u128_r ( int_size. bits_usize ( ) , round, & mut false ) ;
1006
+ ( Scalar :: from_uint ( res. value , int_size) , res. status )
1007
+ }
1008
+ // Signed
1009
+ ty:: Int ( _) => {
1010
+ let res = src. to_i128_r ( int_size. bits_usize ( ) , round, & mut false ) ;
1011
+ ( Scalar :: from_int ( res. value , int_size) , res. status )
1012
+ }
1013
+ // Nothing else
1014
+ _ => span_bug ! (
1015
+ self . cur_span( ) ,
1016
+ "attempted float-to-int conversion with non-int output type {}" ,
1017
+ cast_to. ty,
1018
+ ) ,
1019
+ }
1020
+ }
1021
+
1022
+ /// Converts `src` from floating point to integer type `dest_ty`
1023
+ /// after rounding with mode `round`.
1024
+ /// Returns `None` if `f` is NaN or out of range.
1025
+ pub fn float_to_int_checked (
1026
+ & self ,
1027
+ src : & ImmTy < ' tcx , M :: Provenance > ,
1028
+ cast_to : TyAndLayout < ' tcx > ,
1029
+ round : rustc_apfloat:: Round ,
1030
+ ) -> InterpResult < ' tcx , Option < ImmTy < ' tcx , M :: Provenance > > > {
1031
+ let ty:: Float ( fty) = src. layout . ty . kind ( ) else {
1032
+ bug ! ( "float_to_int_checked: non-float input type {}" , src. layout. ty)
1033
+ } ;
1034
+
1035
+ let ( val, status) = match fty {
1036
+ FloatTy :: F16 => self . float_to_int_inner ( src. to_scalar ( ) . to_f16 ( ) ?, cast_to, round) ,
1037
+ FloatTy :: F32 => self . float_to_int_inner ( src. to_scalar ( ) . to_f32 ( ) ?, cast_to, round) ,
1038
+ FloatTy :: F64 => self . float_to_int_inner ( src. to_scalar ( ) . to_f64 ( ) ?, cast_to, round) ,
1039
+ FloatTy :: F128 => self . float_to_int_inner ( src. to_scalar ( ) . to_f128 ( ) ?, cast_to, round) ,
1040
+ } ;
1041
+
1042
+ if status. intersects (
1043
+ rustc_apfloat:: Status :: INVALID_OP
1044
+ | rustc_apfloat:: Status :: OVERFLOW
1045
+ | rustc_apfloat:: Status :: UNDERFLOW ,
1046
+ ) {
1047
+ // Floating point value is NaN (flagged with INVALID_OP) or outside the range
1048
+ // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1049
+ interp_ok ( None )
1050
+ } else {
1051
+ // Floating point value can be represented by the integer type after rounding.
1052
+ // The INEXACT flag is ignored on purpose to allow rounding.
1053
+ interp_ok ( Some ( ImmTy :: from_scalar ( val, cast_to) ) )
1054
+ }
1055
+ }
1038
1056
}
0 commit comments