@@ -11,7 +11,7 @@ use rustc_apfloat::{ieee, Float, Round, Status};
11
11
use rustc_hir:: lang_items:: LangItem ;
12
12
use rustc_middle:: mir;
13
13
use rustc_middle:: ty:: cast:: { CastTy , IntTy } ;
14
- use rustc_middle:: ty:: layout:: { HasTyCtxt , TyAndLayout } ;
14
+ use rustc_middle:: ty:: layout:: HasTyCtxt ;
15
15
use rustc_middle:: ty:: { self , adjustment:: PointerCast , Instance , Ty , TyCtxt } ;
16
16
use rustc_span:: source_map:: { Span , DUMMY_SP } ;
17
17
use rustc_span:: symbol:: sym;
@@ -385,10 +385,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
385
385
bx. inttoptr ( usize_llval, ll_t_out)
386
386
}
387
387
( CastTy :: Float , CastTy :: Int ( IntTy :: I ) ) => {
388
- cast_float_to_int ( & mut bx, true , llval, ll_t_in, ll_t_out, cast )
388
+ cast_float_to_int ( & mut bx, true , llval, ll_t_in, ll_t_out)
389
389
}
390
390
( CastTy :: Float , CastTy :: Int ( _) ) => {
391
- cast_float_to_int ( & mut bx, false , llval, ll_t_in, ll_t_out, cast )
391
+ cast_float_to_int ( & mut bx, false , llval, ll_t_in, ll_t_out)
392
392
}
393
393
_ => bug ! ( "unsupported cast: {:?} to {:?}" , operand. layout. ty, cast. ty) ,
394
394
} ;
@@ -790,7 +790,6 @@ fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
790
790
x : Bx :: Value ,
791
791
float_ty : Bx :: Type ,
792
792
int_ty : Bx :: Type ,
793
- int_layout : TyAndLayout < ' tcx > ,
794
793
) -> Bx :: Value {
795
794
if let Some ( false ) = bx. cx ( ) . sess ( ) . opts . debugging_opts . saturating_float_casts {
796
795
return if signed { bx. fptosi ( x, int_ty) } else { bx. fptoui ( x, int_ty) } ;
@@ -891,134 +890,39 @@ fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
891
890
let int_min = bx. cx ( ) . const_uint_big ( int_ty, int_min ( signed, int_width) as u128 ) ;
892
891
let zero = bx. cx ( ) . const_uint ( int_ty, 0 ) ;
893
892
894
- // The codegen here differs quite a bit depending on whether our builder's
895
- // `fptosi` and `fptoui` instructions may trap for out-of-bounds values. If
896
- // they don't trap then we can start doing everything inline with a
897
- // `select` instruction because it's ok to execute `fptosi` and `fptoui`
898
- // even if we don't use the results.
899
- if !bx. fptosui_may_trap ( x, int_ty) {
900
- // Step 1 ...
901
- let fptosui_result = if signed { bx. fptosi ( x, int_ty) } else { bx. fptoui ( x, int_ty) } ;
902
- let less_or_nan = bx. fcmp ( RealPredicate :: RealULT , x, f_min) ;
903
- let greater = bx. fcmp ( RealPredicate :: RealOGT , x, f_max) ;
904
-
905
- // Step 2: We use two comparisons and two selects, with %s1 being the
906
- // result:
907
- // %less_or_nan = fcmp ult %x, %f_min
908
- // %greater = fcmp olt %x, %f_max
909
- // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
910
- // %s1 = select %greater, int_ty::MAX, %s0
911
- // Note that %less_or_nan uses an *unordered* comparison. This
912
- // comparison is true if the operands are not comparable (i.e., if x is
913
- // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
914
- // x is NaN.
915
- //
916
- // Performance note: Unordered comparison can be lowered to a "flipped"
917
- // comparison and a negation, and the negation can be merged into the
918
- // select. Therefore, it not necessarily any more expensive than a
919
- // ordered ("normal") comparison. Whether these optimizations will be
920
- // performed is ultimately up to the backend, but at least x86 does
921
- // perform them.
922
- let s0 = bx. select ( less_or_nan, int_min, fptosui_result) ;
923
- let s1 = bx. select ( greater, int_max, s0) ;
924
-
925
- // Step 3: NaN replacement.
926
- // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
927
- // Therefore we only need to execute this step for signed integer types.
928
- if signed {
929
- // LLVM has no isNaN predicate, so we use (x == x) instead
930
- let cmp = bx. fcmp ( RealPredicate :: RealOEQ , x, x) ;
931
- bx. select ( cmp, s1, zero)
932
- } else {
933
- s1
934
- }
893
+ // Step 1 ...
894
+ let fptosui_result = if signed { bx. fptosi ( x, int_ty) } else { bx. fptoui ( x, int_ty) } ;
895
+ let less_or_nan = bx. fcmp ( RealPredicate :: RealULT , x, f_min) ;
896
+ let greater = bx. fcmp ( RealPredicate :: RealOGT , x, f_max) ;
897
+
898
+ // Step 2: We use two comparisons and two selects, with %s1 being the
899
+ // result:
900
+ // %less_or_nan = fcmp ult %x, %f_min
901
+ // %greater = fcmp olt %x, %f_max
902
+ // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
903
+ // %s1 = select %greater, int_ty::MAX, %s0
904
+ // Note that %less_or_nan uses an *unordered* comparison. This
905
+ // comparison is true if the operands are not comparable (i.e., if x is
906
+ // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
907
+ // x is NaN.
908
+ //
909
+ // Performance note: Unordered comparison can be lowered to a "flipped"
910
+ // comparison and a negation, and the negation can be merged into the
911
+ // select. Therefore, it not necessarily any more expensive than a
912
+ // ordered ("normal") comparison. Whether these optimizations will be
913
+ // performed is ultimately up to the backend, but at least x86 does
914
+ // perform them.
915
+ let s0 = bx. select ( less_or_nan, int_min, fptosui_result) ;
916
+ let s1 = bx. select ( greater, int_max, s0) ;
917
+
918
+ // Step 3: NaN replacement.
919
+ // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
920
+ // Therefore we only need to execute this step for signed integer types.
921
+ if signed {
922
+ // LLVM has no isNaN predicate, so we use (x == x) instead
923
+ let cmp = bx. fcmp ( RealPredicate :: RealOEQ , x, x) ;
924
+ bx. select ( cmp, s1, zero)
935
925
} else {
936
- // In this case we cannot execute `fptosi` or `fptoui` and then later
937
- // discard the result. The builder is telling us that these instructions
938
- // will trap on out-of-bounds values, so we need to use basic blocks and
939
- // control flow to avoid executing the `fptosi` and `fptoui`
940
- // instructions.
941
- //
942
- // The general idea of what we're constructing here is, for f64 -> i32:
943
- //
944
- // ;; block so far... %0 is the argument
945
- // %result = alloca i32, align 4
946
- // %inbound_lower = fcmp oge double %0, 0xC1E0000000000000
947
- // %inbound_upper = fcmp ole double %0, 0x41DFFFFFFFC00000
948
- // ;; match (inbound_lower, inbound_upper) {
949
- // ;; (true, true) => %0 can be converted without trapping
950
- // ;; (false, false) => %0 is a NaN
951
- // ;; (true, false) => %0 is too large
952
- // ;; (false, true) => %0 is too small
953
- // ;; }
954
- // ;;
955
- // ;; The (true, true) check, go to %convert if so.
956
- // %inbounds = and i1 %inbound_lower, %inbound_upper
957
- // br i1 %inbounds, label %convert, label %specialcase
958
- //
959
- // convert:
960
- // %cvt = call i32 @llvm.wasm.trunc.signed.i32.f64(double %0)
961
- // store i32 %cvt, i32* %result, align 4
962
- // br label %done
963
- //
964
- // specialcase:
965
- // ;; Handle the cases where the number is NaN, too large or too small
966
- //
967
- // ;; Either (true, false) or (false, true)
968
- // %is_not_nan = or i1 %inbound_lower, %inbound_upper
969
- // ;; Figure out which saturated value we are interested in if not `NaN`
970
- // %saturated = select i1 %inbound_lower, i32 2147483647, i32 -2147483648
971
- // ;; Figure out between saturated and NaN representations
972
- // %result_nan = select i1 %is_not_nan, i32 %saturated, i32 0
973
- // store i32 %result_nan, i32* %result, align 4
974
- // br label %done
975
- //
976
- // done:
977
- // %r = load i32, i32* %result, align 4
978
- // ;; ...
979
- let done = bx. build_sibling_block ( "float_cast_done" ) ;
980
- let mut convert = bx. build_sibling_block ( "float_cast_convert" ) ;
981
- let mut specialcase = bx. build_sibling_block ( "float_cast_specialcase" ) ;
982
-
983
- let result = PlaceRef :: alloca ( bx, int_layout) ;
984
- result. storage_live ( bx) ;
985
-
986
- // Use control flow to figure out whether we can execute `fptosi` in a
987
- // basic block, or whether we go to a different basic block to implement
988
- // the saturating logic.
989
- let inbound_lower = bx. fcmp ( RealPredicate :: RealOGE , x, f_min) ;
990
- let inbound_upper = bx. fcmp ( RealPredicate :: RealOLE , x, f_max) ;
991
- let inbounds = bx. and ( inbound_lower, inbound_upper) ;
992
- bx. cond_br ( inbounds, convert. llbb ( ) , specialcase. llbb ( ) ) ;
993
-
994
- // Translation of the `convert` basic block
995
- let cvt = if signed { convert. fptosi ( x, int_ty) } else { convert. fptoui ( x, int_ty) } ;
996
- convert. store ( cvt, result. llval , result. align ) ;
997
- convert. br ( done. llbb ( ) ) ;
998
-
999
- // Translation of the `specialcase` basic block. Note that like above
1000
- // we try to be a bit clever here for unsigned conversions. In those
1001
- // cases the `int_min` is zero so we don't need two select instructions,
1002
- // just one to choose whether we need `int_max` or not. If
1003
- // `inbound_lower` is true then we're guaranteed to not be `NaN` and
1004
- // since we're greater than zero we must be saturating to `int_max`. If
1005
- // `inbound_lower` is false then we're either NaN or less than zero, so
1006
- // we saturate to zero.
1007
- let result_nan = if signed {
1008
- let is_not_nan = specialcase. or ( inbound_lower, inbound_upper) ;
1009
- let saturated = specialcase. select ( inbound_lower, int_max, int_min) ;
1010
- specialcase. select ( is_not_nan, saturated, zero)
1011
- } else {
1012
- specialcase. select ( inbound_lower, int_max, int_min)
1013
- } ;
1014
- specialcase. store ( result_nan, result. llval , result. align ) ;
1015
- specialcase. br ( done. llbb ( ) ) ;
1016
-
1017
- // Translation of the `done` basic block, positioning ourselves to
1018
- // continue from that point as well.
1019
- * bx = done;
1020
- let ret = bx. load ( result. llval , result. align ) ;
1021
- result. storage_dead ( bx) ;
1022
- ret
926
+ s1
1023
927
}
1024
928
}
0 commit comments