chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
# 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: F401
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import tvm
|
||||
from tvm.script import tirx as T
|
||||
from tvm.target import codegen
|
||||
from tvm.testing import env
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def sve_device_vector_length():
|
||||
c_code = r"""
|
||||
#include <stdio.h>
|
||||
#include <arm_sve.h>
|
||||
|
||||
int main() {
|
||||
printf("%ld\n", svcntb() * 8);
|
||||
}
|
||||
"""
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
c_path = f"{tmp_dir}/vl.c"
|
||||
o_path = f"{tmp_dir}/out.o"
|
||||
with open(c_path, "w") as f:
|
||||
f.write(c_code)
|
||||
tvm.support.cc.create_executable(o_path, c_path, ["-march=native"])
|
||||
out = subprocess.check_output(o_path, shell=True).strip().decode()
|
||||
|
||||
return int(out)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not env.has_cpu_feature("sve"), reason="need aarch64 sve")
|
||||
def test_scalable_div(sve_device_vector_length):
|
||||
np.random.seed(0)
|
||||
target = {"kind": "llvm", "mtriple": "aarch64-linux-gnu", "mattr": ["+sve"]}
|
||||
dev = tvm.cpu(0)
|
||||
|
||||
@T.prim_func(s_tir=True)
|
||||
def my_func(a: T.handle):
|
||||
A = T.match_buffer(a, (1,), "int32")
|
||||
T.func_attr({"global_symbol": "my_module", "tirx.noalias": True})
|
||||
A[0] = T.Div(10000, 4 * T.vscale())
|
||||
|
||||
mod = tvm.compile(my_func, target=target)
|
||||
|
||||
A_nd = tvm.runtime.tensor(np.empty((1,), dtype="int32"), device=dev)
|
||||
mod(A_nd)
|
||||
|
||||
ref = 10000 // (sve_device_vector_length // 32)
|
||||
tvm.testing.assert_allclose(A_nd.numpy()[0], ref)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not env.has_cpu_feature("sve"), reason="need aarch64 sve")
|
||||
def test_scalable_buffer_load_store(sve_device_vector_length):
|
||||
np.random.seed(0)
|
||||
target = {"kind": "llvm", "mtriple": "aarch64-linux-gnu", "mattr": ["+sve"]}
|
||||
num_elements = sve_device_vector_length // 32
|
||||
dev = tvm.cpu(0)
|
||||
|
||||
@T.prim_func(s_tir=True)
|
||||
def my_func(a: T.handle, b: T.handle):
|
||||
A = T.match_buffer(a, (num_elements,), "float32")
|
||||
B = T.match_buffer(b, (num_elements,), "float32")
|
||||
T.func_attr({"global_symbol": "my_module", "tirx.noalias": True})
|
||||
B[T.ramp(0, 1, 4 * T.vscale())] = A[T.ramp(0, 1, 4 * T.vscale())]
|
||||
|
||||
mod = tvm.compile(my_func, target=target)
|
||||
|
||||
A_np = np.random.uniform(size=(num_elements,)).astype("float32")
|
||||
B_np = np.zeros((num_elements,)).astype("float32")
|
||||
A_nd = tvm.runtime.tensor(A_np, device=dev)
|
||||
B_nd = tvm.runtime.tensor(B_np, device=dev)
|
||||
mod(A_nd, B_nd)
|
||||
|
||||
tvm.testing.assert_allclose(B_nd.numpy(), A_np)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not env.has_cpu_feature("sve"), reason="need aarch64 sve")
|
||||
def test_scalable_loop_bound(sve_device_vector_length):
|
||||
np.random.seed(0)
|
||||
|
||||
dtype = "float32"
|
||||
num_elements = sve_device_vector_length // 32
|
||||
target = {"kind": "llvm", "mtriple": "aarch64-linux-gnu", "mattr": ["+sve"]}
|
||||
dev = tvm.cpu(0)
|
||||
|
||||
@T.prim_func(s_tir=True)
|
||||
def my_func(a: T.handle, b: T.handle):
|
||||
A = T.match_buffer(a, (num_elements,), "float32")
|
||||
B = T.match_buffer(b, (num_elements,), "float32")
|
||||
T.func_attr({"global_symbol": "my_module", "tirx.noalias": True})
|
||||
for i in T.serial(0, 4 * T.vscale()):
|
||||
B[i] = A[i]
|
||||
|
||||
mod = tvm.compile(my_func, target=target)
|
||||
|
||||
A_np = np.random.uniform(size=(num_elements,)).astype(dtype)
|
||||
B_np = np.zeros((num_elements,)).astype(dtype)
|
||||
A_nd = tvm.runtime.tensor(A_np, device=dev)
|
||||
B_nd = tvm.runtime.tensor(B_np, device=dev)
|
||||
mod(A_nd, B_nd)
|
||||
|
||||
tvm.testing.assert_allclose(B_nd.numpy(), A_np)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not env.has_cpu_feature("sve"), reason="need aarch64 sve")
|
||||
def test_scalable_broadcast(sve_device_vector_length):
|
||||
target = {"kind": "llvm", "mtriple": "aarch64-linux-gnu", "mattr": ["+sve"]}
|
||||
num_elements = sve_device_vector_length // 32
|
||||
dev = tvm.cpu(0)
|
||||
|
||||
@T.prim_func(s_tir=True)
|
||||
def my_func(a: T.handle):
|
||||
A = T.match_buffer(a, (num_elements,), "float32")
|
||||
T.func_attr({"global_symbol": "my_module", "tirx.noalias": True})
|
||||
A[T.ramp(0, 1, 4 * T.vscale())] = T.broadcast(1, 4 * T.vscale())
|
||||
|
||||
mod = tvm.compile(my_func, target=target)
|
||||
|
||||
A_np = np.zeros((num_elements,)).astype("float32")
|
||||
A_nd = tvm.runtime.tensor(A_np, device=dev)
|
||||
mod(A_nd)
|
||||
|
||||
ref = np.ones((num_elements,))
|
||||
tvm.testing.assert_allclose(A_nd.numpy(), ref)
|
||||
@@ -0,0 +1,105 @@
|
||||
# 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 pytest
|
||||
|
||||
import tvm
|
||||
from tvm.target import Target, _ffi_api, codegen
|
||||
|
||||
LLVM_VERSION = codegen.llvm_version_major()
|
||||
|
||||
|
||||
def test_llvm_targets(capfd):
|
||||
##
|
||||
## check LLVM backend
|
||||
##
|
||||
|
||||
# check blank results
|
||||
assert len(codegen.llvm_get_targets())
|
||||
assert len(codegen.llvm_get_system_cpu())
|
||||
assert len(codegen.llvm_get_system_triple())
|
||||
assert len(codegen.llvm_get_system_x86_vendor())
|
||||
# check ffi vs python
|
||||
assert codegen.llvm_get_system_cpu() == _ffi_api.llvm_get_system_cpu()
|
||||
assert codegen.llvm_get_system_triple() == _ffi_api.llvm_get_system_triple()
|
||||
assert codegen.llvm_get_system_x86_vendor() == _ffi_api.llvm_get_system_x86_vendor()
|
||||
assert str(codegen.llvm_get_targets()) == str(_ffi_api.llvm_get_targets())
|
||||
|
||||
tvm.target.codegen.llvm_get_cpu_features(
|
||||
tvm.target.Target({"kind": "llvm", "mtriple": "x86_64-linux-gnu", "mcpu": "dummy"})
|
||||
)
|
||||
expected_str = (
|
||||
" with `-mcpu=dummy` is not valid in "
|
||||
"`-mtriple=x86_64-linux-gnu`, using default `-mcpu=generic`"
|
||||
)
|
||||
readout_error = capfd.readouterr().err
|
||||
assert "Error: Using LLVM " in readout_error
|
||||
assert expected_str in readout_error
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"min_llvm_version,llvm_target,cpu_arch,cpu_features,is_supported",
|
||||
[
|
||||
(-1, "x86_64", "sandybridge", "sse4.1", True),
|
||||
(-1, "x86_64", "ivybridge", ["sse4.1", "ssse3"], True),
|
||||
(-1, "x86_64", "ivybridge", ["sse4.1", "ssse3", "avx512bw"], False),
|
||||
# 32bit vs 64bit
|
||||
(-1, "aarch64", "cortex-a55", "neon", True),
|
||||
(-1, "aarch64", "cortex-a55", "dotprod", True),
|
||||
(-1, "aarch64", "cortex-a55", "dsp", False),
|
||||
(-1, "arm", "cortex-a55", "dsp", True),
|
||||
(-1, "aarch64", "cortex-a55", ["neon", "dotprod"], True),
|
||||
(-1, "aarch64", "cortex-a55", ["neon", "dotprod", "dsp"], False),
|
||||
(-1, "arm", "cortex-a55", ["neon", "dotprod"], True),
|
||||
(-1, "aarch64", "cortex-a55", ["neon", "dotprod", "dsp"], False),
|
||||
(-1, "arm", "cortex-a55", ["neon", "dotprod", "dsp"], True),
|
||||
],
|
||||
)
|
||||
def test_target_features(min_llvm_version, llvm_target, cpu_arch, cpu_features, is_supported):
|
||||
target = Target({"kind": "llvm", "mtriple": f"{llvm_target}--", "mcpu": cpu_arch})
|
||||
|
||||
##
|
||||
## legalize llvm_target
|
||||
##
|
||||
|
||||
assert llvm_target in codegen.llvm_get_targets()
|
||||
|
||||
##
|
||||
## legalize cpu_arch
|
||||
##
|
||||
|
||||
### with context
|
||||
with target:
|
||||
assert cpu_arch in codegen.llvm_get_cpu_archlist()
|
||||
### no context but with expicit target
|
||||
assert cpu_arch in codegen.llvm_get_cpu_archlist(target)
|
||||
# check ffi vs python
|
||||
assert str(codegen.llvm_get_cpu_archlist(target)) == str(_ffi_api.llvm_get_cpu_archlist(target))
|
||||
|
||||
##
|
||||
## check has_features
|
||||
##
|
||||
|
||||
### with context
|
||||
with target:
|
||||
assert codegen.llvm_cpu_has_features(cpu_features) == is_supported
|
||||
### no context but with expicit target
|
||||
assert codegen.llvm_cpu_has_features(cpu_features, target) == is_supported
|
||||
# check ffi vs python
|
||||
for feat in cpu_features:
|
||||
assert str(codegen.llvm_cpu_has_features(feat, target)) == str(
|
||||
_ffi_api.llvm_cpu_has_feature(feat, target)
|
||||
)
|
||||
@@ -0,0 +1,65 @@
|
||||
# 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, F401
|
||||
import pytest
|
||||
|
||||
import tvm
|
||||
from tvm.target import Target, _ffi_api, codegen
|
||||
from tvm.target.codegen import llvm_get_vector_width, target_has_features
|
||||
|
||||
LLVM_VERSION = codegen.llvm_version_major()
|
||||
|
||||
|
||||
# fmt: off
|
||||
@pytest.mark.parametrize(
|
||||
"min_llvm_version,tvm_target,vec_width",
|
||||
[
|
||||
# generic, no vector -> (default 128)
|
||||
(-1, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv64-linux-gnu", "mcpu": "generic-rv64", "mattr": ["+i", "+m"]}, 128),
|
||||
(-1, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv32-linux-gnu", "mcpu": "generic-rv32", "mattr": ["+64bit", "+a", "+c", "+d", "+f", "+m"]}, 128),
|
||||
# generic, with vector -> (default zvl128b)
|
||||
(-1, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv32-linux-gnu", "mcpu": "generic-rv32", "mattr": ["+i", "+m", "+v"]}, 128),
|
||||
(-1, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv64-linux-gnu", "mcpu": "generic-rv64", "mattr": ["+64bit", "+a", "+c", "+d", "+f", "+m", "+v"]}, 128),
|
||||
# explicit +zvlXXXb
|
||||
(14, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv32-linux-gnu", "mcpu": "generic-rv32", "mattr": ["+i", "+m", "+v", "+zvl64b"]}, 128),
|
||||
(14, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv64-linux-gnu", "mcpu": "generic-rv64", "mattr": ["+64bit", "+a", "+c", "+d", "+f", "+m", "+v", "+zvl256b"]}, 256),
|
||||
(14, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv64-linux-gnu", "mcpu": "generic-rv64", "mattr": ["+64bit", "+a", "+c", "+d", "+f", "+m", "+v", "+zvl512b"]}, 512),
|
||||
# vendor CPU
|
||||
(17, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv64-linux-gnu", "mcpu": "sifive-x280"}, 512),
|
||||
(18, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv64-linux-gnu", "mcpu": "sifive-p670"}, 128),
|
||||
(19, {"kind": "llvm", "device": "riscv_cpu", "mtriple": "riscv64-linux-gnu", "mcpu": "spacemit-x60"}, 256),
|
||||
],
|
||||
)
|
||||
def test_riscv_rvv_features(min_llvm_version, tvm_target, vec_width):
|
||||
"""Test RVV features support for different targets.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
min_llvm_version : int
|
||||
Minimal LLVM version.
|
||||
tvm_target : str
|
||||
TVM target.
|
||||
vec_width : bool
|
||||
Expected vector width.
|
||||
"""
|
||||
|
||||
# skip test on llvm_version
|
||||
if LLVM_VERSION < min_llvm_version:
|
||||
return
|
||||
|
||||
with Target(tvm_target):
|
||||
assert llvm_get_vector_width() == vec_width
|
||||
@@ -0,0 +1,72 @@
|
||||
# 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: F821
|
||||
"""
|
||||
Tests to verify Python interactions with Target Parsing
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from tvm.target import Target
|
||||
|
||||
|
||||
@pytest.mark.parametrize(["cpu_target"], [["c"], ["llvm"]])
|
||||
def test_target_parser_mprofile(cpu_target):
|
||||
parsed_target = Target({"kind": cpu_target, "mcpu": "cortex-m55"})
|
||||
assert len(parsed_target.keys) == 2
|
||||
assert parsed_target.keys[0] == "arm_cpu"
|
||||
assert parsed_target.keys[1] == "cpu"
|
||||
assert parsed_target.features
|
||||
assert parsed_target.features.has_dsp
|
||||
assert parsed_target.features.has_mve
|
||||
|
||||
|
||||
@pytest.mark.parametrize(["cpu_target"], [["c"], ["llvm"]])
|
||||
def test_target_parser_mprofile_no_mve(cpu_target):
|
||||
parsed_target = Target({"kind": cpu_target, "mcpu": "cortex-m7"})
|
||||
assert len(parsed_target.keys) == 2
|
||||
assert parsed_target.keys[0] == "arm_cpu"
|
||||
assert parsed_target.keys[1] == "cpu"
|
||||
assert parsed_target.features
|
||||
assert parsed_target.features.has_dsp
|
||||
assert not parsed_target.features.has_mve
|
||||
|
||||
|
||||
@pytest.mark.parametrize(["cpu_target"], [["c"], ["llvm"]])
|
||||
def test_target_parser_mprofile_no_dsp(cpu_target):
|
||||
parsed_target = Target({"kind": cpu_target, "mcpu": "cortex-m3"})
|
||||
assert len(parsed_target.keys) == 2
|
||||
assert parsed_target.keys[0] == "arm_cpu"
|
||||
assert parsed_target.keys[1] == "cpu"
|
||||
assert parsed_target.features
|
||||
assert not parsed_target.features.has_dsp
|
||||
assert not parsed_target.features.has_mve
|
||||
|
||||
|
||||
@pytest.mark.parametrize(["cpu_target"], [["llvm"]])
|
||||
def test_target_parser_mprofile_mattr(cpu_target):
|
||||
parsed_target = Target({"kind": cpu_target, "mcpu": "cortex-m55", "mattr": ["+nomve", "+woof"]})
|
||||
assert len(parsed_target.keys) == 2
|
||||
assert parsed_target.keys[0] == "arm_cpu"
|
||||
assert parsed_target.keys[1] == "cpu"
|
||||
assert parsed_target.features
|
||||
assert parsed_target.features.has_dsp
|
||||
assert not parsed_target.features.has_mve
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
tvm.testing.main()
|
||||
@@ -0,0 +1,464 @@
|
||||
# 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 json
|
||||
|
||||
import pytest
|
||||
import tvm_ffi
|
||||
|
||||
import tvm
|
||||
import tvm.testing
|
||||
from tvm.target import Target
|
||||
from tvm.testing import env
|
||||
|
||||
|
||||
def test_all_targets_device_type_verify():
|
||||
"""Consistency verification for all targets' device type"""
|
||||
target_kind_set = set(tvm.target.Target.list_kinds())
|
||||
target_kind_set.remove("composite")
|
||||
all_targets = [tvm.target.Target(t) for t in target_kind_set]
|
||||
|
||||
for tgt in all_targets:
|
||||
if tgt.kind.name not in tvm.runtime.Device._DEVICE_NAME_TO_TYPE:
|
||||
raise KeyError(
|
||||
f"Cannot find target kind: {tgt.kind.name} in Device._DEVICE_NAME_TO_TYPE"
|
||||
)
|
||||
|
||||
assert (
|
||||
tgt.get_target_device_type() == tvm.runtime.Device._DEVICE_NAME_TO_TYPE[tgt.kind.name]
|
||||
)
|
||||
|
||||
|
||||
def test_target_string_parse():
|
||||
target = tvm.target.Target({"kind": "cuda", "model": "unknown", "libs": ["cublas", "cudnn"]})
|
||||
|
||||
assert target.kind.name == "cuda"
|
||||
assert target.attrs["model"] == "unknown"
|
||||
assert set(target.keys) == set(["cuda", "gpu"])
|
||||
assert set(target.attrs["libs"]) == set(["cublas", "cudnn"])
|
||||
|
||||
assert (
|
||||
Target({"kind": "opencl", "device": "intel_graphics"}).attrs.get("device", "")
|
||||
== "intel_graphics"
|
||||
)
|
||||
assert Target({"kind": "opencl", "device": "mali"}).attrs.get("device", "") == "mali"
|
||||
assert Target({"kind": "llvm", "device": "arm_cpu"}).attrs.get("device", "") == "arm_cpu"
|
||||
|
||||
|
||||
def test_target_string_with_spaces():
|
||||
target = tvm.target.Target(
|
||||
{"kind": "vulkan", "device_name": "Name of GPU with spaces", "device_type": "discrete"}
|
||||
)
|
||||
assert target.attrs["device_name"] == "Name of GPU with spaces"
|
||||
assert target.attrs["device_type"] == "discrete"
|
||||
|
||||
target = tvm.target.Target(str(target))
|
||||
|
||||
assert target.attrs["device_name"] == "Name of GPU with spaces"
|
||||
assert target.attrs["device_type"] == "discrete"
|
||||
|
||||
|
||||
def test_target_llvm_options():
|
||||
target = tvm.target.Target(
|
||||
{"kind": "llvm", "cl-opt": ["-unroll-threshold:uint=100", "-unroll-count:uint=3"]}
|
||||
)
|
||||
assert sorted(target.attrs["cl-opt"]) == sorted(
|
||||
["-unroll-threshold:uint=100", "-unroll-count:uint=3"]
|
||||
)
|
||||
|
||||
|
||||
def test_target_llvm_jit_options():
|
||||
target = tvm.target.Target({"kind": "llvm", "jit": "mcjit"})
|
||||
assert target.attrs["jit"] == "mcjit"
|
||||
target = tvm.target.Target({"kind": "llvm", "jit": "orcjit"})
|
||||
assert target.attrs["jit"] == "orcjit"
|
||||
|
||||
|
||||
def test_target_llvm_vector_width():
|
||||
target = tvm.target.Target({"kind": "llvm", "vector-width": 256})
|
||||
assert target.attrs["vector-width"] == 256
|
||||
target = tvm.target.Target({"kind": "llvm", "vector-width": 1024})
|
||||
assert target.attrs["vector-width"] == 1024
|
||||
|
||||
|
||||
def test_target_config():
|
||||
"""
|
||||
Test that constructing a target from a dictionary works.
|
||||
"""
|
||||
target_config = {
|
||||
"kind": "llvm",
|
||||
"keys": ["arm_cpu", "cpu"],
|
||||
"device": "arm_cpu",
|
||||
"libs": ["cblas"],
|
||||
"mfloat-abi": "hard",
|
||||
"mattr": ["+neon", "-avx512f"],
|
||||
}
|
||||
# Convert config dictionary to json string.
|
||||
target_config_str = json.dumps(target_config)
|
||||
# Test both dictionary input and json string.
|
||||
for config in [target_config, target_config_str]:
|
||||
target = tvm.target.Target(config)
|
||||
assert target.kind.name == "llvm"
|
||||
assert all([key in target.keys for key in ["arm_cpu", "cpu"]])
|
||||
assert target.attrs.get("device", "") == "arm_cpu"
|
||||
assert list(target.attrs.get("libs", [])) == ["cblas"]
|
||||
assert target.attrs["mfloat-abi"] == "hard"
|
||||
assert all([attr in target.attrs["mattr"] for attr in ["+neon", "-avx512f"]])
|
||||
|
||||
|
||||
def test_config_map():
|
||||
"""
|
||||
Confirm that constructing a target with invalid
|
||||
attributes fails as expected.
|
||||
"""
|
||||
target_config = {"kind": "llvm", "libs": {"a": "b", "c": "d"}}
|
||||
with pytest.raises(ValueError):
|
||||
tvm.target.Target(target_config)
|
||||
|
||||
|
||||
def test_composite_target():
|
||||
tgt = tvm.target.Target(
|
||||
{"kind": "composite", "host": {"kind": "llvm"}, "devices": ["cuda", "opencl"]}
|
||||
)
|
||||
assert tgt.kind.name == "composite"
|
||||
assert tgt.host.kind.name == "llvm"
|
||||
assert len(tgt.attrs["devices"]) == 2
|
||||
cuda_device, opencl_device = tgt.attrs["devices"]
|
||||
assert cuda_device.kind.name == "cuda"
|
||||
assert opencl_device.kind.name == "opencl"
|
||||
|
||||
|
||||
def test_target_tag_0():
|
||||
tgt = tvm.target.Target("nvidia/geforce-rtx-2080-ti")
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.attrs["arch"] == "sm_75"
|
||||
assert tgt.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.attrs["max_threads_per_block"] == 1024
|
||||
assert tgt.attrs["thread_warp_size"] == 32
|
||||
assert tgt.attrs["registers_per_block"] == 65536
|
||||
|
||||
|
||||
def test_target_tag_1():
|
||||
tgt = tvm.target.Target("nvidia/jetson-nano")
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.attrs["arch"] == "sm_53"
|
||||
assert tgt.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.attrs["max_threads_per_block"] == 1024
|
||||
assert tgt.attrs["thread_warp_size"] == 32
|
||||
assert tgt.attrs["registers_per_block"] == 32768
|
||||
|
||||
|
||||
def test_target_tag_override():
|
||||
"""Test creating a target from a tag with attribute overrides."""
|
||||
tgt = tvm.target.Target({"tag": "nvidia/nvidia-a100", "l2_cache_size_bytes": 12345})
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.attrs["arch"] == "sm_80"
|
||||
# Override should take effect
|
||||
assert int(tgt.attrs["l2_cache_size_bytes"]) == 12345
|
||||
# Base tag fields should be preserved
|
||||
assert tgt.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.attrs["thread_warp_size"] == 32
|
||||
# Tag name should be recorded
|
||||
assert tgt.tag == "nvidia/nvidia-a100"
|
||||
|
||||
|
||||
def test_list_kinds():
|
||||
targets = tvm.target.Target.list_kinds()
|
||||
assert len(targets) != 0
|
||||
assert "llvm" in targets
|
||||
assert all(isinstance(target_name, str) for target_name in targets)
|
||||
|
||||
|
||||
def test_target_host_tags():
|
||||
tgt = tvm.target.Target("nvidia/jetson-nano", "nvidia/geforce-rtx-2080-ti")
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.attrs["arch"] == "sm_53"
|
||||
assert tgt.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.attrs["max_threads_per_block"] == 1024
|
||||
assert tgt.attrs["thread_warp_size"] == 32
|
||||
assert tgt.attrs["registers_per_block"] == 32768
|
||||
assert tgt.host.kind.name == "cuda"
|
||||
assert tgt.host.attrs["arch"] == "sm_75"
|
||||
assert tgt.host.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.host.attrs["max_threads_per_block"] == 1024
|
||||
assert tgt.host.attrs["thread_warp_size"] == 32
|
||||
assert tgt.host.attrs["registers_per_block"] == 65536
|
||||
|
||||
|
||||
def test_target_host_tag_dict():
|
||||
tgt = tvm.target.Target("nvidia/jetson-nano", {"kind": "llvm"})
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.attrs["arch"] == "sm_53"
|
||||
assert tgt.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.attrs["max_threads_per_block"] == 1024
|
||||
assert tgt.attrs["thread_warp_size"] == 32
|
||||
assert tgt.attrs["registers_per_block"] == 32768
|
||||
assert tgt.host.kind.name == "llvm"
|
||||
|
||||
|
||||
def test_target_host_single_dict():
|
||||
tgt = tvm.target.Target({"kind": "llvm", "host": "nvidia/jetson-nano"})
|
||||
assert tgt.kind.name == "llvm"
|
||||
assert tgt.host.kind.name == "cuda"
|
||||
assert tgt.host.attrs["arch"] == "sm_53"
|
||||
assert tgt.host.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.host.attrs["max_threads_per_block"] == 1024
|
||||
assert tgt.host.attrs["thread_warp_size"] == 32
|
||||
assert tgt.host.attrs["registers_per_block"] == 32768
|
||||
|
||||
|
||||
def test_target_host_single_string():
|
||||
tgt = tvm.target.Target({"kind": "cuda", "host": {"kind": "llvm"}})
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.host.kind.name == "llvm"
|
||||
|
||||
|
||||
def test_target_host_single_string_with_tag():
|
||||
tgt = tvm.target.Target({"kind": "cuda", "host": "nvidia/jetson-nano"})
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.host.kind.name == "cuda"
|
||||
assert tgt.host.attrs["arch"] == "sm_53"
|
||||
assert tgt.host.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.host.attrs["max_threads_per_block"] == 1024
|
||||
assert tgt.host.attrs["thread_warp_size"] == 32
|
||||
assert tgt.host.attrs["registers_per_block"] == 32768
|
||||
|
||||
|
||||
def test_target_host_merge_0():
|
||||
tgt = tvm.target.Target(tvm.target.Target({"kind": "cuda", "host": "nvidia/jetson-nano"}), None)
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.host.kind.name == "cuda"
|
||||
assert tgt.host.attrs["arch"] == "sm_53"
|
||||
assert tgt.host.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.host.attrs["max_threads_per_block"] == 1024
|
||||
assert tgt.host.attrs["thread_warp_size"] == 32
|
||||
assert tgt.host.attrs["registers_per_block"] == 32768
|
||||
|
||||
|
||||
def test_target_host_merge_1():
|
||||
tgt = tvm.target.Target({"kind": "cuda", "host": {"kind": "llvm"}})
|
||||
tgt = tvm.target.Target(tgt, tgt.host)
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.host.kind.name == "llvm"
|
||||
|
||||
|
||||
def test_target_host_merge_2():
|
||||
"""Test picking the same host is ok."""
|
||||
tgt = tvm.target.Target(
|
||||
tvm.target.Target({"kind": "cuda", "host": {"kind": "llvm"}}),
|
||||
tvm.target.Target("llvm"),
|
||||
)
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.host.kind.name == "llvm"
|
||||
|
||||
|
||||
def test_target_tvm_object():
|
||||
"""Test creating Target by using TVM Objects"""
|
||||
String = tvm_ffi.core.String
|
||||
tgt = tvm.target.Target(target={"kind": "cuda", "host": {"kind": "llvm"}})
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.host.kind.name == "llvm"
|
||||
tgt = tvm.target.Target(target=String("cuda"), host=String("llvm"))
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.host.kind.name == "llvm"
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Causing infinite loop because of pytest and handle issue")
|
||||
def test_target_host_merge_3():
|
||||
with pytest.raises(ValueError, match=r"target host has to be a string or dictionary."):
|
||||
tvm.target.Target(tvm.target.Target({"kind": "cuda", "host": {"kind": "llvm"}}), 12.34)
|
||||
|
||||
|
||||
def test_target_with_host():
|
||||
tgt = tvm.target.Target("cuda")
|
||||
llvm = tvm.target.Target("llvm")
|
||||
tgt = tgt.with_host(llvm)
|
||||
assert tgt.kind.name == "cuda"
|
||||
assert tgt.host.kind.name == "llvm"
|
||||
cuda_host = tvm.target.Target("nvidia/jetson-nano")
|
||||
tgt = tgt.with_host(cuda_host)
|
||||
assert tgt.host.kind.name == "cuda"
|
||||
assert tgt.host.attrs["arch"] == "sm_53"
|
||||
assert tgt.host.attrs["max_shared_memory_per_block"] == 49152
|
||||
assert tgt.host.attrs["max_threads_per_block"] == 1024
|
||||
assert tgt.host.attrs["thread_warp_size"] == 32
|
||||
assert tgt.host.attrs["registers_per_block"] == 32768
|
||||
|
||||
|
||||
def test_target_attr_bool_value():
|
||||
target0 = Target({"kind": "vulkan", "supports_float16": True})
|
||||
assert target0.attrs["supports_float16"] == 1
|
||||
target1 = Target({"kind": "vulkan", "supports_float16": True})
|
||||
assert target1.attrs["supports_float16"] == 1
|
||||
target2 = Target({"kind": "vulkan", "supports_float16": False})
|
||||
assert target2.attrs["supports_float16"] == 0
|
||||
target3 = Target({"kind": "vulkan", "supports_float16": False})
|
||||
assert target3.attrs["supports_float16"] == 0
|
||||
|
||||
|
||||
def test_target_attr_l2_cache_size_bytes():
|
||||
target0 = Target("nvidia/nvidia-a100")
|
||||
assert int(target0.attrs.get("l2_cache_size_bytes", 0)) == 41943040
|
||||
target1 = Target("nvidia/geforce-rtx-4090")
|
||||
assert int(target1.attrs.get("l2_cache_size_bytes", 0)) == 75497472
|
||||
|
||||
|
||||
def test_target_features():
|
||||
target_no_features = Target("cuda")
|
||||
assert target_no_features.features
|
||||
assert not target_no_features.features.is_test
|
||||
|
||||
target_with_features = Target("test")
|
||||
assert target_with_features.features.is_test
|
||||
assert not target_with_features.features.is_missing
|
||||
|
||||
|
||||
@pytest.mark.gpu
|
||||
@pytest.mark.skipif(not env.has_cuda(), reason="need cuda")
|
||||
@pytest.mark.parametrize("input_form", ["string", "device"])
|
||||
def test_target_from_device_cuda(input_form):
|
||||
def run_and_check():
|
||||
dev = tvm.cuda()
|
||||
target = Target.from_device("cuda" if input_form == "string" else dev)
|
||||
assert target.kind.name == "cuda"
|
||||
assert target.attrs["max_threads_per_block"] == dev.max_threads_per_block
|
||||
assert int(target.attrs["max_shared_memory_per_block"]) == dev.max_shared_memory_per_block
|
||||
assert int(target.attrs["thread_warp_size"]) == dev.warp_size
|
||||
assert str(target.attrs.get("arch", "")) == "sm_" + dev.compute_version.replace(".", "")
|
||||
|
||||
tvm.testing.run_with_gpu_lock(run_and_check)
|
||||
|
||||
|
||||
@pytest.mark.gpu
|
||||
@pytest.mark.skipif(not env.has_rocm(), reason="need rocm")
|
||||
@pytest.mark.parametrize("input_form", ["string", "device"])
|
||||
def test_target_from_device_rocm(input_form):
|
||||
def run_and_check():
|
||||
dev = tvm.rocm()
|
||||
target = Target.from_device("rocm" if input_form == "string" else dev)
|
||||
assert target.kind.name == "rocm"
|
||||
assert target.attrs["mtriple"] == "amdgcn-and-amdhsa-hcc"
|
||||
assert target.attrs["max_threads_per_block"] == dev.max_threads_per_block
|
||||
assert int(target.attrs["max_shared_memory_per_block"]) == dev.max_shared_memory_per_block
|
||||
assert int(target.attrs["thread_warp_size"]) == dev.warp_size
|
||||
|
||||
tvm.testing.run_with_gpu_lock(run_and_check)
|
||||
|
||||
|
||||
@pytest.mark.gpu
|
||||
@pytest.mark.skipif(not env.has_vulkan(), reason="need vulkan")
|
||||
@pytest.mark.parametrize("input_form", ["string", "device"])
|
||||
def test_target_from_device_vulkan(input_form):
|
||||
def run_and_check():
|
||||
dev = tvm.vulkan()
|
||||
target = Target.from_device("vulkan" if input_form == "string" else dev)
|
||||
f_get_target_property = tvm.get_global_func("device_api.vulkan.get_target_property")
|
||||
assert target.kind.name == "vulkan"
|
||||
assert target.attrs["max_threads_per_block"] == dev.max_threads_per_block
|
||||
assert int(target.attrs["max_shared_memory_per_block"]) == dev.max_shared_memory_per_block
|
||||
assert int(target.attrs["thread_warp_size"]) == dev.warp_size
|
||||
assert target.attrs["supports_float16"] == f_get_target_property(dev, "supports_float16")
|
||||
assert target.attrs["supports_int16"] == f_get_target_property(dev, "supports_int16")
|
||||
assert target.attrs["supports_int8"] == f_get_target_property(dev, "supports_int8")
|
||||
assert target.attrs["supports_16bit_buffer"] == f_get_target_property(
|
||||
dev, "supports_16bit_buffer"
|
||||
)
|
||||
|
||||
tvm.testing.run_with_gpu_lock(run_and_check)
|
||||
|
||||
|
||||
@pytest.mark.gpu
|
||||
@pytest.mark.skipif(not env.has_opencl(), reason="need opencl")
|
||||
@pytest.mark.parametrize("input_form", ["string", "device"])
|
||||
def test_target_from_device_opencl(input_form):
|
||||
def run_and_check():
|
||||
dev = tvm.opencl()
|
||||
target = Target.from_device("opencl" if input_form == "string" else dev)
|
||||
assert target.kind.name == "opencl"
|
||||
assert target.attrs["max_threads_per_block"] == dev.max_threads_per_block
|
||||
assert int(target.attrs["max_shared_memory_per_block"]) == dev.max_shared_memory_per_block
|
||||
assert int(target.attrs["thread_warp_size"]) == dev.warp_size
|
||||
|
||||
tvm.testing.run_with_gpu_lock(run_and_check)
|
||||
|
||||
|
||||
def test_module_dict_from_deserialized_targets():
|
||||
target = Target("llvm")
|
||||
|
||||
from tvm.script import tirx as T
|
||||
|
||||
@T.prim_func(s_tir=True)
|
||||
def func():
|
||||
T.evaluate(0)
|
||||
|
||||
func = func.with_attr("Target", target)
|
||||
target2 = tvm.ir.load_json(tvm.ir.save_json(target))
|
||||
mod = tvm.IRModule({"main": func})
|
||||
lib = tvm.compile(mod, target=target2)
|
||||
lib["func"]()
|
||||
|
||||
|
||||
def test_json_roundtrip():
|
||||
"""Test that Target(str(target)) roundtrips correctly."""
|
||||
target = Target({"kind": "llvm", "mcpu": "cortex-a53"})
|
||||
target2 = Target(str(target))
|
||||
assert target2.kind.name == "llvm"
|
||||
assert target2.attrs["mcpu"] == "cortex-a53"
|
||||
|
||||
# Test with more complex target
|
||||
target = Target({"kind": "cuda", "arch": "sm_80", "max_threads_per_block": 1024})
|
||||
target2 = Target(str(target))
|
||||
assert target2.kind.name == "cuda"
|
||||
assert target2.attrs["arch"] == "sm_80"
|
||||
|
||||
|
||||
def test_str_is_json():
|
||||
"""Test that str() output is valid JSON."""
|
||||
target = Target({"kind": "llvm", "mcpu": "cortex-a53"})
|
||||
s = str(target)
|
||||
parsed = json.loads(s)
|
||||
assert parsed["kind"] == "llvm"
|
||||
assert parsed["mcpu"] == "cortex-a53"
|
||||
|
||||
|
||||
def test_cli_string_rejected():
|
||||
"""Test that CLI string form is rejected."""
|
||||
with pytest.raises(ValueError):
|
||||
Target("llvm -mcpu=cortex-a53")
|
||||
|
||||
|
||||
def test_webgpu_target_subgroup_attrs():
|
||||
"""Test WebGPU target defaults and supports_subgroups canonicalization."""
|
||||
# Default: thread_warp_size=1, supports_subgroups=False
|
||||
tgt_default = Target({"kind": "webgpu"})
|
||||
assert tgt_default.attrs["thread_warp_size"] == 1
|
||||
assert tgt_default.attrs["supports_subgroups"] == 0
|
||||
|
||||
# With supports_subgroups=True: thread_warp_size is set to 32
|
||||
tgt_subgroups = Target({"kind": "webgpu", "supports_subgroups": True})
|
||||
assert tgt_subgroups.attrs["thread_warp_size"] == 32
|
||||
assert tgt_subgroups.attrs["supports_subgroups"] == 1
|
||||
|
||||
for config in [
|
||||
{"kind": "webgpu", "thread_warp_size": 32},
|
||||
{"kind": "webgpu", "thread_warp_size": 32, "supports_subgroups": False},
|
||||
]:
|
||||
with pytest.raises(ValueError, match="requires supports_subgroups=true"):
|
||||
Target(config)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
tvm.testing.main()
|
||||
@@ -0,0 +1,51 @@
|
||||
# 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: F401
|
||||
import pytest
|
||||
|
||||
import tvm
|
||||
import tvm.testing
|
||||
|
||||
|
||||
def test_make_virtual_device_for_device():
|
||||
virtual_device = tvm.target.VirtualDevice(tvm.device("cuda"))
|
||||
assert virtual_device.dlpack_device_type() == 2
|
||||
# ie kDLCUDA
|
||||
assert virtual_device.virtual_device_id == 0
|
||||
assert virtual_device.target is None
|
||||
assert virtual_device.memory_scope == ""
|
||||
|
||||
|
||||
def test_make_virtual_device_for_device_and_target():
|
||||
target = tvm.target.Target("cuda")
|
||||
virtual_device = tvm.target.VirtualDevice(tvm.device("cuda"), target)
|
||||
assert virtual_device.dlpack_device_type() == 2 # ie kDLCUDA
|
||||
assert virtual_device.target == target
|
||||
assert virtual_device.memory_scope == ""
|
||||
|
||||
|
||||
def test_make_virtual_device_for_device_target_and_memory_scope():
|
||||
target = tvm.target.Target("cuda")
|
||||
scope = "local"
|
||||
virtual_device = tvm.target.VirtualDevice(tvm.device("cuda"), target, scope)
|
||||
assert virtual_device.dlpack_device_type() == 2 # ie kDLCUDA
|
||||
assert virtual_device.target == target
|
||||
assert virtual_device.memory_scope == scope
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
tvm.testing.main()
|
||||
@@ -0,0 +1,243 @@
|
||||
# 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: F841
|
||||
import pytest
|
||||
|
||||
import tvm
|
||||
from tvm.target import Target, _ffi_api, codegen
|
||||
from tvm.target.codegen import target_has_features
|
||||
|
||||
LLVM_VERSION = codegen.llvm_version_major()
|
||||
|
||||
# Some x86 features have been removed from upstream LLVM. Tests for these
|
||||
# features only meaningfully run on LLVM versions that still recognise them.
|
||||
# The keys are feature names (matching the ``x86_feature`` parameter); the
|
||||
# values are the highest LLVM major version that still supports the feature.
|
||||
_FEATURE_REMOVED_AFTER_LLVM = {
|
||||
"avx512er": 18, # removed in LLVM 19
|
||||
"avx512pf": 18, # removed in LLVM 19
|
||||
}
|
||||
|
||||
|
||||
def _feature_supported_by_llvm(x86_feature) -> bool:
|
||||
if not isinstance(x86_feature, str):
|
||||
return True
|
||||
cap = _FEATURE_REMOVED_AFTER_LLVM.get(x86_feature)
|
||||
return cap is None or LLVM_VERSION <= cap
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"min_llvm_version,tvm_target,x86_feature,is_supported",
|
||||
[
|
||||
# sse4.1
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "btver2"}, "sse4a", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "penryn"}, "sse4.1", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "silvermont"}, "sse4.2", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "slm"}, "sse4.2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "goldmont"}, "sse4.2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "goldmont-plus"}, "sse4.2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "tremont"}, "sse4.2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "nehalem"}, "sse4.2", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "corei7"}, "sse4.2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "westmere"}, "sse4.2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "bdver1"}, "sse4.2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "bdver2"}, "sse4.2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "bdver3"}, "sse4.2", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "x86-64-v2"}, "sse4.2", True),
|
||||
# avx
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "sandybridge"}, "avx", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "corei7-avx"}, "avx", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "ivybridge"}, "avx", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "core-avx-i"}, "avx", True),
|
||||
# avx2
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "haswell"}, "avx2", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "core-avx2"}, "avx2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "broadwell"}, "avx2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "skylake"}, "avx2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "bdver4"}, "avx2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "znver1"}, "avx2", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "znver2"}, "avx2", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "znver3"}, "avx2", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "x86-64-v3"}, "avx2", True),
|
||||
# avx512bw
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "skylake-avx512"}, "avx512bw", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "skx"}, "avx512bw", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knl"}, "avx512bw", False),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knl"}, "avx512f", True),
|
||||
(
|
||||
11,
|
||||
{"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knl"},
|
||||
["avx512bw", "avx512f"],
|
||||
False,
|
||||
),
|
||||
(
|
||||
11,
|
||||
{"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knl"},
|
||||
("avx512bw", "avx512f"),
|
||||
False,
|
||||
),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knl"}, "avx512cd", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knl"}, ["avx512cd", "avx512f"], True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knl"}, ("avx512cd", "avx512f"), True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knl"}, "avx512er", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knl"}, "avx512pf", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knm"}, "avx512bw", False),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knm"}, "avx512f", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knm"}, "avx512cd", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knm"}, "avx512er", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "knm"}, "avx512pf", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "x86-64-v4"}, "avx512bw", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "cannonlake"}, "avx512bw", True),
|
||||
# explicit enumeration of VNNI capable due to collision with alderlake
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "alderlake"}, "avx512bw", False),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "cascadelake"}, "avx512bw", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "icelake-client"}, "avx512bw", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "icelake-server"}, "avx512bw", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "rocketlake"}, "avx512bw", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "tigerlake"}, "avx512bw", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "cooperlake"}, "avx512bw", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "sapphirerapids"}, "avx512bw", True),
|
||||
# avx512vnni
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "alderlake"}, "avx512vnni", False),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "alderlake"}, "avxvnni", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "cascadelake"}, "avx512vnni", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "icelake-client"}, "avx512vnni", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "icelake-server"}, "avx512vnni", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "rocketlake"}, "avx512vnni", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "tigerlake"}, "avx512vnni", True),
|
||||
(-1, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "cooperlake"}, "avx512vnni", True),
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "sapphirerapids"}, "avx512vnni", True),
|
||||
# amx-int8
|
||||
(11, {"kind": "llvm", "mtriple": "x86_64--", "mcpu": "sapphirerapids"}, "amx-int8", True),
|
||||
# generic CPU (no features) but with extra -mattr
|
||||
(
|
||||
-1,
|
||||
{
|
||||
"kind": "llvm",
|
||||
"mtriple": "x86_64--",
|
||||
"mcpu": "x86-64",
|
||||
"mattr": ["+sse4.1", "+avx2"],
|
||||
},
|
||||
"avx2",
|
||||
True,
|
||||
),
|
||||
(
|
||||
-1,
|
||||
{
|
||||
"kind": "llvm",
|
||||
"mtriple": "x86_64--",
|
||||
"mcpu": "x86-64",
|
||||
"mattr": ["+sse4.1", "+avx2"],
|
||||
},
|
||||
"sse4.1",
|
||||
True,
|
||||
),
|
||||
# enabling +sse4.1 implies ssse3 presence in LLVM
|
||||
(
|
||||
-1,
|
||||
{
|
||||
"kind": "llvm",
|
||||
"mtriple": "x86_64--",
|
||||
"mcpu": "x86-64",
|
||||
"mattr": ["+sse4.1", "+avx2"],
|
||||
},
|
||||
"ssse3",
|
||||
True,
|
||||
),
|
||||
(
|
||||
-1,
|
||||
{"kind": "llvm", "mtriple": "x86_64--", "mcpu": "ivybridge", "mattr": ["-ssse3"]},
|
||||
"ssse3",
|
||||
False,
|
||||
),
|
||||
# disabling avx512f (foundation) also disables avx512bw
|
||||
(
|
||||
-1,
|
||||
{"kind": "llvm", "mtriple": "x86_64--", "mcpu": "cascadelake", "mattr": ["-avx512f"]},
|
||||
"avx512bw",
|
||||
False,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_x86_target_features(min_llvm_version, tvm_target, x86_feature, is_supported):
|
||||
"""Test X86 features support for different targets.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
min_llvm_version : int
|
||||
Minimal LLVM version.
|
||||
tvm_target : str
|
||||
TVM target.
|
||||
x86_feature : str
|
||||
X86 CPU feature.
|
||||
is_supported : bool
|
||||
Expected result.
|
||||
"""
|
||||
|
||||
##
|
||||
## no context
|
||||
##
|
||||
|
||||
# check for feature via the python api (no explicit target, no context target)
|
||||
try:
|
||||
assert target_has_features(x86_feature) == is_supported
|
||||
assert False
|
||||
except tvm.error.InternalError as e:
|
||||
msg = str(e)
|
||||
assert msg.find("Check failed: (allow_not_defined) is false: Target context required") != -1
|
||||
|
||||
if isinstance(x86_feature, str):
|
||||
# check for feature via the ffi llvm api (no explicit target, no context target)
|
||||
try:
|
||||
assert _ffi_api.target_has_feature(x86_feature, None) == is_supported
|
||||
assert False
|
||||
except tvm.error.InternalError as e:
|
||||
msg = str(e)
|
||||
assert (
|
||||
msg.find("Check failed: (allow_not_defined) is false: Target context required")
|
||||
!= -1
|
||||
)
|
||||
|
||||
# skip test on llvm_version
|
||||
if LLVM_VERSION < min_llvm_version:
|
||||
return
|
||||
|
||||
# skip features that have been removed from the installed LLVM
|
||||
if not _feature_supported_by_llvm(x86_feature):
|
||||
return
|
||||
|
||||
# check for feature via the python api (with explicit target, no context target)
|
||||
assert target_has_features(x86_feature, Target(tvm_target)) == is_supported
|
||||
if isinstance(x86_feature, str):
|
||||
# check for feature via the ffi llvm api (with explicit target, no context target)
|
||||
assert _ffi_api.target_has_feature(x86_feature, Target(tvm_target)) == is_supported
|
||||
|
||||
##
|
||||
## with context
|
||||
##
|
||||
|
||||
with Target(tvm_target):
|
||||
mcpu = str(Target.current(False).attrs.get("mcpu", ""))
|
||||
# check for feature via the python api (current context target)
|
||||
assert target_has_features(x86_feature) == is_supported
|
||||
# check for feature via the python api (with explicit target)
|
||||
assert target_has_features(x86_feature, Target(tvm_target)) == is_supported
|
||||
# check for feature via the ffi llvm api (current context target)
|
||||
(sum(_ffi_api.target_has_feature(feat, None) for feat in x86_feature) > 0) == is_supported
|
||||
# check for feature in target's llvm full x86 CPU feature list
|
||||
if (not list(Target(tvm_target).attrs.get("mattr", []))) and isinstance(x86_feature, str):
|
||||
assert (x86_feature in codegen.llvm_get_cpu_features()) == is_supported
|
||||
Reference in New Issue
Block a user