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

159 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.
# pylint: disable=no-else-return, invalid-name
"""Developer API of add/remove/replace bindings in Relax."""
import tvm_ffi
import tvm
from tvm.runtime import Object
from . import Binding, DataflowBlock, Expr, Function, Var, _ffi_api
@tvm_ffi.register_object("relax.DataflowBlockRewrite")
class DataflowBlockRewrite(Object):
"""
A binding/statement-level dataflow block rewriter.
Notes
-----
Due to the immutable and copy-on-write nature of TVM AST nodes, the rewriting is not done in
place. Instead, a new DataflowBlock is created and returned with mutated_dfb. Similarly, its new
root Function is created and returned by mutated_root_fn. To apply this change for an IRModule,
use mutate_irmodule which rewrites the old function that registered in the constructor.
"""
__slots__ = ("__dict__",)
def __init__(self, dfb: DataflowBlock, root_fn: Function):
"""
Construct a rewriter with the DataflowBlock to rewrite and its root function.
Parameters
----------
dfb : DataflowBlock
The DataflowBlock to rewrite.
root_fn : Function
The root function of the DataflowBlock.
"""
self.func_name = root_fn.__name__ if hasattr(root_fn, "__name__") else None
self.__init_handle_by_constructor__(
_ffi_api.DataflowBlockRewrite,
dfb,
root_fn, # type: ignore
)
def replace_all_uses(self, old_var: Var, new_var: Var) -> None:
"""
Replace all uses of old_var with new_var.
Parameters
----------
old_var : Var
The old variable to replace.
new_var : Var
The new variable to replace with.
"""
_ffi_api.dfb_rewrite_replace_all_uses(self, old_var, new_var) # type: ignore
def add_binding(self, binding: Binding) -> None:
return _ffi_api.dfb_rewrite_add_binding(self, binding) # type: ignore
def add(self, expr: Expr, name: str | None = None, is_dfvar: bool = False) -> None:
"""
Add a new statement to the DataflowBlock with an automatically generated variable name.
Parameters
----------
expr : Expr
The expression to add.
name : Optional[str], optional
Variable name, by default None
is_dfvar : bool, optional
The variable type, by default False
Notes
-----
If the variable name is not given, it will be automatically generated in a form of
"tmp${COUNTER}". The variable type will be DataflowVar if is_dfvar is True, otherwise
it will be Var. Being Var means the variables are output variables of the DataflowBlock.
While being DataflowVar means the variables are internal variables of the DataflowBlock.
"""
_ffi_api.dfb_rewrite_add(self, expr, name, is_dfvar) # type: ignore
def remove_unused(self, var: Var, allow_undef=False) -> None:
"""
Remove a statement by its variable definition if and only if it is unused.
Parameters
----------
var : Var
The unused variable definition.
allow_undef : bool, optional
Whether to allow var being undefined variable, by default False
Raises
------
RuntimeError if the variable is used or undefined (allow_undef=False).
"""
_ffi_api.dfb_rewrite_remove_unused(self, var, allow_undef) # type: ignore
def remove_all_unused(self) -> None:
"""
Remove all unused variables.
Notes
-----
This could remove unused variables in other DataflowBlocks as well.
"""
_ffi_api.dfb_rewrite_remove_all_unused(self) # type: ignore
def mutated_dfb(self) -> DataflowBlock:
"""
Returns the mutated DataflowBlock.
"""
return self.dfb
def mutated_root_fn(self) -> Function:
"""
Returns the mutated root function.
"""
ret = self.root_fn
if self.func_name:
ret.__name__ = self.func_name
return ret
def mutate_irmodule(self, irmodule: tvm.IRModule) -> tvm.IRModule:
"""
Return an updated IRModule by replacing the old function with the mutated root function.
Parameters
----------
irmodule : tvm.IRModule
The base IRModule to update.
Returns
-------
tvm.IRModule
The updated IRModule.
"""
ret = _ffi_api.dfb_rewrite_mutate_irmodule(self, irmodule) # type: ignore
if hasattr(irmodule, "__name__"):
ret.__name__ = irmodule.__name__
return ret