Skip to content

Add --fast-math mode #3155

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 18 commits into from
Sep 30, 2020
Merged

Add --fast-math mode #3155

merged 18 commits into from
Sep 30, 2020

Conversation

kripken
Copy link
Member

@kripken kripken commented Sep 21, 2020

Similar to clang and gcc, --fast-math makes us ignore corner cases of floating-point
math like NaN changes and (not done yet) lack of associativity and so forth.

This undoes some changes (#2958 and #3096) where we assumed it was
ok to not change NaN bits, but @binji corrected us. We can only do such things in fast
math mode. This puts those optimizations behind that flag, adds tests for it, and
restores the interpreter to the simpler code from before with no special cases.

@MaxGraey
Copy link
Contributor

MaxGraey commented Sep 21, 2020

Could --fast-math be a enum mode? For example:
--fast-math 0 - most strict mode, care about NaN bits.
--fast-math 1 - don't care about NaN bits. Make possible x - 0 -> x, x * 1 -> x, -1 * x -> -x
--fast-math 2 - don't care about NaN bits and -0 / +0 consistency. Make possible reduction x + 0 -> x
--fast-math 3 - don't care about NaN at all (for example: x == x -> 1, x - x -> 0.0). Also don't care about precision lost. Make possible x + C - C -> x, x / C -> x * (1 / C) even if C is not power of two. And etc.

@kripken
Copy link
Member Author

kripken commented Sep 21, 2020

@MaxGraey yes, it may make sense to have something more fine-grained eventually. @sunfishcode mentioned that this is what clang and gcc have, with separate flags for NaNs and such.

I think that's a reasonable thing to aim for. For now, I think this PR is a good first step. It fixes fuzzer failures, gets us back to emitting correct code, and avoids just ripping out the relevant optimizations, instead putting them behind a flag.

Copy link
Member

@binji binji left a comment

Choose a reason for hiding this comment

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

nice, lgtm (without knowing much about binaryen stuff)

@@ -1369,7 +1372,8 @@ struct OptimizeInstructions
}
{
double value;
if (matches(curr, binary(Abstract::Sub, any(), fval(&value))) &&
if (fastMath &&
matches(curr, binary(Abstract::Sub, any(), fval(&value))) &&
value == 0.0) {
// x - (-0.0) ==> x + 0.0
Copy link
Member

Choose a reason for hiding this comment

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

What's wrong about this optimization without fastMath? Is it that it doesn't change non-canonical NaN bits but it should?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, actually, re-reading it now I'm not sure. It doesn't remove a math operation (unlike the others), so it would still change NaNs as expected, I think? I guess we'd need to read the spec (wasm? IEEE?) carefully. If no one knows offhand, the safe thing may be to land this with a TODO for later.

Copy link
Contributor

Choose a reason for hiding this comment

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

Imteresting article:
https://754r.ucbtest.org/background/nan-propagation.pdf
See "What should happen when two payloads are combined?"

Copy link
Contributor

Choose a reason for hiding this comment

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

And yes seems to be IEEE754 doesn't specify how two NaNs with different payloads should be combined. I guess it should be reflect on wasm spec tests

Copy link
Contributor

Choose a reason for hiding this comment

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

Btw webassembly spec specify Na N-propogation rules for fneg, fabs and fcopysign:
https://webassembly.github.io/spec/core/bikeshed/index.html#nan-propagation%E2%91%A0

// and assuming math follows the algebraic rules for associativity and so
// forth (which IEEE floats do not, strictly speaking). This is inspired by
// gcc/clang's -ffast-math flag.
bool fastMath = false;
Copy link
Member

Choose a reason for hiding this comment

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

"Fast math" has many meanings, including ignoring negative zero, ignoring infinities, ignoring NaNs, ignoring signaling NaN, allowing for greater precision, and allowing for reduced precision. GCC and clang have moved to have several different flags for these things, as no single definition of "fast math" works for everyone. I encourage Binaryen to follow GCC and clang here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed, @sunfishcode , that is the plan. This is just the first step.

Copy link
Member

Choose a reason for hiding this comment

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

What is the status of this plan?

Copy link
Member Author

Choose a reason for hiding this comment

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

@sunfishcode So far the use cases for the fast math flag have only been ignoring NaNs, AFAIK. So we've not added more specific flags. I imagine we will when we start to optimize them.

Do you have more use cases or ideas perhaps?

Copy link
Contributor

@MaxGraey MaxGraey Oct 19, 2021

Choose a reason for hiding this comment

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

With more levels we could do more floating points optimizations:
#3155 (comment)

Copy link
Member

Choose a reason for hiding this comment

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

A separate ignoreNaNs flag, which could also be enabled by fastMath, would allow users that want to ignore NaNs do so without having to know this implementation detail about Binaryen, and without opting into unknown optimizations in future versions of Binaryen.

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense.

Is this something you'd use soon @sunfishcode ? If so I can open a PR later today probably. (Or maybe @MaxGraey you'd want to?) If it's not urgent we could open an issue so we don't forget.

Copy link
Contributor

Choose a reason for hiding this comment

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

@kripken If this PR only add separate ignoreNaNs flags then I think it would be better that you open PR. I might do a more substantial PR adding a few levels for fastMath a bit later.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, I found some time, PR up: #4262

@kripken
Copy link
Member Author

kripken commented Sep 30, 2020

Added the review suggestion change, and the fuzzer meanwhile found another case I missed, c4cfcba

@kripken kripken merged commit 0704710 into master Sep 30, 2020
@kripken kripken deleted the ff branch September 30, 2020 19:39
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.

5 participants