@@ -1033,7 +1033,7 @@ extension ${Self} {
1033
1033
_value = Builtin . sitofp_Int ${ word_bits} _FPIEEE${ bits} ( v. _value)
1034
1034
}
1035
1035
1036
- // Fast-path for conversion when the source is representable as a 64-bit int,
1036
+ // Fast-path for conversion when the source is representable as int,
1037
1037
// falling back on the generic _convert operation otherwise.
1038
1038
@inlinable // FIXME(inline-always)
1039
1039
@inline ( __always)
@@ -1043,14 +1043,64 @@ extension ${Self} {
1043
1043
let asInt = Int ( truncatingIfNeeded: value)
1044
1044
_value = Builtin . sitofp_Int ${ word_bits} _FPIEEE${ bits} ( asInt. _value)
1045
1045
} else {
1046
- let asUInt = Int ( truncatingIfNeeded: value)
1046
+ let asUInt = UInt ( truncatingIfNeeded: value)
1047
1047
_value = Builtin . uitofp_Int ${ word_bits} _FPIEEE${ bits} ( asUInt. _value)
1048
1048
}
1049
1049
} else {
1050
+ // TODO: we can do much better than the generic _convert here for Float
1051
+ // and Double by pulling out the high-order 32/64b of the integer, ORing
1052
+ // in a sticky bit, and then using the builtin.
1050
1053
self = ${ Self} . _convert ( from: value) . value
1051
1054
}
1052
1055
}
1053
1056
1057
+ // Fast-path for conversion when the source is representable as int,
1058
+ // falling back on the generic _convert operation otherwise.
1059
+ @_alwaysEmitIntoClient @inline ( never)
1060
+ public init? < Source: BinaryInteger> ( exactly value: Source) {
1061
+ if value. bitWidth <= ${ word_bits} {
1062
+ // If the source is small enough to fit in a word, we can use the LLVM
1063
+ // conversion intrinsic, then check if we can round-trip back to the
1064
+ // the original value; if so, the conversion was exact. We need to be
1065
+ // careful, however, to make sure that the first conversion does not
1066
+ // round to a value that is out of the defined range of the second
1067
+ // converion. E.g. Float(Int.max) rounds to Int.max + 1, and converting
1068
+ // that back to Int will trap. For Float, Double, and Float80, this is
1069
+ // only an issue for the upper bound (because the lower bound of [U]Int
1070
+ // is either zero or a power of two, both of which are exactly
1071
+ // representable). For Float16, we also need to check for overflow to
1072
+ // -.infinity.
1073
+ if Source . isSigned {
1074
+ let extended = Int ( truncatingIfNeeded: value)
1075
+ _value = Builtin . sitofp_Int ${ word_bits} _FPIEEE${ bits} ( extended. _value)
1076
+ % if bits == 16 :
1077
+ guard self . isFinite && Int ( self ) == extended else {
1078
+ % else :
1079
+ guard self < 0x1 . 0 p${ word_bits- 1 } && Int ( self ) == extended else {
1080
+ % end
1081
+ return nil
1082
+ }
1083
+ } else {
1084
+ let extended = UInt ( truncatingIfNeeded: value)
1085
+ _value = Builtin . uitofp_Int ${ word_bits} _FPIEEE${ bits} ( extended. _value)
1086
+ % if bits == 16 :
1087
+ guard self . isFinite && UInt ( self ) == extended else {
1088
+ % else :
1089
+ guard self < 0x1 . 0 p${ word_bits} && UInt ( self ) == extended else {
1090
+ % end
1091
+ return nil
1092
+ }
1093
+ }
1094
+ } else {
1095
+ // TODO: we can do much better than the generic _convert here for Float
1096
+ // and Double by pulling out the high-order 32/64b of the integer, ORing
1097
+ // in a sticky bit, and then using the builtin.
1098
+ let ( value_, exact) = Self . _convert ( from: value)
1099
+ guard exact else { return nil }
1100
+ self = value_
1101
+ }
1102
+ }
1103
+
1054
1104
% for src_type in all_floating_point_types ( ) :
1055
1105
% srcBits = src_type. bits
1056
1106
% That = src_type. stdlib_name
0 commit comments