Skip to main content

flydsl-kernel-authoring

Comprehensive reference for authoring FlyDSL GPU kernels on AMD GPUs. Covers the layout algebra, tiled copy/MMA, buffer ops, loop-carried range loops, SharedAllocator (LDS), autotuning, and common patterns. Use when writing, reviewing, or understanding FlyDSL kernel code.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
ROCm/FlyDSL
آخر نشاط في المصدر
١ سبتمبر ٢٠٢٦ في ١٤:٣٤
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢٨٠
التفرعات
١٢١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
flydsl-kernel-authoring
description
Comprehensive reference for authoring FlyDSL GPU kernels on AMD GPUs. Covers the layout algebra, tiled copy/MMA, buffer ops, loop-carried range loops, SharedAllocator (LDS), autotuning, and common patterns. Use when writing, reviewing, or understanding FlyDSL kernel code.
allowed-tools
Read Edit Bash Grep Glob Agent
# FlyDSL Kernel Authoring Skill ## Overview FlyDSL is a Python DSL and MLIR-based compiler for writing high-performance GPU kernels on AMD GPUs (MI300X/MI350). It provides explicit layout algebra for controlling data movement, tiling, and memory access patterns. The layout system is the core abstraction that distinguishes FlyDSL from Triton/Gluon. **Repository**: this checkout (examples below assume it is importable — see 12) **Target GPU**: gfx942 (MI300X, CDNA3), gfx950 (MI350, CDNA4) **Python**: 3.12, ROCm 7.2 **Scope (read this first)**: This skill is the **reference** — the full layout-algebra API surface, per-op tables, MFMA/copy-atom catalogs, environment variables, and an exhaustive troubleshooting list. Reach for it to *look something up* while writing or reviewing kernel code. If instead you want a *guided, step-by-step procedure* that turns a kernel requirement into a finished, tested kernel (classify -> skeleton -> compute -> control flow -> test), use the **flydsl-tile-programming** skill, which is the wizard companion to this reference. For diagnosing a kernel that already compiles but produces NaN/inf/wrong results, use the **debug-flydsl-kernel** skill. --- ## 1. Architecture and Compilation ### Pipeline ``` Python (@flyc.kernel/@flyc.jit) -> AST Rewriting (for/if -> scf.for/scf.if) -> MLIR Tracing (generates Fly dialect + gpu/arith/scf/memref/vector ops) -> MlirCompiler.compile() (Fly -> ROCDL -> LLVM -> HSACO binary) -> JITCFunction (ExecutionEngine wrapper) ``` ### Key Passes Pipeline is built by `RocmBackend._pipeline_parts()` and split into three stages — see `docs/architecture_guide.md` §3 for the per-pass table. Highlights: 1. `fly-rewrite-func-signature` - Rewrite DSL types at function / SCF boundaries to packed LLVM structs 2. `fly-layout-lowering` - Lower layout algebra (`fly.crd2idx`, partitions, divides) to arithmetic 3. `fly-convert-atom-call-to-ssa-form` + `fly-promote-regmem-to-vectorssa` - Lift copy/MMA atom calls and register memory to vector SSA 4. `convert-fly-to-rocdl` - Fly ops -> ROCDL intrinsics 5. `gpu-module-to-binary{format=fatbin}` - Emit HSACO binary via LLVM AMDGPU backend ### Key Source Paths - `python/flydsl/compiler/` - JIT compilation (jit_function.py, kernel_function.py) - `python/flydsl/expr/` - DSL expression API (primitive.py, derived.py, typing.py) - `python/flydsl/expr/primitive.py` - All layout algebra functions - `python/flydsl/expr/derived.py` - CopyAtom, MmaAtom, TiledCopy, TiledMma wrappers - `python/flydsl/expr/gpu.py` - GPU operations (thread_idx, block_idx, barrier) - `python/flydsl/expr/rocdl/` - MFMA/WMMA and other ROCm intrinsics (package: cdna3, cdna4, cdna5, rdna3, rdna4, cluster, inline_asm, tdm_ops, universal; plus `utils.py` / `enum.py` helpers) - `python/flydsl/expr/gpu.py` - `SharedAllocator` for LDS (shared memory), `thread_id`/`block_id`, `barrier` - `python/flydsl/utils/smem_allocator.py` - legacy `SmemAllocator` (un-migrated kernels only) - `kernels/common/buffer_ops.py` - legacy raw AMD buffer load/store intrinsics (moved out of `flydsl.expr` in #880; prefer `fx.rocdl.make_buffer_tensor`) - `kernels/` - Pre-built kernels, organized into subpackages: `gemm/` (preshuffle_gemm.py, mxfp4_preshuffle.py, ...), `norm/` (layernorm/softmax/rmsnorm), `attention/`, `moe/`, `mega_moe/`, `common/` (incl. `common/mma/`), `comm/`, `conv/` --- ## 2. Layout System (Core Abstraction) ### Core Types | Type | Description | Example | |------|-------------|---------| | `!fly.int_tuple` | Integer tuple (can be nested) | `(8, 16)`, `(8, (4, 2))` | | `!fly.layout` | (Shape, Stride) pair | `(8, 16):(1, 8)` (col-major) | | `!fly.memref` | Memory reference with layout | Typed pointer + layout info | ### Construction ```python import flydsl.expr as fx shape = fx.make_shape(8, 16) # IntTuple (8, 16) stride = fx.make_stride(1, 8) # IntTuple (1, 8) layout = fx.make_layout(shape, stride) # Layout (8,16):(1,8) # Shorthand with Python tuples layout = fx.make_layout((8, 16), (1, 8)) # Coordinates coord = fx.make_coord(i, j) # Nested shapes for hierarchical tiling shape_nested = fx.make_shape(9, (4, 8)) # (9, (4, 8)) # Identity layout identity = fx.make_identity_layout((M, N)) ``` ### Coordinate Mapping The fundamental operation maps logical coordinates to physical memory indices. **Formula**: `Index = sum(coord_i * stride_i)` ```python idx = fx.crd2idx(coord, layout) # Coordinate -> linear index coord = fx.idx2crd(idx, layout) # Linear index -> coordinate s = fx.size(layout) # Total element count (product of shape) ``` **Example**: For layout `(8, 16):(1, 8)` (8x16, column-major): - `crd2idx((3, 5), layout)` = `3*1 + 5*8` = 43 - `idx2crd(43, layout)` = `(43 % 8, 43 / 8)` = `(3, 5)` ### Query Operations ```python fx.size(layout) # Total element count fx.get_shape(layout) # Extract shape IntTuple fx.get_stride(layout) # Extract stride IntTuple fx.get(int_tuple, i) # Get i-th element fx.rank(int_tuple) # Number of top-level modes ``` ### Layout Algebra Operations #### Composition: `fx.composition(A, B)` Compose two layouts: `result(x) = A(B(x))`. Used to apply permutations or tile coordinate mappings. #### Complement: `fx.complement(tiler, target_size)` Compute remaining modes not covered by tiler, up to target_size. Internal building block for divides. #### Coalesce: `fx.coalesce(layout)` Simplify layout by merging adjacent modes. Preserves mapping but flattens structure. #### Right Inverse: `fx.right_inverse(layout)` Compute right inverse of layout mapping. #### Recast: `fx.recast_layout(layout, old_bits, new_bits)` Adjust layout for type width change (e.g., FP16->FP8). ### Product Operations (Combine Layouts) Products combine two layouts to create a larger layout: ```python fx.logical_product(layout, tiler) # Basic mode-wise concatenation fx.raked_product(thr, val) # Interleaved access pattern (see make_layout_tv for TV layouts) fx.blocked_product(layout, tiler) # Blocked access pattern fx.zipped_product(layout, tiler) # Zipped modes fx.tiled_product(layout, tiler) # Hierarchical tiled structure fx.flat_product(layout, tiler) # Flattened result ``` ### Divide Operations (Partition Layouts) Divides split a layout by a divisor, creating tile + rest dimensions: ```python fx.logical_divide(layout, divisor) # Basic partitioning (uses complement internally) fx.zipped_divide(layout, divisor) # Zipped division fx.tiled_divide(layout, divisor) # Hierarchical tiled division fx.flat_divide(layout, divisor) # Flattened division ``` ### Structural Operations ```python fx.select(int_tuple, indices=[0, 2]) # Pick specific modes fx.group(int_tuple, begin=1, end=3) # Group modes into nested tuple fx.append(base, elem) # Append mode fx.prepend(base, elem) # Prepend mode fx.slice(src, coord) # Slice at coordinate (None = keep mode) ``` --- ## 3. Writing Kernels ### Basic Pattern ```python import flydsl.compiler as flyc import flydsl.expr as fx from flydsl.expr import const_expr, gpu, range_constexpr, rocdl @flyc.kernel def my_kernel( A: fx.Tensor, # GPU tensor (memref via DLPack) B: fx.Tensor, N: fx.Constexpr[int], # Compile-time constant ): tid = gpu.thread_id("x") bid = gpu.block_id("x") # ... kernel body ... @flyc.jit def launch( A: fx.Tensor, B: fx.Tensor, N: fx.Constexpr[int], stream: fx.Stream = fx.Stream(None), ): my_kernel(A, B, N).launch( grid=(N // 256,), block=(256,), stream=stream ) # Usage: import torch A = torch.randn(1024, device="cuda", dtype=torch.float32) B = torch.empty(1024, device="cuda", dtype=torch.float32) launch(A, B, 1024) ``` ### Current Syntax Quick Reference Use the current public FlyDSL surface from `kernels/gemm/preshuffle_gemm.py` when writing new kernels: ```python Vec = fx.Vector tx = gpu.thread_id("x") bx = gpu.block_id("x") by = gpu.block_id("y") i32_m: fx.Int32 c_m = fx.Int64(i32_m) c4 = fx.Int64(4) zero_f = fx.Float32(0.0) layout = fx.make_layout((4, 64), (64, 1)) coord = fx.idx2crd(tx, layout) wave_id = fx.get(coord, 0) lane_id = fx.get(coord, 1) acc = Vec.filled(4, 0.0, fx.Float32) v_i64 = Vec(raw_vec).bitcast(fx.Int64) elem0 = v_i64[0] buf = fx.rocdl.make_buffer_tensor(tensor) # preferred buffer-resource view tA = fx.make_view(fx.get_iter(buf), fx.make_layout((M, N), (N, 1))) # load/store tA via copy atoms (fx.copy); the raw buffer intrinsics are legacy ``` Older code may use `gpu.thread_idx.x`, `gpu.block_idx.x`, `arith.constant(...)`, `T.i32`, raw `vector.*` helpers, the `ArithValue` wrapper, and `buffer_ops`. Keep those when editing existing code that already uses them heavily, but prefer `gpu.thread_id/block_id`, `fx.Int64`/`fx.Int32`/`fx.Float32`, `fx.Vector`, and `fx.rocdl.make_buffer_tensor` for new code. `ArithValue`, `fx.Index`, and `buffer_ops` are deprecated/legacy — for migrating an existing kernel see the **kernel-code-cleanup** skill. ### Parameter Types | Type | Description | At host boundary | |------|-------------|-----------------| | `fx.Tensor` | GPU tensor (memref) | Auto-converted from torch.Tensor via DLPack | | `fx.Constexpr[int]` | Compile-time constant | Different values -> different compiled kernels | | `fx.Int32` | Runtime i32 | Auto-converted from Python int | | `fx.Stream` | CUDA/HIP stream | `fx.Stream(None)` for default stream | ### Thread/Block Hierarchy ```python from flydsl.expr import gpu tid_x = gpu.thread_id("x") # Preferred current spelling bid_x = gpu.block_id("x") bid_y = gpu.block_id("y") # Legacy spelling still appears in older kernels: tid_x = gpu.thread_idx.x bid_x = gpu.block_idx.x gpu.barrier() # Workgroup synchronization ``` ### Control Flow ```python from flydsl.expr import range_constexpr # Compile-time unrolled loop (emitted inline in IR) for i in range_constexpr(N): ... # Runtime loop (lowered by AST rewriting) for i in range(runtime_value): ... ``` ### Runtime vs Compile-Time Conditions (Current Style) Use Python/DSL operators for runtime SSA comparisons. The AST rewriter lowers dynamic `if` conditions to `scf.IfOp`, and comparison operators like `==`, `<`, `>=` generate the needed MLIR predicates. ```python tid = gpu.thread_id("x") lane = tid % fx.Int64(64) c_zero = fx.Int64(0) c_limit = fx.Int64(8) # Preferred: readable DSL comparisons if lane == c_zero: ... in_range = lane < c_limit val = fx.arith.select(in_range, good_val, zero_val) # Avoid for simple integer comparisons in_range = arith.cmpi(arith.CmpIPredicate.slt, lane, c_limit) ``` Use `const_expr(...)` only for values known at trace/compile time, such as Python booleans, constexpr arguments, loop-unroll choices, or type/layout branches: ```python if const_expr(trans_v): ... if const_expr(max_context_partition_num <= WARP_SIZE): ... ```
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub