Files
tilelang/testing/python/language/test_tilelang_language_func_attrs.py
T
KurisandClaude Opus 4.6 e45ecf7dc4 [Feature] Support T.annotate_compile_flags, T.annotate_pass_configs, and out_idx as PrimFunc attrs (#2006)
Allow configuring pass configs, compile flags, and out_idx directly
inside function bodies using T.annotate_compile_flags(),
T.annotate_pass_configs(), and T.empty()+return. These are stored as
proper PrimFunc attrs (tilelang_compile_flags, tilelang_pass_configs,
tilelang_out_idx) instead of monkey-patching, and merged at compile
time. Annotations can be placed before or after tensor type annotations.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 12:42:47 +08:00

215 lines
6.6 KiB
Python

"""Test T.annotate_compile_flags, T.annotate_pass_configs, and out_idx via PrimFunc attrs."""
import pytest
import torch
import tilelang
from tilelang import language as T
from tilelang.transform import PassConfigKey
def test_out_idx_via_attr_lazy():
"""out_idx should be stored as PrimFunc attr when using T.empty + return."""
@T.prim_func
def kernel(A):
A: T.Tensor[[128, 128], T.float32]
B = T.empty([128, 128], T.float32)
with T.Kernel(1):
for i in T.serial(128):
for j in T.serial(128):
B[i, j] = A[i, j] + 1.0
return B
assert "tilelang_out_idx" in kernel.attrs
assert list(kernel.attrs["tilelang_out_idx"]) == [-1]
compiled = tilelang.compile(kernel)
a = torch.randn(128, 128, device="cuda")
b = compiled(a)
torch.testing.assert_close(b, a + 1.0)
def test_all_attrs_together_lazy():
"""annotate_pass_configs, annotate_compile_flags, and out_idx should all work together."""
@T.prim_func
def kernel(A):
A: T.Tensor[[64, 64], T.float32]
T.annotate_pass_configs({PassConfigKey.TL_ENABLE_FAST_MATH: True})
T.annotate_compile_flags(["--use_fast_math"])
B = T.empty([64, 64], T.float32)
with T.Kernel(1):
for i in T.serial(64):
for j in T.serial(64):
B[i, j] = A[i, j] * 2.0
return B
attrs = kernel.attrs
assert "tilelang_out_idx" in attrs
assert "tilelang_pass_configs" in attrs
assert "tilelang_compile_flags" in attrs
compiled = tilelang.compile(kernel)
a = torch.randn(64, 64, device="cuda")
b = compiled(a)
torch.testing.assert_close(b, a * 2.0)
def test_eager_mode_attrs():
"""Eager mode should support annotate_pass_configs and out_idx via T.empty."""
@tilelang.jit
def kernel(A):
M, N = T.const("M N")
A: T.Tensor[[M, N], T.float32]
B = T.empty([M, N], T.float32)
T.annotate_pass_configs({PassConfigKey.TL_ENABLE_FAST_MATH: True})
with T.Kernel(1):
for i in T.serial(M):
for j in T.serial(N):
B[i, j] = A[i, j] + 1.0
return B
a = torch.randn(32, 32, device="cuda")
result = kernel(a)
torch.testing.assert_close(result, a + 1.0)
def test_out_idx_conflict_detection():
"""Specifying both T.empty return and external out_idx should raise ValueError."""
@T.prim_func
def kernel(A):
A: T.Tensor[[32, 32], T.float32]
B = T.empty([32, 32], T.float32)
with T.Kernel(1):
for i in T.serial(32):
for j in T.serial(32):
B[i, j] = A[i, j]
return B
with pytest.raises(ValueError, match="Out index conflict"):
tilelang.compile(kernel, out_idx=[-1])
def test_no_out_idx_when_not_using_empty():
"""When T.empty is not used, tilelang_out_idx attr should not be present."""
@T.prim_func
def kernel(A, B):
A: T.Tensor[[32, 32], T.float32]
B: T.Tensor[[32, 32], T.float32]
with T.Kernel(1):
for i in T.serial(32):
for j in T.serial(32):
B[i, j] = A[i, j]
assert kernel.attrs is None or "tilelang_out_idx" not in kernel.attrs
compiled = tilelang.compile(kernel, out_idx=[-1])
a = torch.randn(32, 32, device="cuda")
b = compiled(a)
torch.testing.assert_close(b, a)
def test_pass_configs_only_lazy():
"""annotate_pass_configs should work without T.empty or annotate_compile_flags."""
@T.prim_func
def kernel(A, B):
A: T.Tensor[[32, 32], T.float32]
B: T.Tensor[[32, 32], T.float32]
T.annotate_pass_configs({PassConfigKey.TL_ENABLE_FAST_MATH: True})
with T.Kernel(1):
for i in T.serial(32):
for j in T.serial(32):
B[i, j] = A[i, j] + 1.0
assert "tilelang_pass_configs" in kernel.attrs
assert kernel.attrs is None or "tilelang_out_idx" not in kernel.attrs
compiled = tilelang.compile(kernel, out_idx=[-1])
a = torch.randn(32, 32, device="cuda")
b = compiled(a)
torch.testing.assert_close(b, a + 1.0)
def test_compile_flags_only_lazy():
"""annotate_compile_flags should work standalone."""
@T.prim_func
def kernel(A, B):
A: T.Tensor[[32, 32], T.float32]
B: T.Tensor[[32, 32], T.float32]
T.annotate_compile_flags(["--use_fast_math"])
with T.Kernel(1):
for i in T.serial(32):
for j in T.serial(32):
B[i, j] = A[i, j] + 1.0
assert "tilelang_compile_flags" in kernel.attrs
compiled = tilelang.compile(kernel, out_idx=[-1])
a = torch.randn(32, 32, device="cuda")
b = compiled(a)
torch.testing.assert_close(b, a + 1.0)
def test_annotations_before_tensor_type():
"""Annotations placed before tensor type annotations should work."""
@T.prim_func
def kernel(A, B):
T.annotate_pass_configs({PassConfigKey.TL_ENABLE_FAST_MATH: True})
T.annotate_compile_flags(["--use_fast_math"])
A: T.Tensor[[32, 32], T.float32]
B: T.Tensor[[32, 32], T.float32]
with T.Kernel(1):
for i in T.serial(32):
for j in T.serial(32):
B[i, j] = A[i, j] + 1.0
assert "tilelang_pass_configs" in kernel.attrs
assert "tilelang_compile_flags" in kernel.attrs
compiled = tilelang.compile(kernel, out_idx=[-1])
a = torch.randn(32, 32, device="cuda")
b = compiled(a)
torch.testing.assert_close(b, a + 1.0)
def test_annotations_after_tensor_type():
"""Annotations placed after tensor type annotations should work."""
@T.prim_func
def kernel(A, B):
A: T.Tensor[[32, 32], T.float32]
B: T.Tensor[[32, 32], T.float32]
T.annotate_pass_configs({PassConfigKey.TL_ENABLE_FAST_MATH: True})
T.annotate_compile_flags(["--use_fast_math"])
with T.Kernel(1):
for i in T.serial(32):
for j in T.serial(32):
B[i, j] = A[i, j] + 1.0
assert "tilelang_pass_configs" in kernel.attrs
assert "tilelang_compile_flags" in kernel.attrs
compiled = tilelang.compile(kernel, out_idx=[-1])
a = torch.randn(32, 32, device="cuda")
b = compiled(a)
torch.testing.assert_close(b, a + 1.0)
if __name__ == "__main__":
test_out_idx_via_attr_lazy()
test_all_attrs_together_lazy()
test_eager_mode_attrs()
test_out_idx_conflict_detection()
test_no_out_idx_when_not_using_empty()
test_pass_configs_only_lazy()
test_compile_flags_only_lazy()
test_annotations_before_tensor_type()
test_annotations_after_tensor_type()
print("All tests passed!")