Skip to content

Commit e019825

Browse files
committed
Update RFC based on feedback
1 parent 60926a6 commit e019825

File tree

1 file changed

+55
-8
lines changed

1 file changed

+55
-8
lines changed

text/0000-int128.md

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# Summary
77
[summary]: #summary
88

9-
This RFC adds the `i128` and `u128` types to Rust. The `i128` and `u128` are not added to the prelude, and must instead be explicitly imported with `use core::{i128, u128}`.
9+
This RFC adds the `i128` and `u128` primitive types to Rust.
1010

1111
# Motivation
1212
[motivation]: #motivation
@@ -16,11 +16,29 @@ Some algorithms need to work with very large numbers that don't fit in 64 bits,
1616
# Detailed design
1717
[design]: #detailed-design
1818

19-
The `i128` and `u128` types are not added to the Rust prelude since that would break compatibility. Instead they must be explicitly imported with `use core::{i128, u128}` or `use std::{i128, u128}`.
19+
## Compiler support
2020

21-
Implementation-wise, this should just be a matter of adding a new primitive type to the compiler and adding trait implementations for `i128`/`u128` in libcore. Literals will need to be extended to support `i128`/`u128`.
21+
The first step for implementing this feature is to add support for the `i128`/`u128` primitive types to the compiler. This will requires changes to many parts of the compiler, from libsyntax to trans.
2222

23-
LLVM fully supports 128-bit integers on all architectures, however it will emit calls to functions in `compiler-rt` for many operations such as multiplication and division (addition and subtraction are implemented natively). However, `compiler-rt` only provides the functions for 128-bit integers on 64-bit platforms (`#ifdef __LP64__`). We will need to provide our own implementations of the following functions to allow `i128`/`u128` to be available on all architectures:
23+
The compiler will need to be bootstrapped from an older compiler which does not support `i128`/`u128`, but rustc will want to use these types internally for things like literal parsing and constant propagation. This can be solved by using a "software" implementation of these types, similar to the one in the [extprim](https://github.com/kennytm/extprim) crate. Once stage1 is built, stage2 can be compiled using the native LLVM `i128`/`u128` types.
24+
25+
## Runtime library support
26+
27+
The LLVM code generator supports 128-bit integers on all architectures, however it will lower some operations to runtime library calls. This similar to how we currently handle `u64` and `i64` on 32-bit platforms: "complex" operations such as multiplication or division are lowered by LLVM backends into calls to functions in the `compiler-rt` runtime library.
28+
29+
Here is a rough breakdown of which operations are handled natively instead of through a library call:
30+
- Add/Sub/Neg: native, including checked overflow variants
31+
- Compare (eq/ne/gt/ge/lt/le): native
32+
- Bitwise and/or/xor/not: native
33+
- Shift left/right: native on most architectures (some use libcalls instead)
34+
- Bit counting, parity, leading/trailing ones/zeroes: native
35+
- Byte swapping: native
36+
- Mul/Div/Mod: libcall (including checked overflow multiplication)
37+
- Conversion to/from f32/f64: libcall
38+
39+
The `compiler-rt` library that comes with LLVM only implements runtime library functions for 128-bit integers on 64-bit platforms (`#ifdef __LP64__`). We will need to provide our own implementations of the relevant functions to allow `i128`/`u128` to be available on all architectures. Note that this can only be done with a compiler that already supports `i128`/`u128` to match the calling convention that LLVM is expecting.
40+
41+
Here is the list of functions that need to be implemented:
2442

2543
```c
2644
// si_int = i32
@@ -46,17 +64,46 @@ tu_int __udivti3(tu_int a, tu_int b);
4664
tu_int __umodti3(tu_int a, tu_int b);
4765
```
4866
67+
Implementations of these functions will be written in Rust and will be included in libcore.
68+
69+
## Modifications to libcore
70+
71+
Several changes need to be done to libcore:
72+
- `src/libcore/num/i128.rs`: Define `MIN` and `MAX`.
73+
- `src/libcore/num/u128.rs`: Define `MIN` and `MAX`.
74+
- `src/libcore/num/mod.rs`: Implement inherent methods, `Zero`, `One`, `From` and `FromStr` for `u128` and `i128`.
75+
- `src/libcore/num/wrapping.rs`: Implement methods for `Wrapping<u128>` and `Wrapping<i128>`.
76+
- `src/libcore/fmt/num.rs`: Implement `Binary`, `Octal`, `LowerHex`, `UpperHex`, `Debug` and `Display` for `u128` and `i128`.
77+
- `src/libcore/cmp.rs`: Implement `Eq`, `PartialEq`, `Ord` and `PartialOrd` for `u128` and `i128`.
78+
- `src/libcore/nonzero.rs`: Implement `NonZero` for `u128` and `i128`.
79+
- `src/libcore/iter.rs`: Implement `Step` for `u128` and `i128`.
80+
- `src/libcore/clone.rs`: Implement `Clone` for `u128` and `i128`.
81+
- `src/libcore/default.rs`: Implement `Default` for `u128` and `i128`.
82+
- `src/libcore/hash/mod.rs`: Implement `Hash` for `u128` and `i128` and add `write_i128` and `write_u128` to `Hasher`.
83+
- `src/libcore/lib.rs`: Add the `u128` and `i128` modules.
84+
85+
## Modifications to libstd
86+
87+
A few minor changes are required in libstd:
88+
- `src/libstd/lib.rs`: Re-export `core::{i128, u128}`.
89+
- `src/libstd/primitive_docs.rs`: Add documentation for `i128` and `u128`.
90+
91+
## Modifications to other crates
92+
93+
A few external crates will need to be updated to support the new types:
94+
- `rustc-serialize`: Add the ability to serialize `i128` and `u128`.
95+
- `serde`: Add the ability to serialize `i128` and `u128`.
96+
- `rand`: Add the ability to generate random `i128`s and `u128`s.
97+
4998
# Drawbacks
5099
[drawbacks]: #drawbacks
51100
52-
One possible complication is that primitive types aren't currently part of the prelude, instead they are directly added to the global namespace by the compiler. The new `i128` and `u128` types will behave differently and will need to be explicitly imported.
53-
54-
Another possible issue is that a `u128` can hold a very large number that doesn't fit in a `f32`. We need to make sure this doesn't lead to any `undef`s from LLVM. See [this comment](https://github.com/rust-lang/rust/issues/10185#issuecomment-110955148), and [this example code](https://gist.github.com/Amanieu/f87da5f0599b343c5500).
101+
One possible issue is that a `u128` can hold a very large number that doesn't fit in a `f32`. We need to make sure this doesn't lead to any `undef`s from LLVM. See [this comment](https://github.com/rust-lang/rust/issues/10185#issuecomment-110955148), and [this example code](https://gist.github.com/Amanieu/f87da5f0599b343c5500).
55102
56103
# Alternatives
57104
[alternatives]: #alternatives
58105
59-
There have been several attempts to create `u128`/`i128` wrappers based on two `u64` values, but these can't match the performance of LLVM's native 128-bit integers.
106+
There have been several attempts to create `u128`/`i128` wrappers based on two `u64` values, but these can't match the performance of LLVM's native 128-bit integers. For example LLVM is able to lower a 128-bit add into just 2 instructions on 64-bit platforms and 4 instructions on 32-bit platforms.
60107
61108
# Unresolved questions
62109
[unresolved]: #unresolved-questions

0 commit comments

Comments
 (0)