跳到主要内容
TileLang 系统教程

tilelang-tutorial.huandu.me

第 09 章 核心原语详解

/code/09-core-primitives/

01-primitive-ir-map/primitive_ir_map.py10236 字节
#!/usr/bin/env python3
"""第 09 章的「原语 -> IR -> 目标指令」映射表,并核对正文引用的源码行号。

只用标准库;不 import tilelang,不编译 kernel。

    python3 primitive_ir_map.py
    python3 primitive_ir_map.py --no-check
    python3 primitive_ir_map.py --vendor /path/to/tilelang-v0.1.15
"""

from __future__ import annotations

import argparse
from dataclasses import dataclass
from pathlib import Path


@dataclass(frozen=True)
class Cite:
    """一条源码引用:相对某个仓库根的文件路径 + 行号区间(闭区间)。"""

    root: str  # "main" 或 "adapter"
    path: str
    start: int
    end: int


@dataclass(frozen=True)
class Mapping:
    primitive: str
    ir: str
    nv: str
    ascend: str
    cites: tuple[Cite, ...]


MAIN = "main"
ADAPTER = "adapter"

MAPPINGS: tuple[Mapping, ...] = (
    Mapping(
        "T.copy",
        "tl.tileop.copy",
        "SIMT / cp.async / TMA bulk / LDSM / STSM / tcgen05.ld-st",
        "DataCopy / ND2NZ / LoadData / Fixpipe",
        (
            Cite(MAIN, "tilelang/language/copy_op.py", 59, 130),
            Cite(MAIN, "src/op/copy.cc", 481, 545),
            Cite(MAIN, "src/cuda/op/copy.h", 21, 33),
            Cite(MAIN, "src/cuda/op/copy_analysis.cc", 716, 808),
        ),
    ),
    Mapping(
        "T.async_copy",
        "tl.tileop.async_copy",
        "cp.async (+ commit, no wait)",
        "(no equivalent)",
        (
            Cite(MAIN, "tilelang/language/copy_op.py", 188, 229),
            Cite(MAIN, "src/op/copy.cc", 622, 622),
        ),
    ),
    Mapping(
        "T.tma_copy",
        "tl.tileop.tma_copy",
        "expect_tx + tma_load / tma_store (+ arrive, no wait)",
        "(no equivalent)",
        (
            Cite(MAIN, "tilelang/language/copy_op.py", 232, 324),
            Cite(MAIN, "src/op/copy.cc", 640, 640),
        ),
    ),
    Mapping(
        "T.copy_cluster",
        "tl.tileop.copy + dst_block/cluster_mask",
        "TMA multicast / SM-to-SM copy",
        "(no equivalent)",
        (Cite(MAIN, "tilelang/language/copy_op.py", 133, 185),),
    ),
    Mapping(
        "T.gemm",
        "tl.tileop.gemm",
        "cuda.mma / cuda.wgmma / cuda.tcgen05 / cuda.fma",
        "ascend.mad (L0A x L0B -> L0C)",
        (
            Cite(MAIN, "tilelang/language/gemm_op.py", 38, 122),
            Cite(MAIN, "src/cuda/op/gemm.cc", 336, 374),
            Cite(MAIN, "src/ascend/op/gemm.cc", 24, 45),
        ),
    ),
    Mapping(
        "T.gemm_blockscaled",
        "tl.tileop.gemm_blockscaled",
        "tcgen05 block-scaled variant",
        "fused MXFP8 L1 path",
        (
            Cite(MAIN, "src/op/gemm_blockscaled.cc", 105, 105),
            Cite(MAIN, "tilelang/ascend/language/gemm_op.py", 110, 165),
        ),
    ),
    Mapping(
        "T.reduce_sum / max / min",
        "tl.tileop.reduce",
        "thread-local loop + tl::AllReduce<...>::run",
        "ascend_reduce family (direct on UB inside SimdVF)",
        (
            Cite(MAIN, "tilelang/language/reduce_op.py", 25, 173),
            Cite(MAIN, "src/op/reduce.cc", 212, 217),
            Cite(MAIN, "src/tl_templates/cuda/reduce.h", 240, 253),
            Cite(MAIN, "tilelang/ascend/language/reduce_op.py", 43, 88),
        ),
    ),
    Mapping(
        "T.atomic_add",
        "tl.atomic_add_elem_op / tl.tileop.atomicadd",
        "AtomicAdd(x2/x4) / TMA cp.reduce",
        "SetAtomicAdd<T>() + GM store",
        (
            Cite(MAIN, "tilelang/language/atomic.py", 211, 311),
            Cite(MAIN, "src/cuda/op/atomic_add.cc", 36, 62),
            Cite(MAIN, "src/ascend/op/builtin.cc", 446, 451),
        ),
    ),
    Mapping(
        "T.atomic_max / atomic_min",
        "tl.tileop.atomicmax / tl.tileop.atomicmin",
        "AtomicMax / AtomicMin",
        "SetAtomicMax / SetAtomicMin",
        (
            Cite(MAIN, "tilelang/language/atomic.py", 39, 208),
            Cite(MAIN, "src/op/atomic_reduce.cc", 162, 167),
        ),
    ),
    Mapping(
        "T.atomic_load / atomic_store",
        "tl.atomic_load_elem_op / tl.atomic_store_elem_op",
        "memory-ordered load / store",
        "(no public equivalent)",
        (Cite(MAIN, "tilelang/language/atomic.py", 390, 492),),
    ),
    Mapping(
        "T.fill / T.clear",
        "tl.tileop.fill",
        "parallel loop + vectorized store",
        "parallel loop -> Fill/Duplicate",
        (
            Cite(MAIN, "tilelang/language/fill_op.py", 11, 72),
            Cite(MAIN, "src/op/fill.cc", 94, 127),
        ),
    ),
    Mapping(
        "T.transpose",
        "tl.tileop.transpose",
        "SIMT loop (no special layout inference)",
        "T.tile.transpose -> tl.ascend_transpose",
        (
            Cite(MAIN, "tilelang/language/copy_op.py", 525, 562),
            Cite(MAIN, "src/op/transpose.cc", 222, 222),
        ),
    ),
    Mapping(
        "T.tile.* (adapter only)",
        "tl.ascend_<name> intrinsic",
        "(Ascend-only)",
        "AscendC vector intrinsics",
        (
            Cite(ADAPTER, "tilelang/language/ascend_tile.py", 967, 1150),
            Cite(ADAPTER, "src/op/ascend.cc", 975, 1260),
            Cite(ADAPTER, "src/target/codegen_ascend.cc", 522, 630),
        ),
    ),
    Mapping(
        "T.dual_copy",
        "tl.tileop.ascend_copy + dual_dst_ctl",
        "(Ascend-only)",
        "hardware dual-destination (L0C->UB); per-AIV copy otherwise",
        (
            Cite(MAIN, "tilelang/ascend/language/copy_op.py", 53, 163),
            Cite(MAIN, "src/ascend/op/copy.cc", 573, 605),
            Cite(MAIN, "src/ascend/transform/rewrite_dual_copy.cc", 97, 107),
        ),
    ),
    Mapping(
        "T.SimtVF / T.SimdVF",
        "SIMT_VF / SIMD_VF block",
        "(Ascend-only)",
        "asc_vf_call thread body / MicroAPI vector ops",
        (
            Cite(MAIN, "tilelang/ascend/language/frame.py", 107, 195),
            Cite(MAIN, "src/ascend/codegen/codegen_ascend.cc", 904, 940),
        ),
    ),
)


EXTRA_CITES: tuple[Cite, ...] = (
    Cite(MAIN, "tilelang/jit/__init__.py", 507, 509),          # get_kernel_source
    Cite(MAIN, "tilelang/jit/kernel.py", 532, 534),            # get_kernel_source
    Cite(MAIN, "src/transform/lower_tile_op.cc", 207, 224),    # LowerTileOpPass
    Cite(MAIN, "src/transform/lower_tile_op.cc", 1477, 1486),  # tl.LowerTileOp
    Cite(MAIN, "src/op/copy.cc", 530, 545),                    # coalesced_width / loop_layout
    Cite(MAIN, "src/op/copy.cc", 508, 509),                    # dtype cast in SIMT copy
)


def _default_book_root() -> Path:
    # .../chapters/09-core-primitives/code/01-primitive-ir-map/primitive_ir_map.py
    return Path(__file__).resolve().parents[4]


def _column(text: str, width: int) -> str:
    return text if len(text) <= width else text[: width - 1] + "~"


def print_table() -> None:
    widths = (26, 28, 34, 40)
    header = ("primitive", "IR", "NV target", "Ascend target")
    print(" | ".join(_column(h, w).ljust(w) for h, w in zip(header, widths)))
    print("-+-".join("-" * w for w in widths))
    for m in MAPPINGS:
        row = (m.primitive, m.ir, m.nv, m.ascend)
        print(" | ".join(_column(c, w).ljust(w) for c, w in zip(row, widths)))


def check_citations(vendor: Path, adapter: Path) -> int:
    total = 0
    bad: list[str] = []
    skipped = not (vendor.is_dir() and adapter.is_dir())
    if skipped:
        print(
            "checked 0 source citations -> skipped "
            f"(vendor={vendor} exists={vendor.is_dir()}, "
            f"adapter={adapter} exists={adapter.is_dir()})"
        )
        return 0

    labelled: list[tuple[str, Cite]] = []
    for m in MAPPINGS:
        labelled.extend((m.primitive, c) for c in m.cites)
    labelled.extend(("(chapter 5.3)", c) for c in EXTRA_CITES)

    for label, c in labelled:
        total += 1
        root = vendor if c.root == MAIN else adapter
        target = root / c.path
        if not target.is_file():
            bad.append(f"{label}: missing file {c.root}:{c.path}")
            continue
        n_lines = sum(1 for _ in target.open("r", encoding="utf-8", errors="ignore"))
        if not (1 <= c.start <= c.end <= n_lines):
            bad.append(
                f"{label}: {c.root}:{c.path}:{c.start}-{c.end} "
                f"out of range (file has {n_lines} lines)"
            )
    if bad:
        print(f"checked {total} source citations -> {len(bad)} problem(s)")
        for item in bad:
            print(f"  - {item}")
        return 1
    print(f"checked {total} source citations -> all in range")
    return 0


def check_tile_namespace_absence(vendor: Path) -> int:
    """复现「v0.1.15 里没有 T.tile 命名空间」这条结论。"""
    lang_dir = vendor / "tilelang" / "ascend" / "language"
    if not lang_dir.is_dir():
        print("claim \"T.tile absent from v0.1.15\": skipped (vendor missing)")
        return 0
    if (vendor / "tilelang" / "language" / "ascend_tile.py").exists():
        print("claim \"T.tile absent from v0.1.15\": CONTRADICTED (ascend_tile.py exists)")
        return 1
    hits = []
    for py in sorted(lang_dir.glob("*.py")):
        text = py.read_text(encoding="utf-8", errors="ignore")
        if "as tile" in text:
            hits.append(py.name)
    if hits:
        print(f"claim \"T.tile absent from v0.1.15\": CONTRADICTED ({hits})")
        return 1
    print(
        "claim \"T.tile absent from v0.1.15\": confirmed "
        "(no ascend_tile.py, no `as tile` import under tilelang/ascend/language)"
    )
    return 0


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--no-check", action="store_true", help="only print the mapping table")
    parser.add_argument("--vendor", type=Path, default=None, help="path to tilelang-v0.1.15")
    parser.add_argument(
        "--adapter", type=Path, default=None, help="path to tilelang-ascend-v0.1.2.000"
    )
    args = parser.parse_args()

    print_table()
    if args.no_check:
        return 0

    book = _default_book_root()
    vendor = args.vendor or (book / "_vendor" / "tilelang-v0.1.15")
    adapter = args.adapter or (book / "_vendor" / "tilelang-ascend-v0.1.2.000")

    problems = check_citations(vendor, adapter)
    problems += check_tile_namespace_absence(vendor)
    return 1 if problems else 0


if __name__ == "__main__":
    raise SystemExit(main())

← 浏览本章全部代码