(I'm aware of previous discussions regarding tail calls and the corresponding Github issue.)
I am trying to create new CLIF instructions return_call and return_call_indirect. The idea is to translate WASM return_call and return_call_indirect into them respectively.
One roadblock I've hit is that cranelift will complain about the block containing the return_call instruction is not filled when finalizing the translation in the function (FunctionBuilder::finalize(&mut self) in cranelift/frontend/src/frontend.rs:479:17).
In the added return_call instruction, we've used the InstructionFormat of Call and make sure that is_call, is_return and is_terminator is true. In translate_operator() in cranelift/wasm/src/code_translator.rs, I have made sure to set state.reachable to false after translating WASM return_call.
Is there any other places I've overlooked for implementing this CLIR instruction? Thanks!
See attached for the test case I'm working on and the error trace.
error-trace.txt
factorial-return-call.wat
the block should be marked filled on line 159 when the instruction builder is used to insert a terminator instruction
I'd suggest adding some eprintln!s and dbg!s to help debug where your updates to is_terminator and the frontend code is going wrong
but backing up a bit: adding tail call support is something that is going to have pretty deep implications to our calling conventions and I'd encourage you to figure all that out first and reach consensus with the wasmtime/cranelift teams via an RFC on what the updated calling conventions will be since this is so fundamental and spans all of cranelift and wasmtime. for example, the github issue linked links to SpiderMonkey's document describing their new calling convention and everything required to support the union of tail calls, multi-value returns, and reference types with stack maps and it is 25 pages long. we should really agree on what we want things to look like at the end before diving head first into implementation
Last updated: Jan 10 2026 at 20:04 UTC