859498dc01
## Summary This PR adds the initial TIRx support needed for low-level programming of Blackwell-class GPU architectures. As part of the ongoing TIRx refactor, it introduces TVMScript support for directly scripting advanced hardware features without relying on scheduling as the primary programming interface. The change keeps existing `s_tir` script support intact while making direct scripting a first-class path for TIRx programs. ## Main Changes - Add TIRx operator dispatch and layout infrastructure. - Add TVMScript support for new low-level TIRx operations. - Add analysis, transform, and lowering support for TIRx IR nodes. - Add CUDA/Blackwell-oriented codegen and intrinsic coverage. - Add Python and C++ integration points for TIRx scripting and runtime support. ## Validation - `pre-commit run --all-files` - `ninja -C build -j32` - `CUDA_VISIBLE_DEVICES=2 pytest tests/python/tirx/ -n 16` - `1723 passed, 47 skipped, 32 warnings` - `CUDA_VISIBLE_DEVICES=2 python -m pytest -v tests/python/all-platform-minimal-test` - `37 passed, 105 skipped` - `TVM_TEST_TARGETS=llvm python -m pytest -v tests/python/tirx-analysis tests/python/tirx-base tests/python/tirx-transform -n 16` - `664 passed, 25 skipped, 9 xfailed, 1 xpassed` ## Local CI Notes Some full CI-equivalent jobs were not locally reproducible because this machine is missing parts of the Apache TVM CI environment, including `llvm-config-15/17`, Vulkan, ROCm, Maven, Sphinx, Doxygen, Emscripten, and ARM/QEMU cross-toolchain components. Metal-specific tests were skipped locally because no Metal runtime is available.
245 lines
9.1 KiB
Python
245 lines
9.1 KiB
Python
# 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.
|
|
"""Target data structure."""
|
|
|
|
import tvm_ffi
|
|
from tvm_ffi import Map
|
|
from tvm_ffi.core import String
|
|
|
|
from tvm.runtime import Device, Object, convert
|
|
|
|
from . import _ffi_api
|
|
|
|
|
|
@tvm_ffi.register_object("target.TargetKind")
|
|
class TargetKind(Object):
|
|
"""Kind of a compilation target"""
|
|
|
|
@property
|
|
def options(self):
|
|
"""Returns the dict of available option names and types"""
|
|
return dict(_ffi_api.ListTargetKindOptions(self))
|
|
|
|
@staticmethod
|
|
def options_from_name(kind_name: str):
|
|
"""Returns the dict of available option names and types from a name of TargetKind"""
|
|
return dict(_ffi_api.ListTargetKindOptionsFromName(kind_name))
|
|
|
|
|
|
class TargetFeatures:
|
|
def __init__(self, target):
|
|
self.target = target
|
|
|
|
def __getattr__(self, name: str):
|
|
return _ffi_api.TargetGetFeature(self.target, name)
|
|
|
|
|
|
@tvm_ffi.register_object("target.Target")
|
|
class Target(Object):
|
|
"""Target device information, use through TVM API.
|
|
|
|
Targets can be constructed from:
|
|
|
|
- A JSON config dictionary: ``Target({"kind": "cuda", "arch": "sm_80"})``
|
|
- A tag name: ``Target("nvidia/nvidia-a100")``
|
|
- A tag with overrides: ``Target({"tag": "nvidia/nvidia-a100", "l2_cache_size_bytes": 12345})``
|
|
- A kind name: ``Target("cuda")``
|
|
|
|
Use ``target.attrs["key"]`` to access target attributes.
|
|
|
|
Examples
|
|
--------
|
|
.. code-block:: python
|
|
|
|
# From a tag
|
|
target = Target("nvidia/nvidia-a100")
|
|
|
|
# From a tag with attribute overrides
|
|
target = Target({"tag": "qcom/hexagon-v68", "vtcm-capacity": 70000})
|
|
|
|
# From a config dictionary
|
|
target = Target({"kind": "cuda", "arch": "sm_80"})
|
|
"""
|
|
|
|
def __init__(self, target, host=None):
|
|
"""Construct a TVM target object from
|
|
1) Raw target string
|
|
2) Target config dict
|
|
3) Target tag string
|
|
4) Tag with overrides dict
|
|
|
|
Parameters
|
|
----------
|
|
target : Union[str, Dict[str, Any]]
|
|
Can be one of a literal target string, a json string describing
|
|
a configuration, or a dictionary of configuration options.
|
|
When using a dictionary or json string to configure target, the
|
|
possible values are:
|
|
|
|
tag : str (optional)
|
|
A registered tag name (e.g. ``"nvidia/nvidia-a100"``).
|
|
When ``tag`` is present, the tag's base config is loaded and
|
|
any additional fields in the dict override the base values.
|
|
The ``kind`` field is not needed when ``tag`` is specified.
|
|
kind : str (required unless tag is specified)
|
|
Which codegen path to use, for example 'llvm' or 'cuda'.
|
|
keys : List of str (optional)
|
|
A set of strategies that can be dispatched to. When using
|
|
"kind=opencl" for example, one could set keys to ["mali", "opencl", "gpu"].
|
|
device : str (optional)
|
|
A single key that corresponds to the actual device being run on.
|
|
This will be effectively appended to the keys.
|
|
libs : List of str (optional)
|
|
The set of external libraries to use. For example ['cblas', 'mkl'].
|
|
system-lib : bool (optional)
|
|
If True, build a module that contains self registered functions.
|
|
Useful for environments where dynamic loading like dlopen is banned.
|
|
mcpu : str (optional)
|
|
The specific cpu being run on. Serves only as an annotation.
|
|
model : str (optional)
|
|
An annotation indicating what model a workload came from.
|
|
runtime : str (optional)
|
|
An annotation indicating which runtime to use with a workload.
|
|
mtriple : str (optional)
|
|
The llvm triplet describing the target, for example "arm64-linux-android".
|
|
mattr : List of str (optional)
|
|
The llvm features to compile with, for example ["+avx512f", "+mmx"].
|
|
mfloat-abi : str (optional)
|
|
An llvm setting that is one of 'hard' or 'soft' indicating whether to use
|
|
hardware or software floating-point operations.
|
|
mabi : str (optional)
|
|
An llvm setting. Generate code for the specified ABI, for example "lp64d".
|
|
host : Union[str, Dict[str, Any]] (optional)
|
|
Description for target host. Can be recursive. Similar to target.
|
|
host : Optional[Union[str, Dict[str, Any]]]
|
|
Similar to target but for target host. Can be one of a literal target host string,
|
|
a json string describing a configuration, or a dictionary of configuration options.
|
|
When using a dictionary or json string to configure target, the possible values are
|
|
same as target.
|
|
"""
|
|
if isinstance(target, dict | str):
|
|
target = convert(target)
|
|
if isinstance(host, dict | str):
|
|
host = convert(host)
|
|
if target is None or not isinstance(target, Map | String | Target | str):
|
|
raise ValueError(f"target has to be a string or dictionary. instead get {type(target)}")
|
|
if host is not None:
|
|
if not isinstance(host, Map | String | Target | str):
|
|
raise ValueError("target host has to be a string or dictionary.")
|
|
self.__init_handle_by_constructor__(_ffi_api.Target, Target(target), Target(host))
|
|
else:
|
|
self.__init_handle_by_constructor__(_ffi_api.Target, target)
|
|
|
|
def __enter__(self):
|
|
_ffi_api.TargetEnterScope(self)
|
|
return self
|
|
|
|
def __exit__(self, ptype, value, trace):
|
|
_ffi_api.TargetExitScope(self)
|
|
|
|
def export(self):
|
|
return _ffi_api.TargetExport(self)
|
|
|
|
def with_host(self, host=None):
|
|
return _ffi_api.WithHost(self, Target(host))
|
|
|
|
@staticmethod
|
|
def from_device(device: str | Device) -> "Target":
|
|
"""Detects Target associated with the given device. If the device does not exist,
|
|
there will be an Error.
|
|
|
|
Parameters
|
|
----------
|
|
dev : Union[str, Device]
|
|
The device to detect the target for.
|
|
Supported device types: ["cuda", "metal", "rocm", "vulkan", "opencl", "cpu"]
|
|
|
|
Returns
|
|
-------
|
|
target : Target
|
|
The detected target.
|
|
"""
|
|
from .detect_target import ( # pylint: disable=import-outside-toplevel
|
|
detect_target_from_device,
|
|
)
|
|
|
|
return detect_target_from_device(device)
|
|
|
|
@staticmethod
|
|
def current(allow_none=True):
|
|
"""Returns the current target.
|
|
|
|
Parameters
|
|
----------
|
|
allow_none : bool
|
|
Whether allow the current target to be none
|
|
|
|
Raises
|
|
------
|
|
ValueError if current target is not set.
|
|
"""
|
|
return _ffi_api.TargetCurrent(allow_none)
|
|
|
|
@property
|
|
def features(self):
|
|
return TargetFeatures(self)
|
|
|
|
def __getattr__(self, name: str):
|
|
"""Backward-compatible attribute access for target attrs.
|
|
|
|
Historically, code accessed target options via attribute syntax
|
|
(e.g. ``target.arch``). Newer APIs prefer ``target.attrs["arch"]``.
|
|
"""
|
|
attrs = self.attrs
|
|
if name in attrs:
|
|
value = attrs[name]
|
|
return str(value) if isinstance(value, String) else value
|
|
raise AttributeError(f"'Target' object has no attribute '{name}'")
|
|
|
|
def get_kind_attr(self, attr_name):
|
|
"""Get additional attribute about the target kind.
|
|
|
|
Parameters
|
|
----------
|
|
attr_name : str
|
|
The attribute name.
|
|
|
|
Returns
|
|
-------
|
|
value : object
|
|
The attribute value
|
|
"""
|
|
return _ffi_api.TargetKindGetAttr(self.kind, attr_name)
|
|
|
|
def get_target_device_type(self):
|
|
"""Returns the device_type for this target."""
|
|
return _ffi_api.TargetGetDeviceType(self)
|
|
|
|
@staticmethod
|
|
def list_kinds():
|
|
"""Returns the list of available target names."""
|
|
return list(_ffi_api.ListTargetKinds())
|
|
|
|
@staticmethod
|
|
def target_or_current(target):
|
|
"""Returns target, or the current target in the environment if target is None"""
|
|
if target is None:
|
|
target = Target.current()
|
|
if target is None:
|
|
raise ValueError("Target is not set in env or passed as argument.")
|
|
return target
|