Skip to content

[Backend] Add unified backend resolution policy - #2318

Merged
SiriusNEO merged 8 commits into
tile-ai:mainfrom
SiriusNEO:backend_0602
Aug 5, 2026
Merged

SiriusNEO merged 8 commits into
tile-ai:mainfrom
SiriusNEO:backend_0602

Conversation

@SiriusNEO

@SiriusNEO SiriusNEO commented Jun 2, 2026 •

Copy link
Copy Markdown
Collaborator

Tracking Issue: #2115

This PR centralizes backend resolution around a Backend descriptor so target-level capability, codegen, pass pipeline, and JIT execution policy are resolved from one backend-owned entry point.

Summary

  • Add a Backend descriptor and registry as the source of truth for target matching, pass pipelines, codegen hooks, callbacks, feature checks, and execution-backend policy.
  • Register CUDA, ROCm, CPU, Metal, and WebGPU backend descriptors in backend-owned modules.
  • Route lowering, host/device codegen, adapter callback lookup, and JIT execution backend selection through the resolved backend.
  • Preserve the existing PassPipeline entry points while exposing them through Backend.pipeline.

Summary

  • Centralizes backend resolution through Backend descriptors and a global registry.
  • Adds CUDA, ROCm, CPU, Metal, and WebGPU backend descriptors.
  • Routes lowering, device and host code generation, callbacks, feature checks, and execution-backend selection through the resolved backend.
  • Preserves pass-pipeline implementations through Backend.pipeline.
  • Removes separate device-codegen, host-codegen, execution-backend, and pipeline registries.
  • Adds backend registry, execution-policy, codegen, cache, JIT, and target-resolution tests.
  • Updates tracing, diagnostics, cache, and backend-specific tests for the new resolution flow.
  • Documents the descriptor-centered backend architecture and backend registration process.

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to the TileLang project.

Please remember to run pre-commit run --all-files in the root directory of the project to ensure your changes are properly linted and formatted. This will help ensure your contribution passes the format check.

We appreciate you taking this step! Our team will review your contribution, and we look forward to your awesome work! 🚀

@coderabbitai

coderabbitai Bot commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR replaces separate pipeline, device-codegen, host-codegen, and execution-backend registries with unified Backend descriptors. It routes lowering, code generation, JIT adapter selection, cache dispatch, callbacks, and target resolution through the centralized backend registry.

Changes

Centralized backend architecture

Layer / File(s) Summary
Backend descriptors and registry
tilelang/backend/backend.py, tilelang/backend/registry.py, tilelang/backend/codegen.py, tilelang/backend/execution_backend.py, tilelang/backend/__init__.py
Defines Backend and ExecutionBackendSpec, adds target-based registry resolution, and centralizes codegen and execution-backend policies.
Backend implementations
tilelang/cpu/backend.py, tilelang/cuda/backend.py, tilelang/rocm/backend.py, tilelang/metal/backend.py, tilelang/backend/common.py
Moves target-specific codegen, compilation callbacks, feature queries, availability checks, and execution-backend declarations into backend descriptors.
Engine and JIT routing
tilelang/engine/lower.py, tilelang/jit/kernel.py, tilelang/jit/adapter/utils.py, tilelang/cache/__init__.py, tilelang/tools/lower_trace/core.py
Routes lowering, host/device codegen, adapter dispatch, cache selection, source retrieval, and tracing through resolved backends.
Validation and documentation
testing/python/backend/test_tilelang_backend_registry.py, testing/python/{cache,debug,jit,llvm,target,transform,webgpu}/*, tilelang/backend/README.md
Adds registry and policy coverage and updates existing tests and documentation for the descriptor-based architecture.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Target
  participant Registry
  participant Backend
  participant JITKernel
  participant Cache
  Target->>Registry: resolve target backend
  Registry->>Backend: validate availability and callbacks
  Backend-->>Target: lower and generate host/device code
  JITKernel->>Backend: resolve execution-backend specification
  JITKernel->>Cache: dispatch using resolved adapter
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.91% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the PR's main change: unified backend resolution through a centralized policy.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
tilelang/engine/lower.py (1)

132-139: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include LLVM in the CPU device split.

Line 132 still derives the host/device filters from is_cpu_device_backend(target), but that helper only returns True for "c". The new registry path also routes "llvm" through the CPU backend, so LLVM CPU kernels will fall back to the generic DEVICE_KERNEL_LAUNCH check and can be filtered into host_mod instead of device_mod. This also affects tilelang/jit/adapter/utils.py, which imports the same helper.

def is_cpu_device_backend(target: Target):
    return target.kind.name in {"c", "llvm"}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tilelang/engine/lower.py` around lines 132 - 139, The host/device split is
using is_cpu_device_backend(target) but that helper currently only flags "c" and
must also include "llvm" so LLVM CPU kernels are treated as host-side; update
the is_cpu_device_backend implementation (referenced by get_host_call and
get_device_call invocations in lower.py) to return True for target.kind.name in
{"c", "llvm"}, and propagate the same change to any other callers (e.g.,
tilelang/jit/adapter/utils.py) so backend.resolve_backend and backend.lower
continue to route LLVM through the CPU path and the host_mod/device_mod
filtering behaves correctly.
tilelang/jit/kernel.py (2)

451-460: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the resolved adapter key in source helpers, not the execution-backend name.

These branches still key off self.execution_backend, but the new abstraction explicitly allows ExecutionBackendSpec.name != ExecutionBackendSpec.adapter (the new registry tests already exercise that shape). In that case, a backend like ExecutionBackendSpec("fast", adapter="tvm_ffi") will compile correctly and then take the wrong branch here when fetching kernel/host source. Compare against self.execution_backend_spec.adapter (or a capability on the spec) instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tilelang/jit/kernel.py` around lines 451 - 460, The source helper methods
get_kernel_source and get_host_source currently branch on self.execution_backend
but must use the resolved adapter key from the backend spec; update the
conditional checks to compare against self.execution_backend_spec.adapter (or a
capability on self.execution_backend_spec) instead of self.execution_backend so
backends whose .name differs from .adapter (e.g.
ExecutionBackendSpec(name="fast", adapter="tvm_ffi")) correctly route to
self.adapter.get_kernel_source/get_host_source; leave the fallback to
self.artifact.kernel_source unchanged.

350-403: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle the torch adapter in database reconstruction.

Per this PR, Metal can now resolve to a torch execution backend, but _create_adapter_from_database() still rejects adapter_name == "torch" outright. JITKernel.from_database(..., execution_backend="torch", target="metal") will now deterministically fail with the fallback ValueError, even though the normal compile path supports that adapter. Either add the MetalKernelAdapter reconstruction path here or reject that combination earlier before caching/loading it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tilelang/jit/kernel.py` around lines 350 - 403, The
_create_adapter_from_database branch rejects adapter_name=="torch" but
Metal-backed JITs resolve to the "torch" adapter; update
_create_adapter_from_database to handle adapter_name == "torch" by constructing
the adapter via MetalKernelAdapter.from_database with the same
params/result_idx/target/func_or_mod/host_kernel_source/device_kernel_source/kernel_lib_path/pass_configs/compile_flags
signature used for other adapters (import MetalKernelAdapter from the
appropriate module where adapters live), so JITKernel.from_database(...,
execution_backend="torch", target="metal") can reconstruct the adapter from the
DB; alternatively, if you prefer rejecting earlier, add a clear early check in
JITKernel.from_database to raise a descriptive error before caching/loading
instead of falling through to the ValueError.
tilelang/backend/README.md (1)

152-173: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Include backend.py in the backend package layout example.

This tree omits the new backend-owned backend.py modules even though the rest of the document describes them as the entry point for descriptor registration. That makes the package layout section misleading for contributors using it as the template for new backends.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tilelang/backend/README.md` around lines 152 - 173, The README backend
package layout examples omit the new backend-owned backend.py entry points;
update each example tree to include backend.py (e.g., add backend.py under
tilelang/cuda/, tilelang/rocm/, tilelang/cpu/, and tilelang/metal/) so the
documented package layout matches the described entry-point used for descriptor
registration (refer to the backend.py module name when editing the examples).
🧹 Nitpick comments (2)
tilelang/cuda/backend.py (1)

152-159: ⚡ Quick win

Reuse the shared cutedsl target predicate here.

These hooks reimplement target classification with raw key checks instead of _is_cutedsl_target(). Reusing the helper keeps codegen hook selection aligned with the backend’s centralized target policy.

Suggested refactor
 def cuda_device_codegen(device_mod: tvm.IRModule, target: Target) -> tvm.IRModule:
-    global_func = "target.build.tilelang_" + ("cutedsl" if "cutedsl" in target.keys else "cuda")
+    global_func = "target.build.tilelang_" + ("cutedsl" if _is_cutedsl_target(target) else "cuda")
     return build_device_with_global_func(device_mod, target, global_func)
 
 
 def cuda_device_codegen_without_compile(device_mod: tvm.IRModule, target: Target) -> tvm.IRModule:
-    global_func = "target.build.tilelang_" + ("cutedsl" if "cutedsl" in target.keys else "cuda") + "_without_compile"
+    global_func = (
+        "target.build.tilelang_"
+        + ("cutedsl" if _is_cutedsl_target(target) else "cuda")
+        + "_without_compile"
+    )
     return build_device_with_global_func(device_mod, target, global_func)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tilelang/cuda/backend.py` around lines 152 - 159, The two hooks
cuda_device_codegen and cuda_device_codegen_without_compile re-check target type
by inspecting target.keys; replace that raw check with the centralized predicate
_is_cutedsl_target(target) so both functions pick the same cutedsl vs cuda
suffix as other backends; construct the global_func string the same way but use
_is_cutedsl_target(target) to decide between "cutedsl" and "cuda" before passing
it to build_device_with_global_func.
tilelang/backend/registry.py (1)

73-76: ⚡ Quick win

Make callback registration one-shot.

resolve_backend() is now used during lowering, device codegen, and host preprocessing, so the same backend can hit ensure_callbacks_registered() several times in one compile. If a registrar does non-idempotent TVM global registration, this will double-register callbacks or repeat expensive setup. Cache successful registrations by backend name.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tilelang/backend/registry.py` around lines 73 - 76, The call site in
resolve_backend() calls backend.ensure_callbacks_registered() every time which
can re-run non-idempotent registrar work; make callback registration one-shot by
caching successful registrations keyed by backend name (or a per-backend flag).
Modify resolve_backend() (and/or ensure_callbacks_registered()) to check a
module-level set (e.g., registered_backends) or an attribute on the backend
object before invoking ensure_callbacks_registered(), add the backend.name to
that cache after successful registration, and skip calling
ensure_callbacks_registered() on subsequent resolves for the same backend.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tilelang/backend/backend.py`:
- Line 64: Backend is frozen but its nested mappings remain mutable; wrap both
the features and execution_backends mappings in an immutable mapping before
storing so callers can't mutate backend.features or backend.execution_backends.
Import and use types.MappingProxyType (or another immutable mapping wrapper) for
the dataclass default_factory for features and when constructing Backend
instances (the code paths around the Backend dataclass definition and the
registry creation code that sets execution_backends at the block around the
creation lines referenced). Ensure default_factory returns an immutable mapping
(e.g., MappingProxyType({})) and any dict passed into the Backend constructor is
wrapped with MappingProxyType(...) so get_backend() and list_backends() return
truly immutable descriptors.

In `@tilelang/backend/common.py`:
- Around line 15-16: The function webgpu_device_codegen_without_compile
currently calls build_device_with_global_func(device_mod, target,
"target.build.webgpu") which performs device compilation despite the default
policy advertising enable_device_compile=False; either change this function to a
true no-compile codegen path (e.g., return the device module unchanged or call
the appropriate non-compiling helper) or update the default policy to set
enable_device_compile=True so the descriptor matches behavior; update the same
logic in the other affected functions/lines (the block around 19-30) and ensure
references to build_device_with_global_func and enable_device_compile are
consistent.

In `@tilelang/backend/registry.py`:
- Around line 20-26: When overriding a backend in registry.py the code removes
the backend name from _TARGET_INDEX but leaves empty lists in the dict, causing
_ensure_loaded_for_kind to treat the kind as already loaded and skip lazy
imports; update the removal logic that iterates old.target_kinds (and the
analogous block around lines 49-54) to delete the key from _TARGET_INDEX if
names becomes empty (i.e., if not names: del _TARGET_INDEX[kind]) so that
_ensure_loaded_for_kind will still attempt lazy import for that kind.

In `@tilelang/cuda/backend.py`:
- Around line 34-37: The helper _is_nvrtc_available currently returns
bool(is_nvrtc_available) which truth-tests the imported function object instead
of executing the probe; change it to call the probe and return its boolean
result by invoking is_nvrtc_available() and casting/returning that value. Update
the function _is_nvrtc_available to import is_nvrtc_available and return the
result of is_nvrtc_available() (or bool(is_nvrtc_available()) for explicitness)
so the NVRTC backend is only advertised when the probe reports availability.

In `@tilelang/metal/backend.py`:
- Around line 12-13: metal_device_codegen currently calls
build_device_with_global_func(device_mod, target, "target.build.tilelang_metal")
which is also reused for the "without compile" path, causing backends that
should skip device compilation to still invoke the Metal build; either implement
a true no-compile path (e.g., add a device_codegen_without_compile variant that
returns source-only IRModule or a thin wrapper that avoids calling
build_device_with_global_func) or explicitly mark this execution backend as
enable_device_compile=True so the contract is honored; update
metal_device_codegen (and the code path that reuses it for the without-compile
flow) to use the new no-compile hook or set the backend flag accordingly.

In `@tilelang/rocm/backend.py`:
- Around line 9-37: The eager top-level import of tilelang.contrib.hipcc causes
its module-level callback to register on import; to keep registration lazy,
remove the module-level import and perform a local import of hipcc where needed
(either inside _tilelang_callback_hip_compile or at the start of
register_rocm_callbacks) so the hipcc module is only imported when the ROCm
backend is actually resolved; ensure _tilelang_callback_hip_compile still calls
hipcc.compile_hip and register_rocm_callbacks still calls
tvm_ffi.register_global_func("tilelang_callback_hip_compile",
f=_tilelang_callback_hip_compile, override=True).

---

Outside diff comments:
In `@tilelang/backend/README.md`:
- Around line 152-173: The README backend package layout examples omit the new
backend-owned backend.py entry points; update each example tree to include
backend.py (e.g., add backend.py under tilelang/cuda/, tilelang/rocm/,
tilelang/cpu/, and tilelang/metal/) so the documented package layout matches the
described entry-point used for descriptor registration (refer to the backend.py
module name when editing the examples).

In `@tilelang/engine/lower.py`:
- Around line 132-139: The host/device split is using
is_cpu_device_backend(target) but that helper currently only flags "c" and must
also include "llvm" so LLVM CPU kernels are treated as host-side; update the
is_cpu_device_backend implementation (referenced by get_host_call and
get_device_call invocations in lower.py) to return True for target.kind.name in
{"c", "llvm"}, and propagate the same change to any other callers (e.g.,
tilelang/jit/adapter/utils.py) so backend.resolve_backend and backend.lower
continue to route LLVM through the CPU path and the host_mod/device_mod
filtering behaves correctly.

In `@tilelang/jit/kernel.py`:
- Around line 451-460: The source helper methods get_kernel_source and
get_host_source currently branch on self.execution_backend but must use the
resolved adapter key from the backend spec; update the conditional checks to
compare against self.execution_backend_spec.adapter (or a capability on
self.execution_backend_spec) instead of self.execution_backend so backends whose
.name differs from .adapter (e.g. ExecutionBackendSpec(name="fast",
adapter="tvm_ffi")) correctly route to
self.adapter.get_kernel_source/get_host_source; leave the fallback to
self.artifact.kernel_source unchanged.
- Around line 350-403: The _create_adapter_from_database branch rejects
adapter_name=="torch" but Metal-backed JITs resolve to the "torch" adapter;
update _create_adapter_from_database to handle adapter_name == "torch" by
constructing the adapter via MetalKernelAdapter.from_database with the same
params/result_idx/target/func_or_mod/host_kernel_source/device_kernel_source/kernel_lib_path/pass_configs/compile_flags
signature used for other adapters (import MetalKernelAdapter from the
appropriate module where adapters live), so JITKernel.from_database(...,
execution_backend="torch", target="metal") can reconstruct the adapter from the
DB; alternatively, if you prefer rejecting earlier, add a clear early check in
JITKernel.from_database to raise a descriptive error before caching/loading
instead of falling through to the ValueError.

---

Nitpick comments:
In `@tilelang/backend/registry.py`:
- Around line 73-76: The call site in resolve_backend() calls
backend.ensure_callbacks_registered() every time which can re-run non-idempotent
registrar work; make callback registration one-shot by caching successful
registrations keyed by backend name (or a per-backend flag). Modify
resolve_backend() (and/or ensure_callbacks_registered()) to check a module-level
set (e.g., registered_backends) or an attribute on the backend object before
invoking ensure_callbacks_registered(), add the backend.name to that cache after
successful registration, and skip calling ensure_callbacks_registered() on
subsequent resolves for the same backend.

In `@tilelang/cuda/backend.py`:
- Around line 152-159: The two hooks cuda_device_codegen and
cuda_device_codegen_without_compile re-check target type by inspecting
target.keys; replace that raw check with the centralized predicate
_is_cutedsl_target(target) so both functions pick the same cutedsl vs cuda
suffix as other backends; construct the global_func string the same way but use
_is_cutedsl_target(target) to decide between "cutedsl" and "cuda" before passing
it to build_device_with_global_func.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 376e089b-d168-482e-9efe-5f00e6b9cab6

📥 Commits

Reviewing files that changed from the base of the PR and between 4e87322 and 2c641fa.

📒 Files selected for processing (19)
  • testing/python/backend/test_tilelang_backend_registry.py
  • tilelang/backend/README.md
  • tilelang/backend/__init__.py
  • tilelang/backend/backend.py
  • tilelang/backend/codegen.py
  • tilelang/backend/common.py
  • tilelang/backend/registry.py
  • tilelang/cpu/__init__.py
  • tilelang/cpu/backend.py
  • tilelang/cuda/__init__.py
  • tilelang/cuda/backend.py
  • tilelang/engine/lower.py
  • tilelang/jit/adapter/utils.py
  • tilelang/jit/execution_backend.py
  • tilelang/jit/kernel.py
  • tilelang/metal/__init__.py
  • tilelang/metal/backend.py
  • tilelang/rocm/__init__.py
  • tilelang/rocm/backend.py

Comment thread tilelang/backend/backend.py Resolved
Comment thread tilelang/backend/common.py Resolved
Comment thread tilelang/backend/registry.py Resolved
Comment thread tilelang/cuda/backend.py Resolved
Comment thread tilelang/metal/backend.py Resolved
Comment thread tilelang/rocm/backend.py Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@testing/python/backend/test_tilelang_backend_registry.py`:
- Around line 50-61: The test only checks that views are read-only but not that
Backend makes defensive copies of input mappings; update the
test_backend_descriptor_freezes_nested_mappings to keep references to the
original dicts passed into Backend (e.g., features_input and
execution_backends_input), mutate those originals after constructing Backend
(add/remove keys or replace values), and assert backend.features and
backend.execution_backends do not reflect those mutations; if the Backend
implementation is missing defensive copies, modify Backend's constructor to copy
incoming mappings (e.g., copy/deepcopy features and execution_backends) so
external changes to the original dicts cannot mutate the backend descriptor.
- Around line 146-161: The test bypasses the new adapter-key resolution by
directly assigning kernel.adapter and leaving kernel.artifact None; change it to
not inject kernel.adapter and instead set kernel.artifact to contain sources
keyed by the resolved adapter name ("tvm_ffi") so get_kernel_source and
get_host_source exercise the "fast" -> "tvm_ffi" resolution path: leave
execution_backend_spec = ExecutionBackendSpec("fast", adapter="tvm_ffi"), remove
or avoid setting kernel.adapter, set kernel.artifact to a structure that
provides kernel and host sources under the "tvm_ffi" key, then assert
kernel.get_kernel_source(kernel_only=True) and kernel.get_host_source() still
return the expected values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 90e63e1f-9701-47e0-88b9-23e79dc16621

📥 Commits

Reviewing files that changed from the base of the PR and between 2c641fa and 49c36eb.

📒 Files selected for processing (8)
  • testing/python/backend/test_tilelang_backend_registry.py
  • tilelang/backend/README.md
  • tilelang/backend/backend.py
  • tilelang/backend/registry.py
  • tilelang/cuda/backend.py
  • tilelang/engine/lower.py
  • tilelang/jit/kernel.py
  • tilelang/rocm/backend.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • tilelang/rocm/backend.py
  • tilelang/backend/README.md
  • tilelang/engine/lower.py
  • tilelang/jit/kernel.py
  • tilelang/backend/backend.py
  • tilelang/cuda/backend.py
  • tilelang/backend/registry.py

Comment on lines +50 to +61
def test_backend_descriptor_freezes_nested_mappings():
backend = Backend(
"unit-test",
("c",),
features={"feature": lambda target: True},
execution_backends={"fast": ExecutionBackendSpec("fast")},
)

with pytest.raises(TypeError):
backend.features["other"] = lambda target: False
with pytest.raises(TypeError):
backend.execution_backends["slow"] = ExecutionBackendSpec("slow")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Verify defensive copies, not just read-only views.

This only proves writes through backend.features / backend.execution_backends fail. If Backend keeps a proxy over the caller-owned dict, mutating the original mapping after construction still changes the descriptor and this test stays green. Keep handles to the input dicts and assert post-construction mutations do not leak into backend.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@testing/python/backend/test_tilelang_backend_registry.py` around lines 50 -
61, The test only checks that views are read-only but not that Backend makes
defensive copies of input mappings; update the
test_backend_descriptor_freezes_nested_mappings to keep references to the
original dicts passed into Backend (e.g., features_input and
execution_backends_input), mutate those originals after constructing Backend
(add/remove keys or replace values), and assert backend.features and
backend.execution_backends do not reflect those mutations; if the Backend
implementation is missing defensive copies, modify Backend's constructor to copy
incoming mappings (e.g., copy/deepcopy features and execution_backends) so
external changes to the original dicts cannot mutate the backend descriptor.

Comment on lines +146 to +161
def test_jit_source_helpers_use_resolved_adapter_key():
class FakeAdapter:
def get_kernel_source(self, kernel_only=True):
return f"kernel:{kernel_only}"

def get_host_source(self):
return "host"

kernel = JITKernel.__new__(JITKernel)
kernel.execution_backend = "fast"
kernel.execution_backend_spec = ExecutionBackendSpec("fast", adapter="tvm_ffi")
kernel.adapter = FakeAdapter()
kernel.artifact = None

assert kernel.get_kernel_source(kernel_only=True) == "kernel:True"
assert kernel.get_host_source() == "host"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

This bypasses the adapter-key lookup path the PR is changing.

Because kernel.adapter is injected directly and kernel.artifact is None, these assertions still pass if the helpers ignore execution_backend_spec.adapter entirely. To catch regressions in the new "fast" -> "tvm_ffi" resolution path, populate kernel.artifact with sources keyed only by the resolved adapter name and assert get_kernel_source() / get_host_source() still succeed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@testing/python/backend/test_tilelang_backend_registry.py` around lines 146 -
161, The test bypasses the new adapter-key resolution by directly assigning
kernel.adapter and leaving kernel.artifact None; change it to not inject
kernel.adapter and instead set kernel.artifact to contain sources keyed by the
resolved adapter name ("tvm_ffi") so get_kernel_source and get_host_source
exercise the "fast" -> "tvm_ffi" resolution path: leave execution_backend_spec =
ExecutionBackendSpec("fast", adapter="tvm_ffi"), remove or avoid setting
kernel.adapter, set kernel.artifact to a structure that provides kernel and host
sources under the "tvm_ffi" key, then assert
kernel.get_kernel_source(kernel_only=True) and kernel.get_host_source() still
return the expected values.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tilelang/backend/README.md (1)

79-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the WebGPU descriptor location.

The layout shows tilelang/<backend>/backend.py for every backend. This PR defines webgpu_backend in tilelang/backend/common.py. Add a WebGPU exception to the layout, or move the descriptor to tilelang/webgpu/backend.py.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tilelang/backend/README.md` around lines 79 - 85, Update the backend layout
documentation to explicitly identify the WebGPU descriptor exception in
tilelang/backend/common.py, or relocate webgpu_backend to
tilelang/webgpu/backend.py and update the layout accordingly; ensure the
documented location matches the implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@testing/python/jit/test_tilelang_jit_diagnostics.py`:
- Around line 197-200: Disable CUDA binary caching around the
_tilelang_callback_cuda_compile invocation in this test so CUDABinaryCache.load
cannot bypass fake_compile_cuda. Preserve the existing fake compiler assertion
and target setup, ensuring captured["target_format"] is populated
deterministically.

In `@tilelang/backend/pipeline.py`:
- Around line 95-96: Update the error message string near the format validation
in the pipeline code so there is a space before the example parenthesis and the
period follows the closing parenthesis, producing correct punctuation without
changing the message content.

---

Nitpick comments:
In `@tilelang/backend/README.md`:
- Around line 79-85: Update the backend layout documentation to explicitly
identify the WebGPU descriptor exception in tilelang/backend/common.py, or
relocate webgpu_backend to tilelang/webgpu/backend.py and update the layout
accordingly; ensure the documented location matches the implementation.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d29be022-fe62-4586-ac34-839f33745e1d

📥 Commits

Reviewing files that changed from the base of the PR and between 99421b7 and 2ef60f7.

📒 Files selected for processing (47)
  • testing/python/backend/test_tilelang_backend_registry.py
  • testing/python/cache/test_tilelang_cuda_binary_cache.py
  • testing/python/debug/test_lower_trace.py
  • testing/python/jit/test_tilelang_jit_diagnostics.py
  • testing/python/llvm/test_tilelang_llvm_while_repro.py
  • testing/python/target/test_tilelang_target.py
  • testing/python/transform/test_tilelang_transform_verify_parallel_loop.py
  • testing/python/webgpu/test_webgpu_codegen.py
  • tilelang/backend/README.md
  • tilelang/backend/__init__.py
  • tilelang/backend/backend.py
  • tilelang/backend/codegen.py
  • tilelang/backend/common.py
  • tilelang/backend/device_codegen.py
  • tilelang/backend/execution_backend.py
  • tilelang/backend/host_codegen.py
  • tilelang/backend/pass_pipeline/__init__.py
  • tilelang/backend/pass_pipeline/pipeline.py
  • tilelang/backend/pipeline.py
  • tilelang/cache/__init__.py
  • tilelang/contrib/hipcc.py
  • tilelang/cpu/__init__.py
  • tilelang/cpu/backend.py
  • tilelang/cpu/codegen.py
  • tilelang/cpu/execution_backend.py
  • tilelang/cpu/pipeline.py
  • tilelang/cuda/__init__.py
  • tilelang/cuda/backend.py
  • tilelang/cuda/codegen.py
  • tilelang/cuda/execution_backend.py
  • tilelang/cuda/pipeline.py
  • tilelang/engine/lower.py
  • tilelang/jit/kernel.py
  • tilelang/metal/__init__.py
  • tilelang/metal/backend.py
  • tilelang/metal/codegen.py
  • tilelang/metal/execution_backend.py
  • tilelang/metal/pipeline.py
  • tilelang/rocm/__init__.py
  • tilelang/rocm/backend.py
  • tilelang/rocm/codegen.py
  • tilelang/rocm/execution_backend.py
  • tilelang/rocm/pipeline.py
  • tilelang/tools/lower_trace/core.py
  • tilelang/webgpu/__init__.py
  • tilelang/webgpu/codegen.py
  • tilelang/webgpu/pipeline.py
💤 Files with no reviewable changes (19)
  • tilelang/webgpu/codegen.py
  • tilelang/metal/execution_backend.py
  • tilelang/backend/pass_pipeline/init.py
  • tilelang/rocm/codegen.py
  • tilelang/cuda/codegen.py
  • tilelang/rocm/execution_backend.py
  • tilelang/backend/host_codegen.py
  • tilelang/rocm/init.py
  • tilelang/cpu/execution_backend.py
  • tilelang/metal/init.py
  • tilelang/contrib/hipcc.py
  • tilelang/backend/pass_pipeline/pipeline.py
  • tilelang/cuda/init.py
  • tilelang/metal/codegen.py
  • tilelang/cuda/execution_backend.py
  • tilelang/backend/init.py
  • tilelang/backend/device_codegen.py
  • tilelang/cpu/codegen.py
  • tilelang/cpu/init.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • tilelang/rocm/backend.py
  • tilelang/cuda/backend.py
  • tilelang/engine/lower.py
  • tilelang/jit/kernel.py

Comment on lines +197 to +200
monkeypatch.setattr(cuda_backend.nvcc, "compile_cuda", fake_compile_cuda)

target = determine_target({"kind": "cuda", "arch": "sm_100f", "code": ["sm_100a", "sm_103a"]}, return_object=True)
lower.tilelang_callback_cuda_compile("__global__ void kernel() {}", target)
cuda_backend._tilelang_callback_cuda_compile("__global__ void kernel() {}", target)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline testing/python/jit/test_tilelang_jit_diagnostics.py --items all
rg -n -C 4 'CUDABinaryCache|TILELANG_DISABLE_CACHE|enable_cache|disable_cache|test_cuda_compile_callback_uses_fatbin' \
  testing/python/jit/test_tilelang_jit_diagnostics.py tilelang/cache

Repository: tile-ai/tilelang

Length of output: 6138


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== test snippet ==="
sed -n '161,206p' testing/python/jit/test_tilelang_jit_diagnostics.py

echo "=== cuda_binary_cache relevant methods ==="
sed -n '1,180p' tilelang/cache/cuda_binary_cache.py

echo "=== tilelang cache disable/enable symbols and usages ==="
rg -n 'disable_cache|enable_cache|CUDABinaryCache|_tilelang_callback_cuda_compile|compile_cuda' tilelang testing/python/jit/test_tilelang_jit_diagnostics.py

Repository: tile-ai/tilelang

Length of output: 11356


Disable CUDA binary caching for this fake-NVCC assertion.

_tilelang_callback_cuda_compile() calls CUDABinaryCache.load() before running the patched compiler. If a matching cache file exists, fake_compile_cuda() is skipped and captured["target_format"] raises KeyError; disable the cache around this callback call unless this test intentionally covers the cache path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@testing/python/jit/test_tilelang_jit_diagnostics.py` around lines 197 - 200,
Disable CUDA binary caching around the _tilelang_callback_cuda_compile
invocation in this test so CUDABinaryCache.load cannot bypass fake_compile_cuda.
Preserve the existing fake compiler assertion and target setup, ensuring
captured["target_format"] is populated deterministically.

Comment thread tilelang/backend/pipeline.py Outdated
Comment on lines +95 to +96
"You can choose one of the valid formats or a comma-separated list of "
"formats.(e.g. 'txt,png,pdf')"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the error-message punctuation.

The message renders formats.(e.g. 'txt,png,pdf'). Add a space before the parenthesis and place the period after the example.

Proposed fix
-            "formats.(e.g. 'txt,png,pdf')"
+            "formats (e.g. 'txt,png,pdf')."
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"You can choose one of the valid formats or a comma-separated list of "
"formats.(e.g. 'txt,png,pdf')"
"You can choose one of the valid formats or a comma-separated list of "
"formats (e.g. 'txt,png,pdf')."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tilelang/backend/pipeline.py` around lines 95 - 96, Update the error message
string near the format validation in the pipeline code so there is a space
before the example parenthesis and the period follows the closing parenthesis,
producing correct punctuation without changing the message content.

@SiriusNEO
SiriusNEO merged commit fef9f76 into tile-ai:main Aug 5, 2026
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant