Source code for srdatalog.ir.dialects.relation.d2l

'''relation.d2l — Device2LevelIndex dialect.

Today this module owns:
  - `view_count(spec)` and `view_counts_for_specs` — view-slot
    accounting used by `compile.compile_kernel_body` to populate
    `view_counts` for the dialect's view declarations.
  - `D2lSegmentLoop` op (in `ops.py`) — the IIR segment-loop wrapper
    that lets nested CJ pipelines visit both HEAD and FULL segments
    of a D2L FULL_VER source.

Legacy-comment header (kept for the design narrative):

A 2-level index: each relation has a HEAD segment (smaller, dense) and
a FULL segment (the full sorted array). FULL_VER reads expose both
segments as separate views in `views[]`; iteration over the source
visits both segments in turn (HEAD first, FULL second).

Versions:
  - DELTA_VER, NEW_VER:  1 view (FULL only — incremental data)
  - FULL_VER:             2 views (HEAD + FULL)

Compared to `relation.sorted_array` (single-view-per-source DSAI):

  - View-slot accounting: a FULL_VER D2L source occupies 2 contiguous
    slots in `views[]`. `view_count(version) = 2 if version == FULL_VER
    else 1`. The dialect's `emit_view_declarations` honors per-spec
    `view_counts` to compute correct positional slots.

  - Nested CJ segment loop: a nested ColumnJoin whose RHS source is a
    D2L FULL_VER source must wrap its body in
    `for (_nseg = 0; _nseg < 2; ++_nseg) { view_X = views[base+_nseg];
    <cj body> }` so the join visits both segments. This op (planned:
    `D2lSegmentLoop`) is the missing piece keeping D2L pipelines on
    the legacy fallback today.

  - BG histogram segment-aware degree: BG histogram non-first sources
    accumulate degree across both segments before validity checks.
    Lives in `codegen.cuda.render.parallel_data.emit_bg_histogram_kernel`
    (which already handles `view_count > 1`).

Planned ops (N5.x):
  D2lRoot(view_full, view_head)         dual-segment root handle
  D2lPrefix(parent, key)                 cooperative narrow + segment
  D2lSegmentLoop(seg_var, view, body)    iterate over HEAD/FULL
  D2lDualSegmentDegree(handle, view_count)  segment-aware degree sum

The legacy `plugin_view_count` is the underlying source for
`view_count` until we expand the dialect to host its own ops + emit.
'''

from __future__ import annotations

from srdatalog.ir.codegen.cuda.envelope import ViewSpec
from srdatalog.ir.core import Dialect

# Side-effect import: registers D2L's CUDA plugin with
# `codegen.cuda.plugin` so `plugin_view_count` etc. dispatch correctly
# for relations declared `index_type="...Device2LevelIndex"`.
from srdatalog.ir.dialects.relation.d2l import cuda as _cuda
from srdatalog.ir.dialects.relation.d2l.ops import D2lSegmentLoop

DIALECT = Dialect(
  name='relation.d2l',
  ops=[D2lSegmentLoop],
)


[docs] def view_count(version: str, index_type: str) -> int: '''Number of physical view slots a (version, index_type) pair consumes. D2L FULL_VER = 2; DSAI / D2L DELTA / NEW = 1. Delegates to the legacy `plugin_view_count` for the actual resolution. Once the relation-dialect registry hosts D2L ops, the dispatch shifts here and the legacy plugin module retires. ''' from srdatalog.ir.codegen.cuda.plugin import plugin_view_count return plugin_view_count(version, index_type)
[docs] def view_counts_for_specs( view_specs: list[ViewSpec], rel_index_types: dict[str, str], ) -> list[int]: '''Per-spec view_count for a pipeline's view specs. Pass the result to `emit_view_declarations(..., view_counts=...)` so positional slots advance by the right amount per spec. ''' return [view_count(sp.version, rel_index_types.get(sp.rel_name, '')) for sp in view_specs]
__all__ = ['DIALECT', 'D2lSegmentLoop', 'view_count', 'view_counts_for_specs'] # Verifier scaffolding — D2L invariants (segment_depth coherence, etc.) # land incrementally as we encode them. def _register_passes() -> None: from srdatalog.ir.core.passes import verifier @verifier(DIALECT) def _verify(_prog): return [] _register_passes()