Files
wehub-resource-sync 26446540fa
Lint / lint (push) Has been cancelled
CI / MacOS (push) Has been cancelled
CI / Windows (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:36:25 +08:00

138 lines
5.4 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.
# ruff: noqa: RUF005
"""Triton kernel integration with TIR"""
from typing import Any
import triton
from packaging import version
from triton.runtime.jit import type_canonicalisation_dict
from tvm import tirx
from tvm.ir import PointerType, PrimType, is_prim_expr
from tvm.runtime import Module
from tvm.topi.utils import get_const_int
from .external_kernel import BaseKernel
if version.parse(triton.__version__) < version.parse("3.3.0"):
raise ImportError(
f"TIR Triton integration requires Triton >= 3.3.0, but found Triton {triton.__version__}"
)
class TritonKernel(BaseKernel):
"""A kernel from Triton JIT function.
This class bridges the Triton kernel with TVM runtime. The compilation includes the following
steps:
- Deduce the kernel signature and generate the Triton kernel
- Embed the compiled kernel into the current IRModule as an external module
- Generate a call to the Triton kernel following its calling convention via call_packed.
"""
def __init__(self, func):
self.func = func
def compile_to_device_module(
self,
launch_args: list[int | tirx.Expr],
*args: list[Any],
**kwargs: dict[str, Any],
) -> tuple[str, Module, list[Any]]:
"""Compile the kernel to a device module.
Parameters
----------
launch_args : List[int]
The grid size of the kernel. A list of one to three expressions, representing the number
of
"blockIdx.x", "blockIdx.y", and "blockIdx.z" respectively.
args : List[Any]
Arguments to the kernel function.
kwargs : Dict[str, Any]
Additional options for the kernel compilation.
"""
triton_kernel, kernel_args = self._generate_triton_kernel(self.func, *args, **kwargs)
kernel_metadata = triton_kernel.metadata
ptx = triton_kernel.asm["ptx"]
assert kernel_metadata.num_ctas == 1, "Cluster is not supported"
num_warps = kernel_metadata.num_warps
grid = launch_args
launch_param_tags = ["threadIdx.x"] + ["blockIdx.x", "blockIdx.y", "blockIdx.z"][
: len(grid)
]
launch_args = [num_warps * 32] + list(grid)
kernel_arg_types = []
for arg in kernel_args:
if isinstance(arg, int):
kernel_arg_types.append("int64")
elif isinstance(arg.ty, PointerType):
kernel_arg_types.append("handle")
else:
assert is_prim_expr(arg)
kernel_arg_types.append(str(arg.ty.dtype))
if triton_kernel.metadata.shared > 0:
# Add shared memory size to the launch arguments
launch_param_tags.append("tirx.use_dyn_shared_memory")
launch_args.append(triton_kernel.metadata.shared)
kernel_module = self._create_cuda_module(
ptx, kernel_arg_types, launch_param_tags, triton_kernel.name
)
return triton_kernel.name, kernel_module, kernel_args + launch_args
def _generate_triton_kernel(
self, func, *args, **kwargs
) -> tuple["triton.compiler.CompiledKernel", list[tirx.Expr]]:
"""Deduce the kernel signature and generate the Triton kernel"""
kernel_params = func.params
assert len(kernel_params) == len(args), (
f"Number of arguments does not match, expected {len(kernel_params)}, got {len(args)}"
)
signature = {}
constants = {}
kernel_args = [] # Arguments to invoke the kernel
for i, arg in enumerate(args):
if kernel_params[i].is_constexpr:
constants[kernel_params[i].name] = get_const_int(arg)
signature[kernel_params[i].name] = "constexpr"
kernel_args.append(arg)
continue
if isinstance(arg.ty, PointerType):
assert isinstance(arg, tirx.Var)
assert isinstance(arg.ty.element_type, PrimType)
elem_type = arg.ty.element_type.dtype
pointer_type = "*" + type_canonicalisation_dict[elem_type]
signature[kernel_params[i].name] = pointer_type
else:
assert is_prim_expr(arg)
signature[kernel_params[i].name] = type_canonicalisation_dict[arg.ty.dtype]
kernel_args.append(arg)
# TODO: Support default argument in the kernel
# TODO: Add specialization for aligned buffer pointers
source = triton.compiler.ASTSource(fn=func, signature=signature, constexprs=constants)
compiled = triton.compiler.compile(source, options=kwargs)
return compiled, kernel_args