Skip to content

Commit 5227984

Browse files
author
Dave Abrahams
committed
[stdlib/prototype] Scaffolding for multiprecision
Add basic components needed to do multiple-/mixed-precision arithmetic in terms of constituent UWords. With these tools we should be able to implement generic in-place mixed-width arithmetic operations such as anInt16 += aUInt8 and generalize it to BigInt arithmetic.
1 parent fd465ff commit 5227984

File tree

1 file changed

+48
-26
lines changed

1 file changed

+48
-26
lines changed

test/Prototypes/Integers.swift.gyb

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,28 @@ public protocol IntegerType
186186
var mostSignificantBit: Word { get }
187187

188188
@warn_unused_result
189-
func word(n: Word) -> Word
189+
func uword(n: Word) -> UWord
190190

191+
mutating func replaceUWord(n: Word, with newBits: UWord)
192+
191193
init<T : IntegerType>(_ source: T)
192194

193195
init<T : IntegerType>(extendingOrTruncating source: T)
194196
}
195197

198+
extension IntegerType {
199+
/// The number of words required to represent our value. If `self`
200+
/// is negative, returns the index of the least significant words of
201+
/// our representation such that all more-significant words are -1.
202+
/// Has the value -1 if `self` is 0.
203+
@_transparent
204+
public // transparent
205+
var _mostSignificantWord: Word {
206+
let msb = mostSignificantBit
207+
return msb < 0 ? msb : msb / ${word_bits}
208+
}
209+
}
210+
196211
//===--- Homogeneous comparison -------------------------------------------===//
197212
@_transparent
198213
@warn_unused_result
@@ -329,9 +344,9 @@ ${comment}
329344
@warn_unused_result
330345
func countLeadingZeros() -> Word
331346

332-
init(_truncatingBits bits: Word)
347+
init(_truncatingBits bits: UWord)
333348

334-
var _lowWord: Word { get }
349+
var _lowUWord: UWord { get }
335350
}
336351

337352
% for x in binaryBitwise:
@@ -477,7 +492,7 @@ extension FixedWidthIntegerType {
477492
@_transparent
478493
public init<T : IntegerType>(extendingOrTruncating source: T) {
479494
if Self.bitWidth <= ${word_bits} {
480-
self = Self.init(_truncatingBits: source.word(0))
495+
self = Self.init(_truncatingBits: source.uword(0))
481496
}
482497
else {
483498
var result: Self = source < 0 ? ~0 : 0
@@ -488,7 +503,7 @@ extension FixedWidthIntegerType {
488503
// that Self.bitWidth > ${word_bits}. Not masking results in
489504
// infinite recursion.
490505
result &<<= ${word_bits}
491-
result |= Self(_truncatingBits: source.word(n))
506+
result |= Self(_truncatingBits: source.uword(n))
492507
n -= 1
493508
}
494509

@@ -497,25 +512,33 @@ extension FixedWidthIntegerType {
497512
}
498513

499514
@_transparent
500-
public func word(n: Word) -> Word {
515+
public func uword(n: Word) -> UWord {
501516
var n = n
502517
_precondition(n >= 0, "Negative word index")
503518
var x = self
504519
while n > 0 {
505-
// Using a masking shift here allows us to make more things
506-
// transparent, but this would have the wrong semantics if the
507-
// masking ever had an effect.
508-
_sanityCheck(Self.bitWidth > ${word_bits})
509-
x &>>= ${word_bits}
520+
x &>>= Swift.min(Self(_truncatingBits: Self._bitWidth) &- 1, ${word_bits})
510521
n -= 1
511522
}
512-
return x._lowWord
523+
return x._lowUWord
513524
}
514525

526+
@_transparent
527+
public mutating func replaceUWord(n: Word, with newBits: UWord) {
528+
// Make sure the masking shift is going to be OK.
529+
_sanityCheck(Self.bitWidth > ${word_bits} * n)
530+
self ^= Self(_truncatingBits: newBits ^ uword(n)) &<< (${word_bits} * n)
531+
}
532+
515533
@_transparent
516534
public // transparent
517535
static var _highBitIndex: Self {
518-
return Self.init(_truncatingBits: Self.bitWidth - 1)
536+
return Self.init(_truncatingBits: Self._bitWidth &- 1)
537+
}
538+
539+
@_transparent
540+
public static var _bitWidth : UWord {
541+
return UWord(bitWidth._storage)
519542
}
520543
}
521544

@@ -650,6 +673,11 @@ public struct ${Self}
650673
_storage), x))
651674
}
652675

676+
@_transparent
677+
public init(bitPattern x: ${'U' if signed else ''}Int${bits}) {
678+
_storage = x._storage
679+
}
680+
653681
@warn_unused_result
654682
public func isEqualTo(rhs: ${Self}) -> Bool {
655683
return Bool(Builtin.cmp_eq_Int${bits}(_storage, rhs._storage))
@@ -727,31 +755,24 @@ public struct ${Self}
727755
@_transparent
728756
@warn_unused_result
729757
public func countLeadingZeros() -> Word {
730-
return ${Self}(
731-
Builtin.int_ctlz_Int${bits}(self._storage, false.__value))._lowWord
732-
}
733-
734-
@_transparent
735-
public // transparent
736-
var _lowWord: Word {
737-
% truncOrExt = z + 'ext' if bits <= word_bits else 'trunc'
738758
return Word(
739-
Builtin.${truncOrExt}OrBitCast_Int${bits}_Int${word_bits}(_storage)
740-
)
759+
${Self}(
760+
Builtin.int_ctlz_Int${bits}(self._storage, false.__value)
761+
)._lowUWord._storage)
741762
}
742763

743764
@_transparent
744765
public // transparent
745-
var _lowUnsignedWord: Word {
766+
var _lowUWord: UWord {
746767
% truncOrExt = z + 'ext' if bits <= word_bits else 'trunc'
747-
return Word(
768+
return UWord(
748769
Builtin.${truncOrExt}OrBitCast_Int${bits}_Int${word_bits}(_storage)
749770
)
750771
}
751772

752773
@_transparent
753774
public // transparent
754-
init(_truncatingBits bits: Word) {
775+
init(_truncatingBits bits: UWord) {
755776
% truncOrExt = 'zext' if bits > word_bits else 'trunc'
756777
self.init(
757778
Builtin.${truncOrExt}OrBitCast_Int${word_bits}_Int${bits}(bits._storage))
@@ -875,6 +896,7 @@ tests.test("mostSignificantBit") {
875896
expectEqual(7, UInt8.max.mostSignificantBit)
876897
expectEqual(-1, UInt8.min.mostSignificantBit)
877898
expectEqual(6, Int8.max.mostSignificantBit)
899+
expectEqual(-1, (0 as Int8).mostSignificantBit)
878900
expectEqual(6, Int8.min.mostSignificantBit)
879901
}
880902

0 commit comments

Comments
 (0)