Skip to content
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

Test more targets against a custom-built musl libm #300

Merged
merged 14 commits into from
Oct 28, 2024

Conversation

tgross35
Copy link
Contributor

@tgross35 tgross35 commented Oct 5, 2024

We don't currently test on any non-linux targets because results always require running against a linux-musl target. This PR does the following:

  • Add musl-math-sys which builds musl's math symbols with cc for a better test basis
  • Add macros and traits for a generic test framework
  • Add a simple test with 5000 random inputs that compares our libm against the build musl version
  • Now that testing isn't limited to linux, enable CI for all targets tested in compiler-builtins

CI testing is still somewhat limited (MSVC and Wasm can't build musl sources) but these changes should be enough to make future improvements easier.

@tgross35 tgross35 force-pushed the test-refactoring branch 7 times, most recently from fc28dfb to 9df91b3 Compare October 7, 2024 05:24
@tgross35 tgross35 force-pushed the test-refactoring branch 12 times, most recently from 5d19904 to 9dd3156 Compare October 17, 2024 06:30
@tgross35 tgross35 changed the title [wip] Build musl for tests Test for more targets against a custom-built musl libm Oct 17, 2024
@tgross35
Copy link
Contributor Author

@Amanieu when you get the chance this should be ready for a look. The goal here is mostly to get some easier testing options off the ground, which can be followed up with less random inputs (can probably leverage periodicity/domain for better coverage) and more accurate output checks (checking ULP against MPFR).

The PR is pretty heavy because it adds a lot of framework, to make things easier it is by-commit reviewable.

@tgross35 tgross35 changed the title Test for more targets against a custom-built musl libm Test more targets against a custom-built musl libm Oct 17, 2024
@tgross35 tgross35 mentioned this pull request Oct 18, 2024
@tgross35 tgross35 force-pushed the test-refactoring branch 2 times, most recently from 11fb3f5 to 3a15d71 Compare October 19, 2024 01:07
@tgross35
Copy link
Contributor Author

The rules macro was getting pretty cumbersome to work with so I wound up replacing it with a proc macro.

@tgross35 tgross35 force-pushed the test-refactoring branch 2 times, most recently from 7c9a327 to e5ced7a Compare October 21, 2024 21:21
@tgross35 tgross35 force-pushed the test-refactoring branch 5 times, most recently from ae8a70c to 23d4b39 Compare October 28, 2024 04:52
return None;
}

// The musl implementations seem to set the top bit of the mantissa for any NaN on i686.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually caused by the 32-bit x86 "C" calling convention using x87 registers to return values, causing format conversions (and therefore causing signalling NaNs to be quietened as compilers use the standard conversion instructions) on every f32/f64 function return. See llvm/llvm-project#66803 and rust-lang/rust#115567. This will also be a problem for copysign.

(As a side note, musl's fabs implementation does use the x87 fabs instruction via inline ASM, but that's just for efficiency since the result is going to be returned in an x87 register anyway: the problem remains that the loading/storing f32/f64 to and from the x87 register doesn't preserve signalling NaNs when the compiler uses the standard conversion instructions.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the context, updated the comment

.github/workflows/main.yml Outdated Show resolved Hide resolved
@beetrees
Copy link
Contributor

Other than that, LGTM 👍

@tgross35
Copy link
Contributor Author

Other than that, LGTM 👍

Thanks for the review!

This has been through quite a few cycles, let's get it merged.

This crate builds math symbols from a musl checkout and provides a Rust
interface. The intent is that we will be able to compare our
implementations against musl on more than just linux (which are the only
currently the only targets we run `*-musl` targets against for
comparison).

Musl libc can't compile on anything other than Linux; however, the
routines in `src/math` are cross platform enough to build on MacOS and
windows-gnu with only minor adjustments. We take advantage of this and
build only needed files using `cc`.

The build script also performs remapping (via defines) so that e.g.
`cos` gets defined as `musl_cos`. This gives us more certainty that we
are actually testing against the intended symbol; without it, it is easy
to unknowingly link to system libraries or even Rust's `libm` itself and
wind up with an ineffective test. There is also a small procedure to
verify remapping worked correctly by checking symbols in object files.
Introduce `libm_test::for_each_function`. which macro takes a callback
macro and invokes it once per function signature. This provides an
easier way of registering various tests and benchmarks without
duplicating the function names and signatures each time.
Use a build script for `libm-test` to enumerate all symbols provided by
`libm` and provide this list in a variable. This will allow us to make
sure no functions are missed anytime they must be manually listed.

Additionally, introduce some helper config options.
Create a new test that checks `for_each_fn` against `ALL_FUNCTIONS`,
i.e. the manually entered function list against the automatically
collected list. If any are missing (e.g. new symbol added), then this
will produce an error.
These traits are simplified versions of what we have in
`compiler_builtins` and will be used for tests.
These traits give us a more generic way to interface with tuples used
for (1) test input, (2) function arguments, and (3) test input.
Add a type that caches values used to implement `GenerateInput` on a
variety of signatures.
Create a test generator that creates a known number of random inputs and
caches them, such that the same inputs are used for all functions.
Sometimes we want to be able to xfail specific inputs without changing
the checked ULP for all cases or skipping the tests. There are also some
cases where we need to perform extra checks for only specific functions.

Add a trait that provides a hook for providing extra checks or skipping
existing checks on a per-function or per-input basis.
Check our functions against `musl-math-sys`. This is similar to the
existing musl tests that go through binary serialization, but works on
more platforms.
These targets are tested in `compiler-builtins`, but not yet `libm`. Add
dockerfiles to prepare for this.
This brings the targets tested here in line with those tested in
`compiler-builtins`.
@tgross35
Copy link
Contributor Author

Just to be foiled by a Docker 502...

@tgross35 tgross35 merged commit 6bbbed5 into rust-lang:master Oct 28, 2024
28 checks passed
@tgross35 tgross35 deleted the test-refactoring branch October 28, 2024 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants