Hello, I am working on a JIT compiler for a stack-based language similar to Forth.
I have noticed that Cranelift seems to be generating this IR (after calling Context::optimize):
block6:
v32 = iconst.i32 0
br_table v32, block1, [block2, block3, block4, block5] ; v32 = 0
And, Cranelift is emitting x86 instructions for the jump table, even though it knows at compile time which branch will be taken, since the value of v32 is known at compile time. Is this an optimization that the cranelift compiler cannot make, or am I doing something incorrectly? Thanks.
This topic was moved here from #general > Can constants be propagated to jump tables in cranelift IR? by fitzgen (he/him).
Cranelift will not currently do branch folding or rewriting conditional jumps to unconditional jumps in the mid-end
we do some branch folding in the backend but I don't think we will ever rewrite conditional jumps on constant conditions to unconditional jumps at this point, which is what would be necessary for the branch-folding to happen here
I think we could do that during isel/lowering, and I suspect we just haven't done it for br_table yet
hm actually it looks like we don't ever try to turn conditional jumps of constants into unconditional jumps during lowering:
I don;t think there is a reason we couldn't though? cc @Chris Fallin
right, the only reason we don't do this is "no one has done it" :-)
The more complete solution would do it as part of the same fixpoint that optimizes code in the mid-end because this can interact in a recursive way with const propagation -- when we trim the CFG, unreachable paths go away and no longer affect the merged possibility-space, possibly leading to more known constants -- and in fullness of time it'd be great to implement that (the general algorithm to at least draw inspiration from is known as SCCP or sparse conditional constant propagation, though it'd need to be adapted a bit to our egraph framework). But I could see us landing a separate (post-opt) version in the meantime, where brif/br_table-of-constant gets folded to a direct branch
yeah doing we have this comment about simplifying branching instructions in the mid-end, figured that was a slightly longer-term thing than just pattern matching during lowering tho
Right, I guess there's always the conservative approach of actually switching to a direct branch in the CLIF post-mid-end (as a pass after the aegraph before we do lowering) -- we don't have any remaining cached analysis results at that point we'd need to worry about. I think that comment mostly applies to doing anything in the main fixpoint loop
yeah but I wouldn't want to add a new pass just for this, that doesn't seem like an incremental step towards our desired end state -- it feels like work that would be wasted bc we'd throw it away as soon as we made the next improvement
I guess I imagine the useful incremental steps that ~don't waste work being something like this:
(brif (iconst 0) _consequent alternative)) => (jmp_known alternative) etc... rules in the x64 backend (and ideally the others as well)The first step is (a) pretty easy and (b) still useful even with the other things, since it will still fire for ~"free" when we are doing non-optimized compilation and skip the egraphs pass. (As opposed to a whole new pass, which we would throw away by doing the second step.)
Anyways @Stanley if you are interested in implementing that first easy/short-term step, I can explain some more and give you some more code pointers and such
eh, I think a single pass over IR terminators isn't so bad and is probably better than making that change in each individual backend -- the latter is also something we won't need long-term (if the mid-end handles this eventually) but is duplicated 5x, plus potentially more if we have special-case lowerings and have to reason about how the priorities interact...
yeah I guess so
even better would be to do it in the same backwards pass we use when lowering
but this is all a bit less of a good-first-issue material
fitzgen (he/him) said:
Anyways @Stanley if you are interested in implementing that first easy/short-term step, I can explain some more and give you some more code pointers and such
I am very new to Cranelift, and admittedly know very little about its design or the codegen process, but if you believe it to be useful I would be happy to try implementing this. If you could provide some pointers that would be really helpful.
@Stanley unfortunately I think the direction we moved towards in the design discussion made it less amenable to being a good-first issue, so I don't think it would be a good place to dive into Cranelift development for the first time anymore
fitzgen (he/him) said:
Stanley unfortunately I think the direction we moved towards in the design discussion made it less amenable to being a good-first issue, so I don't think it would be a good place to dive into Cranelift development for the first time anymore
I see. I suppose I will try my best to work around this until it is implemented. Do you know if is there an issue tracking this? I would like to stay updated on it. Thanks.
I think https://github.com/bytecodealliance/wasmtime/issues/6106 is probably the best issue to follow
I see, thanks.
Last updated: May 03 2026 at 21:15 UTC