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