Skip to content

Commit a05c56c

Browse files
committed
Merge pull request swiftlang#11161 from natecook1000/nc-dwformatting
[stdlib] DoubleWidth refinements
1 parent 8b4392c commit a05c56c

File tree

2 files changed

+42
-30
lines changed

2 files changed

+42
-30
lines changed

stdlib/public/core/DoubleWidth.swift.gyb

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
252252
let initialOffset = q.leadingZeroBitCount +
253253
(DoubleWidth.bitWidth - rhs.leadingZeroBitCount) - 1
254254

255-
// TODO(performance): Use &>> instead here?
256255
// Start with remainder capturing the high bits of q.
256+
// (These need to be smart shifts, as initialOffset can be > q.bitWidth)
257257
var r = q >> Magnitude(DoubleWidth.bitWidth - initialOffset)
258258
q <<= Magnitude(initialOffset)
259259

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

337337
let low = DoubleWidth<Low>((mid1.partial, a.partial))
338-
let high = DoubleWidth(
339-
(High(mid2.carry + d.carry), mid1.carry + mid2.partial))
338+
let high = DoubleWidth((
339+
High(mid2.carry + d.carry), mid1.carry + mid2.partial
340+
))
340341

341342
if isNegative {
342343
let (lowComplement, overflow) = (~low).addingReportingOverflow(1)
@@ -372,6 +373,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
372373
return
373374
}
374375

376+
// Shift is larger than this type's bit width.
375377
if rhs._storage.high != (0 as High) ||
376378
rhs._storage.low >= DoubleWidth.bitWidth
377379
{
@@ -415,31 +417,31 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
415417
}
416418

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

420423
lhs._storage.high <<= High(rhs._storage.low)
421-
if Base.bitWidth > rhs._storage.low {
422-
lhs._storage.high |= High(extendingOrTruncating: lhs._storage.low >>
423-
(numericCast(Base.bitWidth) - rhs._storage.low))
424-
} else {
425-
lhs._storage.high |= High(extendingOrTruncating: lhs._storage.low <<
426-
(rhs._storage.low - numericCast(Base.bitWidth)))
427-
}
424+
425+
let lowInHigh = Base.bitWidth > rhs._storage.low
426+
? lhs._storage.low >> (numericCast(Base.bitWidth) - rhs._storage.low)
427+
: lhs._storage.low << (rhs._storage.low - numericCast(Base.bitWidth))
428+
lhs._storage.high |= High(truncatingIfNeeded: lowInHigh)
429+
428430
lhs._storage.low <<= rhs._storage.low
429431
}
430432

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

434437
lhs._storage.low >>= rhs._storage.low
435-
if Base.bitWidth > rhs._storage.low {
436-
lhs._storage.low |= Low(extendingOrTruncating: lhs._storage.high <<
437-
numericCast(numericCast(Base.bitWidth) - rhs._storage.low))
438-
} else {
439-
lhs._storage.low |= Low(extendingOrTruncating: lhs._storage.high >>
440-
numericCast(rhs._storage.low - numericCast(Base.bitWidth)))
441-
}
442-
lhs._storage.high >>= High(extendingOrTruncating: rhs._storage.low)
438+
439+
let highInLow = Base.bitWidth > rhs._storage.low
440+
? lhs._storage.high << (numericCast(Base.bitWidth) - rhs._storage.low)
441+
: lhs._storage.high >> (rhs._storage.low - numericCast(Base.bitWidth))
442+
lhs._storage.low |= Low(truncatingIfNeeded: highInLow)
443+
444+
lhs._storage.high >>= High(truncatingIfNeeded: rhs._storage.low)
443445
}
444446

445447
%{
@@ -510,8 +512,10 @@ binaryOperators = [
510512

511513
@_transparent
512514
public var byteSwapped: DoubleWidth {
513-
return DoubleWidth((High(extendingOrTruncating: low.byteSwapped),
514-
Low(extendingOrTruncating: high.byteSwapped)))
515+
return DoubleWidth((
516+
High(truncatingIfNeeded: low.byteSwapped),
517+
Low(truncatingIfNeeded: high.byteSwapped)
518+
))
515519
}
516520
}
517521

test/stdlib/Integers.swift.gyb

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -732,22 +732,30 @@ dwTests.test("inits") {
732732
}
733733

734734
dwTests.test("Bitshifts") {
735-
typealias DWU16 = DoubleWidth<UInt8>
736-
typealias DWU32 = DoubleWidth<DWU16>
737-
typealias DWU64 = DoubleWidth<DWU32>
735+
typealias DWU64 = DoubleWidth<DoubleWidth<DoubleWidth<UInt8>>>
736+
typealias DWI64 = DoubleWidth<DoubleWidth<DoubleWidth<Int8>>>
738737

739-
func f(_ x: UInt64) {
740-
let y = DWU64(x)
741-
for i in -65...65 {
738+
func f<T: FixedWidthInteger, U: FixedWidthInteger>(_ x: T, type: U.Type) {
739+
let y = U(x)
740+
expectEqual(T.bitWidth, U.bitWidth)
741+
for i in -(T.bitWidth + 1)...(T.bitWidth + 1) {
742742
expectTrue(x << i == y << i)
743743
expectTrue(x >> i == y >> i)
744+
745+
expectTrue(x &<< i == y &<< i)
746+
expectTrue(x &>> i == y &>> i)
744747
}
745748
}
746749

747-
f(1)
748-
f(~(~0 >> 1))
749-
f(.max)
750-
f(0b11110000_10100101_11110000_10100101_11110000_10100101_11110000_10100101)
750+
f(1 as UInt64, type: DWU64.self)
751+
f(~(~0 as UInt64 >> 1), type: DWU64.self)
752+
f(UInt64.max, type: DWU64.self)
753+
f(0b11110000_10100101_11110000_10100101_11110000_10100101_11110000_10100101 as UInt64, type: DWU64.self)
754+
755+
f(1 as Int64, type: DWI64.self)
756+
f(Int64.min, type: DWI64.self)
757+
f(Int64.max, type: DWI64.self)
758+
f(0b01010101_10100101_11110000_10100101_11110000_10100101_11110000_10100101 as Int64, type: DWI64.self)
751759
}
752760

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

0 commit comments

Comments
 (0)