| # 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() |