Stream: cranelift

Topic: Cranelift for zkVMs


view this post on Zulip Lucas Clemente Vella (Apr 16 2025 at 20:11):

Cranelift is a hot topic in the relatively small community of Zero Knowledge Virtual Machines (zkVMs). I am part of one of many teams interested in having a Cranelift middle-to-backend geared towards zkISAs, which have very different performance requirements than normal ISAs, (like RISC-V).

In particular, everybody is looking into a way of having Single-Write Memory for stack/registers, which as far as I understand, Cranelift IR is particularly suited, in its block organization. Every time a block is executed, a new frame in the single-write stack is created, and the blocks arguments are copied over, and every variable is written only once, since they are SSA.

The fact that cranelift allows for local stack variables complicates things a little. I understand it is not possible to remove them if the program takes a pointer from them, but for cases that it is possible, is there a transformation that can remove every local stack element and turn them into SSA variables?

view this post on Zulip Lucas Clemente Vella (Apr 16 2025 at 20:15):

Also, when compiling from WASM, is it possible that the IR ends up with a local stack variable? For cases where pointers are necessary, the variables are never placed on function local storage nor in the WASM stack, so there should never be local stack variables if the source program is WASM, right?

view this post on Zulip Chris Fallin (Apr 16 2025 at 20:23):

I think, at a high level, this transform that you are wanting to implement is deeper than implied here, and the semantic gap from what Wasm is to what you want (no overwritable mutable store, correct?) is quite large.

In general, you can think of CLIF (Cranelift's IR) as isomorphic to any other SSA IR. Block parameters are equivalent to phi nodes -- they're just written in a different way, but there is a simple transform between the two. So I don't think there is much depth to the observation that block-calls give you something special here: you could do the same for any SSA IR.

The much harder part is memory. As you observe, Cranelift provides stack slots, but those are only one kind of mutable memory -- in general pointers may come in from the outside and Cranelift has fully general load/store instructions.

Then, when you lower Wasm to CLIF and compile using Cranelift, that lowering step from Wasm was performed by a part of Wasmtime; and the CLIF is specific to Wasmtime's data structures and runtime, and cannot be separated from it. That runtime will definitely not have the properties you want.

In general I think you'd best be served by first answering the question: how do Wasm heap accesses compile to a "single-write" storage medium (it sounds kind of like a journaling filesystem?); and then write your own WebAssembly VM that targets that. Cranelift may be part of the way you implement that, but only superficially, as a JIT backend that takes ordinary SSA IR and compiles to native machine code.

view this post on Zulip Lucas Clemente Vella (Apr 16 2025 at 20:26):

Ah, sorry, I forgot to mention. We are not trying to get away with mutable memory entirely. Those are accessed with normal load/store instructions. We only want to replace the role of stack/registers with the write-only memory. In case of WASM, I think the stack and locals can be made into the write-only memory.

view this post on Zulip Chris Fallin (Apr 16 2025 at 20:29):

Wasmtime's lowering of Wasm to CLIF does not make use of stackslots, so that won't be a problem; but keep in mind that by convention, Wasm programs targeting linear memory (produced by LLVM, etc) typically use a "shadow stack" for stack-memory storage in guest C/C++/Rust; this is part of the linear memory

view this post on Zulip Lucas Clemente Vella (Apr 16 2025 at 20:30):

When compiling C or Rust to WASM, LLVM turns most SSA variables into locals, except the ones that requires pointers, because you can't take pointers from them. They are made into the stack created in the WASM heap memory.

In this regard, I think WASM might be a closer model to what we need than CLIF.

view this post on Zulip Chris Fallin (Apr 16 2025 at 20:30):

Keep in mind that in general what you're planning is a modification of Wasmtime, not just Cranelift. Cranelift doesn't run Wasm, Wasmtime does; Wasmtime produces SSA IR (CLIF) that Cranelift compiles

view this post on Zulip Chris Fallin (Apr 16 2025 at 20:31):

Yes, the only value you're getting from Cranelift here is that it does SSA construction; you can do that at the Wasm level, and honestly that will be more maintainable for you -- transform to new Wasm that invokes whatever primitives you need to implement the storage

view this post on Zulip Lucas Clemente Vella (Apr 16 2025 at 20:31):

Yes, I sorta figured that out when I tried using the cranelift-wasm crate. It didn't have all that was needed for the tranformation.

view this post on Zulip Chris Fallin (Apr 16 2025 at 20:33):

(meta-note: cranelift-wasm has been removed in recent Wasmtime+Cranelift releases and the functionality is folded into Wasmtime. The way we publish crates to crates.io means that when we no longer include a crate in our overall workspace, the last version of the crate that did exist exists forever. We should probably do a better job of signposting that these crates are deprecated/EOL'd.)

view this post on Zulip Lucas Clemente Vella (Apr 16 2025 at 20:38):

Chris Fallin disse:

Yes, the only value you're getting from Cranelift here is that it does SSA construction; you can do that at the Wasm level, and honestly that will be more maintainable for you -- transform to new Wasm that invokes whatever primitives you need to implement the storage

This is exactly my gut feeling. In discussions with the team, we thought that the work done by Wasmtime (which we then called cranelift) in organizing the blocks, that we then could execute in their isolated frames, would help us handle the loops in this write-once memory scenario. But I could never shake the feeling that it would be more trouble than to do WASM directly.


Last updated: Dec 06 2025 at 07:03 UTC