Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 0 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ cmake-build-*/
# GPU core dumps
gpucore.*

# IR dumps
my_ir_dumps*/

# git
*.log
*.diff
Expand Down Expand Up @@ -66,8 +63,6 @@ docs/_build/
python/flydsl/_mlir

# Benchmark/accuracy CSVs emitted by tests/kernels harnesses
fmha_perf_*.csv
run_pa_decode_ps_test.*.csv
.humanize/

# rocprofv3 raw counter/trace output
Expand Down
26 changes: 22 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ FlyDSL/
│ └── mlir_flydsl/ # MLIR Python binding package source
├── include/flydsl/ # C++ TableGen headers for Fly / FlyROCDL dialects and passes
├── lib/ # C++ dialect implementation, conversions, runtime wrappers, Python bindings
│ └── Dialect/FlyROCDL/{CDNA3,CDNA4,GFX11,GFX120X,GFX1250}/ # Per-subtarget atom lowering: MmaAtom (MFMA on CDNA3/4, WMMA on GFX11/120X/1250) + CopyAtom (Buffer/LDS, CDNA3/4 only; TDM on GFX1250)
│ ├── Dialect/FlyROCDL/{CDNA3,CDNA4,...}/ # Per-subtarget atom lowering: MmaAtom (MFMA on CDNA3/4, WMMA on GFX11/120X/1250) + CopyAtom (Buffer/LDS, CDNA3/4 only; TDM on GFX1250)
│ └── Dialect/FlyNVVM/{SM80, ...}/ # NVIDIA atom lowering: mma.sync.aligned, cp.async, ldmatrix (nvvm backend only)
├── tools/ # fly-opt
├── kernels/ # Production kernels, importable as kernels.*
├── tests/
Expand All @@ -67,7 +68,9 @@ FlyDSL/
│ ├── system/ # Cross-cutting compile/system tests
│ ├── mlir/ # FileCheck tests driven by scripts/run_tests.sh
│ └── python/examples/ # AOT compile/cache pytest tests (aot_example.py)
├── examples/ # 01-vectorAdd, 02-tiledCopy, 03-tiledMma, 04-preshuffle_gemm
├── examples/ # Target-neutral, run on every backend
│ ├── rocm/ # AMD ROCm only
│ └── cuda/ # NVIDIA CUDA only
├── scripts/ # build, test, benchmark, wheel, debug helper scripts
├── docs/ # Sphinx documentation source
├── thirdparty/ # Vendored dlpack and tvm-ffi
Expand Down Expand Up @@ -95,9 +98,13 @@ Public docs are deployed from `.github/workflows/docs.yml` to

```bash
bash scripts/build_llvm.sh -j64 # Build LLVM/MLIR once
bash scripts/build.sh -j64 # Build FlyDSL C++ + Python bindings
bash scripts/build.sh -j64 # Build FlyDSL C++ + Python bindings (rocdl backend)
pip install -e . # Editable Python install

# Backend selection (CMake cache var FLYDSL_BACKENDS; default "rocdl").
# One backend per build for now; a combined "rocdl;nvvm" build is not supported yet.
FLYDSL_BACKENDS="nvvm" bash scripts/build.sh -j64 # NVIDIA instead of AMD (needs a CUDA toolkit)

# If not relying on editable install paths:
export PYTHONPATH="${PWD}/build-fly/python_packages:${PWD}:${PYTHONPATH}"
export LD_LIBRARY_PATH="${PWD}/build-fly/python_packages/flydsl/_mlir/_mlir_libs:${LD_LIBRARY_PATH}"
Expand Down Expand Up @@ -138,7 +145,7 @@ Use names from `python/flydsl/utils/env.py`; do not introduce alternate spelling

| Purpose | Variable |
|---|---|
| Compile backend | `FLYDSL_COMPILE_BACKEND` (default `rocm`) |
| Compile backend | `FLYDSL_COMPILE_BACKEND` (default `rocm`; `cuda` selects the NVVM backend) |
| Override compile arch | `ARCH` |
| Compile without execution | `COMPILE_ONLY` |
| JIT cache directory | `FLYDSL_RUNTIME_CACHE_DIR` |
Expand All @@ -165,6 +172,8 @@ helper code that is not part of the traced closure.

## GPU Architecture Support

AMD (`FLYDSL_COMPILE_BACKEND=rocm`, the default):

| Arch | Chips | Wave size | MMA path | Notes |
|---|---|---|---|---|
| `gfx942` | MI300X / MI308X | 64 | MFMA | CDNA3 baseline; preshuffle GEMM, PA decode, CDNA BufferCopy |
Expand All @@ -183,6 +192,15 @@ RDNA and is wave32-true only for `gfx10*`/`gfx11*`/`gfx120*` prefixes; it does
`tests/kernels/test_rdna_gemm.py` shows the gfx11* (v16 ABI) vs gfx120* (v8 ABI)
kernel-selection pattern.

NVIDIA (`FLYDSL_COMPILE_BACKEND=cuda`, requires a `FLYDSL_BACKENDS=nvvm` build):

| Arch | Warp size | MMA path | Notes |
|---|---|---|---|
| `sm_80`+ | 32 | `mma.sync.aligned` | SM80 m16n8k16 f16->f32 MMA, SM80 `cp.async`, SM75+ `ldmatrix`. Arch string comes from `get_cuda_arch()`. |

Target-specific NVIDIA atoms live in `python/flydsl/expr/nvvm/` (reached as
`fx.nvvm`).

## Kernel Entry Points

This is routing guidance, not a complete kernel inventory. Search the current `kernels/` tree before edits; keep user-facing catalogs in `docs/prebuilt_kernels_guide.md`.
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@ FlyDSL/
│ │ └── autotune.py # Triton-style autotune module
│ └── mlir_flydsl/ # MLIR Python bindings (built, not edited)
├── examples/ # Runnable examples
│ ├── 01-vectorAdd.py # Vector addition with layout algebra
│ ├── 02-tiledCopy.py # Tiled copy with partitioned tensors
│ ├── 03-tiledMma.py # Tiled MMA (GEMM) with MFMA atoms
│ └── 04-preshuffle_gemm.py # Preshuffle GEMM end-to-end example
│ ├── 01-vectorAdd.py # Vector addition
│ ├── 02-gather_scatter.py # Row gather/scatter
│ ├── rocm/ # AMD ROCm examples
│ │ ├── 01-tiledCopy.py # Tiled copy with partitioned tensors
│ │ ├── 02-tiledMma.py # Tiled MMA (GEMM) with MFMA atoms
│ │ └── 03-preshuffle_gemm.py # Preshuffle GEMM end-to-end example
Comment thread
sjfeng1999 marked this conversation as resolved.
│ └── cuda/ # NVIDIA CUDA examples
├── kernels/ # Production GPU kernels (importable as `kernels.*`)
├── tests/ # All tests (kernels/, mlir/, unit/)
├── CMakeLists.txt # top-level CMake
Expand Down Expand Up @@ -358,7 +361,7 @@ torch.cuda.synchronize()
print("Result correct:", torch.allclose(C, A + B))
```

See `examples/` for more examples including tiled copy (`02-tiledCopy.py`), tiled MMA (`03-tiledMma.py`), and preshuffle GEMM (`04-preshuffle_gemm.py`).
See `examples/rocm/` for AMD examples including tiled copy (`02-tiledCopy.py`), tiled MMA (`03-tiledMma.py`), and preshuffle GEMM (`04-preshuffle_gemm.py`), and `examples/cuda/` for the NVIDIA NVVM examples.

## ✅ Testing Status

Expand Down
4 changes: 2 additions & 2 deletions cmake/FlyDSLBackends.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

set(FLYDSL_BACKENDS "rocdl"
CACHE STRING "Enabled FlyDSL backend stacks (semicolon-separated)")
set_property(CACHE FLYDSL_BACKENDS PROPERTY STRINGS rocdl)
set_property(CACHE FLYDSL_BACKENDS PROPERTY STRINGS rocdl nvvm)

# ---- Validate ----
list(LENGTH FLYDSL_BACKENDS _n_backends)
Expand All @@ -23,7 +23,7 @@ if(_n_backends GREATER 5)
message(FATAL_ERROR "FLYDSL_FOR_EACH_BACKEND supports at most 5 backends.")
endif()

set(_FLYDSL_BACKENDS_ALLOWED rocdl)
set(_FLYDSL_BACKENDS_ALLOWED rocdl nvvm)
foreach(_b ${FLYDSL_BACKENDS})
if(NOT _b IN_LIST _FLYDSL_BACKENDS_ALLOWED)
message(FATAL_ERROR
Expand Down
37 changes: 37 additions & 0 deletions cmake/backends/nvvm.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2026 FlyDSL Project Contributors
#
# NVVM backend descriptor.
# Self-registers into global properties consumed by downstream CMakeLists.txt.
#
# Stage one ships FlyNVVM SM80 atom types, FlyToNVVM conversion, Python
# bindings, and CUDA runtime support. The Python-side properties below keep the
# generated dialect bindings and stubs in sync with enabled backends.

# TableGen / header subdirectories under include/flydsl/
set_property(GLOBAL APPEND PROPERTY FLYDSL_BACKEND_INCLUDE_DIALECT_SUBDIRS "FlyNVVM")
set_property(GLOBAL APPEND PROPERTY FLYDSL_BACKEND_INCLUDE_CONVERSION_SUBDIRS "FlyToNVVM")

# C++ library subdirectories under lib/
set_property(GLOBAL APPEND PROPERTY FLYDSL_BACKEND_LIB_DIALECT_SUBDIRS "FlyNVVM")
set_property(GLOBAL APPEND PROPERTY FLYDSL_BACKEND_LIB_CONVERSION_SUBDIRS "FlyToNVVM")

# CAPI wrapper subdirectory under lib/CAPI/Dialect/
set_property(GLOBAL APPEND PROPERTY FLYDSL_BACKEND_CAPI_SUBDIRS "FlyNVVM")

# CAPI link targets for _mlirRegisterEverything (EMBED_CAPI_LINK_LIBS)
set_property(GLOBAL APPEND PROPERTY FLYDSL_BACKEND_EMBED_CAPI_LIBS "MLIRCPIFlyNVVM")

# Link targets for fly-opt
set_property(GLOBAL APPEND PROPERTY FLYDSL_BACKEND_FLYOPT_LINK_LIBS "MLIRCPIFlyNVVM")

# Upstream MLIR dialect sources needed by this backend's Python bindings
set_property(GLOBAL APPEND PROPERTY FLYDSL_BACKEND_UPSTREAM_DIALECT_SOURCES
"MLIRPythonSources.Dialects.nvvm")

# Stubgen modules for this backend
set_property(GLOBAL APPEND PROPERTY FLYDSL_BACKEND_STUBGEN_MODULES
"flydsl._mlir._mlir_libs._mlirDialectsFlyNVVM")

# Convenience boolean for Python CMakeLists gating of NVVM-specific bindings.
set(FLYDSL_HAS_NVVM ON)
File renamed without changes.
91 changes: 91 additions & 0 deletions examples/cuda/01-MmaSync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2026 FlyDSL Project Contributors
#
# Run:
# FLYDSL_COMPILE_BACKEND=cuda FLYDSL_RUNTIME_KIND=cuda \
# python3 examples/cuda/01-MmaSync.py

import torch

import flydsl.compiler as flyc
import flydsl.expr as fx

# One mma.sync.aligned instruction tile: M=16, N=8, K=16.
INST_M = 16
INST_N = 8
INST_K = 16


@flyc.kernel
def gemm_kernel(
A: fx.Tensor, # (M, K) row-major
B: fx.Tensor, # (N, K) row-major (so C = A @ B^T)
C: fx.Tensor, # (M, N) row-major
):
tid = fx.thread_idx.x
bid = fx.block_idx.x

bA = fx.zipped_divide(A, (INST_M, INST_K))
bB = fx.zipped_divide(B, (INST_N, INST_K))
bC = fx.zipped_divide(C, (INST_M, INST_N))

bA = fx.slice(bA, (None, bid))
bB = fx.slice(bB, (None, bid))
bC = fx.slice(bC, (None, bid))

mma_atom = fx.make_mma_atom(fx.nvvm.MmaSync(16, 8, 16, fx.Float16))
tiled_mma = fx.make_tiled_mma(mma_atom, fx.make_layout((1, 1, 1), (0, 0, 0)))
thr_mma = tiled_mma.thr_slice(tid)

copy_atom_f16 = fx.make_copy_atom(fx.UniversalCopy16b(), fx.Float16)
copy_atom_f32 = fx.make_copy_atom(fx.UniversalCopy32b(), fx.Float32)
tiled_copy_A = fx.make_tiled_copy_A(copy_atom_f16, tiled_mma)
tiled_copy_B = fx.make_tiled_copy_B(copy_atom_f16, tiled_mma)
tiled_copy_C = fx.make_tiled_copy_C(copy_atom_f32, tiled_mma)

thr_copy_A = tiled_copy_A.get_slice(tid)
thr_copy_B = tiled_copy_B.get_slice(tid)
thr_copy_C = tiled_copy_C.get_slice(tid)

copy_src_A = thr_copy_A.partition_S(bA)
copy_src_B = thr_copy_B.partition_S(bB)
copy_dst_C = thr_copy_C.partition_S(bC)

frag_A = thr_mma.make_fragment_A(bA)
frag_B = thr_mma.make_fragment_B(bB)
frag_C = thr_mma.make_fragment_C(bC)

copy_frag_A = thr_copy_A.retile(frag_A)
copy_frag_B = thr_copy_B.retile(frag_B)
copy_frag_C = thr_copy_C.retile(frag_C)

fx.copy(copy_atom_f16, copy_src_A, copy_frag_A, pred=None)
fx.copy(copy_atom_f16, copy_src_B, copy_frag_B, pred=None)

frag_C.fill(0)
fx.gemm(mma_atom, frag_C, frag_A, frag_B, frag_C)

fx.copy(copy_atom_f32, copy_frag_C, copy_dst_C, pred=None)


@flyc.jit
def nvvm_gemm(
A: fx.Tensor,
B: fx.Tensor,
C: fx.Tensor,
stream: fx.Stream = fx.Stream(None),
):
gemm_kernel(A, B, C).launch(grid=(1, 1, 1), block=(32, 1, 1), stream=stream)


M, N, K = INST_M, INST_N, INST_K
A = torch.randn(M, K, dtype=torch.float16).cuda()
B = torch.randn(N, K, dtype=torch.float16).cuda()
C = torch.zeros(M, N, dtype=torch.float32).cuda()

nvvm_gemm(A, B, C, stream=torch.cuda.Stream())
torch.cuda.synchronize()

expected = A.float() @ B.float().T
is_correct = torch.allclose(C, expected, atol=1e-2, rtol=1e-2)
print("Result correct:", is_correct)
2 changes: 1 addition & 1 deletion examples/notebooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ last.

The whole API these notebooks cover, in one place — enough to write a kernel without
reading the source. The MMA atoms (`make_mma_atom`, `make_tiled_mma`, `gemm`) are the
one piece left for later; `examples/03-tiledMma.py` is the worked reference.
one piece left for later.

```python
# Kernel + launch (00)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
27 changes: 27 additions & 0 deletions include/flydsl-c/FlyNVVMDialect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 FlyDSL Project Contributors

#ifndef FLYDSL_C_FLYNVVMDIALECT_H
#define FLYDSL_C_FLYNVVMDIALECT_H

#include "mlir-c/IR.h"
#include "mlir-c/Support.h"

#ifdef __cplusplus
extern "C" {
#endif

MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(FlyNVVM, fly_nvvm);

MLIR_CAPI_EXPORTED void mlirRegisterFlyToNVVMConversionPass(void);

/// Backend plugin registration: insert all NVVM dialects into \p registry.
MLIR_CAPI_EXPORTED void flydsl_register_nvvm_dialects(MlirDialectRegistry registry);
/// Backend plugin registration: register all NVVM passes.
MLIR_CAPI_EXPORTED void flydsl_register_nvvm_passes(void);

#ifdef __cplusplus
}
#endif

#endif // FLYDSL_C_FLYNVVMDIALECT_H
6 changes: 6 additions & 0 deletions include/flydsl/Conversion/FlyToNVVM/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
set(LLVM_TARGET_DEFINITIONS Passes.td)
mlir_tablegen(Passes.h.inc -gen-pass-decls -name FlyToNVVM)
mlir_tablegen(Passes.capi.h.inc -gen-pass-capi-header --prefix FlyToNVVM)
mlir_tablegen(Passes.capi.cpp.inc -gen-pass-capi-impl --prefix FlyToNVVM)

add_mlir_generic_tablegen_target(FlyToNVVMPassIncGen)
14 changes: 14 additions & 0 deletions include/flydsl/Conversion/FlyToNVVM/FlyToNVVM.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 FlyDSL Project Contributors

#ifndef CONVERSION_FLYTONVVM_FLYTONVVM_H
#define CONVERSION_FLYTONVVM_FLYTONVVM_H

#include "mlir/Pass/Pass.h"

namespace mlir {
#define GEN_PASS_DECL_FLYTONVVMCONVERSIONPASS
#include "flydsl/Conversion/FlyToNVVM/Passes.h.inc"
} // namespace mlir

#endif // CONVERSION_FLYTONVVM_FLYTONVVM_H
15 changes: 15 additions & 0 deletions include/flydsl/Conversion/FlyToNVVM/Passes.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 FlyDSL Project Contributors

include "mlir/Pass/PassBase.td"

def FlyToNVVMConversionPass : Pass<"convert-fly-to-nvvm"> {
let summary = "Lower Fly to MLIR upstream and nvvm dialects ";
let dependentDialects = [
"arith::ArithDialect",
"scf::SCFDialect",
"vector::VectorDialect",
"LLVM::LLVMDialect",
"NVVM::NVVMDialect"
];
}
1 change: 1 addition & 0 deletions include/flydsl/Dialect/FlyNVVM/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(IR)
11 changes: 11 additions & 0 deletions include/flydsl/Dialect/FlyNVVM/IR/Atom.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 FlyDSL Project Contributors

#ifndef FLYNVVM_ATOM
#define FLYNVVM_ATOM

include "flydsl/Dialect/FlyNVVM/IR/Dialect.td"
include "flydsl/Dialect/FlyNVVM/IR/MmaAtom.td"
include "flydsl/Dialect/FlyNVVM/IR/CopyAtom.td"

#endif // FLYNVVM_ATOM
10 changes: 10 additions & 0 deletions include/flydsl/Dialect/FlyNVVM/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
set(LLVM_TARGET_DEFINITIONS Dialect.td)

mlir_tablegen(Dialect.h.inc -gen-dialect-decls)
mlir_tablegen(Dialect.cpp.inc -gen-dialect-defs)

set(LLVM_TARGET_DEFINITIONS Atom.td)
mlir_tablegen(Atom.h.inc -gen-typedef-decls -typedefs-dialect=fly_nvvm)
mlir_tablegen(Atom.cpp.inc -gen-typedef-defs -typedefs-dialect=fly_nvvm)

add_public_tablegen_target(MLIRFlyNVVMIncGen)
32 changes: 32 additions & 0 deletions include/flydsl/Dialect/FlyNVVM/IR/CopyAtom.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 FlyDSL Project Contributors

#ifndef FLYNVVM_COPYATOM
#define FLYNVVM_COPYATOM

include "flydsl/Dialect/FlyNVVM/IR/Dialect.td"

//===----------------------------------------------------------------------===//
// CopyOp SM75 — PTX Warp-level Matrix Load Instruction: ldmatrix
// ldmatrix.sync.aligned.m8n8.x{1,2,4}[.trans].shared.b16
//===----------------------------------------------------------------------===//

def FlyNVVM_CopyOpSM75_LdMatrix : FlyNVVM_CopyOp<"CopyOpSM75_LdMatrix", "sm75.ldmatrix", []> {
let parameters = (ins "int32_t":$num, "bool":$trans);
let assemblyFormat = "`<` `num` `=` $num `,` `trans` `=` $trans `>`";
let genVerifyDecl = 1;
}

//===----------------------------------------------------------------------===//
// CopyOp SM80 — PTX Data Movement and Conversion Instruction: cp.async
// cp.async.{ca,cg}.shared.global (global -> shared, asynchronous)
//===----------------------------------------------------------------------===//

def FlyNVVM_CopyOpSM80_CpAsync : FlyNVVM_CopyOp<"CopyOpSM80_CpAsync", "sm80.cp.async", []> {
let parameters = (ins "int32_t":$bitSize);
let assemblyFormat = "`<` $bitSize `>`"; // TODO: cache modifiers
let genVerifyDecl = 1;
}


#endif // FLYNVVM_COPYATOM
Loading
Loading