Enabling tail calls

267 views
Skip to first unread message

Soeren Balko

unread,
Nov 23, 2021, 6:14:16 PM11/23/21
to emscripten-discuss
I was wondering about the state of WebAssembly tail call support in Emscripten. It's available as an experimental V8 feature in Chrome and will hopefully be mainstreamed in the not-too distant future.

Couldn't find much information on how to build with tail call support in Emscripten, but I suspect that adding the -menable-tail-call linker flag does the trick? Or is there more to it?

@Alon - can you please confirm?

Thank you!
Soeren

Thomas Lively

unread,
Nov 23, 2021, 7:57:46 PM11/23/21
to emscripte...@googlegroups.com
Hi Soeren,

The compiler flag -mtail-call is what you want. This support has been in upstream LLVM for a while, but it hasn't been used very much, so if you run into bugs with it, please let us know!

Best,

Thomas

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/emscripten-discuss/bdcc8072-b7a0-454c-bd05-68b0ae780c77n%40googlegroups.com.

Soeren Balko

unread,
Nov 24, 2021, 12:00:00 AM11/24/21
to emscripten-discuss
Thanks Thomas - haven't run into any issues. There wasn't any measurable performance uplift when using -mtail-call though, which is probably because my workload (FFmpeg) may not use it much.  

That being said, I previously played around with the -menable-tail-call  linker flag. And unlike -mtail-call, it does two things: firstly, it does produce a small (~1%), but consistent performance uplift. At the same time, it doesn't seem to make use of the new WebAssembly opcodes (didn't require me to enable those in V8). Not sure what -menable-tail-call actually does, but it seems different from -mtail-call. Also, it cannot be used as a compiler flag, ie. only the linker will accept it.

Any ideas?

Soeren

Thomas Lively

unread,
Nov 24, 2021, 1:49:26 AM11/24/21
to emscripte...@googlegroups.com
Hmm, I tried finding documentation on -menable-tail-call or an implementation of it but couldn't, so then I tried using it to see if it did anything. I built the in-tree sqlite benchmark at -O2 with no extra flags, with -mtail-call, and with -menable-tail-call. The version built with -mtail-call contained 53 instances of `return_call` or `return_call_indirect` instructions, but the version with no flags and the version with -menable-tail-call were identical. I also confirmed that Emscripten does not warn or error out on unknown flags passed at link time, so I can only conclude that -menable-tail-call is not a real flag. The performance difference you saw must have been noise.

Soeren Balko

unread,
Nov 24, 2021, 8:05:15 PM11/24/21
to emscripten-discuss
I found some faint hints that Clang has -mdisable-tail-calls (see  disable-tail-calls.c | searchcode ) , so I figured I may try -menable-tail-calls. Not sure if that did anything, but I ended up with a very small difference (6 bytes) in file sizes for my FFmpeg build (42789880 vs 42789886 bytes). Not sure where that comes from. That being said, the aforementioned ~1% performance difference could indeed be noise. I'll do some more tests to see what's going on. I may have to disassemble the wasm binary to figure out if there really is anything as a result of the -menable-tail-calls flag. 

Floh

unread,
Dec 1, 2021, 12:50:03 PM12/1/21
to emscripten-discuss
Apologies for jumping in. I tried compiling my home computer emulator code with -mtail-call to see if it makes a difference, but I have a hard time starting Chrome (or Chrome Dev) into a mode where it accepts the new instructions. On the console I get:

~~~
Uncaught (in promise) RuntimeError: Aborted(CompileError: WebAssembly.instantiate(): Compiling function #221 failed: Invalid opcode 0x12 (enable with --experimental-wasm-return_call) @+126726). Build with -s ASSERTIONS=1 for more info.
~~~

I tried (on Mac):
- enabling "Experiments" in Chrome Dev and then:
- starting the Chrome Dev executable with --experimental-wasm-return_call fom the command line option, no effect
- after googling (and finding https://leaningtech.com/extreme-webassembly-2-the-sad-state-of-webassembly-tail-calls/), starting the Chrome Dev exe with --js-flags=”--experimental-wasm-return-call", also no effect

Any ideas (or links) grealy appreciated :)

Floh

unread,
Dec 1, 2021, 1:03:16 PM12/1/21
to emscripten-discuss
Ah nvm, now it's working all of the sudden (with --js-flags="--experimental-wasm-return_call"). Not seeing any performance improvements, but I guess that's to be expected from plain C code without recursions :)
Reply all
Reply to author
Forward
0 new messages