Skip to content

Some notes about addisonal simple optimizations for f32/f64 #1911

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

Closed
MaxGraey opened this issue Feb 14, 2019 · 12 comments
Closed

Some notes about addisonal simple optimizations for f32/f64 #1911

MaxGraey opened this issue Feb 14, 2019 · 12 comments

Comments

@MaxGraey
Copy link
Contributor

MaxGraey commented Feb 14, 2019

  1. Replace a *= -1 to a = -a

Actual:

get_local $p0
f64.const -0x1p+0 (;=-1;)
f64.mul

Expected:

get_local $p0
f64.neg
  1. x * (1 / x) => x / x or x * (1 / y) => x / y

Actual:

get_local $p0
f64.const 0x1p+0 (;=1;)
get_local $p0
f64.div
f64.mul

Expected:

get_local $p0
get_local $p0
f64.div
  1. -x / 1000

Actual:

get_local $p0
f64.neg
f64.const 0x1.f4p+9 (;=1000;)
f64.div

Expected:

get_local $p0
f64.const -0x1.f4p+9 (;=-1000;)
f64.div
@binji
Copy link
Member

binji commented Feb 14, 2019

There are explicit tests in the spec repo that disallow these transformations, see https://github.com/WebAssembly/spec/blob/master/test/core/float_exprs.wast.

@MaxGraey
Copy link
Contributor Author

MaxGraey commented Feb 14, 2019

@binji
I see:
https://github.com/WebAssembly/spec/blob/master/test/core/float_exprs.wast#L163

Hmm, may I ask why this all legalized for LLVM but not for wasm?

nan * -1 produce nan but -nan => -nan. That's main reason?

@MaxGraey
Copy link
Contributor Author

MaxGraey commented Feb 14, 2019

Also LLVM based compilers as Rust and emscripten produce:

get_local $p0
f64.neg

for x * -1.0 without -ffast-math
Should they also disable this optimizations?

@kripken
Copy link
Member

kripken commented Feb 14, 2019

1 / (x / x) => NaN

Hmm, why? E.g. if x == 1, then 1 / (1 / 1) => 1?

@MaxGraey
Copy link
Contributor Author

@kripken Good catch, looks like I meant another expression. Remove that

@binji
Copy link
Member

binji commented Feb 20, 2019

Hmm, may I ask why this all legalized for LLVM but not for wasm?

nan * -1 produce nan but -nan => -nan. That's main reason?

Sorry, was on vacation. The difference is that the nan bitpattern changes. fxx.neg will only flip the sign bit, but fxx.mul (and other operators) will produce an arithmetic nan, which is a quiet nan with an indeterminate sign bit. LLVM can optimize this because AIUI the C language doesn't say anything about
nan bitpatterns.

@MaxGraey
Copy link
Contributor Author

@binji I understand this. But I wondering is it necessary skip this optimizations for LLVM-backed compilers when they targeting to Wasm as well?

@binji
Copy link
Member

binji commented Feb 20, 2019

No, the user of LLVM is operating with a different set of assumptions. If they care about nan bitpatterns, they know that they can't use LLVM for this (at least by default).

@MaxGraey
Copy link
Contributor Author

Wow. This is unexpected!

@dcodeIO
Copy link
Contributor

dcodeIO commented Feb 25, 2019

Would it be viable to make it an optional pass that a user must run explicitly? For instance, we have a discussion over at AssemblyScript to eventually add a compiler flag that emits deterministic code exclusively, but it seems that unless this flag is set, doing such optimizations would be fine.

@kripken
Copy link
Member

kripken commented Feb 27, 2019

Yes, I think an optional pass could do optimizations like these that are unsafe in general, but valid for some compiler.

Another option is to add a pass option, like "don't care about nan bits" - then existing passes can check that and behave accordingly. Sort of like the existing --ignore-implicit-traps.

@MaxGraey
Copy link
Contributor Author

Other possible optimization for floats found on n-body bench:

function div(x: f64): f64 {
    return -x / 1000.0;
}

currently produce:

(func $div (export "div") (type $t0) (param $p0 f64) (result f64)
    get_local $p0
    f64.neg
    f64.const 0x1.f4p+9 (;=1000;)
    f64.div)

but optimal:

(func $div (export "div") (type $t0) (param $p0 f64) (result f64)
    get_local $p0
    f64.const -0x1.f4p+9 (;=-1000;)
    f64.div)

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

No branches or pull requests

4 participants