rewire-frontend-2.8: A Haskell-to-Verilog/VHDL compiler, front end (GHC driver, Eidos, Synolon)
Safe HaskellSafe
LanguageHaskell2010

ReWire.Eidos.Simplify

Description

The Eidos simplifier: occurrence-driven, let-preserving partial evaluation (the retired reduce/specialize/purge loop's successor, doc/eidos.md §8). simplify repeats specialize-on-values, purge, and reduce until every definition is synthable and dictionary-free, bounded by --depth with the retired loop's diagnostic.

  • reduceExp is let-preserving: beta redexes become lets, and a let is inlined only when its binder is dead, used once, bound to an atom, or dictionary-typed (dictTyCons — never representable, so substituted at every occurrence); a representable multi-use binding KEEPS its let (sharing). The one lambda-lifting policy surviving from the retired pipeline is explicit here (Clash's LiftNonRep): a multi-use *function-typed* let cannot stay (it is not representable), so it is lifted to a top-level definition over its captured locals, named with the $LL. compiler-lifted prefix (display-only: the machine fold strips it when naming the Hyle definition). Top-level references are never unfolded — the function hierarchy is preserved; higher-orderness dies by argument baking, not call inlining.
  • specialize on values (the retired value-argument specializer): a call to a top-level definition with *closed* arguments (free variables all top-level) bakes those arguments into a memoized clone named from the baked-argument canon (originTag). Self-calls in the clone still reference the origin — the memo closes recursive loops. Memo keys are alpha-canonical: arguments are renumbered from a disjoint unique supply and printed. Baking is also how non-representable scalar arguments (Integer, String) disappear: their call sites pass closed values.
  • purge: definitions unreachable from the device root (plus the builtin signature carriers, which carry the builtins' type assumptions to the Eidos-to-Hyle fold).

Join points are preserved (dead ones are dropped); datatypes are left untouched.

Synopsis

Documentation

simplify :: MonadError AstError m => Natural -> Program -> m Program Source #

Partial evaluation to the synthable, dictionary-free fixpoint, bounded by the given depth.

purge :: Program -> Program Source #

Definitions transitively reachable from the device root and the builtin signature carriers. Datatypes are left untouched.

reduceExp :: forall (m :: Type -> Type). MonadError AstError m => IntSet -> HashSet Text -> Exp -> SimpT m Exp Source #

One bottom-up reduction pass over an expression: beta redexes become lets; lets inline when dead, single-use, or atom-bound; multi-use function-typed lets are lifted to top level (LiftNonRep); known- constructor and known-literal cases select their alternative; lambdas eta-reduce; dead join points drop. Top-level references are never unfolded. The first argument is the set of top-level uniques (a lift's captures are the free variables outside it); the second is the dictionary-datatype names (dictTyCons): a dictionary-typed binding is substituted at every occurrence rather than shared, because it can never be represented -- multi-use superclass projections would otherwise never see the constructor.

dictTyCons :: [DataDefn] -> HashSet Text Source #

Names of the datatypes with a function-typed constructor field (class dictionaries and their shapes): a value of such a type can never reach Hyle, so bindings of these types must always reduce away.

type SimpT (m :: Type -> Type) = StateT SimpSt m Source #

runSimpT :: Monad m => Program -> SimpT m a -> m a Source #

Run a simplifier action with a supply seeded above the program.