chore: import upstream snapshot with attribution
Lint / lint (push) Has been cancelled
CI / MacOS (push) Has been cancelled
CI / Windows (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:36:25 +08:00
commit 26446540fa
3151 changed files with 974126 additions and 0 deletions
+147
View File
@@ -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()
+464
View File
@@ -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()
+243
View File
@@ -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