Template Function sequant::eval::stamp_lifetime_masks

Function Documentation

template<meta::eval_node_range R>
void sequant::eval::stamp_lifetime_masks(R const &forest)

Stamp each canonical eval node’s cross-occurrence sliced-mode mask (EvalExpr::sliced_modes) &#8212; the runtime residency place_at_this_level consumes to home each value. A mode slices a canonical node iff it slices every occurrence of that node in forest (a meet / set-intersection over occurrences). A node’s occurrence-local sliced set is the union of the enclosing loops opened at or above it &#8212; batch_loops_opened_here (any BatchModeType: External opened at its open site, Contracted opened at its reduction site), each physical loop appearing once &#8212; filtered to the modes that live on the node’s own result slots (slot_modes_of, i.e. canon_indices() taken as-is &#8212; see there for why a composite slot a<i,j> is just mode a, never its i,j proto pair). A node invariant to an outer batched loop &#8212; it does not carry that loop’s mode on any slot &#8212; is thus left all-full even under a batched ancestor, so it stays eligible for loop-invariant reuse. (Sourcing opens, not the per-carrying-node node_slice_mask, is what makes the accumulation a set: an External loop reaches its carriers by inheritance rather than a redundant own-node stamp, and a Contracted loop reaches its below-the-reduction carriers the same way &#8212; the case that genuinely needs the down-propagation.)

This all-batched-modes meet subsumes the former per-occurrence contracted_modes bolt-on: a node variant to an outer contracted (aux) loop carries that aux free on a result slot, so the aux mode survives the meet and lands in sliced_modes directly.

Occurrences are grouped by canonical identity (hash_value plus structural TreeNodeEqualityComparator equivalence). The meet is a set-intersection by Index identity: canonicalization gives consistent labels across occurrences, so a genuinely sliced-everywhere mode survives, while a block-agnostic node (e.g. s*C) whose occurrences bind disjoint concrete modes intersects to empty (all-full).

Idempotent; a no-op on the off path: with no node_slice_mask() stamps every occurrence set is empty, so every meet is empty and every mask is all-full (EvalExpr::sliced_modes_ is default-empty), leaving runtime behavior unchanged.