TileLang → FlyDSL Conversion Skill
What this skill is for
You are translating a kernel written in TileLang (Apache TVM TIR-based,
@T.prim_func decorated, used in tile-ai/tilelang and the TileKernels
operator collection from DeepSeek) into FlyDSL (Python DSL on top of an
MLIR-native fly dialect that targets ROCm/HIP via ROCDL). FlyDSL is a
lower-level kernel authoring surface: tile and thread mappings are explicit,
copies are atom-call based, and GEMMs are emitted through MFMA atoms instead of
a dispatched T.gemm.
Treat the TileLang source as a specification — match its observable
behaviour (input/output shapes, dtypes, math) — and re-derive an equivalent
FlyDSL kernel. Mechanical line-by-line translation rarely works because the two
DSLs sit at different abstraction levels.
When to invoke
Invoke (or load) this skill when any of the following is true:
- The user asks to "port", "convert", "translate", "rewrite" a kernel from
TileLang to FlyDSL, or vice versa references both projects.
- The user references TileKernels (
tile_kernels/...), @T.prim_func,
T.Kernel, T.alloc_shared, etc. and wants the result to land in a FlyDSL
codebase.
- A test in
TileKernels/tests/... must keep passing while the Python wrapper
is re-implemented on top of FlyDSL.
Do not invoke for changes that stay within a single DSL.
Operating constraint: no execution
This skill assumes that you cannot build or run either project from this
environment (no GPU, neither tilelang nor flydsl is necessarily installed).
That means:
- Validation is review-based, not test-based. Use the workflow in
references/workflow.md and the gotcha list in references/gotchas.md to
audit each converted kernel before declaring it complete.
- Never claim "tests pass" or "kernel verified" unless the user has actually
run them and shared the output.
- When a behavioural ambiguity blocks progress, surface it to the user as a
question rather than guessing.
Mental model — the four hard problems
Every TileLang→FlyDSL conversion reduces to four sub-problems. Solve them in
order:
- Launch shape. Translate
with T.Kernel(gx, gy, gz, threads=N) as (pid_x, pid_y, pid_z): into a @flyc.jit host function that calls
kernel(...).launch(grid=(gx, gy, gz), block=(N, 1, 1), stream=stream),
plus bid = fx.block_idx.{x,y,z} and tid = fx.thread_idx.x reads inside
the @flyc.kernel body. Multi-dim block (threads=(tx, ty)) is rare in
TileKernels but does occur — preserve it.
- Memory map. Map every
T.alloc_* to its FlyDSL counterpart:
alloc_shared → SmemAllocator.allocate_array (with finalize() in the
jit body), alloc_local/alloc_fragment → fx.memref_alloca with a
register-space memref type, scalar alloc_var(init=v) → a Python value
threaded through range(..., init=[...]) if it must be loop-carried,
otherwise just a normal Float/Int variable.
- Loop nest. Map
T.Parallel, T.serial, T.unroll, T.vectorized,
T.Pipelined (see references/api_mapping.md row "Loops"). The trickiest
one is T.Parallel — it has no direct FlyDSL counterpart and you must
thread-distribute by hand using tid arithmetic or a tiled copy.
- Data movement.
T.copy(global, shared) and T.copy(shared, global)
call sites become tiled copies in FlyDSL: fx.rocdl.make_buffer_tensor →
zipped_divide/logical_divide → make_tiled_copy(...) →
thr_copy.partition_S/D → fx.copy(copy_atom, ...). A literal
arr[i, j] = ... write becomes a single fx.copy_atom_call(...) with a
one-element register memref, or — when many threads write contiguously —
the same tiled copy machinery.
The compute body in between (arithmetic, reductions, control flow) usually
maps cleanly once 1–4 are in place.
Workflow
Follow references/workflow.md step-by-step on each kernel. The high-level
loop is:
- Read the TileLang source end-to-end. Note the kernel signature, every
T.alloc_*, every T.copy / T.gemm, every loop kind, every reduction.
Identify what is constexpr vs runtime dynamic.
- Read the test that calls it. The Python wrapper signature
(
transpose(x: torch.Tensor), topk_gate(scores, num_topk), ...) is the
contract you must preserve. The test imports
tile_kernels.<module>.<func> and compares against a reference. Keep the
wrapper, replace the JIT factory body.
- Sketch the FlyDSL skeleton using
references/idioms.md for the closest
matching pattern (elementwise / reduction / shared-mem rearrange / GEMM).
- Fill in compute, copy, and reduction blocks. Use
references/api_mapping.md
as a translation dictionary, but do not blindly inline — re-derive the
thread-to-data mapping each time.
- Audit against
references/gotchas.md. Run through every entry; each
one is something the agent has gotten wrong before.
- Report status. Tell the user exactly which review checks you completed
and which require GPU execution to verify.
Reference files
Read these on demand — they are organised as quick lookups, not narrative:
references/api_mapping.md — comprehensive symbol table:
every T.* primitive used in TileKernels paired with its FlyDSL spelling.
references/idioms.md — side-by-side patterns for the five kernel
archetypes: elementwise/cast, reduction (norm / softmax / topk),
shared-memory rearrange (transpose), GEMM, fused
copy+compute+reduce.
references/gotchas.md — pitfalls and review checklist. Read before
declaring a conversion done.
references/workflow.md — the procedure to follow per kernel, including
how to handle the "I cannot run it" constraint with a static review pass.
references/worked_examples/normalize_weight.md — full conversion of a
small reduction kernel (tile_kernels/moe/normalize_weight_kernel.py).
references/worked_examples/batched_transpose.md — full conversion of a
shared-memory rearrange kernel (tile_kernels/transpose/...).
references/worked_examples/gemm_skeleton.md — annotated FlyDSL GEMM
skeleton you can adapt when a TileLang kernel uses T.gemm.
Project structure assumptions
The skill is portable. When applying to a new project, locate these things in
the target codebase rather than assuming the paths from the worked examples:
- TileLang sources usually live at
<repo>/tilelang/tilelang/language/...
if vendored, otherwise tilelang is just a pip dependency. Public surface
is from tilelang import language as T.
- FlyDSL Python expression API is at
<flydsl-checkout>/python/flydsl/expr/{primitive,gpu,buffer_ops,rocdl,vector,math,numeric,typing}.py.
- FlyDSL pre-built kernels at
<flydsl-checkout>/kernels/*.py are the most
reliable references for production patterns (softmax_kernel.py and
rmsnorm_kernel.py are the closest to TileKernels-style elementwise+reduction
kernels; preshuffle_gemm.py is the closest to GEMM).
When asked to convert an unfamiliar TileKernels kernel, default to:
Read the TileLang source.
Read the matching test under TileKernels/tests/<module>/test_<name>.py.
Grep <flydsl>/kernels/ for an analogous existing FlyDSL kernel and
Read it as a structural template.
- Then proceed with the workflow above.
1---2name: tilelang-to-flydsl3description: Port a kernel written in TileLang (the `@T.prim_func` / `with T.Kernel(...)` DSL used by TileKernels and other tile-ai projects) into an equivalent FlyDSL kernel (`@flyc.kernel` / `@flyc.jit` with explicit layout algebra, copy atoms, MMA atoms, and SmemAllocator). Use whenever the task is to rewrite, translate, or migrate a TileLang `@T.prim_func` body into FlyDSL, including converting individual operators in the TileKernels test suite while preserving the Python wrapper signatures so the existing pytest cases keep validating the new implementation.4---56# TileLang → FlyDSL Conversion Skill78## What this skill is for910You are translating a kernel written in **TileLang** (Apache TVM TIR-based,11`@T.prim_func` decorated, used in `tile-ai/tilelang` and the `TileKernels`12operator collection from DeepSeek) into **FlyDSL** (Python DSL on top of an13MLIR-native `fly` dialect that targets ROCm/HIP via ROCDL). FlyDSL is a14*lower-level* kernel authoring surface: tile and thread mappings are explicit,15copies are atom-call based, and GEMMs are emitted through MFMA atoms instead of16a dispatched `T.gemm`.1718Treat the TileLang source as a **specification** — match its observable19behaviour (input/output shapes, dtypes, math) — and re-derive an equivalent20FlyDSL kernel. Mechanical line-by-line translation rarely works because the two21DSLs sit at different abstraction levels.2223## When to invoke2425Invoke (or load) this skill when any of the following is true:2627- The user asks to "port", "convert", "translate", "rewrite" a kernel from28 TileLang to FlyDSL, or vice versa references both projects.29- The user references TileKernels (`tile_kernels/...`), `@T.prim_func`,30 `T.Kernel`, `T.alloc_shared`, etc. and wants the result to land in a FlyDSL31 codebase.32- A test in `TileKernels/tests/...` must keep passing while the Python wrapper33 is re-implemented on top of FlyDSL.3435Do **not** invoke for changes that stay within a single DSL.3637## Operating constraint: no execution3839This skill assumes that you cannot build or run either project from this40environment (no GPU, neither `tilelang` nor `flydsl` is necessarily installed).41That means:4243- Validation is **review-based**, not test-based. Use the workflow in44 `references/workflow.md` and the gotcha list in `references/gotchas.md` to45 audit each converted kernel before declaring it complete.46- Never claim "tests pass" or "kernel verified" unless the user has actually47 run them and shared the output.48- When a behavioural ambiguity blocks progress, surface it to the user as a49 question rather than guessing.5051## Mental model — the four hard problems5253Every TileLang→FlyDSL conversion reduces to four sub-problems. Solve them in54order:55561. **Launch shape.** Translate `with T.Kernel(gx, gy, gz, threads=N) as57 (pid_x, pid_y, pid_z):` into a `@flyc.jit` host function that calls58 `kernel(...).launch(grid=(gx, gy, gz), block=(N, 1, 1), stream=stream)`,59 plus `bid = fx.block_idx.{x,y,z}` and `tid = fx.thread_idx.x` reads inside60 the `@flyc.kernel` body. Multi-dim block (`threads=(tx, ty)`) is rare in61 TileKernels but does occur — preserve it.622. **Memory map.** Map every `T.alloc_*` to its FlyDSL counterpart:63 `alloc_shared` → `SmemAllocator.allocate_array` (with `finalize()` in the64 jit body), `alloc_local`/`alloc_fragment` → `fx.memref_alloca` with a65 register-space memref type, scalar `alloc_var(init=v)` → a Python value66 threaded through `range(..., init=[...])` if it must be loop-carried,67 otherwise just a normal Float/Int variable.683. **Loop nest.** Map `T.Parallel`, `T.serial`, `T.unroll`, `T.vectorized`,69 `T.Pipelined` (see `references/api_mapping.md` row "Loops"). The trickiest70 one is `T.Parallel` — it has *no direct* FlyDSL counterpart and you must71 thread-distribute by hand using `tid` arithmetic or a tiled copy.724. **Data movement.** `T.copy(global, shared)` and `T.copy(shared, global)`73 call sites become tiled copies in FlyDSL: `fx.rocdl.make_buffer_tensor` →74 `zipped_divide`/`logical_divide` → `make_tiled_copy(...)` →75 `thr_copy.partition_S/D` → `fx.copy(copy_atom, ...)`. A literal76 `arr[i, j] = ...` write becomes a single `fx.copy_atom_call(...)` with a77 one-element register memref, or — when many threads write contiguously —78 the same tiled copy machinery.7980The compute body in between (arithmetic, reductions, control flow) usually81maps cleanly once 1–4 are in place.8283## Workflow8485Follow `references/workflow.md` step-by-step on each kernel. The high-level86loop is:87881. **Read the TileLang source end-to-end.** Note the kernel signature, every89 `T.alloc_*`, every `T.copy` / `T.gemm`, every loop kind, every reduction.90 Identify what is *constexpr* vs *runtime dynamic*.912. **Read the test that calls it.** The Python wrapper signature92 (`transpose(x: torch.Tensor)`, `topk_gate(scores, num_topk)`, ...) is the93 contract you must preserve. The test imports94 `tile_kernels.<module>.<func>` and compares against a reference. Keep the95 wrapper, replace the JIT factory body.963. **Sketch the FlyDSL skeleton** using `references/idioms.md` for the closest97 matching pattern (elementwise / reduction / shared-mem rearrange / GEMM).984. **Fill in compute, copy, and reduction blocks.** Use `references/api_mapping.md`99 as a translation dictionary, but do not blindly inline — re-derive the100 thread-to-data mapping each time.1015. **Audit against `references/gotchas.md`.** Run through every entry; each102 one is something the agent has gotten wrong before.1036. **Report status.** Tell the user exactly which review checks you completed104 and which require GPU execution to verify.105106## Reference files107108Read these on demand — they are organised as quick lookups, not narrative:109110- `references/api_mapping.md` — comprehensive symbol table:111 every `T.*` primitive used in TileKernels paired with its FlyDSL spelling.112- `references/idioms.md` — side-by-side patterns for the five kernel113 archetypes: elementwise/cast, reduction (norm / softmax / topk),114 shared-memory rearrange (transpose), GEMM, fused115 copy+compute+reduce.116- `references/gotchas.md` — pitfalls and review checklist. Read **before**117 declaring a conversion done.118- `references/workflow.md` — the procedure to follow per kernel, including119 how to handle the "I cannot run it" constraint with a static review pass.120- `references/worked_examples/normalize_weight.md` — full conversion of a121 small reduction kernel (`tile_kernels/moe/normalize_weight_kernel.py`).122- `references/worked_examples/batched_transpose.md` — full conversion of a123 shared-memory rearrange kernel (`tile_kernels/transpose/...`).124- `references/worked_examples/gemm_skeleton.md` — annotated FlyDSL GEMM125 skeleton you can adapt when a TileLang kernel uses `T.gemm`.126127## Project structure assumptions128129The skill is portable. When applying to a new project, locate these things in130the target codebase rather than assuming the paths from the worked examples:131132- TileLang sources usually live at `<repo>/tilelang/tilelang/language/...`133 if vendored, otherwise `tilelang` is just a pip dependency. Public surface134 is `from tilelang import language as T`.135- FlyDSL Python expression API is at136 `<flydsl-checkout>/python/flydsl/expr/{primitive,gpu,buffer_ops,rocdl,vector,math,numeric,typing}.py`.137- FlyDSL pre-built kernels at `<flydsl-checkout>/kernels/*.py` are the most138 reliable references for production patterns (softmax_kernel.py and139 rmsnorm_kernel.py are the closest to TileKernels-style elementwise+reduction140 kernels; preshuffle_gemm.py is the closest to GEMM).141142When asked to convert an unfamiliar TileKernels kernel, default to:1431441. `Read` the TileLang source.1452. `Read` the matching test under `TileKernels/tests/<module>/test_<name>.py`.1463. `Grep` `<flydsl>/kernels/` for an analogous existing FlyDSL kernel and147 `Read` it as a structural template.1484. Then proceed with the workflow above.