Template Function sequant::eval::detail::run_ordered_contracted_block

Function Documentation

template<Trace EvalTrace, typename node_t, typename F, typename N, bool FHC, typename ScopeGuardFactory>
void sequant::eval::detail::run_ordered_contracted_block(ScopeBlock const &block, ValueNodeMap<node_t> const &vmap, RichSchedule const &rich, OrderedSchedule const &ordered, F const &leaf_evaluator, CacheManager<N, FHC> &parent_cache, std::function<std::size_t(Index const&)> const &target, typename CacheManager<N, FHC>::BatchContext const &ectx, container::vector<char> &built, std::function<bool(node_t const&)> const &is_volatile, CellTable const *table, CellRegistry &registry, CellReadResolver &resolver, container::vector<char> const &skip, ForgoPlan const &forgo_plan, ScopeGuardFactory const &make_scope_guard)

Realize one ScopeBlock's batch loop against parent_cache, executed entirely on the cell table (the explicit-value-cells design, section 4).

block's own steps are a topologically ordered interleaving of BuildStep's (each one produces the value’s Build cell at this block’s exact scope) and nested child ScopeBlock steps (realized recursively, in full, once per batch of this loop). block's outputs are its assemble steps: each names the cell &#8212; at the parent scope &#8212; that this block’s batches assemble, either by summing the per-batch partials (AccumulateSum: a reduced axis) or by scattering them into disjoint slices of one destination (AccumulateScatter: a carried axis). Both read the per-batch form from the table (Production::source), so a block-close handoff spends the same declared life any other read does.

Per batch: every cell bound to this loop instance is dropped from the registry (CellRegistry::clear_bound_to &#8212; the per-batch reset, expressed on cells), the batch context is extended by this block’s axis over the batch’s element range, the steps run in schedule order, and each output folds its per-batch partial into its running result. At close each output’s running result becomes its Assemble cell’s value. There is no home walk, no home slot, no reuse table and no store into a scope cache: the registry owns every result, and the table says where each lives and how long.

The per-block scratch is a bare child cache: it holds no entries at all (the table owns storage) and exists only to carry this block’s batch context and to let the hook lookups &#8212; backend array-ops, the cell read resolver, the peak monitor &#8212; fall through to parent_cache.

A nest’s pass blocks

A nest holding a forced-split axis realizes its loop as that nest’s pass blocks, one per pass (latitude = pass), as sibling ScopeBlock Step's at the same nesting level rather than one nested inside the other, run in schedule order. No special-casing is needed: sibling steps run sequentially, and the root topological sort is dependency-driven (ties broken by first use), not simply ascending by pass &#8212; a later pass’s block is only guaranteed to follow an earlier pass’s block of the same nest where it actually reads that earlier block’s production (every case that matters: a rule-4 materialization, or a carried value’s assembled form); two pass blocks with no such dependency between them may come out in either order, which is harmless since their scopes and cells are distinct. A later pass’s reads name an earlier pass’s assembled cell explicitly (scopes carry their latitude, so each pass’s cells are distinct).

Parameters:
  • skip – The cache-halt skip set over cells (ordered_cache_halt_skip), computed once per call; this block adds the produce_if_absent cells currently held (its own visit’s seeds) and re-closes it.

  • forgo_plan – The sources each consumer cell reads (ordered_forgo_plan), so a skipped production can still spend the reads it will not perform and its sources reach the end of their declared lives.

  • built – The run-completeness ledger, marked at the exact site each scheduled value is produced (or deliberately skipped).