Documentation

Sparkle.IR.Optimize

@[reducible, inline]

O(1) lookup maps built from module data

Equations
Instances For

    Build a name → defining-expression map from assign statements

    Equations
    • One or more equations did not get rendered due to their size.
    Instances For

      Build name → bit-width map from module ports and wires

      Equations
      • One or more equations did not get rendered due to their size.
      Instances For

        Infer the bit-width of an expression

        partial def Sparkle.IR.Optimize.resolveSliceOfConcatAux (remaining : List (AST.Expr × Nat)) (hiEdge sliceHi sliceLo : Nat) :

        Try to resolve a slice of a concat to a direct reference or narrower slice.

        For concat [a(wa), b(wb), c(wc), ...] with total width T:

        • a occupies [T-1 : T-wa]
        • b occupies [T-wa-1 : T-wa-wb]
        • etc. (MSB-first layout, same as Verilog {a, b, c, ...})

        Returns the replacement if the slice maps entirely within one arg.

        def Sparkle.IR.Optimize.resolveSliceOfConcat (args : List AST.Expr) (widths : List Nat) (sliceHi sliceLo : Nat) :
        Equations
        • One or more equations did not get rendered due to their size.
        Instances For
          partial def Sparkle.IR.Optimize.resolveSlice (dm : DefMap) (wm : WidthMap) (name : String) (hi lo fuel : Nat) :

          Resolve a slice of a named wire through the defMap, recursively following:

          1. Ref aliases: X = Y → slice(Y, hi, lo)
          2. Slice chains: X = Y[h:l] → slice(Y, l+hi, l+lo)
          3. Concat args: X = {a, b} → a (if slice matches exactly) Depth-limited to prevent infinite recursion on malformed IR.

          Fold constant expressions

          Equations
          Instances For

            Optimize a single expression by resolving slice chains, folding constants, and propagating constant-assigned wires.

            Collect all reference names from an expression.

            Count uses of each wire across all statements

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For

              Optimize a single statement's expressions

              Equations
              Instances For
                partial def Sparkle.IR.Optimize.substituteExpr (dm : DefMap) (inlinable : Std.HashMap String Bool) (widthOfWire : StringNat) (fuel : Nat) :

                Recursively substitute inlinable references with their defining expressions.

                widthOfWire is the substituted wire's DECLARED width, and it is load- bearing: CSim emits expressions unmasked and re-masks only at named-wire assignment boundaries (self->w = (expr) & 0x7ULL). A wire is therefore a masking point, and inlining one deletes its mask. When the declared width differs from the width C arithmetic naturally wraps at (32 for promoted narrow operands, 64 for wide storage), the value changes: CAVLC's 3-bit slDec = suffixLen - 1 reads 7 as a wire but −1 → 2³²−1 inlined, and 3 << slDec went from 384 to garbage — every emitted bitstream block was wrong. So any inlined definition whose declared width is not exactly 32 or 64 is re-wrapped in an explicit & (2^w − 1), which every backend renders inline and constant-folds.

                Inline single-use wires: replace references with their defining expressions and remove the now-dead assign statements.

                Equations
                • One or more equations did not get rendered due to their size.
                Instances For
                  Equations
                  Instances For

                    Propagate constant and simple-ref assignments into all uses. x = const → replace all refs to x with const x = y → replace all refs to x with y (alias elimination) This runs even for gen (JIT-observable) wires since they're just aliases.

                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For

                      Filter zero-bit elements out of an Expr tree.

                      lowerExpr / runCircuitH-style elaborators can produce IR nodes that thread a bitVector 0 "empty payload" through .concat and .slice chains — for instance bundle2 X (Signal.pure ()) lowers to .concat [X, <0-bit ref>], and the matching Signal.map Prod.fst lowers to a slice that discards the 0-bit tail.

                      Emitting these into SystemVerilog produces invalid constructs like assign x = 0'd0; (a zero-width literal is not legal SV). This pass rewrites the IR so that:

                      • .const v 0 is dropped from .concat arg lists;
                      • .concat [x] (after dropping zero-bit args) collapses to the single remaining arg;
                      • .concat [] collapses to a 1-bit zero placeholder (should be unreachable in practice — pruned later by DCE);
                      • .slice e hi lo where hi - lo + 1 == 0 is rewritten to a 0-bit constant (later dropped at the use site).

                      Sub-expressions are rewritten recursively.

                      Drop Stmt.assign whose LHS has zero width — these only exist as leftover bookkeeping from 0-bit IR construction (see eliminateZeroBitInExpr). Other Stmt kinds are kept as is.

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For

                        Run the 0-bit elimination pass over a module's body and wire list.

                        Equations
                        • One or more equations did not get rendered due to their size.
                        Instances For

                          Resolve a wire name through the CSE substitution map, following chains (w2 → w1 → w0). Chains are acyclic by construction — a wire only enters the map when its defining statement is dropped, and the representative's statement is always kept — so plain recursion terminates.

                          Rewrite every wire reference through the CSE substitution map.

                          Apply f to every expression embedded in a statement.

                          Equations
                          Instances For

                            Phase 0.6: cross-wire common-subexpression elimination + duplicate sub-module instance merging (Issue #107).

                            The synth elaborator re-walks the circuit body once per register next-state leaf; wires derived from let/loop-bound state come out under fresh names per walk (_gen_x, _gen_x_1, …) even though they compute identical expressions over identical base wires, and each walk re-emits the sub-module instances fed by those wires — E = I·(D+1) instances instead of I. The Lean-side caches can't see through the fresh fvars, but at the IR level everything is canonical: the clones are literally assign x_1 = <same rhs> and inst … (<same input connections>).

                            Value-number assigns by their (substitution-rewritten) rhs; when a later assign duplicates an earlier one, drop it and alias its lhs to the representative. Merge instances of the same module whose input connections are identical, aliasing their output wires. A connection .ref w where w is not driven by any non-instance statement (and is not a module input) is an output of that instance — no cross-module port-direction table needed.

                            Merging stateful instances is sound: same module + same inputs + same clock/reset ⇒ same state trajectory ⇒ same outputs, which is exactly the denotation Sparkle's pure semantics assigns to structurally identical calls. (This is the fold yosys's opt_merge refuses to do because it would need sequential equivalence checking; here it is correct by construction.)

                            protectedWire (module outputs + observable waveform taps) never gets aliased away. Iterates to a fixpoint because folding one layer of duplicates makes the next layer's keys equal.

                            Equations
                            • One or more equations did not get rendered due to their size.
                            Instances For

                              Optimize a module: strip zero-bit shapes, eliminate concat/slice chains, then remove dead code.

                              Equations
                              • One or more equations did not get rendered due to their size.
                              Instances For
                                Equations
                                Instances For

                                  Optimize all modules in a design

                                  Equations
                                  • One or more equations did not get rendered due to their size.
                                  Instances For