Files
tilelang/testing/python/issue/test_tilelang_issue_2991.py
T
Rishabh Sinha bdbf32acf9 [Bugfix][Language] Support unary plus on PrimExpr in the eager frontend (#3141)
PrimExpr overloads unary minus and invert but not unary plus, so
`Out[i] = +A[i]` raised TypeError at trace time. Route unary plus through
the builder, the same way `not` already is, and return PrimExpr operands
unchanged; Python values keep their native unary plus.

Fixes #2991
2026-09-04 14:49:09 +08:00

85 lines
2.4 KiB
Python

# Regression test for https://github.com/tile-ai/tilelang/issues/2991
# Unary plus on a traced expression (``+A[i]``) raised
# ``TypeError: bad operand type for unary +: 'BufferLoad'`` at trace time
# because PrimExpr overloads unary minus and invert but not unary plus.
# The structural checks below are host-side and need no GPU.
import pytest
import torch
import tilelang
import tilelang.testing
from tilelang import language as T, tvm
N = 4
def _unary_plus_kernel(dtype):
@T.prim_func
def kernel(A: T.Tensor((N,), dtype), Out: T.Tensor((N,), dtype)):
with T.Kernel(1, threads=1):
for i in T.serial(N):
Out[i] = +A[i]
return kernel
def _identity_kernel(dtype):
@T.prim_func
def kernel(A: T.Tensor((N,), dtype), Out: T.Tensor((N,), dtype)):
with T.Kernel(1, threads=1):
for i in T.serial(N):
Out[i] = A[i]
return kernel
def _compound_unary_plus_kernel():
@T.macro
def plus(x):
return +x
@T.prim_func
def kernel(A: T.Tensor((N,), "float32"), Out: T.Tensor((N,), "float32")):
with T.Kernel(1, threads=1):
# Python scalars keep their native unary plus; PrimExpr operands,
# including loop vars, compound expressions and macro results,
# trace to the operand itself.
for i in T.serial(+N):
Out[i] = +(A[i] * 2.0) + plus(A[i]) + T.cast(+i, "float32") + (+1.5)
return kernel
def _compound_expected_kernel():
@T.macro
def ident(x):
return x
@T.prim_func
def kernel(A: T.Tensor((N,), "float32"), Out: T.Tensor((N,), "float32")):
with T.Kernel(1, threads=1):
for i in T.serial(N):
Out[i] = A[i] * 2.0 + ident(A[i]) + T.cast(i, "float32") + 1.5
return kernel
@pytest.mark.parametrize("dtype", ["int32", "float32"])
def test_unary_plus_traces_to_identity(dtype):
tvm.ir.assert_structural_equal(_unary_plus_kernel(dtype), _identity_kernel(dtype))
def test_unary_plus_on_loop_var_compound_expr_and_macro():
tvm.ir.assert_structural_equal(_compound_unary_plus_kernel(), _compound_expected_kernel())
@tilelang.testing.requires_cuda
def test_unary_plus_runs_on_cuda():
kernel = tilelang.compile(_unary_plus_kernel("int32"), out_idx=[1])
a = torch.tensor([-5, 10, 0, 7], dtype=torch.int32, device="cuda")
assert kernel(a).tolist() == a.tolist()
if __name__ == "__main__":
tilelang.testing.main()