From e0a411ab527e3053b717e4f066380b7fe0df81d5 Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Sat, 19 Feb 2022 18:34:37 -0800 Subject: [PATCH 1/4] [stdlib] Standard clocks: Fix `.now` and `.minimumResolution` implementations These used to set the clock id incorrectly, leading to zero results. Fix that and also make the underlying entry point abort if it gets an invalid ID, preventing this from reoccurring. --- stdlib/public/Concurrency/Clock.cpp | 4 ++++ stdlib/public/Concurrency/Clock.swift | 8 ++------ stdlib/public/Concurrency/ContinuousClock.swift | 4 ++-- stdlib/public/Concurrency/SuspendingClock.swift | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/stdlib/public/Concurrency/Clock.cpp b/stdlib/public/Concurrency/Clock.cpp index e426d8801a1c8..26542ca75f086 100644 --- a/stdlib/public/Concurrency/Clock.cpp +++ b/stdlib/public/Concurrency/Clock.cpp @@ -89,6 +89,8 @@ void swift_get_time( #endif break; } + default: + abort(); } } @@ -136,5 +138,7 @@ switch (clock_id) { #endif break; } + default: + abort(); } } diff --git a/stdlib/public/Concurrency/Clock.swift b/stdlib/public/Concurrency/Clock.swift index f70191ff464b1..89d3ab89225a4 100644 --- a/stdlib/public/Concurrency/Clock.swift +++ b/stdlib/public/Concurrency/Clock.swift @@ -74,8 +74,6 @@ extension Clock { } } -@available(SwiftStdlib 5.7, *) -@usableFromInline enum _ClockID: Int32 { case continuous = 1 case suspending = 2 @@ -83,16 +81,14 @@ enum _ClockID: Int32 { @available(SwiftStdlib 5.7, *) @_silgen_name("swift_get_time") -@usableFromInline internal func _getTime( seconds: UnsafeMutablePointer, nanoseconds: UnsafeMutablePointer, - clock: _ClockID) + clock: CInt) @available(SwiftStdlib 5.7, *) @_silgen_name("swift_get_clock_res") -@usableFromInline internal func _getClockRes( seconds: UnsafeMutablePointer, nanoseconds: UnsafeMutablePointer, - clock: _ClockID) + clock: CInt) diff --git a/stdlib/public/Concurrency/ContinuousClock.swift b/stdlib/public/Concurrency/ContinuousClock.swift index 7a1aac302d240..4d2574cbaad42 100644 --- a/stdlib/public/Concurrency/ContinuousClock.swift +++ b/stdlib/public/Concurrency/ContinuousClock.swift @@ -59,7 +59,7 @@ extension ContinuousClock: Clock { _getClockRes( seconds: &seconds, nanoseconds: &nanoseconds, - clock: .continuous) + clock: _ClockID.continuous.rawValue) return .seconds(seconds) + .nanoseconds(nanoseconds) } @@ -70,7 +70,7 @@ extension ContinuousClock: Clock { _getTime( seconds: &seconds, nanoseconds: &nanoseconds, - clock: .continuous) + clock: _ClockID.continuous.rawValue) return ContinuousClock.Instant(_value: .seconds(seconds) + .nanoseconds(nanoseconds)) } diff --git a/stdlib/public/Concurrency/SuspendingClock.swift b/stdlib/public/Concurrency/SuspendingClock.swift index 295b00363c729..5f630221d7a6e 100644 --- a/stdlib/public/Concurrency/SuspendingClock.swift +++ b/stdlib/public/Concurrency/SuspendingClock.swift @@ -60,7 +60,7 @@ extension SuspendingClock: Clock { _getTime( seconds: &seconds, nanoseconds: &nanoseconds, - clock: .suspending) + clock: _ClockID.suspending.rawValue) return SuspendingClock.Instant(_value: .seconds(seconds) + .nanoseconds(nanoseconds)) } @@ -73,7 +73,7 @@ extension SuspendingClock: Clock { _getClockRes( seconds: &seconds, nanoseconds: &nanoseconds, - clock: .suspending) + clock: _ClockID.suspending.rawValue) return .seconds(seconds) + .nanoseconds(nanoseconds) } From 890a7f25e8e718e5c6d38b4df4ae0cfc7bbe363d Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Sat, 19 Feb 2022 18:37:47 -0800 Subject: [PATCH 2/4] [stdlib] Duration: add an initializer that takes low/high components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having a direct initializer in the ABI is critically important — otherwise we wouldn’t be able to add back deployable conversion initializers in the future (without going through unnecessary overhead). --- stdlib/public/core/Duration.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/Duration.swift b/stdlib/public/core/Duration.swift index 1d0a8e4ce94c7..9e5feba6a1d89 100644 --- a/stdlib/public/core/Duration.swift +++ b/stdlib/public/core/Duration.swift @@ -42,9 +42,14 @@ public struct Duration: Sendable { @usableFromInline internal var _high: Int64 + @inlinable + internal init(_low: UInt64, high: Int64) { + self._low = _low + self._high = high + } + internal init(_attoseconds: _Int128) { - self._low = _attoseconds.low - self._high = _attoseconds.high + self.init(_low: _attoseconds.low, high: _attoseconds.high) } /// Construct a `Duration` by adding attoseconds to a seconds value. From 1da0bb8f2ed99415ad0dee4f48f45ab4d2a09573 Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Sat, 19 Feb 2022 18:40:57 -0800 Subject: [PATCH 3/4] [stdlib] Int128: Fix Words; simplify/tweak some operations `Words.Iterator.next()` used to call `Int128(truncatingIfNeeded:)`, which in turn iterates over words, leading to an infinite recursion. Implement half-width multiplication from scratch instead of masking off the full width results. --- stdlib/public/core/Int128.swift.gyb | 174 ++++++++++++++++------------ 1 file changed, 98 insertions(+), 76 deletions(-) diff --git a/stdlib/public/core/Int128.swift.gyb b/stdlib/public/core/Int128.swift.gyb index f403deba50859..ec8d499c441d5 100644 --- a/stdlib/public/core/Int128.swift.gyb +++ b/stdlib/public/core/Int128.swift.gyb @@ -11,7 +11,9 @@ //===----------------------------------------------------------------------===// % for signed in [False, True]: -% U = 'U' if signed else '' +% U = '' if signed else 'U' +% Self = '_Int128' if signed else '_UInt128' +% Other = '_UInt128' if signed else '_Int128' /// A 128-bit ${'signed' if signed else 'unsigned'} integer type. internal struct _${U}Int128 { internal typealias High = ${U}Int64 @@ -40,6 +42,13 @@ internal struct _${U}Int128 { internal init() { self.init(high: 0, low: 0) } + + internal init(bitPattern v: ${Other}) { + self.init(high: High(bitPattern: v.high), low: v.low) + } + + internal static var zero: Self { Self(high: 0, low: 0) } + internal static var one: Self { Self(high: 0, low: 1) } } extension _${U}Int128: CustomStringConvertible { @@ -82,9 +91,9 @@ extension _${U}Int128 { extension _${U}Int128: AdditiveArithmetic { internal static func - (_ lhs: Self, _ rhs: Self) -> Self { - var lhs = lhs - lhs -= rhs - return lhs + let (result, overflow) = lhs.subtractingReportingOverflow(rhs) + _precondition(!overflow, "Overflow in -") + return result } internal static func -= (_ lhs: inout Self, _ rhs: Self) { @@ -94,9 +103,9 @@ extension _${U}Int128: AdditiveArithmetic { } internal static func + (_ lhs: Self, _ rhs: Self) -> Self { - var lhs = lhs - lhs += rhs - return lhs + let (result, overflow) = lhs.addingReportingOverflow(rhs) + _precondition(!overflow, "Overflow in +") + return result } internal static func += (_ lhs: inout Self, _ rhs: Self) { @@ -110,7 +119,15 @@ extension _${U}Int128: Numeric { internal typealias Magnitude = _UInt128 internal var magnitude: Magnitude { - Magnitude(_wideMagnitude22(self.components)) + % if signed: + var result = _UInt128(bitPattern: self) + guard high._isNegative else { return result } + result.high = ~result.high + result.low = ~result.low + return result.addingReportingOverflow(.one).partialValue + % else: + return self + % end } internal init(_ magnitude: Magnitude) { @@ -148,9 +165,9 @@ extension _${U}Int128: Numeric { } internal static func * (_ lhs: Self, _ rhs: Self) -> Self { - var lhs = lhs - lhs *= rhs - return lhs + let (result, overflow) = lhs.multipliedReportingOverflow(by: rhs) + _precondition(!overflow, "Overflow in *") + return result } internal static func *= (_ lhs: inout Self, _ rhs: Self) { @@ -160,57 +177,49 @@ extension _${U}Int128: Numeric { } } - -% if signed: -extension _Int128 { - internal typealias Words = _UInt128.Words -} -% else: -extension _UInt128 { +extension _${U}Int128 { internal struct Words { - internal var high: High.Words - internal var low: Low.Words - - internal init(_ value: _UInt128) { - self.init(high: value.high.words, low: value.low.words) - } + internal var _value: _${U}Int128 - internal init(_ value: _Int128) { - self.init(_UInt128(truncatingIfNeeded: value)) - } - - internal init(high: High.Words, low: Low.Words) { - self.high = high - self.low = low + internal init(_ value: _${U}Int128) { + self._value = value } } } -extension _UInt128.Words: RandomAccessCollection { +extension _${U}Int128.Words: RandomAccessCollection { + internal typealias Element = UInt internal typealias Index = Int - - internal var startIndex: Index { - 0 - } - - internal var endIndex: Index { - count - } - - internal var count: Int { - low.count + high.count - } - - internal subscript(_ i: Index) -> UInt { - if i < low.count { - return low[i + low.startIndex] + internal typealias Indices = Range + internal typealias SubSequence = Slice + + internal var count: Int { 128 / UInt.bitWidth } + internal var startIndex: Int { 0 } + internal var endIndex: Int { count } + internal var indices: Indices { startIndex ..< endIndex } + internal func index(after i: Int) -> Int { i + 1 } + internal func index(before i: Int) -> Int { i - 1 } + + internal subscript(position: Int) -> UInt { + get { + _precondition(position >= 0 && position < endIndex, + "Word index out of range") + let shift = position &* UInt.bitWidth + _internalInvariant(shift < _${U}Int128.bitWidth) + + let r = _wideMaskedShiftRight( + _value.components, UInt64(truncatingIfNeeded: shift)) + return r.low._lowWord } - return high[i - low.count + high.startIndex] } } -% end extension _${U}Int128: FixedWidthInteger { + @_transparent + internal var _lowWord: UInt { + low._lowWord + } + internal var words: Words { Words(self) } @@ -227,9 +236,7 @@ extension _${U}Int128: FixedWidthInteger { self.init(high: High.min, low: Low.min) } - internal static var bitWidth: Int { - High.bitWidth + Low.bitWidth - } + internal static var bitWidth: Int { 128 } internal func addingReportingOverflow( _ rhs: Self @@ -249,15 +256,23 @@ extension _${U}Int128: FixedWidthInteger { internal func multipliedReportingOverflow( by rhs: Self ) -> (partialValue: Self, overflow: Bool) { - let (carry, product) = multipliedFullWidth(by: rhs) - let result = Self(truncatingIfNeeded: product) - - let isNegative = Self.isSigned && (self._isNegative != rhs._isNegative) - let didCarry = isNegative ? carry != ~Self.zero : carry != Self.zero - let hadPositiveOverflow = Self.isSigned && - !isNegative && product.leadingZeroBitCount == 0 - - return (result, didCarry || hadPositiveOverflow) + % if signed: + let isNegative = (self._isNegative != rhs._isNegative) + let (p, overflow) = self.magnitude.multipliedReportingOverflow( + by: rhs.magnitude) + let r = _Int128(bitPattern: isNegative ? ~(p &- .one) : p) + return (r, overflow || (isNegative != r._isNegative)) + % else: + let h1 = self.high.multipliedReportingOverflow(by: rhs.low) + let h2 = self.low.multipliedReportingOverflow(by: rhs.high) + let h3 = h1.partialValue.addingReportingOverflow(h2.partialValue) + let (h, l) = self.low.multipliedFullWidth(by: rhs.low) + let high = h3.partialValue.addingReportingOverflow(h) + let overflow = ( + (self.high != 0 && rhs.high != 0) + || h1.overflow || h2.overflow || h3.overflow || high.overflow) + return (Self(high: high.partialValue, low: l), overflow) + % end } internal func quotientAndRemainder( @@ -333,7 +348,7 @@ extension _${U}Int128: FixedWidthInteger { low: mid1.high + mid2.low) if isNegative { - let (lowComplement, overflow) = (~low).addingReportingOverflow(1) + let (lowComplement, overflow) = (~low).addingReportingOverflow(.one) return (~high + (overflow ? 1 : 0), lowComplement) } else { return (high, low) @@ -343,15 +358,10 @@ extension _${U}Int128: FixedWidthInteger { internal func dividingFullWidth( _ dividend: (high: Self, low: Self.Magnitude) ) -> (quotient: Self, remainder: Self) { + % if signed: let m = _wideMagnitude22(dividend) - let (q, r) = _wideDivide42( - (m.high.components, m.low.components), - by: self.magnitude.components) - let quotient = Self.Magnitude(q) - let remainder = Self.Magnitude(r) - guard Self.isSigned else { - return (Self(quotient), Self(remainder)) - } + let (quotient, remainder) = self.magnitude.dividingFullWidth(m) + let isNegative = (self.high._isNegative != dividend.high.high._isNegative) let quotient_ = (isNegative ? (quotient == Self.min.magnitude ? Self.min : 0 - Self(quotient)) @@ -360,13 +370,17 @@ extension _${U}Int128: FixedWidthInteger { ? 0 - Self(remainder) : Self(remainder)) return (quotient_, remainder_) + % else: + let (q, r) = _wideDivide42( + (dividend.high.components, dividend.low.components), + by: self.components) + return (Self(q), Self(r)) + % end } -/* disabled since it causes a compile failure in LLDB internal static prefix func ~(x: Self) -> Self { Self(high: ~x.high, low: ~x.low) } -*/ internal static func &= (_ lhs: inout Self, _ rhs: Self) { lhs.low &= rhs.low @@ -413,11 +427,19 @@ extension _${U}Int128: FixedWidthInteger { lhs &>>= rhs } - internal static func &<<= (_ lhs: inout Self, _ rhs: Self) { + internal static func &<< (lhs: Self, rhs: Self) -> Self { + Self(_wideMaskedShiftLeft(lhs.components, rhs.low)) + } + + internal static func &>> (lhs: Self, rhs: Self) -> Self { + Self(_wideMaskedShiftRight(lhs.components, rhs.low)) + } + + internal static func &<<= (lhs: inout Self, rhs: Self) { _wideMaskedShiftLeft(&lhs.components, rhs.low) } - internal static func &>>= (_ lhs: inout Self, _ rhs: Self) { + internal static func &>>= (lhs: inout Self, rhs: Self) { _wideMaskedShiftRight(&lhs.components, rhs.low) } @@ -590,7 +612,7 @@ private func _wideMaskedShiftLeft( var high = lhs.high &<< F(rhs) let rollover = F.Magnitude(F.bitWidth) &- rhs high |= F(truncatingIfNeeded: lhs.low &>> rollover) - var low = lhs.low &<< rhs + let low = lhs.low &<< rhs return (high, low) } From b7cae85482f763184832fff5c53a684b735af14d Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Mon, 21 Feb 2022 12:26:21 -0800 Subject: [PATCH 4/4] [stdlib] Leave [U]Int128.~ disabled for now --- stdlib/public/core/Int128.swift.gyb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stdlib/public/core/Int128.swift.gyb b/stdlib/public/core/Int128.swift.gyb index ec8d499c441d5..cdad5c7fc88c2 100644 --- a/stdlib/public/core/Int128.swift.gyb +++ b/stdlib/public/core/Int128.swift.gyb @@ -378,9 +378,12 @@ extension _${U}Int128: FixedWidthInteger { % end } + #if false // This triggers an unexpected type checking issue with `~0` in an + // lldb test internal static prefix func ~(x: Self) -> Self { Self(high: ~x.high, low: ~x.low) } + #endif internal static func &= (_ lhs: inout Self, _ rhs: Self) { lhs.low &= rhs.low