-
Notifications
You must be signed in to change notification settings - Fork 827
Skip x - 0.0 -> x transform if x is non-canonical NaN #3139
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
Conversation
kripken
left a 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.
This only works if the left side is a constant seen at compile time. What if it's stored to a local and then read from it? I think the same problem can happen.
Perhaps this needs to be fixed like #3096, that is, by special-casing add/subtract in the interpreter?
|
Yes |
|
The NaN does not have to be canonicalized. The NaN payload is allowed to be propagated if it is an arithmetic NaN (i.e. one where the top bit of the payload is set, AKA a "quiet" NaN). |
Yes, but as I know only canonical |
That's allowed, but not required by the spec. The only requirement is that if all NaN inputs to an arithmetic floating-point operation are canonical, then the result will be canonical too. Otherwise the NaN result will be arithmetic (i.e. some quiet NaN). |
Yes, that's what I see.
Hmm, I thought this spec test for example: (assert_return_canonical_nan (invoke "add" (f32.const -nan) (f32.const 0x1p-126)))forces canonicalization due to Line 357 in 24d2749
Or I misunderstand which form of NaN canonical and |
|
According to standart spec interpreter assert_return_canonical_nan compare with positive NaN on bit level. However it seems |
Yes, |
|
Good to know. Thanks for info! So according spec we can't propagate |
Right, but that's only because those are not arithmetic NaNs. If they were, it would be valid (though not required) to do so, e.g. is a valid transformation. EDIT: actually, in your example the result isn't required to be a canonical NaN, it is allowed to be any arithmetic NaN. |
But not for example: So if it canonical ( |
|
Yep, but I think it's easier to think of it like this. Extract the NaN payload: if it is arithmetic (which includes canonical), then it can be folded to the original value, otherwise it should probably be folded to a canonical NaN. That said, it sounds like from @kripken that there are additional constraints that binaryen would like to keep, that may preclude making this optimization. |
|
Sorry if I wasn't clear - IIUC, I think we can do the optimization. We just need to update the interpreter as with #3096 (it's the same issue as there, isn't it? If not I'm missing something). |
|
Yes, just I'm wondering if we not just propagate lhs or rhs but also check NaN's kind in interpreter and canonicalize its if this needs by spec. It will simplify many things in OptimizeInstructions. |
|
@MaxGraey Let's leave the spec discussion as a separate issue? I think we should fix this first, in the interpreter like the similar cases fixed already. |
|
After Reduced example: (module
(type $t0 (func))
(type $t1 (func (param f32)))
(type $t2 (func (result f64)))
(type $t3 (func (param i32 i32 v128) (result f64)))
(import "fuzzing-support" "log-f32" (func $fuzzing-support.log-f32 (type $t1)))
(func $func_130 (export "func_130") (type $t3) (param $p0 i32) (param $p1 i32) (param $p2 v128) (result f64)
(i64.store16
(i32.const 10)
(i64.const -90))
(f64.const 0x1.e17p+12 (;=7703;)))
(func $f2 (type $t2) (result f64)
(local $l0 f32)
(call $fuzzing-support.log-f32
(f32.sub
(f32.load align=2
(i32.const 8))
(local.get $l0)))
(f64.const 0x0p+0 (;=0;)))
(func $func_154_invoker (export "func_154_invoker") (type $t0)
(drop
(call $f2)))
(memory $M0 1 1 shared))and IR before fail: [f32] (f32.sub
[f32] (f32.load offset=4 align=2
[i32] (i32.and
[i32] (global.get $global$1)
[i32] (i32.const 15)
)
)
[f32] (f32.const 0)
) |
|
That's look pretty strange for me: [f32] (f32.sub
[f32] (f32.load offset=4 align=2
[i32] (i32.and
[i32] (global.get $global$1)
[i32] (i32.const 15)
)
)
[f32] (f32.const 0)
)@kripken Why we can't do |
|
It's not a side effect issue, I don't think? Isn't it what I was saying before? I think the issue is the same as with #3096 . We need to update the interpreter to not change NaN bits on an add or subtract of 0. Once we do that, the interpreter will not confuse the fuzzer. That is, the problem is that if we optimize And this is a problem in your last testcase even though it has This is a subtle point, and maybe I'm not explaining myself clearly enough, if you don't see my point yet. I can look into fixing this like #3096 if you prefer. |
Oh, that's make sense. Thanks for explanation!
That's will awesome! I'm not familiar with interpreter part do better if you fix it here by yourself) |
|
Сlosing in favour #3143 |
Fix #3138