|
| 1 | +# 128-bit Integer Types |
| 2 | + |
| 3 | +* Proposal: [SE-NNNN](nnnn-int128.md) |
| 4 | +* Author: [Stephen Canon](https://github.com/stephentyrone) |
| 5 | +* Review Manager: [Doug Gregor](https://github.com/DougGregor) |
| 6 | +* Implementation: https://github.com/stephentyrone/swift-numerics/tree/int128 |
| 7 | +* Status: **Awaiting review** |
| 8 | +* Review: ([Pitch](https://forums.swift.org/t/pitch-128-bit-integer-types/70188)) |
| 9 | + |
| 10 | +## Motivation |
| 11 | + |
| 12 | +128b integers are the largest fixed-size type that is currently commonly |
| 13 | +used in "general-purpose" code. They are much less common than 64b types, |
| 14 | +but common enough that adding them to the standard library makes sense. |
| 15 | +We use them internally in the standard library already (e.g. as an |
| 16 | +implementation detail of Duration). |
| 17 | + |
| 18 | +## Proposed solution |
| 19 | + |
| 20 | +Introduce two new structs, `UInt128` and `Int128`, conforming to all of the |
| 21 | +usual fixed-width integer protocols. |
| 22 | + |
| 23 | +While these will be implemented in the standard library, for the purposes of |
| 24 | +experimentation, I have put them on a branch of swift-numerics. To try these |
| 25 | +types out, use my branch `int128`: |
| 26 | +```swift |
| 27 | +.package( |
| 28 | + url: "https://github.com/stephentyrone/swift-numerics", |
| 29 | + branch: "int128" |
| 30 | +) |
| 31 | +``` |
| 32 | +and add `Int128Demo` as a dependency: |
| 33 | +```swift |
| 34 | +.target(name: "MyTarget", dependencies: [ |
| 35 | + .product(name: "Int128Demo", package: "swift-numerics") |
| 36 | +]), |
| 37 | +``` |
| 38 | +This branch requires a recent nightly toolchain to build. |
| 39 | + |
| 40 | +## Detailed design |
| 41 | + |
| 42 | +The `[U]Int128` types are 16B aligned on 64b targets¹ and have the same |
| 43 | +alignment as `[U]Int64` on 32b targets. They will match the endianness of |
| 44 | +all other integer types. |
| 45 | + |
| 46 | +The clang importer will be updated to bridge `__uint128_t` to `UInt128` and |
| 47 | +`__int128_t` to `Int128`. We will not bridge `_BitInt()` types until |
| 48 | +the ABI problems with those types have been clearly resolved (see Alternatives |
| 49 | +Considered for sordid history). |
| 50 | + |
| 51 | +The `[U]Int128` types conform to `AtomicRepresentable` on targets with |
| 52 | +`_hasAtomicBitWidth(_128)` set (notably x86\_64, arm64, and arm64\_32). |
| 53 | + |
| 54 | +The `[U]Int128` types conform to `Codable`; however, many existing encoders |
| 55 | +and decoders do not support such large integer types. Therefore they are |
| 56 | +encoded as a pair of 64b integers. This pair is always in little-endian |
| 57 | +order, regardless of the endianness of the architecture. |
| 58 | + |
| 59 | +The actual API of the types is uninteresting; they are entirely constrained by |
| 60 | +their protocol conformances. Notably, these types conform to the following |
| 61 | +protocols, and hence to any protocol that they refine: |
| 62 | + |
| 63 | +- Hashable |
| 64 | +- Equatable |
| 65 | +- Comparable |
| 66 | +- Codable |
| 67 | +- Sendable |
| 68 | +- LosslessStringConvertible |
| 69 | +- ExpressibleByIntegerLiteral |
| 70 | +- AdditiveArithmetic |
| 71 | +- [Signed]Numeric |
| 72 | +- BinaryInteger |
| 73 | +- FixedWidthInteger |
| 74 | +- [Unsigned|Signed]Integer |
| 75 | + |
| 76 | +------- |
| 77 | +¹ For the purposes of this discussion, arm64\_32 and similar architectures |
| 78 | +are "64b targets." |
| 79 | + |
| 80 | +## Source compatibility |
| 81 | + |
| 82 | +This proposal has no effect on source compatibility. |
| 83 | + |
| 84 | +## ABI compatibility |
| 85 | + |
| 86 | +This proposal has no effect on ABI compatibility. |
| 87 | + |
| 88 | +## Implications on adoption |
| 89 | + |
| 90 | +Adopting this feature will require a target with runtime support. |
| 91 | + |
| 92 | +## Future directions |
| 93 | + |
| 94 | +Implement clang importer support for `_BitInt(128)` on any platforms where |
| 95 | +the finalized ABI is compatible with our layout. |
| 96 | + |
| 97 | +## Alternatives considered |
| 98 | + |
| 99 | +### Alignment and `_BitInt()` types |
| 100 | +Clang and GCC have historically exposed the extension types `__uint128_t` and |
| 101 | +`__int128_t` on 64b platforms only. These types basically behave like C |
| 102 | +builtin integer types--their size and alignment are 16B. |
| 103 | + |
| 104 | +The C23 standard introduces `_BitInt(N)` as a means to spell arbitrary-width |
| 105 | +integer types, but these still have some warts. In particular, `_BitInt(128)` |
| 106 | +as implemented in clang has 8B alignment on x86\_64 and arm64. For arm64, |
| 107 | +this is clearly a bug; the AAPCS specifies that it should have 16B alignment. |
| 108 | +For x86\_64, the situation is less clear. The x86\_64 psABI document specifies |
| 109 | +that it should have 8B alignment, but the authors of the proposal that added |
| 110 | +the feature tell me that it _should_ be 16B aligned and that they are |
| 111 | +attempting to change the psABI. |
| 112 | + |
| 113 | +We would like to be layout-compatible with `_BitInt(128)` on all platforms, |
| 114 | +but given the currently-murky state of the layout of those types, it makes |
| 115 | +the most sense to guarantee compatibility with the widely-used but non- |
| 116 | +standard `__[u]int128_t` and find mechanisms to make `_BitInt(128)` work |
| 117 | +once its ABI has been finalized on Swift's targeted platforms. |
| 118 | + |
| 119 | +### Generic-sized fixed width integers |
| 120 | +Rather than adding `[U]Int128`, we could implement some form of generic- |
| 121 | +sized fixed-width integer (like `\_BitInt()` in C). Given both the lack |
| 122 | +of consensus around what integer generic parameters ought to look like in |
| 123 | +Swift (or if they ought to exist at all), and the growing pains that |
| 124 | +`\_BitInt()` is currently going through, such a design would be premature. |
| 125 | +While other fixed-width integer types are interesting, 128 bits is a couple |
| 126 | +orders of magnitude more useful than all the others for general-purpose |
| 127 | +software at this point in time. |
| 128 | + |
| 129 | +### Codable conformance |
| 130 | +Because many existing encoders and decoders do not already support 128b |
| 131 | +integers, we use a pair of 64b integers instead. To maximize compatibility, |
| 132 | +or to improve human-readability, we could instead encode these types as |
| 133 | +decimal or hexadecimal strings. However, this would be somewhat less |
| 134 | +efficient in some use cases, and it is possible for users to achieve the |
| 135 | +same effect by converting to a string before encoding. |
| 136 | + |
| 137 | +### NSNumber bridging |
| 138 | +`[U]Int128` will not bridge to `NSNumber`. In the future, Swift will need |
| 139 | +a careful rethinking of how best to handle type-erased numbers, but we don't |
| 140 | +want to pile on the debt by including ever more types in an existing system |
| 141 | +that isn't supported on all platforms. In addition, the most common use for |
| 142 | +such bridging, unpacking type-erased fields from encoded dictionaries, is |
| 143 | +somewhat moot since most existing coders do not support 128b integers. We |
| 144 | +will likely revisit this more holistically in the future. |
0 commit comments