# 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. import re import pytest import tvm import tvm.contrib.hexagon as hexagon import tvm.testing from tvm.script import ir as I from tvm.script import tirx as T from tvm.testing import env @pytest.fixture(autouse=True) def register_linker(): original_linker = hexagon.hexagon_link() # Register a phony linker, so that we can test codegen without a Hexagon toolchain. hexagon.register_linker(lambda: "/bin/true") yield None # Restore registration. hexagon.register_linker(original_linker) @pytest.mark.skipif(not env.has_hexagon(), reason="need hexagon") def test_basic(): target = tvm.target.Target("qcom/hexagon-v66") @I.ir_module(s_tir=True) class Module: @T.prim_func(s_tir=True) def main( C: T.Buffer((128,), "uint8"), A: T.Buffer((128,), "uint8"), A_1: T.Buffer((128,), "uint8"), ): T.func_attr({"tirx.noalias": True}) for i in range(128): with T.sblock("C"): v_i = T.axis.spatial(128, i) T.reads(A[v_i], A_1[v_i]) T.writes(C[v_i]) C[v_i] = A[v_i] + A_1[v_i] hexm = tvm.compile(Module, target=tvm.target.Target(target, target)) asm = hexm.inspect_source("s") vadds = re.findall(r"v[0-9]+.b = vadd\(v[0-9]+.b,v[0-9]+.b\)", asm) assert vadds # Check that it's non-empty @pytest.mark.skipif(not env.has_hexagon(), reason="need hexagon") def test_llvm_target_features(): target = tvm.target.Target("qcom/hexagon-v66") @I.ir_module(s_tir=True) class Module: @T.prim_func(s_tir=True) def add_one(C: T.Buffer((128,), "int32"), A: T.Buffer((128,), "uint8")): T.func_attr({"tirx.noalias": True}) for i in range(128): with T.sblock("C"): v_i = T.axis.spatial(128, i) T.reads(A[v_i]) T.writes(C[v_i]) C[v_i] = T.Cast("int32", A[v_i]) + 1 m = tvm.compile(Module, target=tvm.target.Target(target, target)) llvm_ir = m.inspect_source("ll") # Make sure we find +hvx-length128b in "attributes". fs = re.findall(r"attributes.*\+hvx-length128b", llvm_ir) assert fs # Check that it's non-empty @pytest.mark.skipif(not env.has_hexagon(), reason="need hexagon") def test_llvm_options(): target = tvm.target.Target( { "kind": "hexagon", "mtriple": "hexagon", "mcpu": "hexagonv66", "mattr": ["+hvxv66", "+hvx-length128b"], "num-cores": 4, "vtcm-capacity": 262144, "llvm-options": ["-hexagon-noopt"], } ) @I.ir_module(s_tir=True) class Module: @T.prim_func(s_tir=True) def main(compute: T.Buffer((10,), "int32")): T.func_attr({"tirx.noalias": True}) for _ in range(10): with T.sblock("compute"): v__ = T.axis.spatial(10, _) T.reads() T.writes(compute[v__]) compute[v__] = 0 # Check that BuildHexagon hasn't crashed because of target attribute # type mismatch. tvm.compile(Module, target=tvm.target.Target(target, target)) assert re.search("-hexagon-noopt", str(target)) if __name__ == "__main__": tvm.testing.main()