@@ -311,17 +311,11 @@ extension DoubleWidth : FixedWidthInteger {
311311 by rhs: DoubleWidth
312312 ) -> (partialValue: DoubleWidth, overflow: Bool) {
313313 let (carry, product) = multipliedFullWidth(by: rhs)
314- let result = DoubleWidth(truncatingIfNeeded: product)
315-
316- let isNegative = DoubleWidth.isSigned &&
317- (self < (0 as DoubleWidth)) != (rhs < (0 as DoubleWidth))
318- let didCarry = isNegative
319- ? carry != ~(0 as DoubleWidth)
320- : carry != (0 as DoubleWidth)
321- let hadPositiveOverflow =
322- DoubleWidth.isSigned && !isNegative && product.leadingZeroBitCount == 0
323-
324- return (result, didCarry || hadPositiveOverflow)
314+ let partialValue = DoubleWidth(truncatingIfNeeded: product)
315+ // Overflow has occured if carry is not just the sign-extension of
316+ // partialValue (which is zero when Base is unsigned).
317+ let overflow = carry != (partialValue >> DoubleWidth.bitWidth)
318+ return (partialValue, overflow)
325319 }
326320
327321 public func quotientAndRemainder(
@@ -473,18 +467,21 @@ extension DoubleWidth : FixedWidthInteger {
473467
474468 /// Returns this value "masked" by its bit width.
475469 ///
476- /// "Masking" notionally involves repeatedly incrementing or decrementing this
477- /// value by `self.bitWidth` until the result is contained in the range
478- /// `0..<self.bitWidth`.
470+ /// "Masking" notionally involves repeatedly incrementing or decrementing
471+ /// this value by `self.bitWidth` until the result is contained in the
472+ /// range `0..<self.bitWidth`.
479473 internal func _masked() -> DoubleWidth {
480- // FIXME(integers): test types with bit widths that aren't powers of 2
474+ let bits = DoubleWidth(DoubleWidth.bitWidth)
481475 if DoubleWidth.bitWidth.nonzeroBitCount == 1 {
482- return self & DoubleWidth(DoubleWidth.bitWidth &- 1)
483- }
484- if DoubleWidth.isSigned && self._storage.high < (0 as High) {
485- return self % DoubleWidth(DoubleWidth.bitWidth) + self
476+ return self & (bits &- 1)
486477 }
487- return self % DoubleWidth(DoubleWidth.bitWidth)
478+ let reduced = self % bits
479+ // bitWidth is always positive, but the value being reduced might have
480+ // been negative, in which case reduced will also be negative. We need
481+ // the representative in [0, bitWidth), so conditionally add the count
482+ // to get the positive residue.
483+ if Base.isSigned && reduced < 0 { return reduced &+ bits }
484+ return reduced
488485 }
489486
490487 public static func &<<=(lhs: inout DoubleWidth, rhs: DoubleWidth) {
@@ -555,6 +552,31 @@ binaryOperators = [
555552 }
556553% end
557554
555+ public static func &+(
556+ lhs: DoubleWidth, rhs: DoubleWidth
557+ ) -> DoubleWidth {
558+ let (low, carry) = lhs.low.addingReportingOverflow(rhs.low)
559+ let high = lhs.high &+ rhs.high &+ (carry ? 1 : 0)
560+ return DoubleWidth(high, low)
561+ }
562+
563+ public static func &-(
564+ lhs: DoubleWidth, rhs: DoubleWidth
565+ ) -> DoubleWidth {
566+ let (low, borrow) = lhs.low.subtractingReportingOverflow(rhs.low)
567+ let high = lhs.high &- rhs.high &- (borrow ? 1 : 0)
568+ return DoubleWidth(high, low)
569+ }
570+
571+ public static func &*(
572+ lhs: DoubleWidth, rhs: DoubleWidth
573+ ) -> DoubleWidth {
574+ let p00 = lhs.low.multipliedFullWidth(by: rhs.low)
575+ let p10 = lhs.high &* Base(truncatingIfNeeded: rhs.low)
576+ let p01 = Base(truncatingIfNeeded: lhs.low) &* rhs.high
577+ return DoubleWidth(p10 &+ p01 &+ Base(truncatingIfNeeded: p00.high), p00.low)
578+ }
579+
558580 public init(_truncatingBits bits: UInt) {
559581 _storage.low = Low(_truncatingBits: bits)
560582 _storage.high = High(_truncatingBits: bits >> UInt(Low.bitWidth))
0 commit comments