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

126 lines
4.5 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.
"""Common functionality for legalization."""
from collections.abc import Callable
import tvm
from tvm import te
from tvm.ir import Call
from tvm.runtime import DataTypeCode
from tvm.tirx import FloatImm, IntImm
from ...block_builder import BlockBuilder
from ...expr import Constant, Expr
##################### Types #####################
# The function type of a TE function, which accepts TE Tensors and
# other attributes, and returns the output TE Tensor.
TEFunc = Callable[..., te.Tensor]
# The function type of a legalization function, which takes a
# BlockBuilder and the Call to be legalized, and outputs the legalization
# result Expr.
LegalizeFunc = Callable[[BlockBuilder, Call], Expr]
def _is_relax_expr(expr: object) -> bool:
return isinstance(expr, Expr) and not tvm.ir.is_prim_expr(expr)
def _try_convert_to_scalar_const(
expr: Expr, python_native: bool = False
) -> Expr | FloatImm | IntImm | bool | float | int:
"""Check if the input Expr is a scalar constant.
If it is, return its plain value with the same data type or in native python type.
If it is not, return the input expr.
Note that if the python_native flag is True, the returned value will be in native python type,
this might cause loss of data type for example, a float16 constant will be converted to float32
and a int64 constant will be converted to int32.
Parameters
----------
expr : Expr
The expr to be checked and converted.
Returns
-------
ret : Union[Expr, FloatImm, IntImm, bool, float, int]
Return a FloatImm or IntImm if the given expr is a scalar integer or float constant, and the
python native flag is False. Or return the plain value of the constant in native python type
if the python native flag is True.
Or return the input itself if it is not a scalar constant.
"""
if isinstance(expr, Constant) and expr.ty.ndim == 0:
# get the value of the scalar constant
value = expr.data.numpy()[()].item()
dtype = expr.ty.dtype
dtype_str = str(dtype.dtype)
if python_native:
return value
# preserve the data type of the constant
if dtype.matches_code(DataTypeCode.FLOAT, DataTypeCode.BFLOAT):
return tvm.tirx.FloatImm(dtype_str, value)
elif dtype.matches_code(DataTypeCode.INT, DataTypeCode.UINT, DataTypeCode.BOOL):
return tvm.tirx.IntImm(dtype_str, value)
return expr
def _call_topi_without_attr(te_func: TEFunc, primfunc_name: str | None = None) -> LegalizeFunc:
"""A common wrapper util for the ops who has no attributes and whose
legalization is simply passing its arguments to some TE function.
Parameters
----------
te_func : TEFunc
The input TE function which is to be converted to PrimFunc.
primfunc_name : Optional[str]
The name of the generated PrimFunc.
If it is not specified, the name of `te_func` will be used by default.
Returns
-------
func : LegalizeFunc
The legalization wrapper function, which wraps the input TE function.
"""
if primfunc_name is None:
primfunc_name = te_func.__name__
return lambda bb, call: bb.call_te(te_func, *call.args, primfunc_name_hint=primfunc_name)
##################### Decorators #####################
_LEGALIZE_ATTR_NAME = "FLegalize"
def register_legalize(op_name: str, legal_func: LegalizeFunc = None):
"""Register legal transformation function for a Relax op.
Parameters
----------
op_name : str
The name of the operator
legal_func: function (bb: BlockBuilder, call: Call) -> new_expr: Expr
The function for transforming an expr to another expr.
"""
return tvm.ir.register_op_attr(op_name, _LEGALIZE_ATTR_NAME, legal_func)