chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,510 @@
|
||||
# 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.
|
||||
# pylint: disable=invalid-name, missing-docstring
|
||||
# ruff: noqa: F401, F841
|
||||
"""Unittests for tvm.script.ir_builder.tirx"""
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import tvm
|
||||
import tvm.runtime
|
||||
import tvm.testing
|
||||
from tvm import tirx
|
||||
from tvm.ir.base import assert_structural_equal
|
||||
from tvm.script.ir_builder import IRBuilder
|
||||
from tvm.script.ir_builder import tirx as T
|
||||
|
||||
|
||||
def test_ir_builder_tir_primfunc_base():
|
||||
with IRBuilder() as ib:
|
||||
with T.prim_func(s_tir=True):
|
||||
T.evaluate(0)
|
||||
|
||||
# the prim_func generated by IRBuilder
|
||||
prim_func_actual = ib.get()
|
||||
|
||||
# the expected prim_func
|
||||
prim_func_expected = tirx.PrimFunc(
|
||||
params=[],
|
||||
body=tirx.Evaluate(0),
|
||||
ret_type=None,
|
||||
buffer_map=None,
|
||||
attrs=tvm.ir.make_node("ir.DictAttrs", s_tir=True),
|
||||
)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(prim_func_actual, prim_func_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_primfunc_complete():
|
||||
with IRBuilder() as ib:
|
||||
with T.prim_func(s_tir=True):
|
||||
T.arg("a", T.handle())
|
||||
T.arg("b", T.int64())
|
||||
T.arg("c", T.Buffer((128, 128), "float32"))
|
||||
d = T.arg("d", T.handle())
|
||||
e = T.arg("e", T.Buffer((1024,), "int8"))
|
||||
T.func_attr({"key": "value"})
|
||||
T.func_ret(tvm.ir.PrimType("int64"))
|
||||
buffer_d = T.match_buffer(d, (64, 64), "int64")
|
||||
T.evaluate(0)
|
||||
|
||||
# the prim_func generated by IRBuilder
|
||||
prim_func_actual = ib.get()
|
||||
|
||||
# the expected prim_func
|
||||
c_handle, c_buffer = (
|
||||
tirx.Var("c_handle", tvm.ir.PointerType(tvm.ir.PrimType("void"))),
|
||||
tirx.decl_buffer((128, 128), "float32", name="c", layout=None),
|
||||
)
|
||||
d_handle, d_buffer = (
|
||||
tirx.Var("d", tvm.ir.PointerType(tvm.ir.PrimType("void"))),
|
||||
tirx.decl_buffer((64, 64), "int64", name="d", layout=None),
|
||||
)
|
||||
e_handle, e_buffer = (
|
||||
tirx.Var("e_handle", tvm.ir.PointerType(tvm.ir.PrimType("void"))),
|
||||
tirx.decl_buffer((1024,), "int8", name="e", layout=None),
|
||||
)
|
||||
prim_func_expected = tirx.PrimFunc(
|
||||
params=[
|
||||
tirx.Var("a", tvm.ir.PointerType(tvm.ir.PrimType("void"))),
|
||||
tirx.Var("b", "int64"),
|
||||
c_handle,
|
||||
d_handle,
|
||||
e_handle,
|
||||
],
|
||||
body=tirx.Evaluate(0),
|
||||
ret_type=tvm.ir.PrimType("int64"),
|
||||
buffer_map={c_handle: c_buffer, d_handle: d_buffer, e_handle: e_buffer},
|
||||
attrs=tvm.ir.make_node("ir.DictAttrs", key="value", s_tir=True),
|
||||
)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(prim_func_actual, prim_func_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_block_base():
|
||||
with IRBuilder() as ib:
|
||||
with T.sblock("block"):
|
||||
T.evaluate(0)
|
||||
|
||||
# the block generated by IRBuilder
|
||||
block_realize_actual = ib.get()
|
||||
|
||||
# the expected block
|
||||
block_expected = tirx.SBlock(
|
||||
iter_vars=[],
|
||||
reads=[],
|
||||
writes=[],
|
||||
name_hint="block",
|
||||
body=tirx.Evaluate(0),
|
||||
alloc_buffers=None,
|
||||
match_buffers=None,
|
||||
annotations={"tirx.script_parsing_detect_access": tirx.IntImm("int64", 3)},
|
||||
)
|
||||
block_realize_expected = tirx.SBlockRealize(
|
||||
iter_values=[],
|
||||
predicate=True,
|
||||
block=block_expected,
|
||||
)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(block_realize_actual, block_realize_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_block_complete():
|
||||
with IRBuilder() as ib:
|
||||
a = T.int64()
|
||||
b = T.Buffer((128, 128), "float32")
|
||||
c = T.Buffer((128, 128), "float32")
|
||||
d = T.int32()
|
||||
e = T.Buffer((128, 128), "float32")
|
||||
f = T.int32()
|
||||
with T.sblock("block"):
|
||||
T.where(a > 1)
|
||||
T.reads(b[0:16, 0:16])
|
||||
T.writes(c[d:128, d:128])
|
||||
T.sblock_attr({"key": "value"})
|
||||
T.sblock_alloc_buffer((128, 128), "float32")
|
||||
T.match_buffer(e[0:32, 0:32], (32, 32), "float32")
|
||||
T.axis.spatial(128, f)
|
||||
T.evaluate(0)
|
||||
|
||||
# the block generated by IRBuilder
|
||||
block_realize_actual = ib.get()
|
||||
|
||||
# the expected block
|
||||
var_a = tirx.Var("a", "int64")
|
||||
buffer_b = tirx.decl_buffer((128, 128), "float32", name="b")
|
||||
buffer_c = tirx.decl_buffer((128, 128), "float32", name="c")
|
||||
var_d = tirx.Var("d", "int32")
|
||||
buffer_e = tirx.decl_buffer((128, 128), "float32", name="c")
|
||||
var_f = tirx.Var("f", "int32")
|
||||
block_expected = tirx.SBlock(
|
||||
iter_vars=[tirx.IterVar((0, 128), tirx.Var("", "int32"), iter_type=tirx.IterVar.DataPar)],
|
||||
reads=[buffer_b[0:16, 0:16]],
|
||||
writes=[buffer_c[var_d:128, var_d:128]],
|
||||
name_hint="block",
|
||||
body=tirx.Evaluate(0),
|
||||
alloc_buffers=[tirx.decl_buffer((128, 128), "float32")],
|
||||
match_buffers=[
|
||||
tirx.MatchBufferRegion(tirx.decl_buffer((32, 32), "float32"), buffer_e[0:32, 0:32])
|
||||
],
|
||||
annotations={"key": "value"},
|
||||
)
|
||||
block_realize_expected = tirx.SBlockRealize(
|
||||
iter_values=[var_f],
|
||||
predicate=var_a > 1,
|
||||
block=block_expected,
|
||||
)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(block_realize_actual, block_realize_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_axis():
|
||||
with IRBuilder() as ib:
|
||||
a = T.int32()
|
||||
b = T.int32()
|
||||
c = T.int32()
|
||||
d = T.int32()
|
||||
with T.sblock("block"):
|
||||
T.axis.spatial(8, a)
|
||||
T.axis.reduce(16, b)
|
||||
T.axis.scan(32, c)
|
||||
T.axis.opaque(64, d)
|
||||
T.evaluate(0)
|
||||
|
||||
# the block generated by IRBuilder
|
||||
block_realize_actual = ib.get()
|
||||
|
||||
# the expected block
|
||||
var_a = tirx.Var("a", "int32")
|
||||
var_b = tirx.Var("b", "int32")
|
||||
var_c = tirx.Var("c", "int32")
|
||||
var_d = tirx.Var("d", "int32")
|
||||
block_expected = tirx.SBlock(
|
||||
iter_vars=[
|
||||
tirx.IterVar((0, 8), tirx.Var("", "int32"), iter_type=tirx.IterVar.DataPar),
|
||||
tirx.IterVar((0, 16), tirx.Var("", "int32"), iter_type=tirx.IterVar.CommReduce),
|
||||
tirx.IterVar((0, 32), tirx.Var("", "int32"), iter_type=tirx.IterVar.Ordered),
|
||||
tirx.IterVar((0, 64), tirx.Var("", "int32"), iter_type=tirx.IterVar.Opaque),
|
||||
],
|
||||
reads=[],
|
||||
writes=[],
|
||||
name_hint="block",
|
||||
body=tirx.Evaluate(0),
|
||||
annotations={"tirx.script_parsing_detect_access": tirx.IntImm("int64", 3)},
|
||||
)
|
||||
block_realize_expected = tirx.SBlockRealize(
|
||||
iter_values=[var_a, var_b, var_c, var_d],
|
||||
predicate=True,
|
||||
block=block_expected,
|
||||
)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(block_realize_actual, block_realize_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_for():
|
||||
with IRBuilder() as ib:
|
||||
with T.serial(128) as a:
|
||||
with T.parallel(64) as b:
|
||||
with T.vectorized(32) as c:
|
||||
with T.unroll(16) as d:
|
||||
with T.thread_binding(8, thread="threadIdx.x") as e:
|
||||
T.evaluate(0)
|
||||
|
||||
# the for generated by IRBuilder
|
||||
for_actual = ib.get()
|
||||
|
||||
# the expected for
|
||||
thread_binding_expected = tirx.For(
|
||||
loop_var=tirx.Var("", "int32"),
|
||||
min=0,
|
||||
extent=8,
|
||||
kind=tirx.ForKind.THREAD_BINDING,
|
||||
body=tirx.Evaluate(0),
|
||||
thread_binding=tirx.IterVar(
|
||||
None, tirx.Var("", "int32"), tirx.IterVar.ThreadIndex, "threadIdx.x"
|
||||
),
|
||||
)
|
||||
unroll_expected = tirx.For(
|
||||
loop_var=tirx.Var("", "int32"),
|
||||
min=0,
|
||||
extent=16,
|
||||
kind=tirx.ForKind.UNROLLED,
|
||||
body=thread_binding_expected,
|
||||
)
|
||||
vectorized_expected = tirx.For(
|
||||
loop_var=tirx.Var("", "int32"),
|
||||
min=0,
|
||||
extent=32,
|
||||
kind=tirx.ForKind.VECTORIZED,
|
||||
body=unroll_expected,
|
||||
)
|
||||
parallel_expected = tirx.For(
|
||||
loop_var=tirx.Var("", "int32"),
|
||||
min=0,
|
||||
extent=64,
|
||||
kind=tirx.ForKind.PARALLEL,
|
||||
body=vectorized_expected,
|
||||
)
|
||||
for_expected = tirx.For(
|
||||
loop_var=tirx.Var("", "int32"),
|
||||
min=0,
|
||||
extent=128,
|
||||
kind=tirx.ForKind.SERIAL,
|
||||
body=parallel_expected,
|
||||
)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(for_actual, for_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_for_uint():
|
||||
with IRBuilder() as ib:
|
||||
with T.serial(tirx.const(128, "uint32")) as a:
|
||||
T.evaluate(0)
|
||||
|
||||
# the for generated by IRBuilder
|
||||
for_actual = ib.get()
|
||||
|
||||
for_expected = tirx.For(
|
||||
loop_var=tirx.Var("", "uint32"),
|
||||
min=tirx.const(0, "uint32"),
|
||||
extent=tirx.const(128, "uint32"),
|
||||
kind=tirx.ForKind.SERIAL,
|
||||
body=tirx.Evaluate(0),
|
||||
)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(for_actual, for_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_assert():
|
||||
with IRBuilder() as ib:
|
||||
with T.Assert(T.int32() == 0, message="a is 0"):
|
||||
T.evaluate(0)
|
||||
# the assert generated by IRBuilder
|
||||
assert_actual = ib.get()
|
||||
|
||||
# AssertStmt is a leaf. The frame emits the assert and then the body stmts as siblings.
|
||||
assert_expected = tirx.SeqStmt(
|
||||
[
|
||||
tirx.AssertStmt(
|
||||
T.int32() == 0,
|
||||
tirx.StringImm("RuntimeError"),
|
||||
[tirx.StringImm("a is 0")],
|
||||
),
|
||||
tirx.Evaluate(0),
|
||||
]
|
||||
)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(assert_actual, assert_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_bind():
|
||||
# Test that T.bind emits a flat Bind statement and returns the Var.
|
||||
with IRBuilder() as ib:
|
||||
v = T.bind(tirx.IntImm("int32", 2))
|
||||
# the let binding generated by IRBuilder
|
||||
let_actual = ib.get()
|
||||
|
||||
# Bind is now flat (no body), so a single Bind stmt is emitted.
|
||||
let_expected = tirx.Bind(T.int32(), tirx.IntImm("int32", 2))
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(let_actual, let_expected, map_free_vars=True)
|
||||
# Check that the returned value is a Var
|
||||
assert isinstance(v, tirx.Var)
|
||||
|
||||
|
||||
def test_ir_builder_tir_thread():
|
||||
with IRBuilder() as ib:
|
||||
with T.prim_func(s_tir=True):
|
||||
brow = T.env_thread("blockIdx.y")
|
||||
with T.launch_thread(brow, 1):
|
||||
T.evaluate(0)
|
||||
|
||||
# the prim_func generated by IRBuilder
|
||||
ir_actual = ib.get()
|
||||
|
||||
# the expected prim_func
|
||||
iter_var = tirx.IterVar((0, 1), "v", iter_type=1, thread_tag="blockIdx.y")
|
||||
attr_stmt = tirx.AttrStmt(iter_var, "thread_extent", 1, tirx.Evaluate(0))
|
||||
func = tirx.PrimFunc([], attr_stmt).with_attr("s_tir", True)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(ir_actual, func, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_allocate():
|
||||
with IRBuilder() as ib:
|
||||
with T.prim_func(s_tir=True):
|
||||
T.func_name("test")
|
||||
buf = T.alloc_buffer([10], "float32", scope="local")
|
||||
T.evaluate(1)
|
||||
|
||||
# the allocate generated by IRBuilder
|
||||
ir_actual = ib.get()
|
||||
body = ir_actual.body
|
||||
|
||||
# AllocBuffer is flat: body should be a SeqStmt with [AllocBuffer, Evaluate(1)]
|
||||
assert isinstance(body, tirx.SeqStmt), f"Expected SeqStmt but got {type(body)}"
|
||||
assert len(body) == 2
|
||||
assert isinstance(body[0], tirx.AllocBuffer)
|
||||
assert isinstance(body[1], tirx.Evaluate)
|
||||
assert body[1].value.value == 1
|
||||
|
||||
|
||||
def test_ir_builder_tir_while():
|
||||
with IRBuilder() as ib:
|
||||
with T.While(T.int32() > 0):
|
||||
T.evaluate(0)
|
||||
|
||||
# the while generated by IRBuilder
|
||||
ir_actual = ib.get()
|
||||
|
||||
# the expected while
|
||||
ir_expected = tirx.While(tirx.Var("x", "int32") > 0, tirx.Evaluate(0))
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(ir_actual, ir_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_if_then_else():
|
||||
with IRBuilder() as ib:
|
||||
with T.If(T.int32() < 12):
|
||||
with T.Then():
|
||||
T.evaluate(T.int32(0))
|
||||
with T.Else():
|
||||
T.evaluate(T.int32(1))
|
||||
|
||||
# the if_then_else generated by IRBuilder
|
||||
ir_actual = ib.get()
|
||||
|
||||
# the expected if_then_else
|
||||
ir_expected = tirx.IfThenElse(
|
||||
tirx.Var("c", "int32") < 12,
|
||||
tirx.Evaluate(tirx.IntImm("int32", 0)),
|
||||
tirx.Evaluate(tirx.IntImm("int32", 1)),
|
||||
)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(ir_actual, ir_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_buffer_store():
|
||||
buffer_a = T.Buffer((10, 10), "float32")
|
||||
i = T.int32()
|
||||
with IRBuilder() as ib:
|
||||
T.buffer_store(buffer_a, 0.1, [0, i])
|
||||
|
||||
# the buffer store generated by IRBuilder
|
||||
ir_actual = ib.get()
|
||||
|
||||
# the expected buffer store
|
||||
ir_expected = tirx.BufferStore(buffer_a, 0.1, [0, i])
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(ir_actual, ir_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_buffer_store_scalable_vec():
|
||||
buffer_a = T.Buffer((30,), "float32")
|
||||
value = T.broadcast(0.11, 4 * tvm.tirx.vscale())
|
||||
index = T.ramp(0, 1, 4 * tvm.tirx.vscale())
|
||||
|
||||
with IRBuilder() as ib:
|
||||
T.buffer_store(buffer_a, value, [index])
|
||||
|
||||
# the buffer store generated by IRBuilder
|
||||
ir_actual = ib.get()
|
||||
|
||||
# the expected buffer store
|
||||
ir_expected = tirx.BufferStore(buffer_a, value, [index])
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(ir_actual, ir_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_buffer_store_predicate():
|
||||
buffer_a = T.Buffer((30,), "float32")
|
||||
value = T.broadcast(0.11, T.vscale() * 4)
|
||||
index = T.ramp(0, 1, T.vscale() * 4)
|
||||
predicate = T.broadcast(T.bool(True), T.vscale() * 4)
|
||||
|
||||
with IRBuilder() as ib:
|
||||
T.buffer_store(buffer_a, value, [index], predicate)
|
||||
|
||||
ir_actual = ib.get()
|
||||
ir_expected = tirx.BufferStore(buffer_a, value, [index], predicate)
|
||||
assert_structural_equal(ir_actual, ir_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_evaluate():
|
||||
with IRBuilder() as ib:
|
||||
T.evaluate(0)
|
||||
# the evaluate generated by IRBuilder
|
||||
eval_actual = ib.get()
|
||||
|
||||
# the expected evaluate
|
||||
eval_expected = tirx.Evaluate(0)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(eval_actual, eval_expected, map_free_vars=True)
|
||||
|
||||
|
||||
def test_ir_builder_tir_decl_buffer():
|
||||
with IRBuilder() as ib:
|
||||
with T.prim_func(s_tir=True):
|
||||
T.func_name("test")
|
||||
buf = T.decl_buffer([128, 128], "float32")
|
||||
T.evaluate(1)
|
||||
|
||||
# the decl_buffer generated by IRBuilder
|
||||
ir_actual = ib.get()
|
||||
body = ir_actual.body
|
||||
|
||||
# decl_buffer without data emits AllocBuffer (flat): body should be SeqStmt
|
||||
assert isinstance(body, tirx.SeqStmt), f"Expected SeqStmt but got {type(body)}"
|
||||
assert len(body) == 2
|
||||
assert isinstance(body[0], tirx.AllocBuffer)
|
||||
assert isinstance(body[1], tirx.Evaluate)
|
||||
assert body[1].value.value == 1
|
||||
|
||||
|
||||
def test_ir_builder_tir_inline():
|
||||
with IRBuilder() as ib:
|
||||
m, n = T.meta_var(1), T.meta_var(2)
|
||||
a, b = T.meta_var([3, 4])
|
||||
T.evaluate(m.value + n.value + a.value + b.value)
|
||||
# the evaluate generated by IRBuilder
|
||||
eval_actual = ib.get()
|
||||
|
||||
# the expected evaluate
|
||||
eval_expected = tirx.Evaluate(10)
|
||||
|
||||
# Check if the generated ir is expected
|
||||
assert_structural_equal(eval_actual, eval_expected, map_free_vars=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
tvm.testing.main()
|
||||
Reference in New Issue
Block a user