Skip to main content

Module cascade

Module cascade 

Source
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:

  1. The cascade rules live in one place. Bug fixes apply everywhere.
  2. The most-rigorous version (phase scope’s SRD-13f provenance-aware inlining) becomes the canonical behavior for every scope kind.
  3. 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)

  1. Coord-set detection. Walks parent.program().coord_count() and input_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.
  2. Local-inclusion-chain inline. For each referenced name 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 as emitted. (SRD-13f §“Wire-reference classification” case 3.)
  3. Referenced-name cascade. For each remaining referenced name, looks it up in parent_manifest for its typed port; emits extern NAME: TYPE and marks inherited.
  4. Workload-params cascade. For each entry in workload_params not yet emitted and not pre-emitted, emits extern NAME: TYPE (type detected from value shape). Marks inherited.
  5. 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 as const NAME := <literal>; otherwise cascades as extern NAME: TYPE. (SRD-13f §“Materialization gradient”.)
  6. Parent-input cascade. For each parent.program().input_names() not yet emitted, emits extern 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_emitted so the walker doesn’t re-emit them.
  • Call finalize — that’s the per-scope builder’s responsibility (it threads scope-specific CompileOptions and context labels).

Structs§

CascadeInputs
Per-scope context the walker needs from its caller.
CascadeOutputs
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.