Skip to content

Commit 1da6bec

Browse files
[5.3] Improved codgen for FP inits from Integer (swiftlang#32636)
* Provide an implementation of init?<T:BinaryInteger>(exactly:T) on each stdlib FP type. (swiftlang#32632) Previously these always went through the FloatingPoint-provided default implementation, which is not particularly efficient. Also try removing inlinable from the generic _convert hooks, since we probably never want to actually inline them. * Add explicit init from BinaryInteger to CGFloat The override was previously missing, which meant that we fell back on the generic implementation; we should simply forward this to the NativeType implementation instead.
1 parent 0e314e6 commit 1da6bec

File tree

3 files changed

+57
-6
lines changed

3 files changed

+57
-6
lines changed

stdlib/public/Darwin/CoreGraphics/CGFloat.swift.gyb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,13 @@ public struct CGFloat {
6161
}
6262

6363
extension CGFloat : SignedNumeric {
64+
@_alwaysEmitIntoClient // availability
65+
public init<T: BinaryInteger>(_ source: T) {
66+
self.native = NativeType(source)
67+
}
6468

6569
@_transparent
66-
public init?<T : BinaryInteger>(exactly source: T) {
70+
public init?<T: BinaryInteger>(exactly source: T) {
6771
guard let native = NativeType(exactly: source) else { return nil }
6872
self.native = native
6973
}
@@ -72,7 +76,6 @@ extension CGFloat : SignedNumeric {
7276
public var magnitude: CGFloat {
7377
return CGFloat(native.magnitude)
7478
}
75-
7679
}
7780

7881
extension CGFloat : BinaryFloatingPoint {

stdlib/public/core/FloatingPoint.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,7 +1742,6 @@ extension BinaryFloatingPoint {
17421742
)
17431743
}
17441744

1745-
@inlinable
17461745
public // @testable
17471746
static func _convert<Source: BinaryFloatingPoint>(
17481747
from source: Source
@@ -1931,7 +1930,6 @@ extension BinaryFloatingPoint {
19311930

19321931
extension BinaryFloatingPoint where Self.RawSignificand: FixedWidthInteger {
19331932

1934-
@inlinable
19351933
public // @testable
19361934
static func _convert<Source: BinaryInteger>(
19371935
from source: Source

stdlib/public/core/FloatingPointTypes.swift.gyb

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,7 @@ extension ${Self} {
10331033
_value = Builtin.sitofp_Int${word_bits}_FPIEEE${bits}(v._value)
10341034
}
10351035

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,
10371037
// falling back on the generic _convert operation otherwise.
10381038
@inlinable // FIXME(inline-always)
10391039
@inline(__always)
@@ -1043,14 +1043,64 @@ extension ${Self} {
10431043
let asInt = Int(truncatingIfNeeded: value)
10441044
_value = Builtin.sitofp_Int${word_bits}_FPIEEE${bits}(asInt._value)
10451045
} else {
1046-
let asUInt = Int(truncatingIfNeeded: value)
1046+
let asUInt = UInt(truncatingIfNeeded: value)
10471047
_value = Builtin.uitofp_Int${word_bits}_FPIEEE${bits}(asUInt._value)
10481048
}
10491049
} 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.
10501053
self = ${Self}._convert(from: value).value
10511054
}
10521055
}
10531056

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.0p${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.0p${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+
10541104
% for src_type in all_floating_point_types():
10551105
% srcBits = src_type.bits
10561106
% That = src_type.stdlib_name

0 commit comments

Comments
 (0)