Skip to content

Commit 3c383e1

Browse files
int128 proposal (#2348)
* int128 proposal * Add review manager * Add link to pitch * Add list of conformances for [U]Int128 * Add paragraph on NSNumber bridging.
1 parent 34d50fd commit 3c383e1

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

proposals/nnnn-int128.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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

Comments
 (0)