compiler: IR pass pipeline + constant folding (jolt-2om, nanopass-lite)
jolt.passes is the new portable pipeline stage between the analyzer and the back end: pure IR -> IR rewrites, total over node :ops (unknown ops pass through with folded children), loaded with the compiler namespaces and resolved lazily by analyze-form (JOLT_NO_IR_PASSES=1 disables — the same escape-hatch pattern as the macro oracle). The shape is flatiron's opt.clj applied to the jolt IR, which is what jolt-2om asked for. The first pass is constant folding: a call of a foldable numeric SEED fn (the later tiers don't exist when the compiler loads) whose args are all constant numbers becomes a constant, and an if with a constant test becomes the taken branch (dead-branch elimination — the untaken side never even resolves). Folding computes with the ACTUAL jolt fns, so results match runtime semantics by construction; a fold that would throw (mod 5 0) is left for runtime. Two walk lessons paid for in debugging: let/loop bindings are [name init-ir] PAIRS, not maps (assoc'ing :init into a pair corrupts it); and a throw inside the interpreted pass unwinds past the interpreter's ns restores, so analyze-form restores the compile ns after the (protected) pass call — without that, one pass error left current-ns in jolt.passes and the rest of the tier compile resolved against the wrong namespace (sort-by landed on the 2-arg JANET builtin). ir-passes-test pins folds, conservatism (free vars, throwing folds), and end-to-end eval. Gate exit 0.
This commit is contained in:
parent
40da75cee4
commit
35e8821a92
3 changed files with 151 additions and 2 deletions
|
|
@ -385,7 +385,8 @@
|
|||
# kernel tier must already be loaded (see api/load-core-overlay!).
|
||||
(defn- build-compiler! [ctx]
|
||||
(compile-load ctx "jolt.ir")
|
||||
(compile-load ctx "jolt.analyzer"))
|
||||
(compile-load ctx "jolt.analyzer")
|
||||
(compile-load ctx "jolt.passes"))
|
||||
|
||||
(defn- ensure-analyzer [ctx]
|
||||
# Don't build until the kernel tier is loaded (see api/load-core-overlay! and
|
||||
|
|
@ -435,7 +436,20 @@
|
|||
(def r (protect ((var-get av) ctx form)))
|
||||
(put (ctx :env) :compile-ns nil)
|
||||
(ctx-set-current-ns ctx saved-ns)
|
||||
(if (r 0) (r 1) (error (r 1))))
|
||||
(unless (r 0) (error (r 1)))
|
||||
# IR passes (jolt.passes/run-passes — nanopass-lite, jolt-2om): pure IR->IR
|
||||
# rewrites (constant folding, ...) between the analyzer and the back end.
|
||||
# Resolved lazily; absent during the pre-passes bootstrap window.
|
||||
(def pv (unless (= "1" (os/getenv "JOLT_NO_IR_PASSES"))
|
||||
(ns-find (ctx-find-ns ctx "jolt.passes") "run-passes")))
|
||||
(if pv
|
||||
(let [pr (protect ((var-get pv) (r 1)))]
|
||||
# the pass runs interpreted; a throw inside it unwinds past the
|
||||
# interpreter's ns restores — put the compile ns back either way, or
|
||||
# the REST of this compilation resolves in jolt.passes
|
||||
(ctx-set-current-ns ctx saved-ns)
|
||||
(if (pr 0) (pr 1) (r 1)))
|
||||
(r 1)))
|
||||
|
||||
# The analyzer's deliberate punt signal — (uncompilable why) throws the string
|
||||
# "jolt/uncompilable: <why>". Anything else escaping the compile step is an
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue