Expand description
Shared cascade walker — the single implementation of “given a parent kernel, decide what cascade-extern and inline-const lines to emit for a child scope’s Polydat source.”
Pre-walker, each of the four sister scope builders
(build_phase_scope_kernel, build_do_loop_scope_kernel,
build_op_template_scope_kernel, and the forthcoming
build_for_each_scope_kernel) reinvented this walk with
subtly different precision. This module consolidates the
walk so:
- The cascade rules live in one place. Bug fixes apply everywhere.
- The most-rigorous version (phase scope’s SRD-13f provenance-aware inlining) becomes the canonical behavior for every scope kind.
- Scope-specific bits stay in the per-scope builder — each builder contributes only what’s unique to it (body source, iter-var declarations, counter, etc.).
§What this walker is NOT for
build_op_template_scope_kernel is intentionally not
refactored onto this walker. The op-template uses a
deliberately narrow “lazy cascade” policy — emit externs
only for names the op references, never a broad parent-
output / parent-input sweep. That keeps the op-template
kernel narrow at the cost of more bookkeeping in the
caller. Forcing it onto a broad-cascade walker would
either bloat the walker with op-template-specific knobs or
widen the op-template kernel; neither is desirable. The
op-template stays self-contained.
§What the walker does (in order)
- Coord-set detection. Walks
parent.program().coord_count()andinput_names()to discover which names are parent- coord-slots — those propagate via the kernel chain, not via extern cascade. They’re added to a skip set. - Local-inclusion-chain inline. For each
referencedname that resolves to a non-final cycle binding in the parent’s AST (i.e., would have to be re-computed at this scope), pretty-prints the parent’s inclusion chain and emits it as local matter. Names included this way are marked asemitted. (SRD-13f §“Wire-reference classification” case 3.) - Referenced-name cascade. For each remaining
referencedname, looks it up inparent_manifestfor its typed port; emitsextern NAME: TYPEand marks inherited. - Workload-params cascade. For each entry in
workload_paramsnot yet emitted and not pre-emitted, emitsextern NAME: TYPE(type detected from value shape). Marks inherited. - Parent-output cascade with provenance-aware inlining.
For each
parent.program().output_names()not yet emitted: if the upstream’s value is statically known (provenance == 0), inlines asconst NAME := <literal>; otherwise cascades asextern NAME: TYPE. (SRD-13f §“Materialization gradient”.) - Parent-input cascade. For each
parent.program().input_names()not yet emitted, emitsextern NAME: TYPE. Closes the chain so cascade-extern’d inputs propagate transitively.
§What the walker does NOT do
- Emit the scope’s own body / iter-var / counter
declarations — those come from the per-scope builder and
are passed in as
pre_emittedso the walker doesn’t re-emit them. - Call
finalize— that’s the per-scope builder’s responsibility (it threads scope-specificCompileOptionsand context labels).
Structs§
- Cascade
Inputs - Per-scope context the walker needs from its caller.
- Cascade
Outputs - Per-scope outputs the walker mutates.
Functions§
- cascade_
parent_ into_ source - Run the shared cascade walk. See module docs for the six steps and their order.