Instead of jumps, use boolean variables to represent control flow:
# Rewrite:
if cond: return
body
# To:
var ret = false
if cond: jret = true
if not ret:
body
(In the actual implementation control flow vars get some special instructions like jtrue and jfalse that ensure these collapse to goto instructions without overhead.)
All variables get version numbers (like SSA, but for any location):
(var (v x.0 +0) +42) # x version 0 = 42
(asgn (v x.0 +1) +99) # x version 1 = 99
(call foo (v x.0 +1)) # Use x version 1
SSA's phi nodes are replaced by join information for ifs and either for loop back edges. These are at fixed positions in the tree and cannot occur arbitrarily. The versioning scheme (plus join and either) can be ignored entirely by a code generator.
A single IR to rule them all. Easy to implement:
For a native code generator:
In a single unified optimization pass.
In other words:
# Traditional approach - separate passes:
# Pass 1: CSE
var temp1 = expensive_computation()
var temp2 = expensive_computation() # CSE: use temp1
# Pass 2: Copy propagation
var temp3 = temp1
var temp4 = temp1 # Copy prop: use temp1
# Pass 3: Scalar replacement
var temp5 = temp1.field1
var temp6 = temp1.field2 # Scalar: use temp1.field1, temp1.field2
Now with bind:
# NJVL with bind construct:
(bind :temp1 (call expensive.0))
(bind :temp2 (call expensive.0)) # CSE: use :temp1
(bind :temp3 :temp1)
(bind :temp4 :temp1) # Copy prop: use :temp1
(bind :temp5 (dot :temp1 field1))
(bind :temp6 (dot :temp1 field2)) # Scalar: use :temp1.field1, :temp1.field2Thank you for answering my questions Araq! I wouldn't be too pessimistic, the world is pretty limited on options. The world seems to be stuck on using LLVM, but the same problem of build times continues to surface. Cranelift really feels like the only alternative at the moment, but NIF and NJVL are quite intriguing.
Here were some questions fielded by the Cranelift team, back in 2022, from the developer of Inko (I am not involved with Inko in anyway): https://github.com/bytecodealliance/wasmtime/issues/5141 Further internal discussions by Inko here: https://github.com/inko-lang/inko/issues/674
You'll notice the call out lack of varargs being fully supported (you can call them, but cannot define them) as a major hurdle and link to this still open issue: https://github.com/bytecodealliance/wasmtime/issues/1030
The Odin language (I am also unaffiliated with) has been interested in pivoting from LLVM at least for debug builds as well. I believe they are waiting on a faster C compiler to become more stable then implementing an Odin-to-C compiler and integrating Cuik into their toolchain. https://github.com/RealNeGate/Cuik
I think what you are working on here has a lot of potential, is NJVL in a state that it would be feasible for experimenting with codegening WASM?
https://github.com/nim-lang/nimony/blob/master/doc/njvl-ssu-ideas.md
Why would it be about a single large .NIF file? You can do that already...
I'm newer to compilers and I really don't know why my mind went there, but guessing is fun. 🤷
Thanks for the docs!