Skip to content

Commit

Permalink
Auto merge of #43554 - eddyb:apfloat, r=nikomatsakis
Browse files Browse the repository at this point in the history
APFloat: Rewrite It In Rust and use it for deterministic floating-point CTFE.

As part of the CTFE initiative, we're forced to find a solution for floating-point operations.
By design, IEEE-754 does not explicitly define everything in a deterministic manner, and there is some variability between platforms, at the very least (e.g. NaN payloads).

If types are to evaluate constant expressions involving type (or in the future, const) generics, that evaluation needs to be *fully deterministic*, even across `rustc` host platforms.
That is, if `[T; T::X]` was used in a cross-compiled library, and the evaluation of `T::X` executed a floating-point operation, that operation has to be reproducible on *any other host*, only knowing `T` and the definition of the `X` associated const (as either AST or HIR).

Failure to uphold those rules allows an associated type (e.g. `<Foo as Iterator>::Item`) to be seen as two (or more) different types, depending on the current host, and such type safety violations typically allow writing of a `transmute` in safe code, given enough generics.

The options considered by @rust-lang/compiler were:
1. Ban floating-point operations in generic const-evaluation contexts
2. Emulate floating-point operations in an uniformly deterministic fashion

The former option may seem appealing at first, but floating-point operations *are allowed today*, so they can't be banned wholesale, a distinction has to be made between the code that already works, and future generic contexts. *Moreover*, every computation that succeeded *has to be cached*, otherwise the generic case can be reproduced without any generics. IMO there are too many ways it can go wrong, and a single violation can be enough for an unsoundness hole.
Not to mention we may end up really wanting floating-point operations *anyway*, in CTFE.

I went with the latter option, and seeing how LLVM *already* has a library for this exact purpose (as it needs to perform optimizations independently of host floating-point capabilities), i.e. `APFloat`, that was what I ended up basing this PR on.
But having been burned by the low reusability of bindings that link to LLVM, and because I would *rather* the floating-point operations to be wrong than not deterministic or not memory-safe (`APFloat` does far more pointer juggling than I'm comfortable with), I decided to RIIR.

This way, we have a guarantee of *no* `unsafe` code, a bit more control over the where native floating-point might accidentally be involved, and non-LLVM backends can share it.
I've also ported all the testcases over, *before* any functionality, to catch any mistakes.

Currently the PR replaces all CTFE operations to go through `apfloat::ieee::{Single,Double}`, keeping only the bits of the `f32` / `f64` memory representation in between operations.
Converting from a string also double-checks that `core::num` and `apfloat` agree on the interpretation of a floating-point number literal, in case either of them has any bugs left around.

r? @nikomatsakis
f? @nagisa @est31

<hr/>

Huge thanks to @edef1c for first demoing usable `APFloat` bindings and to @chandlerc for fielding my questions on IRC about `APFloat` peculiarities (also upstreaming some bugfixes).
  • Loading branch information
bors committed Aug 5, 2017
2 parents 5c7add7 + c457b26 commit 2b82b7e
Show file tree
Hide file tree
Showing 19 changed files with 11,641 additions and 154 deletions.
8 changes: 8 additions & 0 deletions src/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/librustc/ich/impls_const_math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
//! This module contains `HashStable` implementations for various data types
//! from `rustc_const_math` in no particular order.

impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat {
F32(val),
F64(val)
impl_stable_hash_for!(struct ::rustc_const_math::ConstFloat {
ty,
bits
});

impl_stable_hash_for!(enum ::rustc_const_math::ConstInt {
Expand Down
11 changes: 11 additions & 0 deletions src/librustc_apfloat/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_apfloat"
version = "0.0.0"

[lib]
name = "rustc_apfloat"
path = "lib.rs"

[dependencies]
rustc_bitflags = { path = "../librustc_bitflags" }
Loading

0 comments on commit 2b82b7e

Please sign in to comment.