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

152 lines
5.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.
# pylint: disable=invalid-name
# ruff: noqa: RUF012
"""A builder to build Relax VM executable."""
from enum import IntEnum
import tvm_ffi
from tvm_ffi import Shape
import tvm
from . import _ffi_api
from .vm_build import VMExecutable
class SpecialReg(IntEnum):
"""Magic numbers that represent special registers in vm."""
VOID_ARG = (1 << 54) + 0
VM_STATE = (1 << 54) + 1
class VMFuncKind(IntEnum):
"""VM function kind code."""
PACKED_FUNC = 0
VM_FUNC = 1
class VMFuncScope:
"""An object corresponds to each VM function, working as a context manager."""
stack: list["VMFuncScope"] = []
def __init__(self, exit_callback):
self.exit_callback = exit_callback
def __enter__(self):
VMFuncScope.stack.append(self)
return self
def __exit__(self, ptype, value, trace):
VMFuncScope.stack.pop()
self.exit_callback()
@tvm_ffi.register_object("relax.ExecBuilder")
class ExecBuilder(tvm_ffi.core.Object):
"""A builder to emit instructions and build executable for the virtual machine."""
def __init__(self) -> None:
self.__init_handle_by_constructor__(_ffi_api.ExecBuilderCreate) # type: ignore
def r(self, idx: int) -> int:
"""set instruction's argument as a register."""
return _ffi_api.ExecBuilderR(self, idx) # type: ignore
def imm(self, value: int) -> int:
"""set instruction's argument as an immediate."""
return _ffi_api.ExecBuilderImm(self, value) # type: ignore
def c(self, idx: int) -> int:
"""set instruction's argument as a constant."""
return _ffi_api.ExecBuilderC(self, idx) # type: ignore
def f(self, name: str) -> int:
"""set instruction's argument as a function."""
return _ffi_api.ExecBuilderF(self, name) # type: ignore
def void_arg(self) -> int:
return self.r(SpecialReg.VOID_ARG)
def vm_state(self) -> int:
return self.r(SpecialReg.VM_STATE)
def declare_function(self, func_name: str, kind: VMFuncKind = VMFuncKind.PACKED_FUNC) -> None:
"""Declare a function"""
_ffi_api.ExecBuilderDeclareFunction(self, func_name, kind) # type: ignore
def function(
self, func_name: str, num_inputs: int | None = 0, param_names: list[str] | None = None
) -> VMFuncScope:
"""annotate a VM function."""
_ffi_api.ExecBuilderEmitFunction(self, func_name, num_inputs, param_names) # type: ignore
return VMFuncScope(lambda: _ffi_api.ExecBuilderEndFunction(self, func_name)) # type: ignore
def _check_scope(self) -> None:
if len(VMFuncScope.stack) == 0:
raise ValueError("emit should happen in a function scope")
def convert_constant(self, const: object) -> int:
return _ffi_api.ExecBuilderConvertConstant(self, const) # type: ignore
def emit_call(
self,
name: str,
args: list[tvm.runtime.Tensor | tvm.DataType] | None = None,
dst: int | None = None,
) -> None:
"""emit a call instruction which calls a packed function."""
self._check_scope()
if dst is None:
dst = SpecialReg.VOID_ARG
args_ = []
if args is not None:
for arg in args:
if isinstance(arg, tuple):
shape_tuple = Shape(arg)
new_arg = self.convert_constant(shape_tuple)
args_.append(new_arg)
elif isinstance(arg, tvm.runtime.Tensor | tvm.DataType | Shape):
new_arg = self.convert_constant(arg)
args_.append(new_arg)
else:
args_.append(arg)
_ffi_api.ExecBuilderEmitCall(self, name, args_, dst) # type: ignore
def emit_ret(self, result: int) -> None:
"""emit a return instruction"""
self._check_scope()
_ffi_api.ExecBuilderEmitRet(self, result) # type: ignore
def emit_goto(self, pc_offset):
"""emit a goto instruction"""
self._check_scope()
_ffi_api.ExecBuilderEmitGoto(self, pc_offset) # type: ignore
def emit_if(self, cond, false_offset):
"""emit an if instruction"""
self._check_scope()
_ffi_api.ExecBuilderEmitIf(self, cond, false_offset) # type: ignore
def get(self) -> VMExecutable:
"""return the executable"""
return VMExecutable(_ffi_api.ExecBuilderGet(self)) # type: ignore