rewire-backend-2.8: A Haskell-to-Verilog/VHDL compiler, the Hyle backend
Safe HaskellSafe
LanguageHaskell2010

ReWire.Hyle.Transform

Description

Hyle-to-Hyle transformations: defn inlining (the uses-at-most-once heuristic, plus flatten-everything), dead-defn purging, the --rtl-opt optimization fixpoint (partial evaluation, zero-width purging, dedupe), and hoisting clocked-extern calls into device instances. Inlining is sound by the substitution property (doc/hyle.md, section 7); bound names in inlined bodies are freshened to avoid capture. Defns are processed callee-first (the call graph is acyclic), so chains of single-use defns collapse fully.

Synopsis

Documentation

inline :: Bool -> Program -> Program Source #

Inline definitions into their call sites: all of them when flatten, otherwise those used at most once. Definitions referenced as extern models are never inlined (the reference is by name), and neither are defns marked noinline -- the pin wins over --flatten, so a noinline defn is always findable as a module in the output. The inlined-away defns are removed by the final purge; a follow-up partialEval fuses the slice/concat plumbing exposed by inlining and drops the argument wires that fusion leaves unused.

inlineBy :: (GId -> Bool) -> Program -> Program Source #

Inline definitions satisfying the predicate into their call sites.

purgeUnused :: Program -> Program Source #

Drop defns unreachable from the device body (following calls and the models of called externs) and extern decls that are never referenced. Not gated on noinline: pinning affects inlining, not liveness, so dead pinned defns don't accumulate.

partialEval :: Program -> Program Source #

Constant folding and wire fusion. Primitives, muxes, slices, and concatenations of literals fold via the interpreter's own evaluator; calls (and extern calls with models) whose arguments are all literals evaluate fully. Lets bound to atomic expressions (literals, variables, don't-cares) substitute away; lets bound to pure wiring (slices and concatenations of atoms) are fused through where they are sliced, so slice-of-concat plumbing simplifies across named wires (both expression lets and device-level wires). Unused expression lets are dropped here; unused device wires are dropped by purgeDevLets.

purgeDevLets :: Program -> Program Source #

Drop device wires (SLets) never read by a later statement (fusion in partialEval is what strands them).

purgeZeroWidth :: Program -> Program Source #

Drop zero-width parameters (and the corresponding arguments at call sites) and zero-width-result defns (calls to them become nil).

dedupe :: Program -> Program Source #

Redirect calls to definitions with identical signatures and bodies to a single representative. Should be followed by purgeUnused. Defns marked noinline are name-pinned: they take no part in merging (neither as survivors nor as redirected losers). Each survivor records the losers redirected to it with an appended "also: ..." doc line.

optimize :: Natural -> Program -> Program Source #

The standard optimization pipeline, iterated to a fixpoint (bounded by the --rtl-opt level).

hoistInstances :: MonadError AstError m => Program -> m Program Source #

Defns containing (transitively) calls to sequential externs are inlined into the device body; sequential-extern calls in the device body then become instances: nested lets are flattened to device-level lets (sound: the language is pure and total) and each seq-XCall is replaced by the concatenation of a fresh instance's output ports, with its inputs driven from the call's arguments.