You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: text/0000-int128.md
+55-8Lines changed: 55 additions & 8 deletions
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@
6
6
# Summary
7
7
[summary]: #summary
8
8
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.
10
10
11
11
# Motivation
12
12
[motivation]: #motivation
@@ -16,11 +16,29 @@ Some algorithms need to work with very large numbers that don't fit in 64 bits,
16
16
# Detailed design
17
17
[design]: #detailed-design
18
18
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
20
20
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.
22
22
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
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:
24
42
25
43
```c
26
44
// si_int = i32
@@ -46,17 +64,46 @@ tu_int __udivti3(tu_int a, tu_int b);
46
64
tu_int __umodti3(tu_int a, tu_int b);
47
65
```
48
66
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.
- `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
+
49
98
# Drawbacks
50
99
[drawbacks]: #drawbacks
51
100
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).
55
102
56
103
# Alternatives
57
104
[alternatives]: #alternatives
58
105
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.
0 commit comments