159 lines
4.8 KiB
Python
159 lines
4.8 KiB
Python
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
"""Test TVMScript with PEP 563 (from __future__ import annotations).
|
|
|
|
IMPORTANT: The `from __future__ import annotations` import below is the
|
|
test condition itself, because we need to test compatibility with it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import tvm
|
|
import tvm.testing
|
|
from tvm.script import ir as I
|
|
from tvm.script import tirx as T
|
|
|
|
|
|
def _normalize(func):
|
|
"""Strip the global_symbol so function names do not affect structural equality."""
|
|
return func.with_attr("global_symbol", "")
|
|
|
|
|
|
def test_prim_func_closure_shape():
|
|
"""Closure variable used in Buffer shape annotation."""
|
|
|
|
def f(M=16):
|
|
@T.prim_func(s_tir=True)
|
|
def func(A: T.Buffer((M,), "float32")):
|
|
T.evaluate(0)
|
|
|
|
return func
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_16(A: T.Buffer((16,), "float32")):
|
|
T.evaluate(0)
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_32(A: T.Buffer((32,), "float32")):
|
|
T.evaluate(0)
|
|
|
|
tvm.ir.assert_structural_equal(_normalize(f(16)), _normalize(expected_16))
|
|
tvm.ir.assert_structural_equal(_normalize(f(32)), _normalize(expected_32))
|
|
|
|
|
|
def test_prim_func_closure_dtype():
|
|
"""Closure variable used as Buffer dtype."""
|
|
|
|
def f(dtype="float32"):
|
|
@T.prim_func(s_tir=True)
|
|
def func(A: T.Buffer((16,), dtype)):
|
|
T.evaluate(0)
|
|
|
|
return func
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_f32(A: T.Buffer((16,), "float32")):
|
|
T.evaluate(0)
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_f16(A: T.Buffer((16,), "float16")):
|
|
T.evaluate(0)
|
|
|
|
tvm.ir.assert_structural_equal(_normalize(f("float32")), _normalize(expected_f32))
|
|
tvm.ir.assert_structural_equal(_normalize(f("float16")), _normalize(expected_f16))
|
|
|
|
|
|
def test_prim_func_nested_closure():
|
|
"""Variables from enclosing scope active on the call stack (grandparent frame fallback).
|
|
|
|
With PEP 563, closure-only variables are missing from __closure__ unless they
|
|
appear in the function body. The ChainMap fallback walks the live call stack,
|
|
so this works when the enclosing frames are still active (outer calls middle
|
|
which applies the decorator, keeping outer's frame alive on the stack).
|
|
"""
|
|
|
|
def outer(M=16):
|
|
def middle(N=8):
|
|
@T.prim_func(s_tir=True)
|
|
def func(A: T.Buffer((M, N), "float32")):
|
|
T.evaluate(0)
|
|
|
|
return func
|
|
|
|
return middle()
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_16_8(A: T.Buffer((16, 8), "float32")):
|
|
T.evaluate(0)
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_32_8(A: T.Buffer((32, 8), "float32")):
|
|
T.evaluate(0)
|
|
|
|
tvm.ir.assert_structural_equal(_normalize(outer(16)), _normalize(expected_16_8))
|
|
tvm.ir.assert_structural_equal(_normalize(outer(32)), _normalize(expected_32_8))
|
|
|
|
|
|
def test_ir_module_closure():
|
|
"""Closure variable in @I.ir_module class method."""
|
|
|
|
def f(M=16):
|
|
@I.ir_module
|
|
class Mod:
|
|
@T.prim_func(s_tir=True)
|
|
def main(A: T.Buffer((M,), "float32")):
|
|
T.evaluate(0)
|
|
|
|
return Mod
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_16(A: T.Buffer((16,), "float32")):
|
|
T.evaluate(0)
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_32(A: T.Buffer((32,), "float32")):
|
|
T.evaluate(0)
|
|
|
|
tvm.ir.assert_structural_equal(_normalize(f(16)["main"]), _normalize(expected_16))
|
|
tvm.ir.assert_structural_equal(_normalize(f(32)["main"]), _normalize(expected_32))
|
|
|
|
|
|
def test_mixed_closure_usage():
|
|
"""Closure var used in both annotation AND body -- regression check."""
|
|
|
|
def f(M=16):
|
|
@T.prim_func(s_tir=True)
|
|
def func(A: T.Buffer((M,), "float32")):
|
|
T.evaluate(M)
|
|
|
|
return func
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_16(A: T.Buffer((16,), "float32")):
|
|
T.evaluate(16)
|
|
|
|
@T.prim_func(s_tir=True)
|
|
def expected_32(A: T.Buffer((32,), "float32")):
|
|
T.evaluate(32)
|
|
|
|
tvm.ir.assert_structural_equal(_normalize(f(16)), _normalize(expected_16))
|
|
tvm.ir.assert_structural_equal(_normalize(f(32)), _normalize(expected_32))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
tvm.testing.main()
|