Template Function sequant::eval::analyze_legality

Function Documentation

template<meta::eval_node_range R>
inline LegalitySchedule sequant::eval::analyze_legality(RichSchedule const &rich, R const &forest, BatchPolicy const &policy)

Fold a RichSchedule into the first real LegalitySchedule: one CellLegality per ValueCell, with its at-node build_site (build_site_of), per_axis classification (classify_axis), home_floor (the LoopLocal subset of per_axis), and forced_split_axes (the LoopCarried subset of per_axis) filled in.

ValueCell does not itself retain the forest node its hash resolves to (only carried, a copy of the node’s canon_indices()), so forest is re-walked once up front into a hash -> representative-node map (the same pattern build_value_node_map, value_node_map.hpp, uses) to recover each cell’s own contracted_indices(node). Under perfect CSE every occurrence of a value shares one node shape, so the first-visited representative suffices.

Forced splits

A value classified LoopCarried on axis L survives the axis into its own result indices, so its producing L-loop must close before any cross-iteration consumer can read it (the consumer, at a different L iteration, reads a value bound to a foreign L index). L is therefore recorded in that value’s forced_split_axes: the axis cannot be a single unbroken loop around this value. This is directly derivable from the per-axis roles alone.

No fixpoint: a value read across a forced split is not demoted here

A value LoopLocal on a forced-split axis L that is read by a later-pass reader is handled entirely by the sequencer (build_ordered_schedule's per-nest pass placement, rule 4), which materializes such a value across the pass boundary at schedule-build time &#8212; “used across the split” is a property of the ordered pass structure the sequencer builds, not of the DAG this function sees, so classification here needs to react to it. analyze_legality is therefore a single deterministic round: one classification per cell, with no re-derivation loop.