Files
tilelang/testing/python/language/test_tilelang_language_view.py
T
LeiWang1999 0e4ad53c6f [Ascend] Refresh comparison snapshot at upstream #3174
Comparison-only snapshot of Ascend at 925bfbb9aff0fb57a4ed9fecc3591b8dcac21c8f.
Use upstream #3174 (62bba8d20d) as the logical synchronization point.

Preserve the complete tree of the previous comparison head d0d2f40be354cc0a4d6ed037b34278c8746fa031,
including submodule references. No source changes or additional integration
resolutions are introduced. This snapshot is for upstream comparison only.
2026-09-08 15:26:25 +08:00

202 lines
6.5 KiB
Python

import tilelang.language as T
from tilelang import tvm as tvm
import tilelang.testing
import tilelang as tl
import pytest
import torch
def view_test(N, M, dtype, new_dtype=None):
new_shape = [N // M, M]
if new_dtype:
from tvm import DataType
dtype_src = DataType(dtype)
dtype_dst = DataType(new_dtype)
src_bits = dtype_src.bits
dst_bits = dtype_dst.bits
scale = src_bits / dst_bits
new_shape[-1] = int(M * scale)
@T.prim_func
def main(
A: T.Tensor((N,), dtype),
B: T.Tensor(new_shape, new_dtype if new_dtype else dtype),
):
with T.Kernel(1) as _:
A_viewed = T.view(A, new_shape, dtype=new_dtype)
T.copy(A_viewed, B)
return main
def run_view(N, M, dtype, new_dtype=None):
program = view_test(N, M, dtype, new_dtype)
jit_kernel = tl.compile(program, out_idx=-1)
profiler = jit_kernel.get_profiler()
def ref_program(A):
if new_dtype:
torch_dtype = T.dtype(new_dtype).as_torch()
return A.view(N // M, M).view(dtype=torch_dtype)
return A.view(N // M, M)
profiler.assert_allclose(ref_program, atol=1e-2, rtol=1e-2)
def test_reshape_view():
# Test view with same dtype
run_view(1024, 32, T.float32)
run_view(2048, 64, T.float16)
# Test view with dtype conversion
run_view(1024, 32, T.float32, T.float16)
run_view(2048, 64, T.float16, T.float32)
def view_shape_mismatch_test(N, M, dtype, new_dtype=None):
new_shape = [N // M, M + 1]
if new_dtype:
from tvm import DataType
dtype_src = DataType(dtype)
dtype_dst = DataType(new_dtype)
src_bits = dtype_src.bits
dst_bits = dtype_dst.bits
scale = src_bits / dst_bits
new_shape[-1] = int(M * scale)
@T.prim_func
def main(
A: T.Tensor((N,), dtype),
B: T.Tensor(new_shape, new_dtype if new_dtype else dtype),
):
with T.Kernel(1) as _:
A_viewed = T.view(A, new_shape, dtype=new_dtype)
T.copy(A_viewed, B)
return main
def test_view_shape_mismatch():
with pytest.raises(ValueError, match="logical bit count"):
view_shape_mismatch_test(1024, 32, T.float32)
def test_view_subbyte_dtype_change():
A = tvm.tirx.decl_buffer((16, 32), "float4_e2m1fn", name="A")
A_viewed = T.view(A, (16, 16), dtype=T.uint8)
assert str(A_viewed.dtype) == "uint8"
assert tuple(int(dim) for dim in A_viewed.shape) == (16, 16)
assert A_viewed.data.same_as(A.data)
def fp4_to_uint8_view_test(rows_per_cta=16, mask_k=256):
@T.prim_func
def main(
A: T.Tensor((rows_per_cta, mask_k), T.bfloat16),
B: T.Tensor((rows_per_cta, mask_k // 2), T.uint8),
):
with T.Kernel(1, threads=256) as _:
A_frag = T.alloc_fragment((rows_per_cta, mask_k), T.bfloat16)
B_shared_fp4 = T.alloc_shared((rows_per_cta, mask_k), T.float4_e2m1fn)
B_shared_uint8 = T.view(B_shared_fp4, (rows_per_cta, mask_k // 2), dtype=T.uint8)
T.copy(A, A_frag)
for i, j in T.Parallel(rows_per_cta, mask_k):
B_shared_fp4[i, j] = T.cast(A_frag[i, j], T.float4_e2m1fn)
T.copy(B_shared_uint8, B)
return main
@tilelang.testing.requires_cuda
@tilelang.testing.requires_cuda_compute_version_ge(10, 0)
def test_view_shared_fp4_to_uint8_compile():
program = fp4_to_uint8_view_test()
kernel = tl.compile(program, out_idx=-1)
src = kernel.get_kernel_source()
assert "fp4_e2" in src
dummy_input = torch.randn((16, 256), device="cuda", dtype=torch.bfloat16)
output = kernel(dummy_input)
assert output.shape == (16, 128)
assert output.dtype == torch.uint8
def annotated_layout_on_dtype_changing_view_test():
@T.prim_func
def main(
A: T.Tensor((64, 64), T.float16),
B: T.Tensor((64, 128), T.int8),
):
with T.Kernel(1, threads=128) as _:
A_stage = T.alloc_shared((2, 64, 64), T.float16, scope="shared.dyn")
A_i8 = T.view(A_stage, (2, 64, 128), dtype=T.int8)
T.annotate_layout({A_i8: T.Layout((2, 64, 128), lambda s, i, j: [s, i, j])})
for i, j in T.Parallel(64, 64):
A_stage[0, i, j] = A[i, j]
for i, j in T.Parallel(64, 128):
B[i, j] = A_i8[0, i, j]
return main
@tilelang.testing.requires_cuda
def test_annotated_layout_on_dtype_changing_view_compile():
program = annotated_layout_on_dtype_changing_view_test()
kernel = tl.compile(program, out_idx=-1)
assert kernel.get_kernel_source()
def shared_reinterpret_view_test(shape, dtype, new_shape, new_dtype, swizzled):
"""Write through the shared allocation, read through its reinterpreting
view: the view's derived layout must induce the same storage-bit map as
the allocation's. The swizzled variant additionally covers the widening
contiguity proof and the TMA descriptor encoding of the derived layout."""
@T.prim_func
def main(
A: T.Tensor(shape, dtype),
B: T.Tensor(new_shape, new_dtype),
):
with T.Kernel(1, threads=128):
A_shared = T.alloc_shared(shape, dtype)
A_view = T.view(A_shared, new_shape, dtype=new_dtype)
if swizzled:
T.annotate_layout({A_shared: tilelang.layout.make_swizzled_layout(A_shared)})
T.copy(A, A_shared)
T.copy(A_view, B)
return main
def run_shared_reinterpret_view(shape, dtype, new_shape, new_dtype, swizzled):
program = shared_reinterpret_view_test(shape, dtype, new_shape, new_dtype, swizzled)
jit_kernel = tl.compile(program, out_idx=-1)
torch_dtype = T.dtype(dtype).as_torch()
lanes = torch.randn(shape[0], shape[1] * torch_dtype.itemsize // 2, device="cuda", dtype=torch.bfloat16)
a = lanes.view(dtype=torch_dtype)
d = jit_kernel(a)
ref = a.view(dtype=T.dtype(new_dtype).as_torch()).view(new_shape)
torch.testing.assert_close(d.view(torch.int16), ref.view(torch.int16), rtol=0, atol=0)
@tilelang.testing.requires_cuda
@pytest.mark.parametrize("swizzled", [False, True], ids=["linear", "swizzled"])
def test_shared_view_narrowing_numeric(swizzled):
run_shared_reinterpret_view((64, 64), T.float32, (64, 128), T.bfloat16, swizzled)
@tilelang.testing.requires_cuda
@pytest.mark.parametrize("swizzled", [False, True], ids=["linear", "swizzled"])
def test_shared_view_widening_numeric(swizzled):
run_shared_reinterpret_view((64, 128), T.bfloat16, (64, 64), T.float32, swizzled)
if __name__ == "__main__":
tilelang.testing.main()