@@ -15,11 +15,14 @@ use rustc::ty::layout::{Layout, LayoutTyper};
15
15
use rustc:: mir:: tcx:: LvalueTy ;
16
16
use rustc:: mir;
17
17
use rustc:: middle:: lang_items:: ExchangeMallocFnLangItem ;
18
+ use rustc_apfloat:: { ieee, Float , Status , Round } ;
19
+ use std:: { u128, i128} ;
18
20
19
21
use base;
20
22
use builder:: Builder ;
21
23
use callee;
22
- use common:: { self , val_ty, C_bool , C_i32 , C_null , C_usize , C_uint } ;
24
+ use common:: { self , val_ty, C_bool , C_i32 , C_u32 , C_u64 , C_null , C_usize , C_uint , C_big_integral } ;
25
+ use consts;
23
26
use adt;
24
27
use machine;
25
28
use monomorphize;
@@ -333,14 +336,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
333
336
bcx. ptrtoint ( llval, ll_t_out) ,
334
337
( CastTy :: Int ( _) , CastTy :: Ptr ( _) ) =>
335
338
bcx. inttoptr ( llval, ll_t_out) ,
336
- ( CastTy :: Int ( _) , CastTy :: Float ) if signed =>
337
- bcx. sitofp ( llval, ll_t_out) ,
338
339
( CastTy :: Int ( _) , CastTy :: Float ) =>
339
- bcx . uitofp ( llval, ll_t_out) ,
340
+ cast_int_to_float ( & bcx , signed , llval, ll_t_in , ll_t_out) ,
340
341
( CastTy :: Float , CastTy :: Int ( IntTy :: I ) ) =>
341
- bcx . fptosi ( llval, ll_t_out) ,
342
+ cast_float_to_int ( & bcx , true , llval, ll_t_in , ll_t_out) ,
342
343
( CastTy :: Float , CastTy :: Int ( _) ) =>
343
- bcx . fptoui ( llval, ll_t_out) ,
344
+ cast_float_to_int ( & bcx , false , llval, ll_t_in , ll_t_out) ,
344
345
_ => bug ! ( "unsupported cast: {:?} to {:?}" , operand. ty, cast_ty)
345
346
} ;
346
347
OperandValue :: Immediate ( newval)
@@ -815,3 +816,172 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &Builder, ty: Ty) -> ValueRef {
815
816
816
817
bcx. ccx . get_intrinsic ( & name)
817
818
}
819
+
820
+ fn cast_int_to_float ( bcx : & Builder ,
821
+ signed : bool ,
822
+ x : ValueRef ,
823
+ int_ty : Type ,
824
+ float_ty : Type ) -> ValueRef {
825
+ // Most integer types, even i128, fit into [-f32::MAX, f32::MAX] after rounding.
826
+ // It's only u128 -> f32 that can cause overflows (i.e., should yield infinity).
827
+ // LLVM's uitofp produces undef in those cases, so we manually check for that case.
828
+ let is_u128_to_f32 = !signed && int_ty. int_width ( ) == 128 && float_ty. float_width ( ) == 32 ;
829
+ if is_u128_to_f32 && bcx. sess ( ) . opts . debugging_opts . saturating_float_casts {
830
+ // f32::MAX + 0.5 ULP as u128. All inputs greater or equal to this should be
831
+ // rounded to infinity, for everything else LLVM's uitofp works just fine.
832
+ let max = C_big_integral ( int_ty, 0xffffff80000000000000000000000000_u128 ) ;
833
+ let overflow = bcx. icmp ( llvm:: IntUGE , x, max) ;
834
+ let infinity_bits = C_u32 ( bcx. ccx , ieee:: Single :: INFINITY . to_bits ( ) as u32 ) ;
835
+ let infinity = consts:: bitcast ( infinity_bits, float_ty) ;
836
+ bcx. select ( overflow, infinity, bcx. uitofp ( x, float_ty) )
837
+ } else {
838
+ if signed {
839
+ bcx. sitofp ( x, float_ty)
840
+ } else {
841
+ bcx. uitofp ( x, float_ty)
842
+ }
843
+ }
844
+ }
845
+
846
+ fn cast_float_to_int ( bcx : & Builder ,
847
+ signed : bool ,
848
+ x : ValueRef ,
849
+ float_ty : Type ,
850
+ int_ty : Type ) -> ValueRef {
851
+ if !bcx. sess ( ) . opts . debugging_opts . saturating_float_casts {
852
+ if signed {
853
+ return bcx. fptosi ( x, int_ty) ;
854
+ } else {
855
+ return bcx. fptoui ( x, int_ty) ;
856
+ }
857
+ }
858
+ // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the
859
+ // destination integer type after rounding towards zero. This `undef` value can cause UB in
860
+ // safe code (see issue #10184), so we implement a saturating conversion on top of it:
861
+ // Semantically, the mathematical value of the input is rounded towards zero to the next
862
+ // mathematical integer, and then the result is clamped into the range of the destination
863
+ // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
864
+ // the destination integer type. NaN is mapped to 0.
865
+ //
866
+ // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
867
+ // a value representable in int_ty.
868
+ // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
869
+ // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
870
+ // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
871
+ // representable. Note that this only works if float_ty's exponent range is sufficently large.
872
+ // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
873
+ // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
874
+ // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
875
+ // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
876
+ // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
877
+ fn compute_clamp_bounds < F : Float > ( signed : bool , int_ty : Type ) -> ( u128 , u128 , Status ) {
878
+ let f_min = if signed {
879
+ let int_min = i128:: MIN >> ( 128 - int_ty. int_width ( ) ) ;
880
+ let rounded_min = F :: from_i128_r ( int_min, Round :: TowardZero ) ;
881
+ assert_eq ! ( rounded_min. status, Status :: OK ) ;
882
+ rounded_min. value
883
+ } else {
884
+ F :: ZERO
885
+ } ;
886
+
887
+ let rounded_max = F :: from_u128_r ( int_max ( signed, int_ty) , Round :: TowardZero ) ;
888
+ assert ! ( rounded_max. value. is_finite( ) ) ;
889
+
890
+ ( f_min. to_bits ( ) , rounded_max. value . to_bits ( ) , rounded_max. status )
891
+ }
892
+ fn int_max ( signed : bool , int_ty : Type ) -> u128 {
893
+ let shift_amount = 128 - int_ty. int_width ( ) ;
894
+ if signed {
895
+ i128:: MAX as u128 >> shift_amount
896
+ } else {
897
+ u128:: MAX >> shift_amount
898
+ }
899
+ }
900
+ let ( f_min, f_max, f_max_status) = match float_ty. float_width ( ) {
901
+ 32 => compute_clamp_bounds :: < ieee:: Single > ( signed, int_ty) ,
902
+ 64 => compute_clamp_bounds :: < ieee:: Double > ( signed, int_ty) ,
903
+ n => bug ! ( "unsupported float width {}" , n) ,
904
+ } ;
905
+ let float_bits_to_llval = |bits| {
906
+ let bits_llval = match float_ty. float_width ( ) {
907
+ 32 => C_u32 ( bcx. ccx , bits as u32 ) ,
908
+ 64 => C_u64 ( bcx. ccx , bits as u64 ) ,
909
+ n => bug ! ( "unsupported float width {}" , n) ,
910
+ } ;
911
+ consts:: bitcast ( bits_llval, float_ty)
912
+ } ;
913
+ let f_min = float_bits_to_llval ( f_min) ;
914
+ let f_max = float_bits_to_llval ( f_max) ;
915
+ // To implement saturation, we perform the following steps (not all steps are necessary for
916
+ // all combinations of int_ty and float_ty, but we'll deal with that below):
917
+ //
918
+ // 1. Clamp x into the range [f_min, f_max] in such a way that NaN becomes f_min.
919
+ // 2. If x is NaN, replace the result of the clamping with 0.0, otherwise
920
+ // keep the clamping result.
921
+ // 3. Now cast the result of step 2 with fpto[su]i.
922
+ // 4. If x > f_max, return int_ty::MAX, otherwise return the result of step 3.
923
+ //
924
+ // This avoids undef because values in range [f_min, f_max] by definition fit into the
925
+ // destination type. More importantly, it correctly implements saturating conversion.
926
+ // Proof (sketch):
927
+ // If x is NaN, step 2 yields 0.0, which is converted to 0 in step 3, and NaN > f_max does
928
+ // not hold in step 4, therefore 0 is returned, as desired.
929
+ // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max.
930
+ // This yields three cases to consider:
931
+ // (1) if x in [f_min, f_max], steps 1, 2, and 4 do nothing and the result of fpto[su]i
932
+ // is returned, which agrees with saturating conversion for inputs in that range.
933
+ // (2) if x > f_max, then x is larger than int_ty::MAX and step 4 correctly returns
934
+ // int_ty::MAX. This holds even if f_max is rounded (i.e., if f_max < int_ty::MAX)
935
+ // because in those cases, nextUp(f_max) is already larger than int_ty::MAX.
936
+ // (3) if x < f_min, then x is smaller than int_ty::MIN and is clamped to f_min. As shown
937
+ // earlier, f_min exactly equals int_ty::MIN and therefore no fixup analogous to step 4
938
+ // is needed. Instead, step 3 casts f_min to int_ty::MIN and step 4 returns this cast
939
+ // result, as desired.
940
+ // QED.
941
+
942
+ // Step 1: Clamping. Computed as:
943
+ // clamped_to_min = if f_min < x { x } else { f_min };
944
+ // clamped_x = if f_max < clamped_to_min { f_max } else { clamped_to_min };
945
+ // Note that for x = NaN, both of the above variables become f_min.
946
+ let clamped_to_min = bcx. select ( bcx. fcmp ( llvm:: RealOLT , f_min, x) , x, f_min) ;
947
+ let clamped_x = bcx. select (
948
+ bcx. fcmp ( llvm:: RealOLT , f_max, clamped_to_min) ,
949
+ f_max,
950
+ clamped_to_min
951
+ ) ;
952
+
953
+ // Step 2: NaN replacement.
954
+ // For unsigned types, f_min == 0.0 and therefore clamped_x is already zero.
955
+ // Therefore we only need to execute this step for signed integer types.
956
+ let clamped_x = if signed {
957
+ let zero = match float_ty. float_width ( ) {
958
+ 32 => float_bits_to_llval ( ieee:: Single :: ZERO . to_bits ( ) ) ,
959
+ 64 => float_bits_to_llval ( ieee:: Double :: ZERO . to_bits ( ) ) ,
960
+ n => bug ! ( "unsupported float width {}" , n) ,
961
+ } ;
962
+ // LLVM has no isNaN predicate, so we use (x == x) instead
963
+ bcx. select ( bcx. fcmp ( llvm:: RealOEQ , x, x) , clamped_x, zero)
964
+ } else {
965
+ clamped_x
966
+ } ;
967
+
968
+ // Step 3: fpto[su]i cast
969
+ let cast_result = if signed {
970
+ bcx. fptosi ( clamped_x, int_ty)
971
+ } else {
972
+ bcx. fptoui ( clamped_x, int_ty)
973
+ } ;
974
+
975
+ // Step 4: f_max fixup.
976
+ // Note that x > f_max implies that x was clamped to f_max in step 1, and therefore the
977
+ // cast result is the integer equal to f_max. If the conversion from int_ty::MAX to f_max
978
+ // was exact, then the result of casting f_max is again int_ty::MAX, so we'd return the same
979
+ // value whether or not x > f_max holds. Therefore, we only need to execute this step
980
+ // if f_max is inexact.
981
+ if f_max_status. contains ( Status :: INEXACT ) {
982
+ let int_max = C_big_integral ( int_ty, int_max ( signed, int_ty) ) ;
983
+ bcx. select ( bcx. fcmp ( llvm:: RealOGT , x, f_max) , int_max, cast_result)
984
+ } else {
985
+ cast_result
986
+ }
987
+ }
0 commit comments