Skip to content

LLVM wasm backend emitting non-trapping fp-to-int conversion sequences #5863

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
sunfishcode opened this issue Nov 28, 2017 · 11 comments
Closed
Labels

Comments

@sunfishcode
Copy link
Collaborator

WIth LLVM r319128, LLVM is now translating fptosi/fptoui into sequences which don't trap when the input is outside their domain. This fixes the associated LLVM bugs. It also means that Binaryen won't be able to provide configurable fp-to-int trapping behavior when used with LLVM wasm backend output.

This feature will be precluded by the nontrapping float-to-int conversion feature being added to wasm eventually anyway, so unless there are reasons to keep it, it seems better to me to omit this feature from the LLVM wasm backend rather than do something more complex to support it temporarily.

The test test_binaryen_trap_mode is currently failing with the LLVM wasm backend; assuming the various modes won't be supported, this test should be disabled.

@kripken
Copy link
Member

kripken commented Nov 28, 2017

precluded

Typo? Or do I not understand that word? :)

This feature will be precluded by the nontrapping float-to-int conversion feature being added to wasm eventually anyway

Won't the trapping ones be smaller and faster?

@sunfishcode
Copy link
Collaborator Author

This feature will be precluded by the nontrapping float-to-int conversion feature

I meant "This feature" to refer to Binaryen's trap-mode feature, which is the thing which would be precluded when LLVM eventually switches to the non-trapping instructions.

Won't the trapping ones be smaller and faster?

They're one byte smaller in wasm, but these operations aren't frequent enough to be significant.

On ARM, the non-trapping instruction will map to a single instruction, which will be faster than the trapping version. On x86, trapping and non-trapping both need extra checks, so they're not significantly different in speed.

@kripken
Copy link
Member

kripken commented Nov 28, 2017

I wasn't just kidding before: Do you literally mean "preclude" as in "make impossible"?

I think we will still want a trap mode, but it might have 2 options rather than 3: "normal" (the non-trapping mode wasm is adding) and "js". The latter is useful for debugging. That's why I'm asking if this change would make that impossible. Or perhaps we should consider removing it too?

@sunfishcode
Copy link
Collaborator Author

sunfishcode commented Nov 28, 2017

I meant that it would impossible for Binaryen to implement trapping behavior reliably, because LLVM may have speculated the conversion past a branch.

However, are you thinking of having Binaryen have a mode to insert traps for non-trapping instructions anyway? I agree that that's doable, with the caveat that it'll sometimes have some false positives. In fact, I added support for non-trapping instructions already -- enable them in clang with -fnontrapping-fptoint -mnontrapping-fptoint or llc with -mattr=+nontrapping-fptoint -- so you could even implement this today without having to pattern-match the code LLVM is now emitting.

@kripken
Copy link
Member

kripken commented Nov 28, 2017

Sorry, maybe I wasn't clear. I'm talking about the exact opposite: the second mode would be "js" which does not trap, it applies JS semantics. For existing asm.js users, it helps debug things as it removes a source of wasm/asm.js divergence.

It seems like that could be done by just replacing the operations with the JS versions? Or am I missing something?

@sunfishcode
Copy link
Collaborator Author

Sure; you could do that too. Enable the non-trapping operators in LLVM with the flags I mentioned above, and then have Binaryen replace those operators with whatever you want.

@kripken
Copy link
Member

kripken commented Nov 28, 2017

Sounds good.

So, how are we moving forward here? In the short term, this creates a difference between asm2wasm and the wasm backend output, which makes migration to the wasm backend by default less smooth. We can disable that test, but the difference is still there. Should we move to change asm2wasm in a similar way? Or something else?

@sunfishcode
Copy link
Collaborator Author

I suggest disabling the test for now. My assumption is that the specific behavior, other than not trapping, is not very significant for C/C++ code. In all the discussions of float-to-int conversion operators, I myself haven't heard from real-world use cases that care what the behavior is, except for cases that just need it to be non-trapping. It's UB in C/C++. It's flagged as a bug by UBSan. x86, ARM, Power, RISC-V, and JS all have different behavior on float-to-int conversion, and I'm not aware of other C++ compilers offering features to emulate the behavior of different platforms.

@kripken
Copy link
Member

kripken commented Nov 28, 2017

I agree real-world code generally doesn't care. But a use case for us devs is debugging a program that works in asm2wasm but fails in the wasm backend or vice versa: if they don't have identical behavior on this stuff, execution logs diverge, when they might otherwise be easily diffed and the bug found.

aheejin added a commit to aheejin/emscripten that referenced this issue Nov 29, 2017
After llvm-mirror/llvm@9f86840#diff-15ffc2fb5830c3a8c3c4c354857b1631, LLVM has two behaviors:
When executing llc with `-mattr=+nontrapping-fptoint`:
It generates nontrapping version of instructions, those with :sat
varient.

When executing llc with `-mattr=-nontrapping-fptoint`:
It generates trapping version of instructions, but it inserts
conditional checks around them so they don't trap and clamp to the
predefined value.

So it seems not very possible to support this trapping test including
three modes (allow, trap, and js) for wasm backend now.

Related: WebAssembly/binaryen/emscripten-core#1168, emscripten-core#5863
@jgravelle-google
Copy link
Contributor

I think the level of sophistication of how we should handle this is dictated by the question "will we want the js trap mode in five years?" I'm thinking no, because by that point we should only have the wasm-via-LLVM path, so anything we do here should be considered transitional work that gets us there without too much breakage.

For the immediate future, that means disabling the test.
After that, I think the best we can do is remove binaryen trap mode from s2wasm, and make the clamp mode in asm2wasm match what the backend emits. Is that reasonable?

kripken pushed a commit that referenced this issue Nov 30, 2017
* Disable binaryen trap test on Wasm backend

After llvm-mirror/llvm@9f86840#diff-15ffc2fb5830c3a8c3c4c354857b1631, LLVM has two behaviors:
When executing llc with `-mattr=+nontrapping-fptoint`:
It generates nontrapping version of instructions, those with :sat
varient.

When executing llc with `-mattr=-nontrapping-fptoint`:
It generates trapping version of instructions, but it inserts
conditional checks around them so they don't trap and clamp to the
predefined value.

So it seems not very possible to support this trapping test including
three modes (allow, trap, and js) for wasm backend now.

Related: WebAssembly/binaryen/#1168, #5863
@stale
Copy link

stale bot commented Sep 19, 2019

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 7 days. Feel free to re-open at any time if this issue is still relevant.

@stale stale bot added the wontfix label Sep 19, 2019
@stale stale bot closed this as completed Sep 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants