Skip to content

Commit 6a72622

Browse files
authored
Merge pull request #11161 from natecook1000/nc-dwformatting
[stdlib] DoubleWidth refinements
2 parents 53ebbf0 + 4e45358 commit 6a72622

File tree

2 files changed

+41
-31
lines changed

2 files changed

+41
-31
lines changed

stdlib/public/core/DoubleWidth.swift.gyb

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,8 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
314314
let initialOffset = q.leadingZeroBitCount +
315315
(DoubleWidth.bitWidth - rhs.leadingZeroBitCount) - 1
316316

317-
// TODO(performance): Use &>> instead here?
318317
// Start with remainder capturing the high bits of q.
318+
// (These need to be smart shifts, as initialOffset can be > q.bitWidth)
319319
var r = q >> Magnitude(DoubleWidth.bitWidth - initialOffset)
320320
q <<= Magnitude(initialOffset)
321321

@@ -396,8 +396,9 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
396396
let mid2 = sum(b.carry, c.carry, d.partial)
397397

398398
let low = DoubleWidth<Low>((mid1.partial, a.partial))
399-
let high = DoubleWidth(
400-
(High(mid2.carry + d.carry), mid1.carry + mid2.partial))
399+
let high = DoubleWidth((
400+
High(mid2.carry + d.carry), mid1.carry + mid2.partial
401+
))
401402

402403
if isNegative {
403404
let (lowComplement, overflow) = (~low).addingReportingOverflow(1)
@@ -433,6 +434,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
433434
return
434435
}
435436

437+
// Shift is larger than this type's bit width.
436438
if rhs._storage.high != (0 as High) ||
437439
rhs._storage.low >= DoubleWidth.bitWidth
438440
{
@@ -476,32 +478,30 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
476478
}
477479

478480
public static func &<<=(lhs: inout DoubleWidth, rhs: DoubleWidth) {
481+
// Need to use smart shifts here, since rhs can be > Base.bitWidth
479482
let rhs = rhs & DoubleWidth(DoubleWidth.bitWidth - 1)
480483

481484
lhs._storage.high <<= High(rhs._storage.low)
482-
if Base.bitWidth > rhs._storage.low {
483-
lhs._storage.high |= High(truncatingIfNeeded: lhs._storage.low >>
484-
(numericCast(Base.bitWidth) - rhs._storage.low))
485-
} else {
486-
lhs._storage.high |= High(truncatingIfNeeded: lhs._storage.low <<
487-
(rhs._storage.low - numericCast(Base.bitWidth)))
488-
}
485+
486+
let lowInHigh = Base.bitWidth > rhs._storage.low
487+
? lhs._storage.low >> (numericCast(Base.bitWidth) - rhs._storage.low)
488+
: lhs._storage.low << (rhs._storage.low - numericCast(Base.bitWidth))
489+
lhs._storage.high |= High(truncatingIfNeeded: lowInHigh)
490+
489491
lhs._storage.low <<= rhs._storage.low
490492
}
491493

492494
public static func &>>=(lhs: inout DoubleWidth, rhs: DoubleWidth) {
495+
// Need to use smart shifts here, since rhs can be > Base.bitWidth
493496
let rhs = rhs & DoubleWidth(DoubleWidth.bitWidth - 1)
494497

495498
lhs._storage.low >>= rhs._storage.low
496-
if Base.bitWidth > rhs._storage.low {
497-
lhs._storage.low |= Low(
498-
truncatingIfNeeded:
499-
lhs._storage.high << (numericCast(Base.bitWidth) - rhs._storage.low))
500-
} else {
501-
lhs._storage.low |= Low(
502-
truncatingIfNeeded: lhs._storage.high >>
503-
(rhs._storage.low - numericCast(Base.bitWidth)))
504-
}
499+
500+
let highInLow = Base.bitWidth > rhs._storage.low
501+
? lhs._storage.high << (numericCast(Base.bitWidth) - rhs._storage.low)
502+
: lhs._storage.high >> (rhs._storage.low - numericCast(Base.bitWidth))
503+
lhs._storage.low |= Low(truncatingIfNeeded: highInLow)
504+
505505
lhs._storage.high >>= High(truncatingIfNeeded: rhs._storage.low)
506506
}
507507

@@ -573,8 +573,10 @@ binaryOperators = [
573573

574574
@_transparent
575575
public var byteSwapped: DoubleWidth {
576-
return DoubleWidth((High(truncatingIfNeeded: low.byteSwapped),
577-
Low(truncatingIfNeeded: high.byteSwapped)))
576+
return DoubleWidth((
577+
High(truncatingIfNeeded: low.byteSwapped),
578+
Low(truncatingIfNeeded: high.byteSwapped)
579+
))
578580
}
579581
}
580582

test/stdlib/Integers.swift.gyb

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -761,22 +761,30 @@ dwTests.test("TwoWords") {
761761
}
762762

763763
dwTests.test("Bitshifts") {
764-
typealias DWU16 = DoubleWidth<UInt8>
765-
typealias DWU32 = DoubleWidth<DWU16>
766-
typealias DWU64 = DoubleWidth<DWU32>
764+
typealias DWU64 = DoubleWidth<DoubleWidth<DoubleWidth<UInt8>>>
765+
typealias DWI64 = DoubleWidth<DoubleWidth<DoubleWidth<Int8>>>
767766

768-
func f(_ x: UInt64) {
769-
let y = DWU64(x)
770-
for i in -65...65 {
767+
func f<T: FixedWidthInteger, U: FixedWidthInteger>(_ x: T, type: U.Type) {
768+
let y = U(x)
769+
expectEqual(T.bitWidth, U.bitWidth)
770+
for i in -(T.bitWidth + 1)...(T.bitWidth + 1) {
771771
expectTrue(x << i == y << i)
772772
expectTrue(x >> i == y >> i)
773+
774+
expectTrue(x &<< i == y &<< i)
775+
expectTrue(x &>> i == y &>> i)
773776
}
774777
}
775778

776-
f(1)
777-
f(~(~0 >> 1))
778-
f(.max)
779-
f(0b11110000_10100101_11110000_10100101_11110000_10100101_11110000_10100101)
779+
f(1 as UInt64, type: DWU64.self)
780+
f(~(~0 as UInt64 >> 1), type: DWU64.self)
781+
f(UInt64.max, type: DWU64.self)
782+
f(0b11110000_10100101_11110000_10100101_11110000_10100101_11110000_10100101 as UInt64, type: DWU64.self)
783+
784+
f(1 as Int64, type: DWI64.self)
785+
f(Int64.min, type: DWI64.self)
786+
f(Int64.max, type: DWI64.self)
787+
f(0b01010101_10100101_11110000_10100101_11110000_10100101_11110000_10100101 as Int64, type: DWI64.self)
780788
}
781789

782790
dwTests.test("Remainder/DividingBy0") {

0 commit comments

Comments
 (0)