blob: 1df2b2a919a31114a4cf308897e3627c0f580514 [file]
# 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.
"""Unit tests for target hooks."""
import sys
import numpy as np
import pytest
import logging
import tvm
import tvm.testing
from tvm import relay, IRModule
from utils.external_codegen import (
parametrize_external_codegen_checks,
set_external_func_attr,
check_aot_executor_result,
check_graph_executor_result,
check_vm_result,
)
logging.basicConfig(level=logging.INFO)
@parametrize_external_codegen_checks
def test_tir_external_generation_inline_without_target_instance(check_result):
shape = (8,)
x_data = np.random.randint(255, size=shape).astype("float32")
y_data = np.random.randint(255, size=shape).astype("float32")
inputs = {"x": x_data, "y": y_data}
x0 = relay.var("x0", shape=shape, dtype="float32")
y0 = relay.var("y0", shape=shape, dtype="float32")
z = x0 + y0
f = relay.Function([x0, y0], z)
f = set_external_func_attr(f, "example_target_hook", "replace_add_with_subtract")
x = relay.var("x", shape=(8,), dtype="float32")
y = relay.var("y", shape=(8,), dtype="float32")
call = relay.Call(f, [x, y])
func = IRModule.from_expr(call)
check_result(func, inputs, (8,), x_data - y_data)
# TODO(mbs): The check_aot_executor_result does not support list-of-targets, mostly because
# tvm.testing.aot.compile_and_run requires the target to be a kind name string, and
# tvm.testing.aot.compile_models requires a single Target object. However, code outside of
# tvm.testing.aot is ready for this more general form.
@pytest.mark.parametrize("check_result", [check_graph_executor_result, check_vm_result])
def test_tir_external_generation_outline_with_target_instance(check_result):
shape = (8,)
x_data = np.random.randint(255, size=shape).astype("float32")
y_data = np.random.randint(255, size=shape).astype("float32")
inputs = {"x": x_data, "y": y_data}
# Compile with an instance of the hooked target kind to demonstrate plumbing target attributes
# into custom passes.
host_target = tvm.target.Target("llvm")
generic_target = tvm.target.Target("llvm", host=host_target)
extern_codegen_target = tvm.target.Target(
"example_target_hook -example_attribute=42", host=host_target
)
mod = tvm.relay.fromtext(
"""
#[version = "0.0.5"]
def @main(%x: Tensor[(8), float32], %y: Tensor[(8), float32]) -> Tensor[(8), float32] {
@replace_add_with_subtract(%x, %y) * 2.0f
}
def @replace_add_with_subtract(%x: Tensor[(8), float32], %y: Tensor[(8), float32],
Inline=1,
Primitive=1,
Compiler="example_target_hook",
global_symbol="replace_add_with_subtract") -> Tensor[(8), float32] {
%x + %y // will be rewritten to TIR implementing %x - %y - 42.0f by custom pass
}
"""
)
check_result(
mod,
inputs,
(8,),
(x_data - y_data - 42.0) * 2.0,
target=[generic_target, extern_codegen_target],
)
@pytest.mark.parametrize("check_result", [check_aot_executor_result, check_graph_executor_result])
def test_runtime_module_generation(check_result):
shape = (8,)
x_data = np.random.randint(255, size=shape).astype("float32")
y_data = np.random.randint(255, size=shape).astype("float32")
inputs = {"x": x_data, "y": y_data}
x0 = relay.var("x0", shape=shape, dtype="float32")
y0 = relay.var("y0", shape=shape, dtype="float32")
z = x0 + y0
func = relay.Function([x0, y0], z)
func = set_external_func_attr(func, "example_target_hook", "replace_add_with_subtract")
# Test hook to trigger TIRToRuntime code generation
func = func.with_attr("tir_to_runtime", True)
x = relay.var("x", shape=(8,), dtype="float32")
y = relay.var("y", shape=(8,), dtype="float32")
call = relay.Call(func, [x, y])
func = IRModule.from_expr(call)
check_result(func, inputs, (8,), x_data * y_data)
if __name__ == "__main__":
tvm.testing.main()