-
Notifications
You must be signed in to change notification settings - Fork 787
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
Add --fast-math mode #3155
Changes from all commits
c7dd870
71e9ecb
95a27c0
87aec7d
5f85c59
b6a9f3c
9ec23ee
32646b7
80270a1
26c1e06
e7f5a9a
2936b8a
301c14e
e661403
10a814a
4c10bc5
c4cfcba
dfef85a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -161,7 +161,10 @@ struct OptimizeInstructions | |
#endif | ||
} | ||
|
||
bool fastMath; | ||
|
||
void doWalkFunction(Function* func) { | ||
fastMath = getPassOptions().fastMath; | ||
// first, scan locals | ||
{ | ||
LocalScanner scanner(localInfo, getPassOptions()); | ||
|
@@ -1402,14 +1405,15 @@ 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's wrong about this optimization without There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Imteresting article: There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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: |
||
if (std::signbit(value)) { | ||
curr->op = Abstract::getBinary(type, Abstract::Add); | ||
right->value = right->value.neg(); | ||
return curr; | ||
} else { | ||
} else if (fastMath) { | ||
// x - 0.0 ==> x | ||
return curr->left; | ||
} | ||
|
@@ -1418,19 +1422,18 @@ struct OptimizeInstructions | |
{ | ||
// x + (-0.0) ==> x | ||
double value; | ||
if (matches(curr, binary(Abstract::Add, any(), fval(&value))) && | ||
if (fastMath && | ||
matches(curr, binary(Abstract::Add, any(), fval(&value))) && | ||
value == 0.0 && std::signbit(value)) { | ||
return curr->left; | ||
} | ||
} | ||
// Note that this is correct even on floats with a NaN on the left, | ||
// as a NaN would skip the computation and just return the NaN, | ||
// and that is precisely what we do here. but, the same with -1 | ||
// (change to a negation) would be incorrect for that reason. | ||
if (matches(curr, binary(Abstract::Mul, any(&left), constant(1))) || | ||
matches(curr, binary(Abstract::DivS, any(&left), constant(1))) || | ||
matches(curr, binary(Abstract::DivU, any(&left), constant(1)))) { | ||
return left; | ||
if (curr->type.isInteger() || fastMath) { | ||
return left; | ||
} | ||
} | ||
return nullptr; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
(module | ||
(type $none_=>_f32 (func (result f32))) | ||
(export "div" (func $0)) | ||
(export "mul1" (func $1)) | ||
(export "mul2" (func $2)) | ||
(export "add1" (func $1)) | ||
(export "add2" (func $2)) | ||
(export "add3" (func $2)) | ||
(export "add4" (func $2)) | ||
(export "sub1" (func $1)) | ||
(export "sub2" (func $2)) | ||
(func $0 (; has Stack IR ;) (result f32) | ||
(f32.const -nan:0x23017a) | ||
) | ||
(func $1 (; has Stack IR ;) (result f32) | ||
(f32.const -nan:0x34546d) | ||
) | ||
(func $2 (; has Stack IR ;) (result f32) | ||
(f32.const -nan:0x74546d) | ||
) | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
;; with fast-math we can optimize some of these patterns | ||
(module | ||
(func "div" (result f32) | ||
(f32.div | ||
(f32.const -nan:0x23017a) | ||
(f32.const 1) | ||
) | ||
) | ||
(func "mul1" (result f32) | ||
(f32.mul | ||
(f32.const -nan:0x34546d) | ||
(f32.const 1) | ||
) | ||
) | ||
(func "mul2" (result f32) | ||
(f32.mul | ||
(f32.const 1) | ||
(f32.const -nan:0x34546d) | ||
) | ||
) | ||
(func "add1" (result f32) | ||
(f32.add | ||
(f32.const -nan:0x34546d) | ||
(f32.const -0) | ||
) | ||
) | ||
(func "add2" (result f32) | ||
(f32.add | ||
(f32.const -0) | ||
(f32.const -nan:0x34546d) | ||
) | ||
) | ||
(func "add3" (result f32) | ||
(f32.add | ||
(f32.const -nan:0x34546d) | ||
(f32.const 0) | ||
) | ||
) | ||
(func "add4" (result f32) | ||
(f32.add | ||
(f32.const 0) | ||
(f32.const -nan:0x34546d) | ||
) | ||
) | ||
(func "sub1" (result f32) | ||
(f32.sub | ||
(f32.const -nan:0x34546d) | ||
(f32.const 0) | ||
) | ||
) | ||
(func "sub2" (result f32) | ||
(f32.sub | ||
(f32.const -nan:0x34546d) | ||
(f32.const -0) | ||
) | ||
) | ||
) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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 byfastMath
, 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.There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.There was a problem hiding this comment.
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