跳到主要内容
TileLang 系统教程

tilelang-tutorial.huandu.me

第 09 章 核心原语详解

/code/09-core-primitives/

05-ascend-primitives/ascend_tile_library_sketch.py3246 字节
"""适配器仓库的 T.tile.* 向量内联函数骨架(select / sort / atomic_add)。

静态核对来源:_vendor/tilelang-ascend-v0.1.2.000/
  tilelang/language/__init__.py:86      (from . import ascend_tile as tile)
  tilelang/language/ascend_tile.py:707  (select)
  tilelang/language/ascend_tile.py:412  (sort)
  tilelang/language/ascend_tile.py:550  (topk)
  tilelang/language/ascend_tile.py:313  (atomic_add)
  src/op/ascend.cc:975-1260             (tl.ascend_* 内建 op)
  src/target/codegen_ascend.cc:522-630  (C++ 代码生成分支)

注意:这些 API 只存在于 tilelang-ascend 适配器仓库,**不在** TileLang 主干 v0.1.15。

运行前提:昇腾 NPU + CANN + torch_npu + tilelang-ascend v0.1.2.000。
作者验证级别:仅静态核对(py_compile + API 逐条比对),未在 NPU 上运行。
"""

from __future__ import annotations

import torch
import torch_npu  # noqa: F401
import tilelang
import tilelang.language as T


@tilelang.jit(target="ascend", out_idx=-1)
def select_and_sort(N: int, K: int):
    """一个刻意拼凑的示例:select 做掩码选择,sort 取降序 (值, 索引) 对。"""

    @T.prim_func
    def main(
        X: T.Tensor((N,), "float32"),
        Y: T.Tensor((N,), "float32"),
        Mask: T.Tensor((N // 8,), "uint8"),   # bit-packed 掩码
        Selected: T.Tensor((N,), "float32"),
        Sorted: T.Tensor((2 * N,), "float32"),  # 交错 (值, 索引)
    ):
        with T.Kernel(1) as bx:
            x_ub = T.alloc_ub((N,), "float32")
            y_ub = T.alloc_ub((N,), "float32")
            m_ub = T.alloc_ub((N // 8,), "uint8")
            sel_ub = T.alloc_ub((N,), "float32")
            sorted_ub = T.alloc_ub((2 * N,), "float32")

            T.copy(X, x_ub)
            T.copy(Y, y_ub)
            T.copy(Mask, m_ub)

            # dst[i] = selMask.bit[i] ? src0[i] : src1[i]
            T.tile.select(sel_ub, m_ub, x_ub, y_ub, "VSEL_CMPMASK_SPR")
            T.copy(sel_ub, Selected)

            # 降序全量排序,输出 [val0, idx0, val1, idx1, ...];
            # float32 输入时,actual_num..aligned_count 之间的位置会被原地填 -inf。
            T.tile.sort(sorted_ub, x_ub, N)
            T.copy(sorted_ub, Sorted)

    return main


@tilelang.jit(target="ascend", out_idx=-1)
def grouped_accumulate(M: int, N: int, num_parts: int):
    """把多个 partial result 用原子累加写回同一个 GM 输出。"""

    @T.prim_func
    def main(
        Parts: T.Tensor((num_parts, M, N), "float32"),
        Out: T.Tensor((M, N), "float32"),
    ):
        with T.Kernel(num_parts) as bx:
            src_ub = T.alloc_ub((M, N), "float32")
            T.copy(Parts[bx, :, :], src_ub)
            # V1 模型:dst 必须是 GM,src 必须是本地 tensor(UB 或 L0C)。
            # 若语义是从 0 开始累加,调用前需要先把 Out 清零。
            T.tile.atomic_add(Out, src_ub)

    return main


def main() -> None:
    n = 1024
    kernel = select_and_sort(n, 0)
    x = torch.randn(n, device="npu", dtype=torch.float32)
    y = torch.randn(n, device="npu", dtype=torch.float32)
    mask = torch.randint(0, 256, (n // 8,), device="npu", dtype=torch.uint8)
    selected, sorted_pairs = kernel(x, y, mask)
    bits = torch.tensor(
        [(b >> i) & 1 for b in mask.tolist() for i in range(8)], device="npu"
    )[:n].to(torch.bool)
    torch.testing.assert_close(selected, torch.where(bits, x, y))
    vals = sorted_pairs[0::2]
    assert bool(torch.all(vals[:-1] >= vals[1:])), "sort output is not descending"
    print("select + sort passed.")


if __name__ == "__main__":
    main()

← 浏览本章全部代码