Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/srdatalog/ir/codegen/cuda/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def compile_kernel_body(
pipeline=DEFAULT_KERNEL_PIPELINE,
)
body_text = state.body_text
assert body_text is not None, 'compile_kernel_body: CudaRenderShim left body_text unset'
assert body_text is not None, 'compile_kernel_body: RenderShim left body_text unset'
return body_text


Expand Down
2 changes: 1 addition & 1 deletion src/srdatalog/ir/codegen/cuda/complete_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
has_tiled_cartesian_eligible,
)
from srdatalog.ir.codegen.cuda.plugin import plugin_gen_host_view_setup, plugin_view_count
from srdatalog.ir.mir.passes import ep_has_work_stealing

# Pure-template phase emitters now live in the dialect's runner module.
# Local aliases preserve the legacy call sites until the rest of this
Expand Down Expand Up @@ -75,6 +74,7 @@
compute_total_view_count,
source_spec_key,
)
from srdatalog.ir.mir.passes import ep_has_work_stealing

# -----------------------------------------------------------------------------
# Source spec extraction helpers (mirror Nim's inline lambdas)
Expand Down
34 changes: 17 additions & 17 deletions src/srdatalog/ir/default_pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

DEFAULT_KERNEL_PIPELINE — KernelCtx(ep, ...) -> body string
AssignHandlesShim, CollectViewSpecsShim, EmitViewDeclsShim,
LowerScanPipelineShim, CudaRenderShim
LowerKernelBodyShim, RenderShim

Each shim is a `ProgramPass` subclass mirroring one block of either
`compile_to_mir` (src/srdatalog/ir/hir/__init__.py:96-124) or
Expand Down Expand Up @@ -261,14 +261,14 @@ def _fn(state: KernelCtx, _compiler: Any) -> KernelCtx:
)


class LowerScanPipelineShim(ProgramPass):
class LowerKernelBodyShim(ProgramPass):
'''Wraps `lower_scan_pipeline` (sorted_array dialect). Builds a
`LoweringCtx` from the populated state and runs the MIR -> IIR
walk. Adds `iir` to state.'''

def __init__(self) -> None:
super().__init__(
name='lower_scan_pipeline',
name='lower_kernel_body',
consumes=('view_decls',),
produces=('iir',),
fn=self._fn,
Expand All @@ -281,8 +281,8 @@ def _fn(state: KernelCtx, _compiler: Any) -> KernelCtx:
lower_scan_pipeline,
)

assert state.name_map is not None, 'LowerScanPipelineShim: name_map not set'
assert state.base_map is not None, 'LowerScanPipelineShim: base_map not set'
assert state.name_map is not None, 'LowerKernelBodyShim: name_map not set'
assert state.base_map is not None, 'LowerKernelBodyShim: base_map not set'
lower_ctx = LoweringCtx(
view_var_names=state.name_map,
is_counting=state.is_counting,
Expand Down Expand Up @@ -310,18 +310,18 @@ class VerifyRenderabilityShim(ProgramPass):
would surface, and with a precise message pointing at the missing
plugin contribution.

Today's IIR rewrite step is conceptual — `LowerScanPipelineShim`
Today's IIR rewrite step is conceptual — `LowerKernelBodyShim`
produces the final IIR directly. So this shim runs AFTER
`LowerScanPipelineShim` (which produces the IIR) and BEFORE
`CudaRenderShim` (which consumes it). The shim is structurally a
`LowerKernelBodyShim` (which produces the IIR) and BEFORE
`RenderShim` (which consumes it). The shim is structurally a
pass-through on `KernelCtx` — it neither inspects nor mutates the
state beyond the closure check.

`consumes=('iir',)` + `produces=()` because the check doesn't
introduce a new pseudo-dialect; it's a gate, not a transformation.
Per the spec note in `code_discipline.md` R3, this is exactly the
"pipeline-stage closure verification" that prevents silent
fall-through in `CudaRenderShim`.'''
fall-through in `RenderShim`.'''

def __init__(self) -> None:
super().__init__(
Expand All @@ -340,14 +340,14 @@ def _fn(state: KernelCtx, compiler: Any) -> KernelCtx:
return state


class CudaRenderShim(ProgramPass):
class RenderShim(ProgramPass):
'''Wraps `srdatalog.ir.codegen.cuda.emit.emit` with an
`EmitCtx(indent_level=4)`. Concatenates `view_decls` + emitted IIR
into the final `body_text`.'''

def __init__(self) -> None:
super().__init__(
name='cuda_render',
name='render',
consumes=('iir',),
produces=('body_text',),
fn=self._fn,
Expand All @@ -357,8 +357,8 @@ def __init__(self) -> None:
def _fn(state: KernelCtx, _compiler: Any) -> KernelCtx:
from srdatalog.ir.codegen.cuda.emit import EmitCtx, emit

assert state.iir is not None, 'CudaRenderShim: iir not set'
assert state.view_decls is not None, 'CudaRenderShim: view_decls not set'
assert state.iir is not None, 'RenderShim: iir not set'
assert state.view_decls is not None, 'RenderShim: view_decls not set'
emit_ctx = EmitCtx(indent_level=4)
body_text = state.view_decls + emit(state.iir, emit_ctx)
return dataclasses.replace(state, body_text=body_text)
Expand All @@ -381,9 +381,9 @@ def _fn(state: KernelCtx, _compiler: Any) -> KernelCtx:
AssignHandlesShim(),
CollectViewSpecsShim(),
EmitViewDeclsShim(),
LowerScanPipelineShim(),
LowerKernelBodyShim(),
VerifyRenderabilityShim(),
CudaRenderShim(),
RenderShim(),
]


Expand All @@ -392,14 +392,14 @@ def _fn(state: KernelCtx, _compiler: Any) -> KernelCtx:
'DEFAULT_PROGRAM_PIPELINE',
'AssignHandlesShim',
'CollectViewSpecsShim',
'CudaRenderShim',
'EmitViewDeclsShim',
'HirPlanningShim',
'HirToMirShim',
'InitialProg',
'KernelCtx',
'LowerScanPipelineShim',
'LowerKernelBodyShim',
'MirOptShim',
'MirProgramAssembly',
'RenderShim',
'VerifyRenderabilityShim',
]
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@

Caller posture during the migration:

- `LowerScanPipelineShim` (in `srdatalog.ir.default_pipelines`)
- `LowerKernelBodyShim` (in `srdatalog.ir.default_pipelines`)
still calls `lower_scan_pipeline(state.ep.pipeline, lower_ctx)`
directly. That direct call is byte-equivalent to going through
the registered `@lowering` (this module's entry is a 1-line
delegate to the same function). The registry-driven dispatch
path is a follow-up — see the TODO at
`LowerScanPipelineShim._fn` — that requires plumbing the
`LowerKernelBodyShim._fn` — that requires plumbing the
Compiler reference through `KernelCtx` (F3's `LowerCtx`
already carries one; `KernelCtx` does not yet).
- `compile_pipeline(ep)` and `compile_kernel_body(ep, ...)` route
through `LowerScanPipelineShim` (post-F5.3) so they inherit the
through `LowerKernelBodyShim` (post-F5.3) so they inherit the
same direct-call path. The new `@lowering` entry here is the
discoverable canonical surface; direct callers and the shim are
free to invoke it OR the underlying `lower_scan_pipeline`
Expand Down
22 changes: 11 additions & 11 deletions tests/test_default_pipelines_shims.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
DEFAULT_PROGRAM_PIPELINE,
AssignHandlesShim,
CollectViewSpecsShim,
CudaRenderShim,
EmitViewDeclsShim,
HirPlanningShim,
HirToMirShim,
InitialProg,
KernelCtx,
LowerScanPipelineShim,
LowerKernelBodyShim,
MirOptShim,
MirProgramAssembly,
RenderShim,
)

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -100,9 +100,9 @@ def test_kernel_pipeline_names_unique_and_ordered():
'assign_handles',
'collect_view_specs',
'emit_view_decls',
'lower_scan_pipeline',
'lower_kernel_body',
'verify_renderability',
'cuda_render',
'render',
]
assert len(set(names)) == len(names)

Expand Down Expand Up @@ -217,22 +217,22 @@ def test_emit_view_decls_shim_populates_maps():
assert all(k.isdigit() for k in out.name_map)


def test_lower_scan_pipeline_shim_produces_iir():
def test_lower_kernel_body_shim_produces_iir():
state = _build_kernel_ctx()
state = AssignHandlesShim().apply(state, None)
state = CollectViewSpecsShim().apply(state, None)
state = EmitViewDeclsShim().apply(state, None)
out = LowerScanPipelineShim().apply(state, None)
out = LowerKernelBodyShim().apply(state, None)
assert out.iir is not None


def test_cuda_render_shim_returns_string_body():
def test_render_shim_returns_string_body():
state = _build_kernel_ctx()
state = AssignHandlesShim().apply(state, None)
state = CollectViewSpecsShim().apply(state, None)
state = EmitViewDeclsShim().apply(state, None)
state = LowerScanPipelineShim().apply(state, None)
out = CudaRenderShim().apply(state, None)
state = LowerKernelBodyShim().apply(state, None)
out = RenderShim().apply(state, None)
assert isinstance(out.body_text, str)
assert len(out.body_text) > 0
# Should contain the view-decls preamble + emitted body.
Expand Down Expand Up @@ -449,8 +449,8 @@ def test_assign_handles_shim_is_idempotent():
test_assign_handles_shim_runs_in_isolation()
test_collect_view_specs_shim_runs_in_isolation()
test_emit_view_decls_shim_populates_maps()
test_lower_scan_pipeline_shim_produces_iir()
test_cuda_render_shim_returns_string_body()
test_lower_kernel_body_shim_produces_iir()
test_render_shim_returns_string_body()
test_default_program_pipeline_end_to_end()
test_default_kernel_pipeline_end_to_end()
test_kernel_pipeline_count_phase_runs()
Expand Down
10 changes: 5 additions & 5 deletions tests/test_lower_mir_execute_pipeline_byte_equivalent.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
- looking up the registered Lowering on the dialect and applying it
yields the same IIR tree as the direct call,
- `compile_kernel_body(ep, ...)` still works end-to-end (it routes
through `LowerScanPipelineShim` which still calls
through `LowerKernelBodyShim` which still calls
`lower_scan_pipeline` directly today),
- `compile_pipeline(ep)` produces byte-identical CUDA text.
- EP carrying a `DedupHash` pragma still lowers through the
Expand Down Expand Up @@ -144,7 +144,7 @@ def _new_ctx(**kwargs: Any) -> LoweringCtx:


def _real_ep_with_view_vars() -> tuple[mir.ExecutePipeline, dict[str, Any]]:
'''Run the kernel pipeline up to (but excluding) `LowerScanPipelineShim`
'''Run the kernel pipeline up to (but excluding) `LowerKernelBodyShim`
to obtain a fully-prepared EP + view_var maps. Returns the pair so
byte-equivalence tests on the real TC fixture can build a matching
`LoweringCtx`.
Expand Down Expand Up @@ -192,7 +192,7 @@ def test_direct_invocation_matches_legacy_lower_scan_pipeline():
def test_direct_invocation_on_real_tc_pipeline():
'''Same byte-equivalence claim against an EP produced by the
production HIR->MIR pipeline (richer shape than the hand-built
fixture). Uses the kernel-pipeline's pre-LowerScanPipelineShim
fixture). Uses the kernel-pipeline's pre-LowerKernelBodyShim
state to populate `view_var_names` / `view_slot_bases` so the
inner ops resolve their view vars correctly.'''
ep_pre, ctx_kwargs = _real_ep_with_view_vars()
Expand Down Expand Up @@ -261,7 +261,7 @@ def test_registered_lowering_matches_legacy_on_real_ep():


def test_compile_kernel_body_still_works_through_kernel_pipeline():
'''`compile_kernel_body(ep)` routes through `LowerScanPipelineShim`
'''`compile_kernel_body(ep)` routes through `LowerKernelBodyShim`
(post-F5.3). The shim still calls `lower_scan_pipeline` directly
today — the new registered `@lowering` gives the same lowering a
discoverable entry point but does not change the shim's path.
Expand Down Expand Up @@ -323,7 +323,7 @@ def test_pragma_dedup_hash_still_lowers_through_registered_path():
goes through the same `MirPragmaPass` consumer.'''
ep_base = _simple_scan_ep()
# Clone with dedup_hash=True; the field flows into LoweringCtx via
# LowerScanPipelineShim and affects InsertInto emit. We're just
# LowerKernelBodyShim and affects InsertInto emit. We're just
# checking the EP wrap (`lower_mir_execute_pipeline`) doesn't choke
# on it — the delegation pattern means anything that works in
# `lower_scan_pipeline` works here.
Expand Down
24 changes: 12 additions & 12 deletions tests/test_verify_renderability.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
4. Integration: `Compiler.run(KernelCtx, pipeline=DEFAULT_KERNEL_PIPELINE)`
on a TC fixture passes (because every op renders); inserting a
fake shim that produces an unrenderable op raises at the
`VerifyRenderabilityShim` step, BEFORE `CudaRenderShim` runs.
`VerifyRenderabilityShim` step, BEFORE `RenderShim` runs.
'''

from __future__ import annotations
Expand Down Expand Up @@ -117,7 +117,7 @@ def _real_iir_tree() -> object:
prog_state = compiler.run(InitialProg(program=_tc_program()), pipeline=DEFAULT_PROGRAM_PIPELINE)
assert prog_state.mir_program is not None
ep = _first_ep(prog_state.mir_program)
# Run kernel pipeline up through LowerScanPipelineShim (inclusive)
# Run kernel pipeline up through LowerKernelBodyShim (inclusive)
# — i.e. everything BEFORE the gate we're testing. This avoids
# recursion (we're literally building the fixture the gate consumes).
partial_pipeline = []
Expand Down Expand Up @@ -249,13 +249,13 @@ def _identity_rewrite(op, _compiler):
# -----------------------------------------------------------------------------


def test_verify_renderability_shim_is_between_lower_scan_and_cuda_render():
'''Pipeline shape contract: the gate runs AFTER LowerScanPipelineShim
(which produces IIR) and BEFORE CudaRenderShim (which consumes it).'''
def test_verify_renderability_shim_is_between_lower_kernel_body_and_render():
'''Pipeline shape contract: the gate runs AFTER LowerKernelBodyShim
(which produces IIR) and BEFORE RenderShim (which consumes it).'''
names = [p.name for p in DEFAULT_KERNEL_PIPELINE]
i_lower = names.index('lower_scan_pipeline')
i_lower = names.index('lower_kernel_body')
i_verify = names.index('verify_renderability')
i_render = names.index('cuda_render')
i_render = names.index('render')
assert i_lower < i_verify < i_render


Expand Down Expand Up @@ -295,7 +295,7 @@ def test_kernel_pipeline_with_injected_unrenderable_op_raises_at_gate():
'''Negative integration: insert a shim that REPLACES the IIR with a
tree containing an unrenderable synthetic op. The pipeline must
raise `UnrenderableOpError` at `VerifyRenderabilityShim` — BEFORE
`CudaRenderShim` runs (which would otherwise hit its own KeyError).
`RenderShim` runs (which would otherwise hit its own KeyError).

The injected shim consumes 'iir' and produces 'iir' so the pipeline
ordering check still passes; only the closure check fires.'''
Expand All @@ -322,12 +322,12 @@ def _fn(state: KernelCtx, _compiler):
ep = _first_ep(prog_state.mir_program)

# Build a pipeline that injects the unrenderable op AFTER
# LowerScanPipelineShim but BEFORE the gate. The gate must catch it.
# LowerKernelBodyShim but BEFORE the gate. The gate must catch it.
inject = _InjectUnrenderable()
patched: list = []
for p in DEFAULT_KERNEL_PIPELINE:
patched.append(p)
if p.name == 'lower_scan_pipeline':
if p.name == 'lower_kernel_body':
patched.append(inject)

with pytest.raises(UnrenderableOpError) as excinfo:
Expand All @@ -338,7 +338,7 @@ def _fn(state: KernelCtx, _compiler):

def test_verify_renderability_shim_consumes_iir_produces_nothing():
'''Pipeline-data contract: the gate consumes the iir dialect produced
by LowerScanPipelineShim. Because it doesn't introduce a new
by LowerKernelBodyShim. Because it doesn't introduce a new
pseudo-dialect, `produces=()`.'''
shim = VerifyRenderabilityShim()
assert shim.consumes == ('iir',)
Expand All @@ -353,7 +353,7 @@ def test_verify_renderability_shim_consumes_iir_produces_nothing():
test_verify_renderability_raises_on_nested_unrenderable_op()
test_verify_renderability_raises_on_unknown_target()
test_rewrite_closes_an_otherwise_unrenderable_op()
test_verify_renderability_shim_is_between_lower_scan_and_cuda_render()
test_verify_renderability_shim_is_between_lower_kernel_body_and_render()
test_verify_renderability_shim_is_a_pass_through()
test_default_kernel_pipeline_runs_end_to_end_with_gate()
test_kernel_pipeline_with_injected_unrenderable_op_raises_at_gate()
Expand Down
Loading