579 lines
19 KiB
Python
579 lines
19 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.
|
|
# ruff: noqa: E501, F841
|
|
|
|
import sys
|
|
import tempfile
|
|
|
|
import numpy as np
|
|
import pytest
|
|
import tvm_ffi
|
|
|
|
import tvm
|
|
import tvm.testing
|
|
from tvm import relax
|
|
from tvm.script import ir as I
|
|
from tvm.script import relax as R
|
|
from tvm.script import tirx as T
|
|
|
|
exec_mode = tvm.testing.parameter("bytecode", "compiled")
|
|
|
|
|
|
@tvm.script.ir_module
|
|
class InputModule:
|
|
@R.function
|
|
def foo(x: R.Tensor(("m", "n"), "int64")):
|
|
y = R.unique(x, sorted=False)
|
|
y_sorted = R.unique(x)
|
|
return y, y_sorted
|
|
|
|
|
|
def run_cpu(mod, func_name, *args, exec_mode):
|
|
if isinstance(mod, relax.Function):
|
|
func = mod
|
|
args = [func_name, *args]
|
|
func_name = func.attrs["global_symbol"]
|
|
mod = tvm.IRModule.from_expr(func)
|
|
|
|
target = tvm.target.Target("llvm")
|
|
ex = relax.build(mod, target, exec_mode=exec_mode)
|
|
vm = relax.VirtualMachine(ex, tvm.cpu())
|
|
|
|
return vm[func_name](*args)
|
|
|
|
|
|
def test_unique(exec_mode):
|
|
# TODO(prakalp): also add test for compiling and running on CUDA device.
|
|
data_numpy = np.random.randint(0, 16, (16, 16))
|
|
data = tvm.runtime.tensor(data_numpy)
|
|
result, result_sorted = run_cpu(InputModule, "foo", data, exec_mode=exec_mode)
|
|
|
|
expected_output_sorted, indices = np.unique(data_numpy, return_index=True)
|
|
expected_output = [data_numpy.flatten()[index] for index in sorted(indices)]
|
|
|
|
np.testing.assert_array_equal(expected_output_sorted, result_sorted.numpy())
|
|
np.testing.assert_array_equal(expected_output, result.numpy())
|
|
|
|
|
|
@tvm.script.ir_module
|
|
class PrintTest:
|
|
@R.function(pure=False)
|
|
def foo(x: R.Tensor((), "int32")):
|
|
# results have to be bound, but we don't use them
|
|
# TODO: We should allow calls whose results are not bound for side effects;
|
|
# it would be easy syntactic sugar to add.
|
|
p1 = R.print(x)
|
|
p2 = R.print(x, format="Number: {}")
|
|
t = (x, x)
|
|
p3 = R.print(t, format="Tuple: {}")
|
|
p4 = R.print(x, t)
|
|
p5 = R.print(x, x, format="Custom print: {} {}")
|
|
p6 = R.print(x, t, format="Another print: {} {}")
|
|
return x
|
|
|
|
|
|
def test_print(exec_mode):
|
|
try:
|
|
stdout = sys.stdout
|
|
with tempfile.TemporaryFile(mode="w+") as test_out:
|
|
sys.stdout = test_out
|
|
run_cpu(
|
|
PrintTest,
|
|
"foo",
|
|
tvm.runtime.tensor(np.array(1).astype("int32")),
|
|
exec_mode=exec_mode,
|
|
)
|
|
test_out.seek(0)
|
|
printed_text = str(test_out.read())
|
|
expected = "1\nNumber: 1\nTuple: (1, 1)\n1 (1, 1)\nCustom print: 1 1\nAnother print: 1 (1, 1)\n"
|
|
assert printed_text in expected, ("printed_text is ", printed_text)
|
|
finally:
|
|
sys.stdout = stdout
|
|
|
|
|
|
def test_assert_passes(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(x: R.Tensor((), "int32")):
|
|
_ = R.assert_op(relax.const(True))
|
|
return x
|
|
|
|
run_cpu(func, tvm.runtime.tensor(np.array(1).astype("int32")), exec_mode=exec_mode)
|
|
|
|
|
|
def test_assert_passes_with_format_args(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(x: R.Tensor((), "int32")):
|
|
_ = R.assert_op(relax.const(True), x, format="You won't see me")
|
|
return x
|
|
|
|
run_cpu(func, tvm.runtime.tensor(np.array(1).astype("int32")), exec_mode=exec_mode)
|
|
|
|
|
|
def test_assert_fails(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(x: R.Tensor((), "int32")):
|
|
_ = R.assert_op(relax.const(False))
|
|
return x
|
|
|
|
with pytest.raises(AssertionError, match="Assertion Failed"):
|
|
run_cpu(func, tvm.runtime.tensor(np.array(1).astype("int32")), exec_mode=exec_mode)
|
|
|
|
|
|
def test_assert_fails_with_message(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(x: R.Tensor((), "int32")):
|
|
_ = R.assert_op(relax.const(False), format="I failed...")
|
|
return x
|
|
|
|
with pytest.raises(AssertionError, match="I failed..."):
|
|
run_cpu(func, tvm.runtime.tensor(np.array(1).astype("int32")), exec_mode=exec_mode)
|
|
|
|
|
|
def test_assert_fails_with_args(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(x: R.Tensor((), "int32")):
|
|
_ = R.assert_op(relax.const(False), [x, x])
|
|
return x
|
|
|
|
with pytest.raises(AssertionError, match="5, 5"):
|
|
run_cpu(func, tvm.runtime.tensor(np.array(5).astype("int32")), exec_mode=exec_mode)
|
|
|
|
|
|
def test_assert_fails_with_formatted_args(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(x: R.Tensor((), "int32")):
|
|
_ = R.assert_op(relax.const(False), x, format="Number: {}")
|
|
return x
|
|
|
|
with pytest.raises(AssertionError, match="Number: 6"):
|
|
run_cpu(func, tvm.runtime.tensor(np.array(6).astype("int32")), exec_mode=exec_mode)
|
|
|
|
|
|
def test_assert_on_argument_passes(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(condition: R.Tensor((), "bool"), x: R.Tensor((), "int32")):
|
|
_ = R.assert_op(condition)
|
|
return x
|
|
|
|
condition = tvm.runtime.tensor(np.array(True))
|
|
x = tvm.runtime.tensor(np.array(5).astype("int32"))
|
|
run_cpu(func, condition, x, exec_mode=exec_mode)
|
|
|
|
|
|
def test_assert_on_argument_fails(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(condition: R.Tensor((), "bool"), x: R.Tensor((), "int32")):
|
|
_ = R.assert_op(condition)
|
|
return x
|
|
|
|
condition = tvm.runtime.tensor(np.array(False))
|
|
x = tvm.runtime.tensor(np.array(5).astype("int32"))
|
|
with pytest.raises(AssertionError):
|
|
run_cpu(func, condition, x, exec_mode=exec_mode)
|
|
|
|
|
|
def test_assert_on_symbolic_var_passes(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(x: R.Tensor(["N"], "int32")):
|
|
N = T.int64()
|
|
_ = R.assert_op(R.prim_value(N % 8 == 0))
|
|
return x
|
|
|
|
x = tvm.runtime.tensor(np.arange(8, dtype="int32"))
|
|
run_cpu(func, x, exec_mode=exec_mode)
|
|
|
|
|
|
def test_assert_on_symbolic_var_fails(exec_mode):
|
|
@R.function(pure=False)
|
|
def func(x: R.Tensor(["N"], "int32")):
|
|
N = T.int64()
|
|
_ = R.assert_op(R.prim_value(N % 8 == 0))
|
|
return x
|
|
|
|
x = tvm.runtime.tensor(np.arange(10, dtype="int32"))
|
|
with pytest.raises(AssertionError):
|
|
run_cpu(func, x, exec_mode=exec_mode)
|
|
|
|
|
|
@tvm.script.ir_module
|
|
class ShapeOfTest:
|
|
@R.function
|
|
def get_shape(t: R.Tensor(ndim=-1, dtype="int32")) -> R.Shape(ndim=-1):
|
|
return R.shape_of(t)
|
|
|
|
@R.function
|
|
def get_constrained_shape(t: R.Tensor(ndim=1, dtype="int32")) -> R.Shape(ndim=1):
|
|
# require the input tensor to have rank 1
|
|
return R.shape_of(t)
|
|
|
|
@R.function
|
|
def get_scalar_shape() -> R.Shape(()):
|
|
x: R.Tensor((), "int32") = R.const(1, dtype="int32")
|
|
return R.shape_of(x)
|
|
|
|
@R.function
|
|
def get_constant_shape() -> R.Shape((2, 2)):
|
|
x: R.Tensor((2, 2), "int32") = R.const(
|
|
np.array([[1, 2], [3, 4]], dtype="int32"), dtype="int32"
|
|
)
|
|
return R.shape_of(x)
|
|
|
|
|
|
def test_op_shape_of(exec_mode):
|
|
unit_shape = run_cpu(ShapeOfTest, "get_scalar_shape", exec_mode=exec_mode)
|
|
assert unit_shape == tvm_ffi.Shape([])
|
|
|
|
const_shape = run_cpu(ShapeOfTest, "get_constant_shape", exec_mode=exec_mode)
|
|
assert const_shape == tvm_ffi.Shape([2, 2])
|
|
|
|
scalar_shape = run_cpu(
|
|
ShapeOfTest,
|
|
"get_shape",
|
|
tvm.runtime.tensor(np.array(1, dtype="int32")),
|
|
exec_mode=exec_mode,
|
|
)
|
|
assert scalar_shape == tvm_ffi.Shape([])
|
|
|
|
tensor_shape = run_cpu(
|
|
ShapeOfTest,
|
|
"get_shape",
|
|
tvm.runtime.tensor(np.zeros((1, 2, 3)).astype("int32")),
|
|
exec_mode=exec_mode,
|
|
)
|
|
assert tensor_shape == tvm_ffi.Shape([1, 2, 3])
|
|
|
|
constrained_shape = run_cpu(
|
|
ShapeOfTest,
|
|
"get_constrained_shape",
|
|
tvm.runtime.tensor(np.zeros((1,)).astype("int32")),
|
|
exec_mode=exec_mode,
|
|
)
|
|
assert constrained_shape == tvm_ffi.Shape([1])
|
|
|
|
|
|
@tvm.script.ir_module
|
|
class ShapeToTensorTest:
|
|
@R.function
|
|
def const_shape(shape: R.Shape(ndim=-1)) -> R.Tensor(ndim=-1):
|
|
return R.shape_to_tensor(shape)
|
|
|
|
@R.function
|
|
def symbolic_shape(shape: R.Shape(("m", "n"))) -> R.Tensor(ndim=-1):
|
|
m = T.int64()
|
|
n = T.int64()
|
|
return R.shape_to_tensor(shape)
|
|
|
|
|
|
def test_op_shape_to_tensor(exec_mode):
|
|
# Check type
|
|
isinstance(ShapeToTensorTest["const_shape"].body.ty, tvm.relax.TensorType)
|
|
assert ShapeToTensorTest["const_shape"].body.ty.ndim == 1
|
|
isinstance(ShapeToTensorTest["symbolic_shape"].body.ty, tvm.relax.TensorType)
|
|
assert ShapeToTensorTest["symbolic_shape"].body.ty.ndim == 1
|
|
|
|
# Check its functionality
|
|
out2d = run_cpu(ShapeToTensorTest, "const_shape", tvm_ffi.Shape([3, 2]), exec_mode=exec_mode)
|
|
assert isinstance(out2d, tvm.runtime.Tensor)
|
|
assert np.array_equal(out2d.numpy(), np.array([3, 2]))
|
|
|
|
out3d = run_cpu(ShapeToTensorTest, "const_shape", tvm_ffi.Shape([3, 3, 2]), exec_mode=exec_mode)
|
|
assert isinstance(out3d, tvm.runtime.Tensor)
|
|
assert np.array_equal(out3d.numpy(), np.array([3, 3, 2]))
|
|
|
|
out4d = run_cpu(
|
|
ShapeToTensorTest, "const_shape", tvm_ffi.Shape([3, 3, 2, 2]), exec_mode=exec_mode
|
|
)
|
|
assert isinstance(out4d, tvm.runtime.Tensor)
|
|
assert np.array_equal(out4d.numpy(), np.array([3, 3, 2, 2]))
|
|
|
|
outs = run_cpu(ShapeToTensorTest, "symbolic_shape", tvm_ffi.Shape([3, 2]), exec_mode=exec_mode)
|
|
assert isinstance(outs, tvm.runtime.Tensor)
|
|
assert np.array_equal(outs.numpy(), np.array([3, 2]))
|
|
|
|
|
|
def test_op_call_pure_packed(exec_mode):
|
|
@tvm.script.ir_module
|
|
class CallPureTest:
|
|
@R.function
|
|
def pure_copy(x: R.Tensor((3, 4), "float32")):
|
|
z = R.call_pure_packed(
|
|
"vm.builtin.copy", x, ty_args=(R.Tensor((3, 4), dtype="float32"))
|
|
)
|
|
return z
|
|
|
|
np.random.seed(0) # to avoid flakiness
|
|
arr = np.random.rand(3, 4).astype("float32")
|
|
copy_found = run_cpu(CallPureTest, "pure_copy", tvm.runtime.tensor(arr), exec_mode=exec_mode)
|
|
assert (copy_found.numpy() == arr).all()
|
|
|
|
|
|
def test_op_call_inplace_packed(exec_mode):
|
|
# in this case we can use the same test as above
|
|
@tvm.script.ir_module
|
|
class CallInplaceTest:
|
|
@R.function
|
|
def pure_copy(x: R.Tensor((3, 4), "float32")):
|
|
z = R.call_inplace_packed(
|
|
"vm.builtin.copy",
|
|
x,
|
|
inplace_indices=0,
|
|
ty_args=(R.Tensor((3, 4), dtype="float32")),
|
|
)
|
|
return z
|
|
|
|
@tvm.register_global_func("test.inplace.add", override=True)
|
|
def inplace_add(a, b):
|
|
arr_a = a.numpy()
|
|
arr_b = b.numpy()
|
|
for i in range(len(arr_a)):
|
|
for j in range(len(arr_a[i])):
|
|
arr_a[i][j] = arr_a[i][j] + arr_b[i][j]
|
|
a.copyfrom(arr_a)
|
|
return a
|
|
|
|
@tvm.script.ir_module
|
|
class CallInplaceAddTest:
|
|
@R.function
|
|
def inplace_add(x: R.Tensor((3, 4), "float32"), y: R.Tensor((3, 4), "float32")):
|
|
z = R.call_inplace_packed(
|
|
"test.inplace.add",
|
|
x,
|
|
y,
|
|
inplace_indices=0,
|
|
ty_args=(R.Tensor((3, 4), dtype="float32")),
|
|
)
|
|
return z
|
|
|
|
np.random.seed(1) # to avoid flakiness
|
|
arr_a = np.random.rand(3, 4).astype("float32")
|
|
arr_b = np.random.rand(3, 4).astype("float32")
|
|
sum = arr_a + arr_b
|
|
tvm_arr_a = tvm.runtime.tensor(arr_a)
|
|
result = run_cpu(
|
|
CallInplaceAddTest, "inplace_add", tvm_arr_a, tvm.runtime.tensor(arr_b), exec_mode=exec_mode
|
|
)
|
|
assert result == tvm_arr_a
|
|
assert (result.numpy() == sum).all()
|
|
|
|
@tvm.register_global_func("test.inplace.tuple_add", override=True)
|
|
def inplace_tuple_add(a, b):
|
|
arr_a = a.numpy()
|
|
arr_b = b.numpy()
|
|
c = tvm.runtime.tensor(arr_a + arr_b)
|
|
for i in range(len(arr_a)):
|
|
for j in range(len(arr_a[i])):
|
|
arr_a[i][j] = arr_a[i][j] + arr_b[i][j]
|
|
a.copyfrom(arr_a)
|
|
return tvm.runtime.convert([a, c])
|
|
|
|
@tvm.script.ir_module
|
|
class CallInplaceTuple:
|
|
@R.function
|
|
def inplace_tuple(x: R.Tensor((3, 4), "float32"), y: R.Tensor((3, 4), "float32")):
|
|
z = R.call_inplace_packed(
|
|
"test.inplace.tuple_add",
|
|
x,
|
|
y,
|
|
inplace_indices=[0, -1],
|
|
ty_args=(R.Tensor((3, 4), dtype="float32"), R.Tensor((3, 4), dtype="float32")),
|
|
)
|
|
return z
|
|
|
|
np.random.seed(2) # to avoid flakiness
|
|
arr_a = np.random.rand(3, 4).astype("float32")
|
|
arr_b = np.random.rand(3, 4).astype("float32")
|
|
sum = arr_a + arr_b
|
|
tvm_arr_a = tvm.runtime.tensor(arr_a)
|
|
tvm_arr_b = tvm.runtime.tensor(arr_b)
|
|
result = run_cpu(CallInplaceTuple, "inplace_tuple", tvm_arr_a, tvm_arr_b, exec_mode=exec_mode)
|
|
assert result[0] == tvm_arr_a
|
|
assert (result[0].numpy() == sum).all()
|
|
assert result[1] != tvm_arr_a and result[1] != tvm_arr_b
|
|
assert (result[1].numpy() == sum).all()
|
|
|
|
|
|
def test_op_call_py_func(exec_mode):
|
|
"""Test R.call_py_func operator functionality."""
|
|
import torch
|
|
|
|
def torch_relu(x):
|
|
if isinstance(x, tvm.runtime.Tensor):
|
|
x_torch = torch.from_numpy(x.numpy())
|
|
elif hasattr(x, "asnumpy"):
|
|
x_torch = torch.from_numpy(x.asnumpy())
|
|
else:
|
|
x_np = np.array(x)
|
|
if isinstance(x_np, tvm.runtime.Tensor):
|
|
x_torch = torch.from_numpy(x_np.numpy())
|
|
elif len(x_np) > 0 and isinstance(x_np[0], tvm.runtime.Tensor):
|
|
x_torch = torch.from_numpy(np.array([t.numpy() for t in x_np]))
|
|
if x_torch.ndim > 1:
|
|
x_torch = x_torch.flatten()
|
|
else:
|
|
x_torch = torch.from_numpy(x_np)
|
|
result = torch.relu(x_torch)
|
|
return tvm.runtime.tensor(result.numpy())
|
|
|
|
def torch_sigmoid(x):
|
|
if isinstance(x, tvm.runtime.Tensor):
|
|
x_torch = torch.from_numpy(x.numpy())
|
|
elif hasattr(x, "asnumpy"):
|
|
x_torch = torch.from_numpy(x.asnumpy())
|
|
else:
|
|
x_np = np.array(x)
|
|
if isinstance(x_np, tvm.runtime.Tensor):
|
|
x_torch = torch.from_numpy(x_np.numpy())
|
|
elif len(x_np) > 0 and isinstance(x_np[0], tvm.runtime.Tensor):
|
|
x_torch = torch.from_numpy(np.array([t.numpy() for t in x_np]))
|
|
if x_torch.ndim > 1:
|
|
x_torch = x_torch.flatten()
|
|
else:
|
|
x_torch = torch.from_numpy(x_np)
|
|
result = torch.sigmoid(x_torch)
|
|
return tvm.runtime.tensor(result.numpy())
|
|
|
|
register_func = tvm.get_global_func("vm.builtin.register_py_func")
|
|
register_func("torch_relu", torch_relu)
|
|
register_func("torch_sigmoid", torch_sigmoid)
|
|
|
|
@tvm.script.ir_module
|
|
class CallPyFuncTest:
|
|
@R.function
|
|
def simple_call(x: R.Tensor((3,), "float32")):
|
|
result = R.call_py_func(R.str("torch_relu"), (x,), out_ty=R.Tensor((3,), "float32"))
|
|
return result
|
|
|
|
@R.function
|
|
def multiple_calls(x: R.Tensor((2,), "float32")):
|
|
y = R.call_py_func(R.str("torch_relu"), (x,), out_ty=R.Tensor((2,), "float32"))
|
|
z = R.call_py_func(R.str("torch_sigmoid"), (y,), out_ty=R.Tensor((2,), "float32"))
|
|
return z
|
|
|
|
np.random.seed(0)
|
|
x_data = np.array([-1.0, 0.0, 1.0], dtype=np.float32)
|
|
x_tvm = tvm.runtime.tensor(x_data)
|
|
|
|
result = run_cpu(CallPyFuncTest, "simple_call", x_tvm, exec_mode=exec_mode)
|
|
expected = np.maximum(x_data, 0.0)
|
|
assert (result.numpy() == expected).all()
|
|
|
|
y_data = np.array([-0.5, 0.5], dtype=np.float32)
|
|
y_tvm = tvm.runtime.tensor(y_data)
|
|
|
|
result2 = run_cpu(CallPyFuncTest, "multiple_calls", y_tvm, exec_mode=exec_mode)
|
|
expected2 = 1.0 / (1.0 + np.exp(-np.maximum(y_data, 0.0)))
|
|
assert (result2.numpy() == expected2).all()
|
|
|
|
clear_func = tvm.get_global_func("vm.builtin.clear_py_func_registry")
|
|
clear_func()
|
|
|
|
|
|
def test_op_to_device(exec_mode):
|
|
@tvm.script.ir_module
|
|
class CallToDevice:
|
|
@R.function
|
|
def to_dev(x: R.Tensor((3, 4), "float32")):
|
|
z = R.call_pure_packed(
|
|
"vm.builtin.to_device",
|
|
x,
|
|
1,
|
|
0,
|
|
ty_args=(R.Tensor((3, 4), dtype="float32")),
|
|
)
|
|
return z
|
|
|
|
np.random.seed(0) # to avoid flakiness
|
|
arr = np.random.rand(3, 4).astype("float32")
|
|
copy_found = run_cpu(CallToDevice, "to_dev", tvm.runtime.tensor(arr), exec_mode=exec_mode)
|
|
assert (copy_found.numpy() == arr).all()
|
|
|
|
|
|
def test_op_to_vdevice(exec_mode):
|
|
@tvm.script.ir_module
|
|
class ToVDevice:
|
|
I.module_global_infos({"vdevice": [I.vdevice("llvm")]})
|
|
|
|
@R.function
|
|
def to_vdev(x: R.Tensor((3, 4), "float32")):
|
|
dst_vdev = tvm.ir.VDevice("llvm", 0, "global")
|
|
ret = R.to_vdevice(x, "llvm")
|
|
return ret
|
|
|
|
np.random.seed(0)
|
|
arr = np.random.rand(3, 4).astype("float32")
|
|
copy_found = run_cpu(ToVDevice, "to_vdev", tvm.runtime.tensor(arr), exec_mode=exec_mode)
|
|
assert (copy_found.numpy() == arr).all()
|
|
|
|
|
|
def test_scalar_tensor_as_branch_condition(exec_mode):
|
|
"""The condition of a branch may be a scalar tensor"""
|
|
|
|
@R.function
|
|
def func(condition: R.Tensor((), "bool")):
|
|
if condition:
|
|
out = R.prim_value(5)
|
|
else:
|
|
out = R.prim_value(10)
|
|
return out
|
|
|
|
res = run_cpu(func, tvm.runtime.tensor(np.array(True)), exec_mode=exec_mode)
|
|
assert res == 5
|
|
|
|
res = run_cpu(func, tvm.runtime.tensor(np.array(False)), exec_mode=exec_mode)
|
|
assert res == 10
|
|
|
|
|
|
def test_prim_value_as_branch_condition(exec_mode):
|
|
"""The condition may be a Expr"""
|
|
|
|
@R.function
|
|
def func(condition: R.Prim("bool")):
|
|
if condition:
|
|
out = R.prim_value(5)
|
|
else:
|
|
out = R.prim_value(10)
|
|
return out
|
|
|
|
res = run_cpu(func, True, exec_mode=exec_mode)
|
|
assert res == 5
|
|
|
|
res = run_cpu(func, False, exec_mode=exec_mode)
|
|
assert res == 10
|
|
|
|
|
|
def test_computed_prim_value_as_branch_condition(exec_mode):
|
|
"""The R.Prim condition may be computed within the function"""
|
|
|
|
@R.function
|
|
def func(x: R.Tensor(["N"], "int64")):
|
|
N = T.int64()
|
|
if R.prim_value(N % 16 == 0):
|
|
out = R.prim_value(5)
|
|
else:
|
|
out = R.prim_value(10)
|
|
return out
|
|
|
|
res = run_cpu(func, tvm.runtime.tensor(np.arange(16)), exec_mode=exec_mode)
|
|
assert res == 5
|
|
|
|
res = run_cpu(func, tvm.runtime.tensor(np.arange(20)), exec_mode=exec_mode)
|
|
assert res == 10
|
|
|
|
|
|
if __name__ == "__main__":
|
|
tvm.testing.main()
|