Skip to content

Advance the port all the way to the end of 2022. #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
b6f2ebb
Track the current LLVM commit hash of the port in the version number.
eddyb Jul 18, 2023
7c82f2d
README: fill in most of the remaining details (history, versioning).
eddyb Jul 18, 2023
697bf3c
Advance the port to https://github.com/llvm/llvm-project/commit/768d6…
eddyb Jul 11, 2023
45c2345
Advance the port to https://github.com/llvm/llvm-project/commit/69f60…
eddyb Jul 12, 2023
bacc0a9
Advance the port to https://github.com/llvm/llvm-project/commit/2b6b8…
eddyb Jul 12, 2023
6a67d49
Advance the port to https://github.com/llvm/llvm-project/commit/b198f…
eddyb Jul 13, 2023
e4703ec
Advance the port to https://github.com/llvm/llvm-project/commit/a2588…
eddyb Jul 13, 2023
a3362d1
fuzz: add float->float->float roundtrip ops (through `f32`/`Single` a…
eddyb Jul 13, 2023
6f8bd3a
Advance the port to https://github.com/llvm/llvm-project/commit/6dabc…
eddyb Jul 13, 2023
9905076
fuzz: remove `--strict-hard-qnan-vs-snan` flag now that APFloat handl…
eddyb Jul 15, 2023
c5ad989
fuzz: add two more flags to control NaN strictness (vs hardware) and …
eddyb Jul 15, 2023
dc40e34
Advance the port to https://github.com/llvm/llvm-project/commit/f45d5…
eddyb Jul 15, 2023
b079515
Advance the port to https://github.com/llvm/llvm-project/commit/462a3…
eddyb Jul 17, 2023
01745f2
fuzz: add `bruteforce-tiny` subcommand for exhaustively checking 8-bi…
eddyb Jul 17, 2023
68abe98
ieee: increase robustness around special combinations of `category` a…
eddyb Jul 18, 2023
02bb6cf
Bump version to `0.1.0`.
eddyb Jul 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
members = ["fuzz"]

[workspace.package]
version = "0.0.0"
version = "0.1.0+llvm-462a31f5a5ab"
edition = "2021"
license = "Apache-2.0 WITH LLVM-exception"

Expand Down
66 changes: 63 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,68 @@
# `rustc_apfloat` (Rust port of C++ `llvm::APFloat` library)
# `rustc_apfloat`<br><sub>(Rust port of the C++ `llvm::APFloat` "softfloat" library)</sub>

## History

LLVM's `APFloat` (aka `llvm::APFloat`) software floating-point (or "softfloat")
library was first ported to Rust (and named `rustc_apfloat`) back in 2017,
in the Rust pull request [`rust-lang/rust#43554`](https://github.com/rust-lang/rust/pull/43554),
as part of an effort to expand Rust compile-time capabilities without sacrificing
determinism (and therefore soundness, if the type-system was involved).

<sub>Note: while using the original C++ `llvm::APFloat` directly would've been an option,
certain high-level API design differences made in the Rust port, without behavioral impact
(C++ raw pointers and dynamic allocations vs Rust generics, traits and `#![no_std]`),
made the Rust port more appealing from a determinism standpoint (mostly thanks to
lacking all 3 of: `unsafe` code, host floating-point use, `std` access - and only
allocating to handle the arbitrary precision needed for conversions to/from decimal),
*even though there was a chance it had correctness issues unique to it*.</sub>

However, that port had a fatal flaw: it was added to the `rust-lang/rust` repository
without its unique licensing status (as a port of a C++ library with its own license)
being properly tracked, communicated, taken into account, etc.
The end result was years of limbo, mostly chronicled in the Rust issue
[`rust-lang/rust#55993`](https://github.com/rust-lang/rust/issues/55993), in which
the in-tree port couldn't really receive proper updated or even maintenance, due
due to its unclear status.

### Revival (as `rust-lang/rustc_apfloat`)

This repository (`rust-lang/rustc_apfloat`) is the result of a 2022 plan on
[the relevant Zulip topic](https://rust-lang.zulipchat.com/#narrow/stream/231349-t-core.2Flicensing/topic/apfloat), fully put into motion during 2023:
* the `git` history of the in-tree `compiler/rustc_apfloat` library was extracted
(see the separate [`rustc_apfloat-git-history-extraction`](https://github.com/LykenSol/rustc_apfloat-git-history-extraction) repository for more details)
* only commits that were *both* necessary *and* had clear copyright status, were kept
* any missing functionality or bug fixes, would have to be either be re-contributed,
or rebuilt from the ground up (mostly the latter ended up being done, see below)

Most changes since the original port had been aesthetic (e.g. spell-checking, `rustfmt`),
so little was lost in the process.

Starting from that much smaller "trusted" base:
* everything could use LLVM's new (since 2019) license, "`Apache-2.0 WITH LLVM-exception`"
(see the ["Licensing"](#licensing) section below and/or [LICENSE-DETAILS.md](./LICENSE-DETAILS.md) for more details)
* new facilities were built (benchmarks, and [a fuzzer comparing Rust/C++/hardware](#fuzzing))
* excessive testing was performed (via a combination of fuzzing and bruteforce search)
* latent bugs were discovered (e.g. LLVM issues
[#63895](https://github.com/llvm/llvm-project/issues/63895) and
[#63938](https://github.com/llvm/llvm-project/issues/63938))
* the port has been forwarded in time, to include upstream (`llvm/llvm-project`) changes
to `llvm::APFloat` over the years (since 2017), removing the need for selective backports

## Versioning

As this is, for the time being, a "living port", tracking upstream (`llvm/llvm-project`)
`llvm::APFloat` changes, the `rustc_apfloat` crate will have versions of the form:

## 🚧 Work In Progress 🚧
```
0.X.Y+llvm-ZZZZZZZZZZZZ
```
* `X` is always bumped after semver-incompatible API changes,
or when updating the upstream (`llvm/llvm-project`) commit the port is based on
* `Y` is only bumped when other parts of the version don't need to be (e.g. for bug fixes)
* `+llvm-ZZZZZZZZZZZZ` is ["version metadata"](https://doc.rust-lang.org/cargo/reference/resolver.html#version-metadata) (which Cargo itself ignores),
and `ZZZZZZZZZZZZ` always holds the first 12 hexadecimal digits of
the upstream (`llvm/llvm-project`) `git` commit hash the port is based on

**NOTE**: the repo (and [`rustc_apfloat-git-history-extraction`](https://github.com/LykenSol/rustc_apfloat-git-history-extraction)) might be public already, but only for convenience of discussion, see [relevant Zulip topic](https://rust-lang.zulipchat.com/#narrow/stream/231349-t-core.2Flicensing/topic/apfloat) for more details.

## Testing

Expand Down
41 changes: 41 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// HACK(eddyb) easier dep-tracking if we let `rustc` do it.
const SRC_LIB_RS_CONTENTS: &str = include_str!("src/lib.rs");

const EXPECTED_SRC_LIB_RS_PREFIX: &str = "\
//! Port of LLVM's APFloat software floating-point implementation from the
//! following C++ sources (please update commit hash when backporting):
//! https://github.com/llvm/llvm-project/commit/";

fn main() {
// HACK(eddyb) disable the default of re-running the build script on *any*
// change to *the entire source tree* (i.e. the default is roughly `./`).
println!("cargo:rerun-if-changed=build.rs");

let llvm_commit_hash = SRC_LIB_RS_CONTENTS
.strip_prefix(EXPECTED_SRC_LIB_RS_PREFIX)
.ok_or(())
.map_err(|_| format!("expected `src/lib.rs` to start with:\n\n{EXPECTED_SRC_LIB_RS_PREFIX}"))
.and_then(|commit_hash_plus_rest_of_file| {
Ok(commit_hash_plus_rest_of_file
.split_once('\n')
.ok_or("expected `src/lib.rs` to have more than 3 lines")?)
})
.and_then(|(commit_hash, _)| {
if commit_hash.len() != 40 || !commit_hash.chars().all(|c| matches!(c, '0'..='9'|'a'..='f')) {
Err(format!("expected `src/lib.rs` to have a valid commit hash, found {commit_hash:?}"))
} else {
Ok(commit_hash)
}
})
.unwrap_or_else(|e| {
eprintln!("\n{e}\n");
panic!("failed to validate `src/lib.rs`'s commit hash (see above)")
});

let expected_version_metadata = format!("+llvm-{}", &llvm_commit_hash[..12]);
let actual_version = env!("CARGO_PKG_VERSION");
if !actual_version.ends_with(&expected_version_metadata) {
eprintln!("\nexpected version ending in `{expected_version_metadata}`, found `{actual_version}`\n");
panic!("failed to validate Cargo package version (see above)");
}
}
16 changes: 8 additions & 8 deletions fuzz/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ fn main() -> std::io::Result<ExitCode> {
// change to *the entire source tree* (i.e. the default is roughly `./`).
println!("cargo:rerun-if-changed=build.rs");

// NOTE(eddyb) `rustc_apfloat`'s own `build.rs` validated the version string.
let (_, llvm_commit_hash) = env!("CARGO_PKG_VERSION").split_once("+llvm-").unwrap();
assert_eq!(llvm_commit_hash.len(), 12);

let out_dir = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
std::fs::write(out_dir.join("generated_fuzz_ops.rs"), ops::generate_rust())?;

Expand Down Expand Up @@ -40,11 +44,7 @@ fn main() -> std::io::Result<ExitCode> {
let sh_script_exit_status = Command::new("sh")
.args(["-c", SH_SCRIPT])
.envs([
// FIXME(eddyb) ensure this is kept in sync.
(
"llvm_project_git_hash",
"f3598e8fca83ccfb11f58ec7957c229e349765e3",
),
("llvm_project_git_hash", llvm_commit_hash),
("cxx_apf_fuzz_exports", &cxx_exported_symbols.join(",")),
(
"cxx_apf_fuzz_is_fuzzing",
Expand All @@ -68,7 +68,7 @@ curl -sS "$llvm_project_tgz_url" | tar -C "$OUT_DIR" -xz
llvm="$OUT_DIR"/llvm-project-"$llvm_project_git_hash"/llvm

mkdir -p "$OUT_DIR"/fake-config/llvm/Config
touch "$OUT_DIR"/fake-config/llvm/Config/{abi-breaking,llvm-config}.h
touch "$OUT_DIR"/fake-config/llvm/Config/{abi-breaking,config,llvm-config}.h

# HACK(eddyb) we want standard `assert`s to work, but `NDEBUG` also controls
# unrelated LLVM facilities that are spread all over the place and it's harder
Expand All @@ -91,8 +91,8 @@ echo | clang++ -x c++ - -std=c++17 \
$clang_codegen_flags \
-I "$llvm"/include \
-I "$OUT_DIR"/fake-config \
-DNDEBUG \
--include="$llvm"/lib/Support/{APInt,APFloat,SmallVector}.cpp \
-DNDEBUG -DHAVE_UNISTD_H -DLLVM_ON_UNIX -DLLVM_ENABLE_THREADS=0 \
--include="$llvm"/lib/Support/{APInt,APFloat,SmallVector,ErrorHandling}.cpp \
--include="$OUT_DIR"/cxx_apf_fuzz.cpp \
-c -emit-llvm -o "$OUT_DIR"/cxx_apf_fuzz.bc

Expand Down
Loading