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

1537 lines
48 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, unidiomatic-typecheck, invalid-name, arguments-differ
# ruff: noqa: RUF012
"""The expression functor of Relax."""
from collections.abc import Callable
import tvm_ffi
from tvm.ir import Call, Op
from tvm.ir.utils import derived_object
from tvm.runtime import Object
from ..ir.module import IRModule
from . import _ffi_api
from .block_builder import BlockBuilder
from .expr import (
Binding,
BindingBlock,
Constant,
DataflowBlock,
DataflowVar,
DataTypeImm,
Expr,
ExternFunc,
Function,
GlobalVar,
If,
MatchCast,
SeqExpr,
ShapeExpr,
Span,
StringImm,
Tuple,
TupleGetItem,
Var,
VarBinding,
)
from .type import Type
visitor = derived_object
"""
A decorator to wrap user-customized PyExprVisitor as TVM object _PyExprVisitor.
Parameters
----------
visitor_cls : PyExprVisitor
The user-customized PyExprVisitor.
Returns
-------
cls : _PyExprVisitor
The decorated TVM object _PyExprVisitor(ExprVisitor on the C++ side).
Example
-------
.. code-block:: python
@relax.expr_functor.visitor
class MyExprVisitor(PyExprVisitor):
# customize visit function
def visit_call_(self, op: Call) -> None:
# just for demo purposes
...
# myvisitor is now a special visitor that visit every Call with
# user-customized visit_call_
myvisitor = MyExprVisitor()
# apply myvisitor to Expr/Binding/BindingBlock/VarDef
myvisitor.visit_expr(expr)
myvisitor.visit_binding(binding)
myvisitor.visit_binding_block(bindingblock)
myvisitor.visit_var_def(var)
"""
mutator = derived_object
"""
A decorator to wrap user-customized PyExprMutator as TVM object _PyExprMutator.
Note: Cannot override visit function and post-order rewrite at the same time.
Parameters
----------
mutator_cls : PyExprMutator
The user-customized PyExprMutator.
Returns
-------
cls : _PyExprMutator
The decorated TVM object _PyExprMutator(ExprMutator on the C++ side).
Example
-------
.. code-block:: python
@relax.expr_functor.mutator
class MyExprMutator(PyExprMutator):
# customize rewrite function
def visit_tuple_(self, op: Tuple) -> Expr:
# just for demo purposes
...
# mymutator is now a special mutator that rewrite every Tuple with
# user-customized visit_tuple_
mymutator = MyExprMutator()
# apply mymutator to Expr/Binding/BindingBlock/VarDef
mymutator.visit_expr(expr)
mymutator.visit_binding(binding)
mymutator.visit_binding_block(bindingblock)
mymutator.visit_var_def(var)
"""
class ExprFunctor:
"""
An abstract visitor defined over Expr.
Defines the default dispatch over expressions, and
implements memoization.
"""
def visit_expr(self, expr: Expr) -> Expr:
"""Apply the visitor to an expression."""
if isinstance(expr, Constant): # type: ignore
ret = self.visit_constant_(expr)
elif isinstance(expr, Tuple):
ret = self.visit_tuple_(expr)
elif isinstance(expr, DataflowVar):
ret = self.visit_dataflow_var_(expr)
elif isinstance(expr, Var):
ret = self.visit_var_(expr)
elif isinstance(expr, ShapeExpr):
ret = self.visit_shape_expr_(expr)
elif isinstance(expr, ExternFunc):
ret = self.visit_extern_func_(expr)
elif isinstance(expr, GlobalVar): # type: ignore
ret = self.visit_global_var_(expr)
elif isinstance(expr, Function):
ret = self.visit_function_(expr)
elif isinstance(expr, Call): # type: ignore
ret = self.visit_call_(expr)
elif isinstance(expr, SeqExpr):
ret = self.visit_seq_expr_(expr)
elif isinstance(expr, If): # type: ignore
ret = self.visit_if_(expr)
elif isinstance(expr, Op):
ret = self.visit_op_(expr)
elif isinstance(expr, TupleGetItem):
ret = self.visit_tuple_getitem_(expr)
elif isinstance(expr, StringImm):
ret = self.visit_string_imm_(expr)
elif isinstance(expr, DataTypeImm):
ret = self.visit_data_type_imm_(expr)
elif isinstance(expr, Expr):
ret = self.visit_expr_fallback_(expr)
else:
raise TypeError(f"Invalid type: {type(expr)}")
return ret
def visit_constant_(self, op: Constant):
raise NotImplementedError()
def visit_tuple_(self, op: Tuple):
raise NotImplementedError()
def visit_dataflow_var_(self, op: DataflowVar):
raise NotImplementedError()
def visit_var_(self, op: Var):
raise NotImplementedError()
def visit_shape_expr_(self, op: ShapeExpr):
raise NotImplementedError()
def visit_extern_func_(self, op: ExternFunc):
raise NotImplementedError()
def visit_global_var_(self, op: GlobalVar):
raise NotImplementedError()
def visit_function_(self, op: Function):
raise NotImplementedError()
def visit_call_(self, op: Call):
raise NotImplementedError()
def visit_seq_expr_(self, op: SeqExpr):
raise NotImplementedError()
def visit_if_(self, op: If):
raise NotImplementedError()
def visit_op_(self, op: Op):
raise NotImplementedError()
def visit_tuple_getitem_(self, op: TupleGetItem):
raise NotImplementedError()
def visit_expr_fallback_(self, op: Expr):
raise NotImplementedError()
def visit_string_imm_(self, op: StringImm):
raise NotImplementedError()
def visit_data_type_imm_(self, op: DataTypeImm):
raise NotImplementedError()
def visit_var_binding_(self, binding: VarBinding):
raise NotImplementedError()
def visit_match_cast_(self, binding: MatchCast):
raise NotImplementedError()
def visit_binding_block_(self, block: BindingBlock):
raise NotImplementedError()
def visit_dataflow_block_(self, block: DataflowBlock):
raise NotImplementedError()
def visit_var_def_(self, var: Var):
raise NotImplementedError()
def visit_dataflow_var_def_(self, var: DataflowVar):
raise NotImplementedError()
def visit_binding(self, binding: Binding):
if isinstance(binding, MatchCast):
self.visit_match_cast_(binding)
elif isinstance(binding, VarBinding):
self.visit_var_binding_(binding)
else:
raise TypeError(f"Invalid type: {type(binding)}")
def visit_binding_block(self, block: BindingBlock):
if isinstance(block, DataflowBlock):
self.visit_dataflow_block_(block)
elif isinstance(block, BindingBlock):
self.visit_binding_block_(block)
else:
raise TypeError(f"Invalid type: {type(block)}")
def visit_var_def(self, var: Var):
if isinstance(var, DataflowVar):
self.visit_dataflow_var_def_(var)
elif isinstance(var, Var):
self.visit_var_def_(var)
else:
raise TypeError(f"Invalid type: {type(var)}")
@tvm_ffi.register_object("expr_functor.PyExprVisitor")
class _PyExprVisitor(tvm_ffi.core.Object):
"""
A TVM object to support customization of ExprVisitor on the python side.
This is the decorated result returned from visitor decorator.
WARNING: This is NOT the user facing class for method overwriting inheritance.
See also: visitor, PyExprVisitor
"""
def __init__(
self,
f_visit_expr: Callable | None = None,
f_visit_constant_: Callable | None = None,
f_visit_tuple_: Callable | None = None,
f_visit_var_: Callable | None = None,
f_visit_dataflow_var_: Callable | None = None,
f_visit_shape_expr_: Callable | None = None,
f_visit_extern_func_: Callable | None = None,
f_visit_global_var_: Callable | None = None,
f_visit_function_: Callable | None = None,
f_visit_call_: Callable | None = None,
f_visit_seq_expr_: Callable | None = None,
f_visit_if_: Callable | None = None,
f_visit_op_: Callable | None = None,
f_visit_tuple_getitem_: Callable | None = None,
f_visit_expr_fallback_: Callable | None = None,
f_visit_string_imm_: Callable | None = None,
f_visit_data_type_imm_: Callable | None = None,
f_visit_binding: Callable | None = None,
f_visit_var_binding_: Callable | None = None,
f_visit_match_cast_: Callable | None = None,
f_visit_binding_block: Callable | None = None,
f_visit_binding_block_: Callable | None = None,
f_visit_dataflow_block_: Callable | None = None,
f_visit_var_def: Callable | None = None,
f_visit_var_def_: Callable | None = None,
f_visit_dataflow_var_def_: Callable | None = None,
f_visit_span: Callable | None = None,
) -> None:
"""Constructor."""
self.__init_handle_by_constructor__(
_ffi_api.MakePyExprVisitor, # type: ignore
f_visit_expr,
f_visit_constant_,
f_visit_tuple_,
f_visit_var_,
f_visit_dataflow_var_,
f_visit_shape_expr_,
f_visit_extern_func_,
f_visit_global_var_,
f_visit_function_,
f_visit_call_,
f_visit_seq_expr_,
f_visit_if_,
f_visit_op_,
f_visit_tuple_getitem_,
f_visit_expr_fallback_,
f_visit_string_imm_,
f_visit_data_type_imm_,
f_visit_binding,
f_visit_var_binding_,
f_visit_match_cast_,
f_visit_binding_block,
f_visit_binding_block_,
f_visit_dataflow_block_,
f_visit_var_def,
f_visit_var_def_,
f_visit_dataflow_var_def_,
f_visit_span,
)
def visit_expr(self, expr: Expr) -> None:
"""Generic dispatcher for Expr.
Parameters
----------
expr : Expr
The expr to be visited.
"""
return _ffi_api.PyExprVisitorVisitExpr(self, expr) # type: ignore
def visit_binding(self, binding: Binding) -> None:
"""Generic dispatcher for Binding.
Parameters
----------
binding : Binding
The binding to be visited.
"""
return _ffi_api.PyExprVisitorVisitBinding(self, binding) # type: ignore
def visit_binding_block(self, block: BindingBlock) -> None:
"""Generic dispatcher for BindingBlock.
Parameters
----------
block : BindingBlock
The block to be visited.
"""
return _ffi_api.PyExprVisitorVisitBindingBlock(self, block) # type: ignore
def visit_var_def(self, var: Var) -> None:
"""Generic dispatcher for visiting the var definition site.
Note that visit_var_() will only visit the usage site of an Var.
Parameters
----------
var : Var
The var to be visited.
"""
return _ffi_api.PyExprVisitorVisitVarDef(self, var) # type: ignore
class PyExprVisitor:
"""
An abstract ExprVisitor with customized methods on the python-side.
This is the user facing class for method overwriting inheritance.
_tvm_metadata discribes the class to inherit("cls"), the methods
that users can overwrite("methods").
Note: @relax.expr_functor.visitor is required for proper usage of any inherited class.
See also: visitor, _PyExprVisitor
Example:
.. code-block:: python
@relax.expr_functor.visitor
def MyExprVisitor(PyExprVisitor):
...
"""
_tvm_metadata = {
"cls": _PyExprVisitor,
"methods": [
"visit_expr",
"visit_constant_",
"visit_tuple_",
"visit_var_",
"visit_dataflow_var_",
"visit_shape_expr_",
"visit_extern_func_",
"visit_global_var_",
"visit_function_",
"visit_call_",
"visit_seq_expr_",
"visit_if_",
"visit_op_",
"visit_tuple_getitem_",
"visit_expr_fallback_",
"visit_string_imm_",
"visit_data_type_imm_",
"visit_binding",
"visit_var_binding_",
"visit_match_cast_",
"visit_binding_block",
"visit_binding_block_",
"visit_dataflow_block_",
"visit_var_def",
"visit_var_def_",
"visit_dataflow_var_def_",
"visit_span",
],
}
def visit_expr(self, expr: Expr) -> None:
"""Generic dispatcher for Expr.
Users can customized this function to overwrite VisitExpr(const Expr& expr) on the C++ side.
Parameters
----------
expr : Expr
The expr to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.PyExprVisitorVisitExpr(self._outer(), expr) # type: ignore
def visit_binding(self, binding: Binding) -> None:
"""Generic dispatcher for Binding.
Users can customized this function to overwrite VisitBinding(const Binding& binding)
on the C++ side.
Parameters
----------
binding : Binding
The binding to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.PyExprVisitorVisitBinding(self._outer(), binding) # type: ignore
def visit_binding_block(self, block: BindingBlock) -> None:
"""Generic dispatcher for BindingBlock.
Users can customized this function to overwrite VisitBindingBlock(const BindingBlock& block)
on the C++ side.
Parameters
----------
block : BindingBlock
The block to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.PyExprVisitorVisitBindingBlock(self._outer(), block) # type: ignore
def visit_var_def(self, var: Var) -> None:
"""Generic dispatcher for visiting the var definition site.
Users can customized this function to overwrite VisitVarDef(const Var& var) on the C++ side.
Note that visit_var_() will only visit the usage site of an Var.
Parameters
----------
var : Var
The var to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.PyExprVisitorVisitVarDef(self._outer(), var) # type: ignore
def visit_constant_(self, op: Constant) -> None:
"""Visit Constant.
Users can customized this function to overwrite VisitExpr_(const ConstantNode* op)
on the C++ side.
Parameters
----------
op : Constant
The Constant to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_tuple_(self, op: Tuple) -> None:
"""Visit Tuple.
Users can customized this function to overwrite VisitExpr_(const TupleNode* op)
on the C++ side.
Parameters
----------
op : Tuple
The Tuple to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_var_(self, op: Var) -> None:
"""Visit Var.
Users can customized this function to overwrite VisitExpr_(const VarNode* op)
on the C++ side.
Parameters
----------
op : Var
The Var to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_dataflow_var_(self, op: DataflowVar) -> None:
"""Visit DataflowVar.
Users can customized this function to overwrite VisitExpr_(const DataflowVarNode* op)
on the C++ side.
Parameters
----------
op : DataflowVar
The DataflowVar to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_shape_expr_(self, op: ShapeExpr) -> None:
"""Visit ShapeExpr.
Users can customized this function to overwrite VisitExpr_(const ShapeExprNode* op)
on the C++ side.
Parameters
----------
op : ShapeExpr
The ShapeExpr to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_extern_func_(self, op: ExternFunc) -> None:
"""Visit ExternFunc.
Users can customized this function to overwrite VisitExpr_(const ExternFuncNode* op)
on the C++ side.
Parameters
----------
op : ExternFunc
The ExternFunc to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_global_var_(self, op: GlobalVar) -> None:
"""Visit GlobalVar.
Users can customized this function to overwrite VisitExpr_(const GlobalVarNode* op)
on the C++ side.
Parameters
----------
op : GlobalVar
The GlobalVar to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_function_(self, op: Function) -> None:
"""Visit Function.
Users can customized this function to overwrite VisitExpr_(const FunctionNode* op)
on the C++ side.
Parameters
----------
op : Function
The Function to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_call_(self, op: Call) -> None:
"""Visit Call.
Users can customized this function to overwrite VisitExpr_(const CallNode* op)
on the C++ side.
Parameters
----------
op : Call
The Call to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_seq_expr_(self, op: SeqExpr) -> None:
"""Visit SeqExpr.
Users can customized this function to overwrite VisitExpr_(const SeqExprNode* op)
on the C++ side.
Parameters
----------
op : SeqExpr
The SeqExpr to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_if_(self, op: If) -> None:
"""Visit If.
Users can customized this function to overwrite VisitExpr_(const IfNode* op)
on the C++ side.
Parameters
----------
op : If
The If to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_op_(self, op: Op) -> None:
"""Visit Op.
Users can customized this function to overwrite VisitExpr_(const OpNode* op)
on the C++ side.
Parameters
----------
op : Op
The Op to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_tuple_getitem_(self, op: TupleGetItem) -> None:
"""Visit TupleGetItem.
Users can customized this function to overwrite VisitExpr_(const TupleGetItemNode* op)
on the C++ side.
Parameters
----------
op : TupleGetItem
The TupleGetItem to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_expr_fallback_(self, op: Expr) -> None:
"""Visit an expression handled by the C++ fallback.
Parameters
----------
op : Expr
The expression to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExprFallback(self._outer(), op) # type: ignore
def visit_string_imm_(self, op: StringImm) -> None:
"""Visit StringImm.
Users can customized this function to overwrite VisitExpr_(const StringImmNode* op)
on the C++ side.
Parameters
----------
op : StringImm
The StringImm to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_data_type_imm_(self, op: DataTypeImm) -> None:
"""Visit DataTypeImm.
Users can customized this function to overwrite VisitExpr_(const DataTypeImmNode* op)
on the C++ side.
Parameters
----------
op : DataTypeImm
The DataTypeImm to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitExpr(self._outer(), op) # type: ignore
def visit_var_binding_(self, binding: VarBinding) -> None:
"""Visit VarBinding.
Users can customized this function to overwrite VisitBinding_(const VarBindingNode* binding)
on the C++ side.
Parameters
----------
binding : VarBinding
The VarBinding to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitBinding(self._outer(), binding) # type: ignore
def visit_match_cast_(self, binding: MatchCast) -> None:
"""Visit MatchCast.
Users can customized this function to overwrite VisitBinding_(const MatchCastNode* binding)
on the C++ side.
Parameters
----------
binding : MatchCast
The MatchCast to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitBinding(self._outer(), binding) # type: ignore
def visit_binding_block_(self, block: BindingBlock) -> None:
"""Visit BindingBlock.
Users can customized this function to overwrite VisitBindingBlock_(const BindingBlockNode*
block) on the C++ side.
Parameters
----------
block : BindingBlock
The BindingBlock to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitBindingBlock(self._outer(), block) # type: ignore
def visit_dataflow_block_(self, block: DataflowBlock) -> None:
"""Visit DataflowBlock.
Users can customized this function to overwrite VisitBindingBlock_(const DataflowBlockNode*
block) on the C++ side.
Parameters
----------
block : DataflowBlock
The DataflowBlock to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitBindingBlock(self._outer(), block) # type: ignore
def visit_var_def_(self, var: Var) -> None:
"""Visit the Var definition site.
Users can customized this function to overwrite VisitVarDef_(const VarNode* var)
on the C++ side.
Parameters
----------
var : Var
The Var to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitVarDef(self._outer(), var) # type: ignore
def visit_dataflow_var_def_(self, var: DataflowVar) -> None:
"""Visit the DataflowVar definition site.
Users can customized this function to overwrite VisitVarDef_(const DataflowVarNode* var)
on the C++ side.
Parameters
----------
var : DataflowVar
The DataflowVar to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitVarDef(self._outer(), var) # type: ignore
def visit_span(self, span: Span) -> None:
"""Visit Span.
Users can customized this function to overwrite VisitSpan(const Span& span) on the C++ side.
Parameters
----------
span : Span
The Span to be visited.
"""
# Using self._outer() to ref _PyExprVisitor
return _ffi_api.ExprVisitorVisitSpan(self._outer(), span) # type: ignore
@tvm_ffi.register_object("expr_functor.PyExprMutator")
class _PyExprMutator(Object):
"""
A TVM object to support customization of ExprMutator on the python side.
This is the decorated result returned from mutator decorator.
WARNING: This is NOT the user facing class for method overwriting inheritance.
See also: mutator, PyExprmutator
"""
def __init__(
self,
builder: BlockBuilder = None,
f_visit_expr: Callable | None = None,
f_visit_constant_: Callable | None = None,
f_visit_tuple_: Callable | None = None,
f_visit_var_: Callable | None = None,
f_visit_dataflow_var_: Callable | None = None,
f_visit_shape_expr_: Callable | None = None,
f_visit_extern_func_: Callable | None = None,
f_visit_global_var_: Callable | None = None,
f_visit_function_: Callable | None = None,
f_visit_call_: Callable | None = None,
f_visit_seq_expr_: Callable | None = None,
f_visit_if_: Callable | None = None,
f_visit_op_: Callable | None = None,
f_visit_tuple_getitem_: Callable | None = None,
f_visit_expr_fallback_: Callable | None = None,
f_visit_string_imm_: Callable | None = None,
f_visit_data_type_imm_: Callable | None = None,
f_visit_binding: Callable | None = None,
f_visit_var_binding_: Callable | None = None,
f_visit_match_cast_: Callable | None = None,
f_visit_binding_block: Callable | None = None,
f_visit_binding_block_: Callable | None = None,
f_visit_dataflow_block_: Callable | None = None,
f_visit_var_def: Callable | None = None,
f_visit_var_def_: Callable | None = None,
f_visit_dataflow_var_def_: Callable | None = None,
f_visit_span: Callable | None = None,
) -> None:
"""Constructor."""
self.__init_handle_by_constructor__(
_ffi_api.MakePyExprMutator, # type: ignore
builder,
f_visit_expr,
f_visit_constant_,
f_visit_tuple_,
f_visit_var_,
f_visit_dataflow_var_,
f_visit_shape_expr_,
f_visit_extern_func_,
f_visit_global_var_,
f_visit_function_,
f_visit_call_,
f_visit_seq_expr_,
f_visit_if_,
f_visit_op_,
f_visit_tuple_getitem_,
f_visit_expr_fallback_,
f_visit_string_imm_,
f_visit_data_type_imm_,
f_visit_binding,
f_visit_var_binding_,
f_visit_match_cast_,
f_visit_binding_block,
f_visit_binding_block_,
f_visit_dataflow_block_,
f_visit_var_def,
f_visit_var_def_,
f_visit_dataflow_var_def_,
f_visit_span,
)
def visit_expr(self, expr: Expr) -> Expr:
"""Generic dispatcher for Expr.
Parameters
----------
expr : Expr
The expr to be visited.
Returns
-------
result : Expr
The Expr after transformation.
"""
return _ffi_api.PyExprMutatorVisitExpr(self, expr) # type: ignore
def visit_binding(self, binding: Binding) -> None:
"""Generic dispatcher for Binding.
Parameters
----------
binding : Binding
The binding to be visited.
"""
return _ffi_api.PyExprMutatorVisitBinding(self, binding) # type: ignore
def visit_binding_block(self, block: BindingBlock) -> BindingBlock:
"""Generic dispatcher for BindingBlock.
Parameters
----------
block : BindingBlock
The block to be visited.
Returns
-------
result : BindingBlock
The binding block after transformation.
"""
return _ffi_api.PyExprMutatorVisitBindingBlock(self, block) # type: ignore
def visit_var_def(self, var: Var) -> Var:
"""Generic dispatcher for visiting the var definition site.
Note that visit_var_() will only visit the usage site of an Var.
Parameters
----------
var : Var
The var to be visited.
Returns
-------
result : Var
The var after post-order rewritten.
"""
return _ffi_api.PyExprMutatorVisitVarDef(self, var) # type: ignore
class PyExprMutator:
"""
An abstract ExprMutator with customized methods on the python-side.
This is the user facing class for method overwriting inheritance.
_tvm_metadata discribes the class to inherit("cls"), the methods that users can
overwrite("methods"), the constructor's parameters("fields")
Note: @relax.expr_functor.mutator is required for proper usage of any inherited class.
See also: visitor, _PyExprVisitor
Example:
.. code-block:: python
@relax.expr_functor.mutator
def MyExprMutator(PyExprMutator):
...
"""
_tvm_metadata = {
"cls": _PyExprMutator,
"fields": ["builder_"],
"methods": [
"visit_expr",
"visit_constant_",
"visit_tuple_",
"visit_var_",
"visit_dataflow_var_",
"visit_shape_expr_",
"visit_extern_func_",
"visit_global_var_",
"visit_function_",
"visit_call_",
"visit_seq_expr_",
"visit_if_",
"visit_op_",
"visit_tuple_getitem_",
"visit_expr_fallback_",
"visit_string_imm_",
"visit_data_type_imm_",
"visit_binding",
"visit_var_binding_",
"visit_match_cast_",
"visit_binding_block",
"visit_binding_block_",
"visit_dataflow_block_",
"visit_var_def",
"visit_var_def_",
"visit_dataflow_var_def_",
"visit_span",
],
}
def __init__(self, mod: IRModule | None = None) -> None:
"""Constructor"""
self.builder_ = BlockBuilder(mod)
def visit_expr(self, expr: Expr) -> Expr:
"""Generic dispatcher for Expr.
Users can customized this function to overwrite VisitExpr(const Expr& expr) on the C++ side.
Parameters
----------
expr : Expr
The expr to be visited.
Returns
-------
result : Expr
The Expr after transformation.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.PyExprMutatorVisitExpr(self._outer(), expr) # type: ignore
def visit_binding(self, binding: Binding) -> None:
"""Generic dispatcher for Binding.
Users can customized this function to overwrite VisitBinding(const Binding& binding)
on the C++ side.
Parameters
----------
binding : Binding
The binding to be visited.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.PyExprMutatorVisitBinding(self._outer(), binding) # type: ignore
def visit_binding_block(self, block: BindingBlock) -> BindingBlock:
"""Generic dispatcher for BindingBlock.
Users can customized this function to overwrite VisitBindingBlock(const BindingBlock& block)
on the C++ side.
Parameters
----------
block : BindingBlock
The block to be visited.
Returns
-------
result : BindingBlock
The binding block after transformation.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.PyExprMutatorVisitBindingBlock(self._outer(), block) # type: ignore
def visit_var_def(self, var: Var) -> Var:
"""Generic dispatcher for visiting the var definition site.
Users can customized this function to overwrite VisitVarDef(const Var& var) on the C++ side.
Note that visit_var_() will only visit the usage site of an Var.
Parameters
----------
var : Var
The var to be visited.
Returns
-------
result: Var
The var after post-order rewritten.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.PyExprMutatorVisitVarDef(self._outer(), var) # type: ignore
def visit_constant_(self, op: Constant) -> Expr:
"""Visit Constant.
Users can customized this function to overwrite VisitExpr_(const ConstantNode* op)
on the C++ side.
Parameters
----------
op : Constant
The Constant to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_tuple_(self, op: Tuple) -> Expr:
"""Visit Tuple.
Users can customized this function to overwrite VisitExpr_(const TupleNode* op)
on the C++ side.
Parameters
----------
op : Tuple
The Tuple to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_var_(self, op: Var) -> Expr:
"""Visit Var.
Users can customized this function to overwrite VisitExpr_(const VarNode* op)
on the C++ side.
Parameters
----------
op : Var
The Var to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_dataflow_var_(self, op: DataflowVar) -> Expr:
"""Visit DataflowVar.
Users can customized this function to overwrite VisitExpr_(const DataflowVarNode* op)
on the C++ side.
Parameters
----------
op : DataflowVar
The DataflowVar to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_shape_expr_(self, op: ShapeExpr) -> Expr:
"""Visit ShapeExpr.
Users can customized this function to overwrite VisitExpr_(const ShapeExprNode* op)
on the C++ side.
Parameters
----------
op : ShapeExpr
The ShapeExpr to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_extern_func_(self, op: ExternFunc) -> Expr:
"""Visit ExternFunc.
Users can customized this function to overwrite VisitExpr_(const ExternFuncNode* op)
on the C++ side.
Parameters
----------
op : ExternFunc
The ExternFunc to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_global_var_(self, op: GlobalVar) -> Expr:
"""Visit GlobalVar.
Users can customized this function to overwrite VisitExpr_(const GlobalVarNode* op)
on the C++ side.
Parameters
----------
op : GlobalVar
The GlobalVar to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_function_(self, op: Function) -> Expr:
"""Visit Function.
Users can customized this function to overwrite VisitExpr_(const FunctionNode* op)
on the C++ side.
Parameters
----------
op : Function
The Function to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_call_(self, op: Call) -> Expr:
"""Visit Call.
Users can customized this function to overwrite VisitExpr_(const CallNode* op)
on the C++ side.
Parameters
----------
op : Call
The Call to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_seq_expr_(self, op: SeqExpr) -> Expr:
"""Visit SeqExpr.
Users can customized this function to overwrite VisitExpr_(const SeqExprNode* op)
on the C++ side.
Parameters
----------
op : SeqExpr
The SeqExpr to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_if_(self, op: If) -> Expr:
"""Visit If.
Users can customized this function to overwrite VisitExpr_(const IfNode* op)
on the C++ side.
Parameters
----------
op : If
The If to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_op_(self, op: Op) -> Expr:
"""Visit Op.
Users can customized this function to overwrite VisitExpr_(const OpNode* op)
on the C++ side.
Parameters
----------
op : Op
The Op to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_tuple_getitem_(self, op: TupleGetItem) -> Expr:
"""Visit TupleGetItem.
Users can customized this function to overwrite VisitExpr_(const TupleGetItemNode* op)
on the C++ side.
Parameters
----------
op : TupleGetItem
The TupleGetItem to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_expr_fallback_(self, op: Expr) -> Expr:
"""Visit an expression handled by the C++ fallback.
Parameters
----------
op : Expr
The expression to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExprFallback(self._outer(), op) # type: ignore
def visit_string_imm_(self, op: StringImm) -> Expr:
"""Visit StringImm.
Users can customized this function to overwrite VisitExpr_(const StringImmNode* op)
on the C++ side.
Parameters
----------
op : StringImm
The StringImm to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_data_type_imm_(self, op: DataTypeImm) -> Expr:
"""Visit DataTypeImm.
Users can customized this function to overwrite VisitExpr_(const DataTypeImmNode* op)
on the C++ side.
Parameters
----------
op : DataTypeImm
The DataTypeImm to be visited.
Returns
-------
result : Expr
The Expr after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitExpr(self._outer(), op) # type: ignore
def visit_var_binding_(self, binding: VarBinding) -> None:
"""Visit VarBinding.
Users can customized this function to overwrite VisitBinding_(const VarBindingNode* binding)
on the C++ side.
Parameters
----------
binding : VarBinding
The VarBinding to be visited.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitBinding(self._outer(), binding) # type: ignore
def visit_match_cast_(self, binding: MatchCast) -> None:
"""Visit MatchCast.
Users can customized this function to overwrite VisitBinding_(const MatchCastNode* binding)
on the C++ side.
Parameters
----------
binding : MatchCast
The MatchCast to be visited.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitBinding(self._outer(), binding) # type: ignore
def visit_binding_block_(self, block: BindingBlock) -> BindingBlock:
"""Visit BindingBlock.
Users can customized this function to overwrite VisitBindingBlock_(const BindingBlockNode*
block) on the C++ side.
Parameters
----------
block : BindingBlock
The BindingBlock to be visited.
Returns
-------
result : BindingBlock
The binding block after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitBindingBlock(self._outer(), block) # type: ignore
def visit_dataflow_block_(self, block: DataflowBlock) -> BindingBlock:
"""Visit DataflowBlock.
Users can customized this function to overwrite VisitBindingBlock_(const DataflowBlockNode*
block) on the C++ side.
Parameters
----------
block : DataflowBlock
The DataflowBlock to be visited.
Returns
-------
result : BindingBlock
The binding block after transformation
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitBindingBlock(self._outer(), block) # type: ignore
def visit_var_def_(self, var: Var) -> Var:
"""Visit the Var definition site.
Users can customized this function to overwrite VisitVarDef_(const VarNode* var)
on the C++ side.
Parameters
----------
var : Var
The Var to be visited.
Returns
-------
result : Var
The var after post-order rewritten.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitVarDef(self._outer(), var) # type: ignore
def visit_dataflow_var_def_(self, var: DataflowVar) -> Var:
"""Visit the DataflowVar definition site.
Users can customized this function to overwrite VisitVarDef_(const DataflowVarNode* var)
on the C++ side.
Parameters
----------
var : DataflowVar
The DataflowVar to be visited.
Returns
-------
result : Var
The var after post-order rewritten.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.ExprMutatorVisitVarDef(self._outer(), var) # type: ignore
def visit_span(self, span: Span) -> Span:
"""Visit Span.
Users can customized this function to overwrite VisitSpan(const Span& span) on the C++ side.
Parameters
----------
span : Span
The Span to be visited.
Returns
-------
result : Span
The span after transformation.
"""
raise NotImplementedError
def visit_expr_post_order(self, expr: Expr) -> Expr:
"""Post-order rewrite an Expr and normalize.
Parameters
----------
expr : Expr
The Expr to be rewritten.
Returns
-------
result : Expr
The Expr after post-order rewritten.
"""
return _ffi_api.PyExprMutatorVisitExprPostOrder(self._outer(), expr) # type: ignore
def set_var_remap(self, old_var: Var, new_var: Var) -> None:
"""Remap a var to a new var in use-site.
Parameters
----------
old_var : Var
The old var.
new_var : Var
The new var.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.PyExprMutatorSetVarRemap( # type: ignore
self._outer(), old_var, new_var
)
def get_var_remap(self, var: Var) -> Var:
"""Remap a var to a new var in use-site.
Parameters
----------
var : Var
The old var.
Returns
-------
var : Var
The remapped var.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.PyExprMutatorGetVarRemap(self._outer(), var) # type: ignore
def visit_with_new_scope(self, expr: Expr) -> Expr:
"""Rewrite the expr with a new scope, used in a Function's body and the branches of If.
Parameters
----------
expr : Expr
The expr to be visited.
Returns
-------
var : Var
The expr after visiting.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.PyExprMutatorVisitWithNewScope(self._outer(), expr) # type: ignore
def lookup_binding(self, var: Var) -> Expr | None:
"""Look up the value bound to a variable.
Note: For function parameters, this function returns std::nullopt.
Parameters
----------
var : Var
The var to be looked up.
Returns
-------
var : Var
The value bound to the input var.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.PyExprMutatorLookupBinding(self._outer(), var) # type: ignore
def with_type(self, var: Var, ty: Type) -> Var:
"""Create a new var with specified shape and type if the original var's shape or type does
not match with the specified ones.
Parameters
----------
var : Var
The var to be updated.
ty : Type
The type.
Returns
-------
var : Var
The var filled with shape and type.
"""
# Using self._outer() to ref _PyExprMutator
return _ffi_api.PyExprMutatorWithType(self._outer(), var, ty) # type: ignore