This is an automated email from the ASF dual-hosted git repository.
tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new d0002f3c6a [RELAX] Unify call_tir primitive arguments (#20009)
d0002f3c6a is described below
commit d0002f3c6a63b39477d2c129e805e8267f79c43f
Author: Tianqi Chen <[email protected]>
AuthorDate: Thu Jul 16 05:02:36 2026 +0800
[RELAX] Unify call_tir primitive arguments (#20009)
---
python/tvm/relax/block_builder.py | 12 +-
python/tvm/relax/dpl/pattern.py | 10 +-
python/tvm/relax/frontend/nn/op.py | 23 ++--
python/tvm/relax/op/base.py | 37 ++----
python/tvm/relax/op/distributed/distributed.py | 14 +--
python/tvm/relax/script/builder/distributed/ir.py | 14 +--
python/tvm/relax/script/builder/ir.py | 4 +-
.../tvm/relax/transform/legalize_ops/manipulate.py | 8 +-
python/tvm/relax/utils.py | 18 +--
.../transform/lower_global_view_to_local_view.cc | 24 +++-
src/relax/ir/dataflow_pattern.cc | 6 +-
src/relax/op/distributed/distributed.cc | 17 +--
src/relax/op/op.cc | 133 ++++-----------------
src/relax/script/builder/distributed.cc | 12 +-
src/relax/script/printer/call.cc | 7 +-
src/relax/transform/call_tir_rewrite.cc | 11 +-
src/relax/transform/fold_constant.cc | 3 -
src/relax/transform/fuse_tir.cc | 103 +++++-----------
...ributed_transform_lower_global_to_local_view.py | 4 -
...est_distributed_transform_propagate_sharding.py | 16 +--
tests/python/relax/test_analysis_well_formed.py | 70 +++++++++++
tests/python/relax/test_blockbuilder_emit_te.py | 12 +-
tests/python/relax/test_dataflow_pattern.py | 8 +-
tests/python/relax/test_frontend_nn_op.py | 17 +--
tests/python/relax/test_op_index.py | 9 +-
tests/python/relax/test_transform.py | 36 ++++++
tests/python/relax/test_transform_fold_constant.py | 10 +-
tests/python/relax/test_transform_fuse_tir.py | 75 ++++++++----
.../relax/test_transform_lazy_transform_params.py | 10 +-
.../test_transform_legalize_ops_create_datatype.py | 12 +-
.../test_transform_legalize_ops_distributed.py | 4 +-
..._transform_legalize_ops_index_linear_algebra.py | 4 +-
.../test_transform_legalize_ops_manipulate.py | 4 +-
.../python/relax/test_transform_legalize_ops_nn.py | 4 +-
.../relax/test_transform_lift_transform_params.py | 16 +--
.../test_transform_rewrite_dataflow_reshape.py | 10 +-
tests/python/relax/test_tvmscript_parser.py | 4 +-
tests/python/relax/test_tvmscript_printer_relax.py | 8 +-
38 files changed, 344 insertions(+), 445 deletions(-)
diff --git a/python/tvm/relax/block_builder.py
b/python/tvm/relax/block_builder.py
index 3a2cd4178d..d67c70e0cb 100644
--- a/python/tvm/relax/block_builder.py
+++ b/python/tvm/relax/block_builder.py
@@ -361,13 +361,13 @@ class BlockBuilder(Object):
"""
primfunc_name = kwargs.pop("primfunc_name_hint", None)
- tir_func, call_args, output_ty, tir_vars = gen_call_tir_inputs(func,
*args, **kwargs)
+ tir_func, call_args, output_ty = gen_call_tir_inputs(func, *args,
**kwargs)
if not primfunc_name:
primfunc_name = func.__name__
gvar = self.add_func(tir_func, primfunc_name)
- return call_tir(gvar, call_args, output_ty, tir_vars)
+ return call_tir(gvar, call_args, output_ty)
def call_te_with_grad(
self,
@@ -413,7 +413,7 @@ class BlockBuilder(Object):
"""
primfunc_name = kwargs.pop("primfunc_name_hint", None)
- tir_func, call_args, output_ty, tir_vars = gen_call_tir_inputs(func,
*args, **kwargs)
+ tir_func, call_args, output_ty = gen_call_tir_inputs(func, *args,
**kwargs)
if te_grad_kwargs is None:
te_grad_kwargs = {}
@@ -422,9 +422,7 @@ class BlockBuilder(Object):
primfunc_name = func.__name__
gvar = self.add_func(tir_func, primfunc_name)
- return call_tir_with_grad(
- gvar, call_args, output_ty, te_grad_name, te_grad_kwargs, tir_vars
- )
+ return call_tir_with_grad(gvar, call_args, output_ty, te_grad_name,
te_grad_kwargs)
def emit_te(self, func: Callable, *args: Any, **kwargs: Any) -> Var:
"""Emit a call node according to the te function.
@@ -541,7 +539,7 @@ class BlockBuilder(Object):
def rx_func(x: Tensor((n,), "float32"), y: Tensor(((n + 1),),
"float32"))
-> Tensor(None, "float32", ndim=-1):
# block 0
- gv = relax.call_tir(te_func, (y,), R.Tensor((n + 1,),
"float32"), (n,))
+ gv = relax.call_tir(te_func, (y, n), R.Tensor((n + 1,),
"float32"))
return gv
"""
name_hint = kwargs.pop("name_hint", "")
diff --git a/python/tvm/relax/dpl/pattern.py b/python/tvm/relax/dpl/pattern.py
index 648de6ebf1..caa04bb8f0 100644
--- a/python/tvm/relax/dpl/pattern.py
+++ b/python/tvm/relax/dpl/pattern.py
@@ -864,23 +864,19 @@ def is_shape(shape: list[tvm.ir.Expr]) ->
"PrimArrPattern":
def _is_call_tir(
func_pattern: DFPattern,
args: list | tuple | TuplePattern = None,
- tir_vars: DFPattern | None = None,
) -> CallPattern:
if args is None:
args = wildcard()
elif isinstance(args, list | tuple):
args = TuplePattern(args)
- if tir_vars is None:
- return is_op("relax.call_tir")(func_pattern, args,
add_constraint=False)
- return is_op("relax.call_tir")(func_pattern, args, tir_vars,
add_constraint=False)
+ return is_op("relax.call_tir")(func_pattern, args, add_constraint=False)
# Todo(relax-team): Dataflow pattern for Type, and match out_ty
def is_call_tir(
func_name: str,
args: list | tuple | TuplePattern = None,
- tir_vars: DFPattern | None = None,
) -> CallPattern:
"""
Syntax sugar for creating a CallPattern for call_tir that calls an
function through global var.
@@ -891,15 +887,13 @@ def is_call_tir(
Name of the CPS function to call.
args : Union[List[DFPattern], Tuple[DFPattern]], optional
Arguments in expected call_packed, by default None meaning arbitrary
(number of) arguments
- tir_vars : Optional[DFPattern]
- Pattern to match the tuple of integers that are unpacked when calling
the tirx func.
Returns
-------
CallPattern
The resulting CallPattern
"""
func_pattern = GlobalVarPattern(func_name)
- return _is_call_tir(func_pattern, args, tir_vars)
+ return _is_call_tir(func_pattern, args)
def _is_call_dps_packed(
diff --git a/python/tvm/relax/frontend/nn/op.py
b/python/tvm/relax/frontend/nn/op.py
index a12c96cdbe..13a93097ff 100644
--- a/python/tvm/relax/frontend/nn/op.py
+++ b/python/tvm/relax/frontend/nn/op.py
@@ -2069,15 +2069,17 @@ def tensor_ir_op(
"""
from tvm import relax as rx # pylint: disable=import-outside-toplevel
- call_tir_args, tir_vars = [], []
+ call_tir_args = []
if not isinstance(args, tuple | list):
args = [args]
for arg in args:
if isinstance(arg, Tensor):
call_tir_args.append(arg._expr)
- elif isinstance(arg, rx.ShapeExpr) or tvm.ir.is_prim_expr(arg):
- tir_vars.append(arg)
+ elif isinstance(arg, rx.ShapeExpr):
+ call_tir_args.extend(arg.values)
+ elif tvm.ir.is_prim_expr(arg):
+ call_tir_args.append(arg)
else:
raise TypeError(
"Unsupported type: tensor_ir_op args expect Tensor or
ShapeExpr or Expr,"
@@ -2092,11 +2094,8 @@ def tensor_ir_op(
bb = BlockBuilder.current()
global_var = bb.add_func(func, name_hint)
- if len(tir_vars) == 0:
- tir_vars = None
-
return wrap_nested(
- bb.emit(rx.call_tir(global_var, call_tir_args, out_ty,
tir_vars=tir_vars)),
+ bb.emit(rx.call_tir(global_var, call_tir_args, out_ty)),
name=name_hint,
)
@@ -2139,15 +2138,17 @@ def tensor_ir_inplace_op(
"""
from tvm import relax as rx # pylint: disable=import-outside-toplevel
- call_tir_args, tir_vars = [], []
+ call_tir_args = []
if not isinstance(args, tuple | list):
args = [args]
for arg in args:
if isinstance(arg, Tensor):
call_tir_args.append(arg._expr)
- elif isinstance(arg, rx.ShapeExpr) or tvm.ir.is_prim_expr(arg):
- tir_vars.append(arg)
+ elif isinstance(arg, rx.ShapeExpr):
+ call_tir_args.extend(arg.values)
+ elif tvm.ir.is_prim_expr(arg):
+ call_tir_args.append(arg)
else:
raise TypeError(
"Unsupported type: tensor_ir_inplace_op args expect Tensor or
ShapeExpr or"
@@ -2163,7 +2164,7 @@ def tensor_ir_inplace_op(
global_var = bb.add_func(func, name_hint)
return wrap_nested(
- bb.emit(rx.call_tir_inplace(global_var, call_tir_args,
inplace_indices, out_ty, tir_vars)),
+ bb.emit(rx.call_tir_inplace(global_var, call_tir_args,
inplace_indices, out_ty)),
name=name_hint,
)
diff --git a/python/tvm/relax/op/base.py b/python/tvm/relax/op/base.py
index e1a3d46002..e0e89d49bb 100644
--- a/python/tvm/relax/op/base.py
+++ b/python/tvm/relax/op/base.py
@@ -26,7 +26,7 @@ import tvm.runtime
from tvm.ir import Call
from tvm.runtime import Object, ObjectConvertible
-from ..expr import Expr, ExternFunc, GlobalVar, ShapeExpr, StringImm, Var
+from ..expr import Expr, ExternFunc, GlobalVar, StringImm, Var
from ..type import TensorType, Type
from ..utils import convert_to_expr
from . import _ffi_api
@@ -93,7 +93,6 @@ def call_tir(
gvar: GlobalVar,
args: Expr,
out_ty: TensorType | list[TensorType],
- tir_vars: ShapeExpr | tuple[Expr] | list[Expr] | None = None,
) -> Call:
"""
Call a tirx.prim_func and return the output.
@@ -104,16 +103,14 @@ def call_tir(
The GlobalVar referring to a tirx PrimFunc.
args : Expr
- The input arguments.
+ The ordered tensor and primitive input arguments. These correspond
+ positionally to the leading parameters of the PrimFunc.
out_ty : Union[TensorType, List[TensorType]]
The type information of the call_tir output.
It should be a single or a list of TensorType. Each one denotes the
type information of a returned tensor.
- tir_vars : Optional[Union[ShapeExpr, Tuple[Expr], List[Expr]]]
- ShapeExpr representing a tuple of integers to unpack when calling
func. Is null if not used
-
Returns
-------
ret: Call
@@ -124,10 +121,7 @@ def call_tir(
if not isinstance(out_ty, list):
out_ty = [out_ty]
- if isinstance(tir_vars, list | tuple):
- tir_vars = ShapeExpr(tir_vars)
-
- return _ffi_api.call_tir(gvar, args, out_ty, tir_vars) # type: ignore
+ return _ffi_api.call_tir(gvar, args, out_ty) # type: ignore
def call_tir_with_grad(
@@ -136,7 +130,6 @@ def call_tir_with_grad(
out_ty: TensorType | list[TensorType],
te_grad_name: str,
te_grad_kwargs: dict[str, Object] | None = None,
- tir_vars: ShapeExpr | tuple[Expr] | list[Expr] | None = None,
) -> Call:
"""
Call a tirx.prim_func and return the output. This intrinsic will bind a te
gradient function
@@ -149,7 +142,8 @@ def call_tir_with_grad(
The GlobalVar referring to a tirx PrimFunc.
args : Expr
- The input arguments.
+ The ordered tensor and primitive input arguments. These correspond
+ positionally to the leading parameters of the PrimFunc.
out_ty : Union[TensorType, List[TensorType]]
The type information of the call_tir_with_grad output.
@@ -164,9 +158,6 @@ def call_tir_with_grad(
The keyword arguments passed to the te gradient function.
Optionally provided as a keyword argument. Default: {}.
- tir_vars : Optional[Union[ShapeExpr, Tuple[Expr], List[Expr]]]
- ShapeExpr representing a tuple of integers to unpack when calling
func. Is null if not used
-
Returns
-------
ret: Call
@@ -177,14 +168,11 @@ def call_tir_with_grad(
if not isinstance(out_ty, list):
out_ty = [out_ty]
- if isinstance(tir_vars, list | tuple):
- tir_vars = ShapeExpr(tir_vars)
-
if te_grad_kwargs is None:
te_grad_kwargs = {}
return _ffi_api.call_tir_with_grad( # type: ignore
- gvar, args, out_ty, te_grad_name, te_grad_kwargs, tir_vars
+ gvar, args, out_ty, te_grad_name, te_grad_kwargs
)
@@ -193,7 +181,6 @@ def call_tir_inplace(
args: Expr,
inplace_indices: int | list[int],
out_ty: TensorType | list[TensorType],
- tir_vars: ShapeExpr | tuple[Expr] | list[Expr] | None = None,
) -> Call:
"""
Call a TIR PrimFunc and return the result, doing the specified
computations in-place
@@ -214,7 +201,8 @@ def call_tir_inplace(
The GlobalVar referring to a TIR PrimFunc.
args : Expr
- The input arguments.
+ The ordered tensor and primitive input arguments. These correspond
+ positionally to the leading parameters of the PrimFunc.
inplace_indices : Union[int, List[int]]
Specify which arguments should be used for in-place computations.
@@ -230,9 +218,6 @@ def call_tir_inplace(
Each one denotes the type information of a returned tensor.
If a list of `TensorType` is given, the result will be a tuple of
`TensorType`.
- tir_vars : Optional[Union[ShapeExpr, Tuple[Expr], List[Expr]]]
- ShapeExpr representing a tuple of integers to unpack when calling
func. Is null if not used
-
Returns
-------
ret: Call
@@ -246,15 +231,11 @@ def call_tir_inplace(
if not isinstance(out_ty, list):
out_ty = [out_ty]
- if isinstance(tir_vars, list | tuple):
- tir_vars = ShapeExpr(tir_vars)
-
return _ffi_api.call_tir_inplace( # type: ignore
gvar,
args,
inplace_indices,
out_ty,
- tir_vars,
)
diff --git a/python/tvm/relax/op/distributed/distributed.py
b/python/tvm/relax/op/distributed/distributed.py
index e39b227669..38d79ffc84 100644
--- a/python/tvm/relax/op/distributed/distributed.py
+++ b/python/tvm/relax/op/distributed/distributed.py
@@ -20,7 +20,7 @@
from tvm.ir import Call
from tvm.relax.distributed import DeviceMesh, DTensorType, Placement
-from ...expr import Expr, GlobalVar, ShapeExpr
+from ...expr import Expr, GlobalVar
from ...expr import Tuple as RxTuple
from ...utils import convert_to_expr
from . import _ffi_api
@@ -69,7 +69,6 @@ def call_tir_local_view(
gvar: GlobalVar,
args: Expr,
out_ty: DTensorType | list[DTensorType],
- tir_vars: ShapeExpr | tuple[Expr] | list[Expr] | None = None,
) -> Call:
"""
Call a tirx.prim_func and return the output. The prim_func should be a
worker-local function
@@ -82,16 +81,14 @@ def call_tir_local_view(
The GlobalVar referring to a tirx PrimFunc.
args : Expr
- The input arguments.
+ The ordered distributed-tensor and primitive input arguments. These
+ correspond positionally to the leading parameters of the PrimFunc.
out_ty : Union[DTensorType, List[DTensorType]]
The type information of the call_tir output.
It should be a single or a list of DTensorType. Each one denotes the
type information of a returned tensor.
- tir_vars : Optional[Union[ShapeExpr, Tuple[Expr], List[Expr]]]
- ShapeExpr representing a tuple of integers to unpack when calling
func. Is null if not used
-
Returns
-------
ret: Call
@@ -105,10 +102,7 @@ def call_tir_local_view(
if not isinstance(out_ty, list):
out_ty = [out_ty]
- if isinstance(tir_vars, list | tuple):
- tir_vars = ShapeExpr(tir_vars)
-
- return _ffi_api.call_tir_local_view(gvar, args, out_ty, tir_vars) # type:
ignore
+ return _ffi_api.call_tir_local_view(gvar, args, out_ty) # type: ignore
def redistribute_replica_to_shard(input: Expr, num_workers: int, axis: int) ->
Expr:
diff --git a/python/tvm/relax/script/builder/distributed/ir.py
b/python/tvm/relax/script/builder/distributed/ir.py
index 82d5e9805e..738199ab25 100644
--- a/python/tvm/relax/script/builder/distributed/ir.py
+++ b/python/tvm/relax/script/builder/distributed/ir.py
@@ -28,7 +28,7 @@ import tvm
from tvm import base as _base
from tvm.ir import Call
from tvm.relax.distributed import DeviceMesh, DTensorType, Placement
-from tvm.relax.expr import Constant, Expr, ExternFunc, ShapeExpr
+from tvm.relax.expr import Constant, Expr, ExternFunc
from tvm.relax.expr import Tuple as RxTuple
from tvm.relax.op.distributed import (
annotate_sharding as _annotate_sharding,
@@ -53,7 +53,6 @@ def call_tir(
func: str | Expr,
args: Expr,
out_ty: DTensorType | list[DTensorType],
- tir_vars: ShapeExpr | tuple[Expr] | list[Expr] | None = None,
) -> Call:
"""Distributed version of call_tir
@@ -63,16 +62,14 @@ def call_tir(
The destination-passing-style function, can be ExternFunc or PrimFunc.
args : Expr
- The input arguments.
+ The ordered distributed-tensor and primitive input arguments. These
+ correspond positionally to the leading parameters of the PrimFunc.
out_ty : Union[DTensorType, List[DTensorType]]
The type information of the call_tir output.
It should be a single or a list of DTensorType. Each one denotes the
type information of a returned distributed tensor.
- tir_vars : Optional[Union[ShapeExpr, Tuple[Expr], List[Expr]]]
- ShapeExpr representing a tuple of integers to unpack when calling
func. Is null if not used
-
Returns
-------
ret: Call
@@ -89,10 +86,7 @@ def call_tir(
if not isinstance(out_ty, list):
out_ty = [out_ty]
- if isinstance(tir_vars, list | tuple):
- tir_vars = ShapeExpr(tir_vars)
-
- return _ffi_api.call_tir_dist(func, args, out_ty, tir_vars) # type: ignore
+ return _ffi_api.call_tir_dist(func, args, out_ty) # type: ignore
def const(
diff --git a/python/tvm/relax/script/builder/ir.py
b/python/tvm/relax/script/builder/ir.py
index 0396ebec60..1f19fbb05b 100644
--- a/python/tvm/relax/script/builder/ir.py
+++ b/python/tvm/relax/script/builder/ir.py
@@ -582,11 +582,11 @@ def emit_te(func: Callable, *args: Any, **kwargs: Any) ->
Call:
A newly created call that calls into a tirx function.
"""
primfunc_name_hint = kwargs.pop("primfunc_name_hint", None)
- tir_func, call_args, out_ty, tir_vars = gen_call_tir_inputs(func, *args,
**kwargs)
+ tir_func, call_args, out_ty = gen_call_tir_inputs(func, *args, **kwargs)
if not primfunc_name_hint:
primfunc_name_hint = func.__name__
gvar = decl_function(primfunc_name_hint, tir_func) # type: ignore
- return call_tir(gvar, call_args, out_ty, tir_vars)
+ return call_tir(gvar, call_args, out_ty)
def emit_match_cast(value: Expr, ty: Type) -> Var:
diff --git a/python/tvm/relax/transform/legalize_ops/manipulate.py
b/python/tvm/relax/transform/legalize_ops/manipulate.py
index f94dc67501..ac72f032f9 100644
--- a/python/tvm/relax/transform/legalize_ops/manipulate.py
+++ b/python/tvm/relax/transform/legalize_ops/manipulate.py
@@ -321,7 +321,7 @@ def _layout_transform(bb: BlockBuilder, call: Call) -> Expr:
def te_layout_transform(data, name):
"""
Returns a passthrough TE compute with appropriate name. This is needed
to generate
- TIR function, output shape info, TIR vars from gen_call_tir_inputs
function.
+ TIR function and output shape info from gen_call_tir_inputs function.
"""
return te.compute(
data.shape,
@@ -353,9 +353,7 @@ def _layout_transform(bb: BlockBuilder, call: Call) -> Expr:
primfunc_name += "_with_pad"
if len(axis_separators) != 0:
primfunc_name += "_axis_separator"
- tir_func, call_args, _, tir_vars = gen_call_tir_inputs(
- te_layout_transform, call.args[0], primfunc_name
- )
+ tir_func, call_args, _ = gen_call_tir_inputs(te_layout_transform,
call.args[0], primfunc_name)
# Create TIR schedule to apply layout changes with axis separators
sch = tvm.s_tir.Schedule(tir_func)
sch.transform_layout(primfunc_name, ("write", 0), index_map, pad_value)
@@ -366,4 +364,4 @@ def _layout_transform(bb: BlockBuilder, call: Call) -> Expr:
output_shape = index_map.map_shape(list(call_args[0].ty.shape))
output_dtype = call_args[0].ty.dtype
output_ty = [TensorType(output_shape, output_dtype)]
- return call_tir(gvar, call_args, output_ty, tir_vars)
+ return call_tir(gvar, call_args, output_ty)
diff --git a/python/tvm/relax/utils.py b/python/tvm/relax/utils.py
index a7cc1403a8..78242bd070 100644
--- a/python/tvm/relax/utils.py
+++ b/python/tvm/relax/utils.py
@@ -14,7 +14,7 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-# ruff: noqa: F401, RUF005
+# ruff: noqa: F401
# pylint: disable=invalid-name,too-many-locals
@@ -145,7 +145,7 @@ def copy_with_new_vars(func: Function) -> Function:
def gen_call_tir_inputs(
func: Callable, *args: Any, **kwargs: Any
-) -> tuple[tirx.PrimFunc, Expr, list[TensorType], ShapeExpr | None]:
+) -> tuple[tirx.PrimFunc, Expr, list[TensorType]]:
"""Generate the inputs for call_tir according to the te function.
This function converts arguments from relax expression to te tensor,
The callback func should return a te tensor or a list of te tensors.
@@ -165,9 +165,9 @@ def gen_call_tir_inputs(
Returns
-------
- ret : Tuple[tirx.PrimFunc, Expr, List[TensorType], Optional[ShapeExpr]]
+ ret : Tuple[tirx.PrimFunc, Expr, List[TensorType]]
ret contains the inputs for call_tir, including a tirx prim_func, args,
- out_ty, and tir_vars.
+ and out_ty.
"""
tir_var_map: dict[tvm.ir.Var, tirx.Var] = {}
@@ -350,7 +350,7 @@ def gen_call_tir_inputs(
outs = [te_out] if isinstance(te_out, te_Tensor) else list(te_out)
unbound_tir_vars = _get_unbound_tir_vars([*create_primfunc_args, *outs],
extra_tir_args_list)
- inputs = [*create_primfunc_args] + outs + unbound_tir_vars
+ inputs = [*create_primfunc_args, *unbound_tir_vars, *outs]
tir_func = create_prim_func(inputs, "int64")
if primfunc_attrs:
@@ -374,8 +374,8 @@ def gen_call_tir_inputs(
for out in outs
]
- tir_vars = None
- if len(unbound_tir_vars) > 0:
- tir_vars = _shape_with_old_tir_var(unbound_tir_vars,
tir_var_inverse_map)
+ call_tir_args.extend(
+ tirx.stmt_functor.substitute(value, tir_var_inverse_map) for value in
unbound_tir_vars
+ )
- return (tir_func, call_tir_args, output_ty, tir_vars)
+ return (tir_func, call_tir_args, output_ty)
diff --git a/src/relax/distributed/transform/lower_global_view_to_local_view.cc
b/src/relax/distributed/transform/lower_global_view_to_local_view.cc
index 8c9ca99fb6..aa1c54fd51 100644
--- a/src/relax/distributed/transform/lower_global_view_to_local_view.cc
+++ b/src/relax/distributed/transform/lower_global_view_to_local_view.cc
@@ -401,18 +401,30 @@ class LowerTIRToLocalView : public ExprMutator {
}
std::vector<ShardingSpec> sharding_specs;
ffi::Array<Expr> args = val->args[1].as_or_throw<Tuple>()->fields;
- for (const auto& arg : args) {
- const auto* ty = GetTypeAs<DTensorTypeNode>(arg);
- TVM_FFI_ICHECK(ty);
- sharding_specs.push_back(ShardingSpec(ty->device_mesh, ty->placement));
+ GlobalVar gvar = val->args[0].as_or_throw<GlobalVar>();
+ tirx::PrimFunc prim_func = MatchPrimFunc(builder_->GetContextIRModule(),
gvar).value();
+ TVM_FFI_ICHECK_LE(args.size(), prim_func->params.size());
+ for (size_t i = 0; i < args.size(); ++i) {
+ const Expr& arg = args[i];
+ const tirx::Var& param = prim_func->params[i];
+ if (prim_func->buffer_map.count(param)) {
+ const auto* ty = GetTypeAs<DTensorTypeNode>(arg);
+ TVM_FFI_CHECK(ty, TypeError)
+ << "Expected buffer parameter " << param << " to receive a
distributed tensor, but "
+ << arg << " has type " << GetType(arg);
+ sharding_specs.push_back(ShardingSpec(ty->device_mesh, ty->placement));
+ } else {
+ TVM_FFI_CHECK(arg.as<PrimExpr>(), TypeError)
+ << "Expected scalar parameter " << param
+ << " to receive an individual primitive expression, but " << arg
<< " has type "
+ << GetType(arg);
+ }
}
Var output_var = binding->var;
ffi::Array<DTensorType> output_tys = ExtractDTensorType(output_var);
for (const auto& ty : output_tys) {
sharding_specs.push_back(ShardingSpec(ty->device_mesh, ty->placement));
}
- GlobalVar gvar = val->args[0].as_or_throw<GlobalVar>();
- tirx::PrimFunc prim_func = MatchPrimFunc(builder_->GetContextIRModule(),
gvar).value();
tirx::PrimFunc new_prim_func;
std::string allreduce_kind;
std::tie(new_prim_func, allreduce_kind) =
diff --git a/src/relax/ir/dataflow_pattern.cc b/src/relax/ir/dataflow_pattern.cc
index 7514ffceb2..5f0de5942f 100644
--- a/src/relax/ir/dataflow_pattern.cc
+++ b/src/relax/ir/dataflow_pattern.cc
@@ -650,8 +650,7 @@ ConstantPattern IsConst() { return
ConstantPattern(ffi::make_object<ConstantPatt
WildcardPattern Wildcard() { return
WildcardPattern(ffi::make_object<WildcardPatternNode>()); }
ExprPattern IsExpr(const Expr& expr) { return ExprPattern(expr); }
ExprPattern IsOp(const ffi::String& op_name) { return
IsExpr(Op::Get(op_name)); }
-CallPattern IsCallTIR(const ffi::String& name, ffi::Optional<TuplePattern>
var_args,
- ffi::Optional<DFPattern> tir_vars) {
+CallPattern IsCallTIR(const ffi::String& name, ffi::Optional<TuplePattern>
var_args) {
DFPattern arg_pattern;
if (!var_args.has_value()) {
arg_pattern = Wildcard();
@@ -659,9 +658,6 @@ CallPattern IsCallTIR(const ffi::String& name,
ffi::Optional<TuplePattern> var_a
arg_pattern = var_args.value();
}
- if (tir_vars.has_value()) {
- return IsOp("relax.call_tir")(GlobalVarPattern(name), arg_pattern,
tir_vars.value());
- }
return IsOp("relax.call_tir")(GlobalVarPattern(name), arg_pattern);
}
diff --git a/src/relax/op/distributed/distributed.cc
b/src/relax/op/distributed/distributed.cc
index 51aa1606b1..e2969517e3 100644
--- a/src/relax/op/distributed/distributed.cc
+++ b/src/relax/op/distributed/distributed.cc
@@ -110,17 +110,13 @@ Type InferTypeCallTIRLocalView(const Call& call, const
BlockBuilder& ctx) {
}
TVM_REGISTER_OP("relax.dist.call_tir_local_view")
- .set_num_inputs(3)
+ .set_num_inputs(2)
.add_argument("func", "Expr", "The destination-passing-style function.")
.add_argument("args", "Tuple", "The input arguments.")
- .add_argument("packed_ints", "Expr",
- "ShapeExpr representing a tuple of ints to unpack during
runtime. Omitted from "
- "args if unused")
.set_attr<FInferType>("FInferType", InferTypeCallTIRLocalView)
.set_attr<bool>("FPurity", true);
-Expr MakeCallTIRLocalView(Expr func, Tuple args,
ffi::Array<distributed::DTensorType> out_ty_list,
- ffi::Optional<Expr> packed_ints) {
+Expr MakeCallTIRLocalView(Expr func, Tuple args,
ffi::Array<distributed::DTensorType> out_ty_list) {
for (const distributed::DTensorType& ty : out_ty_list) {
const auto* shape = ty->tensor_ty->shape.as<ShapeExprNode>();
TVM_FFI_ICHECK(shape != nullptr)
@@ -137,14 +133,7 @@ Expr MakeCallTIRLocalView(Expr func, Tuple args,
ffi::Array<distributed::DTensor
}
static const Op& op = Op::Get("relax.dist.call_tir_local_view");
- Call call;
- if (!packed_ints) {
- // don't use additional optional argument
- call = Call(Type::Missing(), op, {func, args}, {}, {out_ty});
- } else {
- call = Call(Type::Missing(), op, {func, args, packed_ints.value()}, {},
{out_ty});
- }
- return call;
+ return Call(Type::Missing(), op, {func, args}, {}, {out_ty});
}
TVM_FFI_STATIC_INIT_BLOCK() {
diff --git a/src/relax/op/op.cc b/src/relax/op/op.cc
index 08a11ef2d6..80de3c8f8e 100644
--- a/src/relax/op/op.cc
+++ b/src/relax/op/op.cc
@@ -274,8 +274,6 @@ TVM_FFI_STATIC_INIT_BLOCK() {
*
* \param func_ty The Type of the TIR callee.
* \param arg_ty The Type of the argument tuple.
- * \param packed_ints_ty The Type of the ffi::Shape argument,
- * if present.
* \param opt_inplace_indices For `R.call_tir_inplace`, an array of
* indices indicating which outputs are constructed from in-place
* mutation of the inputs. See
@@ -285,8 +283,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
* Otherwise, std::nullopt.
*/
static ffi::Optional<Type> InferCallTIROutputTypeFromArguments(
- Type func_ty, Type arg_ty, ffi::Optional<Type> packed_ints_ty,
- ffi::Optional<ffi::Array<int64_t>> opt_inplace_indices) {
+ Type func_ty, Type arg_ty, ffi::Optional<ffi::Array<int64_t>>
opt_inplace_indices) {
auto opt_callee_ty = func_ty.as<FuncType>();
TVM_FFI_CHECK(opt_callee_ty, TypeError)
<< "The first argument to `R.call_tir` must be a function, "
@@ -303,34 +300,18 @@ static ffi::Optional<Type>
InferCallTIROutputTypeFromArguments(
TVM_FFI_CHECK(args, TypeError) << "The second argument to `R.call_tir` must
be a tuple, "
<< "but instead received expression of type "
<< arg_ty;
- // R.call_tir expects the PrimFunc to have three groups of arguments.
+ // R.call_tir expects the PrimFunc to have two groups of arguments.
//
// 1. Input arguments that are explicitly provided as Relax arguments.
// 2. Output tensor arguments.
- // 3. Shape arguments, represented as `T.int64` in the PrimFunc, and
- // as an optional ShapeExpr argument in the `relax::Call` node.
//
// In order to determine the return type of `R.call_tir`, we must
// identify the PrimFunc arguments that will be in group (2).
size_t num_input_arguments = args->fields.size();
- size_t num_trailing_int_arguments = 0;
- const ShapeTypeNode* packed_tuple_ty = nullptr;
- if (packed_ints_ty) {
- auto packed_ty = packed_ints_ty.value();
- packed_tuple_ty = packed_ty.as<ShapeTypeNode>();
- TVM_FFI_CHECK(packed_tuple_ty && !packed_tuple_ty->IsUnknownNdim(),
TypeError)
- << "The third argument to `R.call_tir`, if present, "
- << "must be a ffi::Shape with known dimensionality. "
- << "However, the argument received was of type " << packed_ty;
- num_trailing_int_arguments = packed_tuple_ty->ndim;
- } else {
- num_trailing_int_arguments = 0;
- }
- TVM_FFI_CHECK_LE(num_input_arguments + num_trailing_int_arguments,
callee_params.size(),
- ValueError)
- << "R.call_tir attempted to call a function using " <<
num_input_arguments
- << " input arguments and " << num_trailing_int_arguments << " trailing
integer arguments. "
+ TVM_FFI_CHECK_LE(args->fields.size(), callee_params.size(), ValueError)
+ << "R.call_tir attempted to call a function using " <<
args->fields.size()
+ << " explicit arguments. "
<< "However, the callee only accepts " << callee_params.size() << "
arguments in total.";
// While Relax can specify a distributed tensor, TIR cannot. The
@@ -366,14 +347,7 @@ static ffi::Optional<Type>
InferCallTIROutputTypeFromArguments(
auto dummy_callee_ty = [&]() -> FuncType {
ffi::Array<Type> dummy_params(callee_params.begin(),
callee_params.begin() + num_input_arguments);
-
- for (size_t i = callee_params.size() - num_trailing_int_arguments; i <
callee_params.size();
- i++) {
- dummy_params.push_back(callee_params[i]);
- }
-
- ffi::Array<Type> dummy_ret(callee_params.begin() + num_input_arguments,
- callee_params.end() -
num_trailing_int_arguments);
+ ffi::Array<Type> dummy_ret(callee_params.begin() + num_input_arguments,
callee_params.end());
if (opt_inplace_indices) {
// For R.call_tir_inplace, the `inplace_indices` are used to
@@ -401,24 +375,8 @@ static ffi::Optional<Type>
InferCallTIROutputTypeFromArguments(
return FuncType(dummy_params, dummy_out_ty);
}();
- auto dummy_args = [&]() -> ffi::Array<Expr> {
- ffi::Array<Expr> dummy_args =
- args->fields.Map([](const Type& ty) -> Expr { return
Var("dummy_leading_arg", ty); });
-
- for (size_t i = 0; i < num_trailing_int_arguments; i++) {
- TVM_FFI_ICHECK(packed_tuple_ty);
- PrimType dummy_arg_ty = [&]() {
- if (packed_tuple_ty->values) {
- return PrimType(packed_tuple_ty->values.value()[i].ty());
- } else {
- return PrimType::Int(64);
- }
- }();
- dummy_args.push_back(Var("dummy_trailing_arg", dummy_arg_ty));
- }
-
- return dummy_args;
- }();
+ ffi::Array<Expr> dummy_args =
+ args->fields.Map([](const Type& ty) -> Expr { return Var("dummy_arg",
ty); });
Type derived_ret_ty = DeriveCallRetType(
dummy_callee_ty, Call(Type::Missing(), Var("dummy_callee",
dummy_callee_ty), dummy_args),
@@ -450,9 +408,8 @@ Expr NormalizeCallTIR(const BlockBuilder& ctx, Call call) {
// `relax.call_tir_inplace`. Therefore, all error messages should
// be written in terms of `call->op`, and should not explicitly
// reference the `relax.call_tir` operator.`
- TVM_FFI_ICHECK(call->args.size() == 2 || call->args.size() == 3)
- << "Operation " << call->op << " expects either two arguments [callee,
arg_tuple], "
- << "or three arguments [callee, arg_tuple, tir_args], "
+ TVM_FFI_ICHECK_EQ(call->args.size(), 2)
+ << "Operation " << call->op << " expects two arguments [callee,
arg_tuple], "
<< "but " << call << " has " << call->args.size() << " arguments.";
auto callee = call->args[0];
@@ -472,14 +429,6 @@ Expr NormalizeCallTIR(const BlockBuilder& ctx, Call call) {
<< ", which is neither an in-line tuple, "
<< "nor a variable binding that may be normalized to an in-line tuple.";
- if (call->args.size() > 2) {
- Expr packed_ints = call->args[2];
- TVM_FFI_ICHECK(packed_ints->ty.as<ShapeTypeNode>())
- << "Operation " << call->op << " expects the optional third argument, "
- << "if present, to be a ffi::Shape. "
- << "However, the third argument " << packed_ints << " has type " <<
packed_ints->ty;
- }
-
TVM_FFI_ICHECK_EQ(call->ty_args.size(), 1)
<< "R.call_tir should have exactly one `ty_args` parameter, "
<< "which defines the output of the PrimFunc.";
@@ -542,14 +491,6 @@ void ValidateCallTIR(Call call) {
auto callee = call->args[0];
Expr arg_tuple = call->args[1];
- auto packed_int_ty = [&]() -> ffi::Optional<Type> {
- if (call->args.size() <= 2) {
- return std::nullopt;
- } else {
- return GetType(call->args[2]);
- }
- }();
-
auto opt_inplace_indices = [&]() -> ffi::Optional<ffi::Array<int64_t>> {
if (const auto* attrs = call->attrs.as<CallTIRInplaceAttrs>()) {
return attrs->inplace_indices;
@@ -559,8 +500,8 @@ void ValidateCallTIR(Call call) {
}();
Type explicit_ty = call->ty_args[0];
- auto inferred_ty = InferCallTIROutputTypeFromArguments(GetType(callee),
GetType(arg_tuple),
- packed_int_ty,
opt_inplace_indices);
+ auto inferred_ty =
+ InferCallTIROutputTypeFromArguments(GetType(callee), GetType(arg_tuple),
opt_inplace_indices);
if (inferred_ty.has_value()) {
TVM_FFI_CHECK(IsBaseOf(inferred_ty.value(), explicit_ty), TypeError)
<< "The `out_ty` argument for R.call_tir must be compatible with the
PrimFunc. "
@@ -570,19 +511,15 @@ void ValidateCallTIR(Call call) {
}
TVM_REGISTER_OP("relax.call_tir")
- .set_num_inputs(3)
+ .set_num_inputs(2)
.add_argument("func", "Expr", "The destination-passing-style function.")
.add_argument("args", "Tuple", "The input arguments.")
- .add_argument("packed_ints", "Expr",
- "ShapeExpr representing a tuple of ints to unpack during
runtime. Omitted from "
- "args if unused")
.set_attr<FInferType>("FInferType", InferTypeCallTIR)
.set_attr<FNormalize>("FNormalize", NormalizeCallTIR)
.set_attr<FValidate>("FValidate", ValidateCallTIR)
.set_attr<bool>("FPurity", true);
-Expr MakeCallTIR(Expr func, Tuple args, ffi::Array<TensorType> out_ty_list,
- ffi::Optional<Expr> packed_ints) {
+Expr MakeCallTIR(Expr func, Tuple args, ffi::Array<TensorType> out_ty_list) {
for (const TensorType& ty : out_ty_list) {
const auto* shape = ty->shape.as<ShapeExprNode>();
TVM_FFI_ICHECK(shape != nullptr)
@@ -599,14 +536,7 @@ Expr MakeCallTIR(Expr func, Tuple args,
ffi::Array<TensorType> out_ty_list,
}
static const Op& op = Op::Get("relax.call_tir");
- Call call;
- if (!packed_ints) {
- // don't use additional optional argument
- call = Call(Type::Missing(), op, {func, args}, {}, {out_ty});
- } else {
- call = Call(Type::Missing(), op, {func, args, packed_ints.value()}, {},
{out_ty});
- }
- return call;
+ return Call(Type::Missing(), op, {func, args}, {}, {out_ty});
}
TVM_FFI_STATIC_INIT_BLOCK() {
@@ -617,21 +547,17 @@ TVM_FFI_STATIC_INIT_BLOCK() {
// call_tir_with_grad
TVM_REGISTER_OP("relax.call_tir_with_grad")
- .set_num_inputs(3)
+ .set_num_inputs(2)
.set_attrs_type<CallTIRWithGradAttrs>()
.add_argument("func", "Expr", "The destination-passing-style function.")
.add_argument("args", "Tuple", "The input arguments.")
- .add_argument("packed_ints", "Expr",
- "ShapeExpr representing a tuple of ints to unpack during
runtime. Omitted from "
- "args if unused")
.set_attr<FInferType>("FInferType", InferTypeCallTIR)
.set_attr<FNormalize>("FNormalize", NormalizeCallTIR)
.set_attr<FValidate>("FValidate", ValidateCallTIR)
.set_attr<bool>("FPurity", true);
Expr MakeCallTIRWithGrad(Expr func, Tuple args, ffi::Array<TensorType>
out_ty_list,
- ffi::String te_grad_name, ffi::Map<ffi::String,
ffi::Any> te_grad_kwargs,
- ffi::Optional<Expr> packed_ints) {
+ ffi::String te_grad_name, ffi::Map<ffi::String,
ffi::Any> te_grad_kwargs) {
for (const TensorType& ty : out_ty_list) {
const auto* shape = ty->shape.as<ShapeExprNode>();
TVM_FFI_ICHECK(shape != nullptr)
@@ -652,14 +578,7 @@ Expr MakeCallTIRWithGrad(Expr func, Tuple args,
ffi::Array<TensorType> out_ty_li
attrs->te_grad_kwargs = te_grad_kwargs;
static const Op& op = Op::Get("relax.call_tir_with_grad");
- Call call;
- if (!packed_ints) {
- // don't use additional optional argument
- call = Call(Type::Missing(), op, {func, args}, Attrs(attrs), {out_ty});
- } else {
- call = Call(Type::Missing(), op, {func, args, packed_ints.value()},
Attrs(attrs), {out_ty});
- }
- return call;
+ return Call(Type::Missing(), op, {func, args}, Attrs(attrs), {out_ty});
}
TVM_FFI_STATIC_INIT_BLOCK() {
@@ -757,13 +676,10 @@ Expr NormalizeCallTIRInPlace(const BlockBuilder& ctx,
Call call) {
}
TVM_REGISTER_OP("relax.call_tir_inplace")
- .set_num_inputs(3)
+ .set_num_inputs(2)
.set_attrs_type<CallTIRInplaceAttrs>()
.add_argument("func", "Expr", "The destination-passing-style function.")
.add_argument("args", "Tuple", "The input arguments.")
- .add_argument("packed_ints", "Expr",
- "ShapeExpr representing a tuple of ints to unpack during
runtime. Omitted from "
- "args if unused")
.set_attr<FInferType>("FInferType", InferTypeCallTIR)
.set_attr<FNormalize>("FNormalize", NormalizeCallTIRInPlace)
.set_attr<FValidate>("FValidate", ValidateCallTIR)
@@ -773,7 +689,7 @@ TVM_REGISTER_OP("relax.call_tir_inplace")
.set_attr<bool>("FPurity", true);
Expr MakeCallTIRInplace(Expr func, Tuple args, ffi::Array<int64_t>
inplace_indices,
- ffi::Array<TensorType> out_ty_list,
ffi::Optional<Expr> packed_ints) {
+ ffi::Array<TensorType> out_ty_list) {
for (const TensorType& ty : out_ty_list) {
const auto* shape = ty->shape.as<ShapeExprNode>();
TVM_FFI_ICHECK(shape != nullptr)
@@ -793,14 +709,7 @@ Expr MakeCallTIRInplace(Expr func, Tuple args,
ffi::Array<int64_t> inplace_indic
}
static const Op& op = Op::Get("relax.call_tir_inplace");
- Call call;
- if (!packed_ints) {
- // don't use additional optional argument
- call = Call(Type::Missing(), op, {func, args}, Attrs(attrs), {out_ty});
- } else {
- call = Call(Type::Missing(), op, {func, args, packed_ints.value()},
Attrs(attrs), {out_ty});
- }
- return call;
+ return Call(Type::Missing(), op, {func, args}, Attrs(attrs), {out_ty});
}
TVM_FFI_STATIC_INIT_BLOCK() {
diff --git a/src/relax/script/builder/distributed.cc
b/src/relax/script/builder/distributed.cc
index 496b33606b..dc9440bdee 100644
--- a/src/relax/script/builder/distributed.cc
+++ b/src/relax/script/builder/distributed.cc
@@ -28,8 +28,7 @@
namespace tvm {
namespace relax {
-Expr MakeCallTIRDist(Expr func, Tuple args,
ffi::Array<distributed::DTensorType> out_ty_list,
- ffi::Optional<Expr> packed_ints) {
+Expr MakeCallTIRDist(Expr func, Tuple args,
ffi::Array<distributed::DTensorType> out_ty_list) {
for (const distributed::DTensorType& ty : out_ty_list) {
const auto* shape = ty->tensor_ty->shape.as<ShapeExprNode>();
TVM_FFI_ICHECK(shape != nullptr)
@@ -46,14 +45,7 @@ Expr MakeCallTIRDist(Expr func, Tuple args,
ffi::Array<distributed::DTensorType>
}
static const Op& op = Op::Get("relax.call_tir");
- Call call;
- if (!packed_ints) {
- // don't use additional optional argument
- call = Call(Type::Missing(), op, {func, args}, {}, {out_ty});
- } else {
- call = Call(Type::Missing(), op, {func, args, packed_ints.value()}, {},
{out_ty});
- }
- return call;
+ return Call(Type::Missing(), op, {func, args}, {}, {out_ty});
}
TVM_FFI_STATIC_INIT_BLOCK() {
diff --git a/src/relax/script/printer/call.cc b/src/relax/script/printer/call.cc
index 9b3b41e565..b330fd3c03 100644
--- a/src/relax/script/printer/call.cc
+++ b/src/relax/script/printer/call.cc
@@ -82,7 +82,7 @@ ffi::Optional<ExprDoc> PrintCallTIRDPSPacked(const Call& n,
const AccessPath& n_
!n->op.same_as(call_tir_inplace_op)) {
return std::nullopt;
}
- TVM_FFI_ICHECK(n->args.size() == 2 || n->args.size() == 3);
+ TVM_FFI_ICHECK_EQ(n->args.size(), 2);
TVM_FFI_ICHECK(n->ty_args.size() == 1);
ffi::Array<ExprDoc> args;
ffi::Array<ffi::String> kwargs_keys;
@@ -145,11 +145,6 @@ ffi::Optional<ExprDoc> PrintCallTIRDPSPacked(const Call&
n, const AccessPath& n_
if (n->op.same_as(call_dps_packed_op)) {
return Relax(d, "call_dps_packed")->Call(args, kwargs_keys, kwargs_values);
}
- // Step 4. Print n->args[2], the tirx variables
- if (n->args.size() == 3) {
- kwargs_keys.push_back("tir_vars");
- kwargs_values.push_back(d->AsDoc<ExprDoc>(n->args[2],
n_p->Attr("args")->ArrayItem(2)));
- }
if (n->op.same_as(call_tir_local_view)) {
return Relax(d, "dist.call_tir_local_view")->Call(args, kwargs_keys,
kwargs_values);
} else if (is_dtensor) {
diff --git a/src/relax/transform/call_tir_rewrite.cc
b/src/relax/transform/call_tir_rewrite.cc
index 8c1a16c66a..e1d9a265dc 100644
--- a/src/relax/transform/call_tir_rewrite.cc
+++ b/src/relax/transform/call_tir_rewrite.cc
@@ -68,8 +68,6 @@ class CallTIRMutator : public ExprMutator {
static const Op& call_tir_inplace_op = Op::Get("relax.call_tir_inplace");
static const Op& call_dps_packed_op = Op::Get("relax.call_dps_packed");
static const Op& alloc_tensor_op = Op::Get("relax.builtin.alloc_tensor");
- static const Op& call_tir_dyn_op = Op::Get("relax.vm.call_tir_dyn");
-
if (call->op.same_as(call_tir_op) || call->op.same_as(call_tir_inplace_op)
||
call->op.same_as(call_dps_packed_op)) {
bool is_inplace = call->op.same_as(call_tir_inplace_op);
@@ -157,14 +155,7 @@ class CallTIRMutator : public ExprMutator {
}
}
}
-
- if (call->args.size() == 2) {
- builder_->Emit(Call(Type::Missing(), call->args[0], args), "_");
- } else {
- // unpack semantics
- args.push_back(call->args[2]);
- builder_->Emit(Call(Type::Missing(), call_tir_dyn_op,
{call->args[0], Tuple(args)}), "_");
- }
+ builder_->Emit(Call(Type::Missing(), call->args[0], args), "_");
} else {
if (!is_inplace) {
args = outs;
diff --git a/src/relax/transform/fold_constant.cc
b/src/relax/transform/fold_constant.cc
index 3930cf33a3..274ad7b0a5 100644
--- a/src/relax/transform/fold_constant.cc
+++ b/src/relax/transform/fold_constant.cc
@@ -280,9 +280,6 @@ class ConstantFolder : public ExprMutator {
if (!func || !arr_args) return {};
- // tir_vars are passed as extra scalar arguments to the PrimFunc, which we
cannot supply here.
- if (call->args.size() > 2) return {};
-
// Handle tuple output: ty_args[0] is a TupleType.
if (const auto* tuple_ty = call->ty_args[0].as<TupleTypeNode>()) {
return ConstEvaluateCallTIRTuple(func.value(), arr_args.value(),
tuple_ty);
diff --git a/src/relax/transform/fuse_tir.cc b/src/relax/transform/fuse_tir.cc
index 54f7e5af35..e74584856d 100644
--- a/src/relax/transform/fuse_tir.cc
+++ b/src/relax/transform/fuse_tir.cc
@@ -578,16 +578,9 @@ class FusedTIRConstructor : public ExprVisitor {
func_info_.expr2buffers.Set(relax_param, param_buffers);
}
- // Move all scalar params after buffer params. To ensure that the
- // order is deterministic and predictable for testing purposes,
- // std::stable_sort is used instead of std::sort.
- std::stable_sort(prim_func_params.begin(), prim_func_params.end(),
- [](const auto& a, const auto& b) {
- bool a_is_var = a.template
as<tirx::PrimVar>().has_value();
- bool b_is_var = b.template
as<tirx::PrimVar>().has_value();
- return a_is_var < b_is_var;
- });
-
+ // Preserve the Relax function's parameter order. Tensor and primitive
+ // parameters are both explicit call_tir arguments, while output buffers
+ // are appended after the complete explicit argument prefix.
for (const auto& param : prim_func_params) {
if (auto opt = param.as<tirx::Buffer>()) {
auto buffer = opt.value();
@@ -600,6 +593,8 @@ class FusedTIRConstructor : public ExprVisitor {
tirx::Var param = tirx::Var("p_" + buffer->name,
PointerType::VoidPointerTy());
func_info_.params.push_back(param);
func_info_.buffer_map.Set(param, buffer);
+ } else if (auto var = param.as<tirx::PrimVar>()) {
+ func_info_.params.push_back(var.value());
}
}
@@ -649,14 +644,7 @@ class FusedTIRConstructor : public ExprVisitor {
func_info_.output_buffers.insert(buffers[i].get());
}
- // Step 4. Append symbolic vars
- for (const auto& param : prim_func_params) {
- if (auto var = param.as<tirx::PrimVar>()) {
- func_info_.params.push_back(var.value());
- }
- }
-
- // Step 5. Create PrimFunc
+ // Step 4. Create PrimFunc
fused_tir_ = ConstructFunc();
}
@@ -711,23 +699,6 @@ class FusedTIRConstructor : public ExprVisitor {
AllocateIntermediateBuffer(call, prim_func, output_buffer_shapes);
- // Step 6. Update tir_vars
- if (call->args.size() > 2) {
- TVM_FFI_ICHECK(call->args.size() == 3);
- const Expr& tir_vars = call->args[2];
- if (const auto* shape_expr = tir_vars.as<ShapeExprNode>()) {
- const auto& args = shape_expr->values;
- size_t num_params = prim_func->params.size();
- TVM_FFI_ICHECK_GE(num_params, args.size());
- for (size_t i = 0; i < args.size(); ++i) {
- const tirx::Var& param = prim_func->params[num_params - args.size()
+ i];
- func_info_.symbolic_var_matcher.Match(param.as_or_throw<PrimExpr>(),
args[i]);
- }
- } else {
- TVM_FFI_THROW(InternalError)
- << "TIR vars should be a shape expr, but got: " <<
tir_vars->GetTypeKey();
- }
- }
// Update fused func name
func_info_.global_name += "_" + gv->name_hint;
}
@@ -833,17 +804,23 @@ class FusedTIRConstructor : public ExprVisitor {
void MapInputBuffer(const tirx::PrimFunc& func, const relax::Expr& args) {
ffi::Array<Expr> arg_list;
ffi::Array<tirx::Buffer> buffer_list;
- if (const auto* arg_tuple = args.as<TupleNode>()) {
- arg_list = arg_tuple->fields;
- } else {
- arg_list = {args};
- }
+ ffi::Array<Expr> call_args = args.as_or_throw<Tuple>()->fields;
- TVM_FFI_ICHECK_GE(func->params.size(), arg_list.size());
- for (size_t i = 0; i < arg_list.size(); ++i) {
+ TVM_FFI_ICHECK_GE(func->params.size(), call_args.size());
+ for (size_t i = 0; i < call_args.size(); ++i) {
+ const Expr& arg = call_args[i];
const tirx::Var& param = func->params[i];
- const tirx::Buffer& buffer = func->buffer_map.at(param);
- buffer_list.push_back(buffer);
+ if (func->buffer_map.count(param)) {
+ arg_list.push_back(arg);
+ buffer_list.push_back(func->buffer_map.at(param));
+ } else {
+ auto prim_arg = arg.as<PrimExpr>();
+ TVM_FFI_CHECK(prim_arg.has_value(), TypeError)
+ << "Expected scalar parameter " << param
+ << " to receive an individual primitive expression, but " << arg
<< " has type "
+ << GetType(arg);
+ func_info_.symbolic_var_matcher.Match(param.as_or_throw<PrimExpr>(),
prim_arg.value());
+ }
}
MapArgsToBuffer(arg_list, buffer_list);
@@ -852,7 +829,6 @@ class FusedTIRConstructor : public ExprVisitor {
static ffi::Array<tirx::Var> GetPrimFuncOutputParams(const tirx::PrimFunc&
func,
const
ffi::Array<int64_t>& output_indices) {
size_t n = func->params.size();
- int symbolic_var_index = -1;
size_t output_size = output_indices.size();
TVM_FFI_ICHECK_GE(n, output_size);
@@ -860,24 +836,11 @@ class FusedTIRConstructor : public ExprVisitor {
for (int64_t idx : output_indices) {
int i = static_cast<int>(idx);
const tirx::Var& param = func->params[static_cast<size_t>(i)];
- auto param_ty = param->ty.as<PrimType>();
- if (param_ty && (param_ty.value().code() == DLDataTypeCode::kDLInt ||
- param_ty.value().code() == DLDataTypeCode::kDLUInt)) {
- if (symbolic_var_index == -1) symbolic_var_index = i;
- } else if (param->ty.as<PointerTypeNode>()) {
- TVM_FFI_ICHECK(symbolic_var_index == -1)
- << "The scalar input should be at the ending of the "
- "parameter list.";
- ret.push_back(param);
- } else {
- TVM_FFI_THROW(InternalError)
- << "The params of PrimFunc are expected to be Buffer handle or
scalar, but got: "
- << param->ty;
- }
+ TVM_FFI_ICHECK(param->ty.as<PointerTypeNode>())
+ << "The output params of a PrimFunc must be buffer handles, but
parameter " << i
+ << " has type " << param->ty;
+ ret.push_back(param);
}
-
- size_t end_index = symbolic_var_index == -1 ? n : symbolic_var_index;
- TVM_FFI_ICHECK_GE(end_index, output_size);
return ret;
}
@@ -909,16 +872,16 @@ class FusedTIRConstructor : public ExprVisitor {
}
ffi::Array<tirx::Var> output_params = GetPrimFuncOutputParams(func,
output_idxs);
- auto input_buffers = func_info_.expr2buffers.Get(call->args[1]);
for (size_t i = 0; i < output_size; ++i) {
const tirx::Var& param = output_params[i];
const tirx::Buffer& buffer = func->buffer_map.at(param);
// if this is an inplace output, do not do an intermediate allocation
if (output_idxs[i] < num_inputs) {
- TVM_FFI_ICHECK(input_buffers.has_value())
- << "Inplace functions must have some defined input";
- output_buffers.push_back(input_buffers.value()[output_idxs[i]]);
+ auto it = func_info_.buffer_subst_map.find(buffer);
+ TVM_FFI_ICHECK(it != func_info_.buffer_subst_map.end())
+ << "Inplace output buffer " << buffer << " must be mapped to a
defined input";
+ output_buffers.push_back((*it).second);
continue;
}
@@ -1241,7 +1204,6 @@ class TIRFuseMutator : public ExprMutator {
// are not supported by PrimFunc, so this step verifies that
// ExpandTupleArguments has already removed them.
ffi::Array<Expr> arg_list;
- ffi::Array<PrimExpr> tir_vars;
for (size_t i = 0; i < call->args.size(); ++i) {
auto arg = call->args[i];
auto ty = GetType(arg);
@@ -1260,11 +1222,11 @@ class TIRFuseMutator : public ExprMutator {
for (const PrimExpr& prim_value : shape->values.value()) {
TVM_FFI_ICHECK(prim_value.as<tirx::PrimVar>())
<< "All shape inputs are expected to be single tirx var.";
- tir_vars.push_back(prim_value);
+ arg_list.push_back(prim_value);
}
} else if (ty.as<PrimTypeNode>()) {
if (auto literal = arg.as<PrimExpr>()) {
- tir_vars.push_back(literal.value());
+ arg_list.push_back(literal.value());
} else {
TVM_FFI_THROW(TypeError) << "FuseTIR expects scalar arguments to be
PrimExpr, "
<< "but received " << arg;
@@ -1277,9 +1239,6 @@ class TIRFuseMutator : public ExprMutator {
// Step b. Create call_tir or call_tir_inplace
ffi::Array<Expr> call_args = {fused_tir_gv, Tuple(arg_list)};
- if (!tir_vars.empty()) {
- call_args.push_back(ShapeExpr(tir_vars));
- }
Op call_op = call_tir_op_;
Attrs call_attrs = call->attrs;
if (replacement.inplace_indices.size()) {
diff --git
a/tests/python/relax/distributed/test_distributed_transform_lower_global_to_local_view.py
b/tests/python/relax/distributed/test_distributed_transform_lower_global_to_local_view.py
index a7b9061b57..1cf1f0bb92 100644
---
a/tests/python/relax/distributed/test_distributed_transform_lower_global_to_local_view.py
+++
b/tests/python/relax/distributed/test_distributed_transform_lower_global_to_local_view.py
@@ -715,13 +715,11 @@ def test_llama_attention():
cls.rotary_embedding,
(lv9, cos_cached, sin_cached),
out_ty=R.DTensor((1, 256, 32, 128), "float16", "mesh[0]",
"S[2]"),
- tir_vars=R.shape([256]),
)
lv17 = R.dist.call_tir(
cls.rotary_embedding,
(lv12, cos_cached, sin_cached),
out_ty=R.DTensor((1, 256, 32, 128), "float16", "mesh[0]",
"S[2]"),
- tir_vars=R.shape([256]),
)
lv18 = R.dist.call_tir(
cls.reshape1,
@@ -1406,7 +1404,6 @@ def test_llama_attention():
cls.rotary_embedding1,
(lv9, cos_cached, sin_cached),
out_ty=R.DTensor((1, 256, 32, 128), "float16", "mesh[0]",
"S[2]"),
- tir_vars=R.shape([256]),
)
)
lv17: R.DTensor((1, 256, 32, 128), "float16", "mesh[0]", "S[2]") =
(
@@ -1414,7 +1411,6 @@ def test_llama_attention():
cls.rotary_embedding1,
(lv12, cos_cached, sin_cached),
out_ty=R.DTensor((1, 256, 32, 128), "float16", "mesh[0]",
"S[2]"),
- tir_vars=R.shape([256]),
)
)
lv18: R.DTensor((256, 32, 128), "float16", "mesh[0]", "S[1]") = (
diff --git
a/tests/python/relax/distributed/test_distributed_transform_propagate_sharding.py
b/tests/python/relax/distributed/test_distributed_transform_propagate_sharding.py
index 7f8b1cadcf..bcfe0d34c7 100644
---
a/tests/python/relax/distributed/test_distributed_transform_propagate_sharding.py
+++
b/tests/python/relax/distributed/test_distributed_transform_propagate_sharding.py
@@ -1595,8 +1595,8 @@ def test_decoder_layer_dynamic_shape():
var_A: T.handle,
B: T.Buffer((T.int64(2048), T.int64(128)), "float16"),
C: T.Buffer((T.int64(2048), T.int64(128)), "float16"),
- var_rotary: T.handle,
m: T.int64,
+ var_rotary: T.handle,
):
T.func_attr({"tirx.noalias": True})
n = T.int64()
@@ -1673,15 +1673,13 @@ def test_decoder_layer_dynamic_shape():
)
lv16 = R.call_tir(
cls.rotary_embedding,
- (lv9, cos_cached, sin_cached),
+ (lv9, cos_cached, sin_cached, m),
out_ty=R.Tensor((1, n, 32, 128), dtype="float16"),
- tir_vars=R.shape([m]),
)
lv17 = R.call_tir(
cls.rotary_embedding,
- (lv12, cos_cached, sin_cached),
+ (lv12, cos_cached, sin_cached, m),
out_ty=R.Tensor((1, n, 32, 128), dtype="float16"),
- tir_vars=R.shape([m]),
)
lv18: R.Tensor((n, 32, 128), dtype="float16") = R.reshape(lv17,
R.shape([n, 32, 128]))
lv19: R.Tensor((n, 32, 128), dtype="float16") = R.reshape(lv15,
R.shape([n, 32, 128]))
@@ -1797,8 +1795,8 @@ def test_decoder_layer_dynamic_shape():
var_A: T.handle,
B: T.Buffer((T.int64(2048), T.int64(128)), "float16"),
C: T.Buffer((T.int64(2048), T.int64(128)), "float16"),
- var_rotary: T.handle,
m: T.int64,
+ var_rotary: T.handle,
):
T.func_attr({"tirx.noalias": True})
n = T.int64()
@@ -1868,15 +1866,13 @@ def test_decoder_layer_dynamic_shape():
)
lv16 = R.dist.call_tir(
cls.rotary_embedding,
- (lv9, cos_cached, sin_cached),
+ (lv9, cos_cached, sin_cached, m),
out_ty=R.DTensor((1, n, 32, 128), "float16", "mesh[0]",
"S[2]"),
- tir_vars=R.shape([m]),
)
lv17 = R.dist.call_tir(
cls.rotary_embedding,
- (lv12, cos_cached, sin_cached),
+ (lv12, cos_cached, sin_cached, m),
out_ty=R.DTensor((1, n, 32, 128), "float16", "mesh[0]",
"S[2]"),
- tir_vars=R.shape([m]),
)
lv18: R.DTensor((n, 32, 128), "float16", "mesh[0]", "S[1]") =
R.reshape(
lv17, R.shape([n, 32, 128])
diff --git a/tests/python/relax/test_analysis_well_formed.py
b/tests/python/relax/test_analysis_well_formed.py
index da81d642aa..ed37b367e2 100644
--- a/tests/python/relax/test_analysis_well_formed.py
+++ b/tests/python/relax/test_analysis_well_formed.py
@@ -748,6 +748,76 @@ def test_call_tir_with_matching_arguments():
rx.analysis.well_formed(Module)
+def test_call_tir_with_interspersed_primitive_argument():
+ """Primitive values are positional arguments in the call_tir tuple."""
+
+ @I.ir_module(s_tir=True)
+ class Module:
+ @R.function
+ def main(
+ A: R.Tensor([16], "float16"),
+ scale: R.Prim("float32"),
+ C: R.Tensor([16], "float16"),
+ ):
+ B = R.call_tir(Module.add_scaled, (A, scale, C),
out_ty=R.Tensor([16], "float16"))
+ return B
+
+ @T.prim_func(s_tir=True)
+ def add_scaled(
+ A: T.Buffer([T.int64(16)], "float16"),
+ scale: T.float32,
+ C: T.Buffer([T.int64(16)], "float16"),
+ B: T.Buffer([T.int64(16)], "float16"),
+ ):
+ for i in range(T.int64(16)):
+ B[i] = A[i] + T.Cast("float16", scale) * C[i]
+
+ rx.analysis.well_formed(Module)
+
+
+def test_call_tir_with_incorrect_primitive_argument_dtype():
+ """Primitive call_tir arguments must match the PrimFunc parameter dtype."""
+
+ @I.ir_module(check_well_formed=False, s_tir=True)
+ class Module:
+ @R.function
+ def main(A: R.Tensor([16], "float16"), scale: R.Prim("int64")):
+ B = R.call_tir(Module.scale, (A, scale), out_ty=R.Tensor([16],
"float16"))
+ return B
+
+ @T.prim_func(s_tir=True)
+ def scale(
+ A: T.Buffer([T.int64(16)], "float16"),
+ scale: T.float32,
+ B: T.Buffer([T.int64(16)], "float16"),
+ ):
+ for i in range(T.int64(16)):
+ B[i] = A[i] * T.Cast("float16", scale)
+
+ assert not rx.analysis.check_well_formed(Module)
+
+
+def test_call_tir_shape_expr_is_not_a_primitive_argument():
+ """ShapeExpr groups must be unpacked into positional primitive values."""
+
+ @I.ir_module(check_well_formed=False, s_tir=True)
+ class Module:
+ @R.function
+ def main():
+ B = R.call_tir(
+ Module.make_tensor,
+ (R.shape([1, 2]),),
+ out_ty=R.Tensor([1], "float32"),
+ )
+ return B
+
+ @T.prim_func(s_tir=True)
+ def make_tensor(m: T.int64, n: T.int64, B: T.Buffer([T.int64(1)],
"float32")):
+ B[0] = T.Cast("float32", m + n)
+
+ assert not rx.analysis.check_well_formed(Module)
+
+
def test_call_tir_input_ndim():
"""Arguments to R.call_tir must have the correct dimensionality
diff --git a/tests/python/relax/test_blockbuilder_emit_te.py
b/tests/python/relax/test_blockbuilder_emit_te.py
index 6c7f192373..b7bb6eec94 100644
--- a/tests/python/relax/test_blockbuilder_emit_te.py
+++ b/tests/python/relax/test_blockbuilder_emit_te.py
@@ -47,8 +47,8 @@ def test_emit_te_with_symbolic_arg():
@T.prim_func(private=True, s_tir=True)
def te_func(
A: T.Buffer((T.int64(10),), "float32"),
- B: T.Buffer((T.int64(10),), "float32"),
m: T.int64,
+ B: T.Buffer((T.int64(10),), "float32"),
):
T.func_attr({"tirx.noalias": True})
for i in range(T.int64(10)):
@@ -65,9 +65,8 @@ def test_emit_te_with_symbolic_arg():
cls = Expected
gv = R.call_tir(
cls.te_func,
- (x,),
+ (x, m),
out_ty=R.Tensor((10,), dtype="float32"),
- tir_vars=R.shape([m]),
)
return gv
@@ -75,7 +74,7 @@ def test_emit_te_with_symbolic_arg():
def test_symbolic_shape_in_prim_value():
- """Scalar primitive Vars flow through the optimistic tir_vars path."""
+ """Scalar primitive Vars become ordinary call_tir arguments."""
def te_slice(tensor, i):
return tvm.te.compute([tensor.shape[1]], lambda j: tensor[i, j],
name="slice")
@@ -96,8 +95,8 @@ def test_symbolic_shape_in_prim_value():
@T.prim_func(private=True, s_tir=True)
def te_slice(
A: T.Buffer([T.int64(16), T.int64(16)], "float32"),
- Output: T.Buffer(T.int64(16), "float32"),
row_index: T.int64,
+ Output: T.Buffer(T.int64(16), "float32"),
):
T.func_attr({"tirx.noalias": True})
@@ -115,9 +114,8 @@ def test_symbolic_shape_in_prim_value():
gv = R.call_tir(
cls.te_slice,
- (A,),
+ (A, arg_row_index),
out_ty=R.Tensor([16], "float32"),
- tir_vars=R.shape([arg_row_index]),
)
return gv
diff --git a/tests/python/relax/test_dataflow_pattern.py
b/tests/python/relax/test_dataflow_pattern.py
index c507ea6f46..57b81444a7 100644
--- a/tests/python/relax/test_dataflow_pattern.py
+++ b/tests/python/relax/test_dataflow_pattern.py
@@ -59,7 +59,7 @@ class Module:
B[vi, vj] = T.max(A[vi, vj], 0.0)
@T.prim_func(s_tir=True)
- def tir_zeros(x: T.handle, n: T.int64):
+ def tir_zeros(n: T.int64, x: T.handle):
T.func_attr({"global_symbol": "tir_zeros"})
A = T.match_buffer(x, [n])
for i in range(n):
@@ -73,9 +73,7 @@ class Module:
with R.dataflow():
lv0 = R.call_tir(cls.tir_matmul, (x, w), R.Tensor((32, 32),
dtype="float32"))
lv1 = R.call_tir(cls.tir_relu, (lv0), R.Tensor((32, 32),
dtype="float32"))
- lv2 = R.call_tir(
- cls.tir_zeros, [], R.Tensor((32,), dtype="float32"),
tir_vars=R.ShapeExpr([32])
- )
+ lv2 = R.call_tir(cls.tir_zeros, [32], R.Tensor((32,),
dtype="float32"))
gv = (lv1, lv2)
R.output(gv)
return gv
@@ -305,7 +303,7 @@ def test_is_call_tir():
assert is_call_tir("tir_relu").match(lv1_val)
assert is_call_tir("tir_relu", [is_call_tir("tir_matmul")]).match(lv1_val,
var2val=var2val)
assert not is_call_tir("tir_relu",
[is_call_tir("tir_relu")]).match(lv1_val, var2val=var2val)
- assert is_call_tir("tir_zeros", wildcard(), wildcard()).match(lv2_val,
var2val=var2val)
+ assert is_call_tir("tir_zeros", [wildcard()]).match(lv2_val,
var2val=var2val)
@R.function(pure=False)
diff --git a/tests/python/relax/test_frontend_nn_op.py
b/tests/python/relax/test_frontend_nn_op.py
index 2877ef11c7..ef313b95b5 100644
--- a/tests/python/relax/test_frontend_nn_op.py
+++ b/tests/python/relax/test_frontend_nn_op.py
@@ -638,18 +638,10 @@ def test_tensor_ir_op():
@T.prim_func(private=True, s_tir=True)
def fused_rope( # pylint: disable=too-many-locals
var_qkv: T.handle,
+ offset: T.int64,
var_q: T.handle,
var_k: T.handle,
var_v: T.handle,
- # Scalar arguments must be specified after tensor arguments,
- # including the output tensor arguments
- #
- # TODO(Lunderberg): Update
- # `tvm.relax.frontend.nn.op.tensor_ir_op` to use `Expr`
- # instead of `tir_vars`, so that the order can be consistent
- # between the function definition and the arguments in
- # `op.tensor_ir_op`.
- offset: T.int64,
):
batch_size = T.int64()
seq_len = T.int64()
@@ -677,7 +669,7 @@ def test_tensor_ir_op():
@I.ir_module(s_tir=True)
class Expected:
@T.prim_func(private=True, s_tir=True)
- def llama_fused_rope(var_qkv: T.handle, var_q: T.handle, var_k:
T.handle, var_v: T.handle, offset: T.int64):
+ def llama_fused_rope(var_qkv: T.handle, offset: T.int64, var_q:
T.handle, var_k: T.handle, var_v: T.handle):
batch_size, seq_len = T.int64(), T.int64()
qkv = T.match_buffer(var_qkv, (batch_size, seq_len, 24, 16),
"float16")
q = T.match_buffer(var_q, (batch_size, seq_len, 8, 16), "float16")
@@ -700,7 +692,7 @@ def test_tensor_ir_op():
R.func_attr({"num_input": 3})
cls = Expected
with R.dataflow():
- lv1 = R.call_tir(cls.llama_fused_rope, (qkv,),
out_ty=[R.Tensor((1, 1, 8, 16), dtype="float16"), R.Tensor((1, 1, 8, 16),
dtype="float16"), R.Tensor((1, 1, 8, 16), dtype="float16")],
tir_vars=R.shape([offset_1]))
+ lv1 = R.call_tir(cls.llama_fused_rope, (qkv, offset_1),
out_ty=[R.Tensor((1, 1, 8, 16), dtype="float16"), R.Tensor((1, 1, 8, 16),
dtype="float16"), R.Tensor((1, 1, 8, 16), dtype="float16")])
llama_fused_rope_0: R.Tensor((1, 1, 8, 16), dtype="float16") =
lv1[0]
llama_fused_rope_1: R.Tensor((1, 1, 8, 16), dtype="float16") =
lv1[1]
llama_fused_rope_2: R.Tensor((1, 1, 8, 16), dtype="float16") =
lv1[2]
@@ -798,10 +790,9 @@ def test_tensor_ir_inplace_op():
with R.dataflow():
lv1 = R.call_tir_inplace(
cls.inplace_take,
- (embedding_table, input_ids, embedding_dst),
+ (embedding_table, input_ids, embedding_dst, offset_1),
out_ty=R.Tensor((total_seq_len, hidden_size), dtype),
inplace_indices=[2],
- tir_vars=R.shape([offset_1]),
)
gv1: R.Tensor((total_seq_len, hidden_size), dtype) = lv1
R.output(gv1)
diff --git a/tests/python/relax/test_op_index.py
b/tests/python/relax/test_op_index.py
index c102b0fdc6..f70e542b95 100644
--- a/tests/python/relax/test_op_index.py
+++ b/tests/python/relax/test_op_index.py
@@ -911,16 +911,15 @@ def test_legalize_dynamic_begin_end():
index = T.int64()
return R.call_tir(
expected.strided_slice,
- (A,),
+ (A, index),
out_ty=R.Tensor((1, 16), "float32"),
- tir_vars=R.shape([index]),
)
@T.prim_func(private=True, s_tir=True)
def strided_slice(
A: T.Buffer((T.int64(16), T.int64(16))),
- B: T.Buffer((T.int64(1), T.int64(16))),
index: T.int64,
+ B: T.Buffer((T.int64(1), T.int64(16))),
):
T.func_attr({"tirx.noalias": True})
for iters in T.grid(*B.shape):
@@ -948,7 +947,7 @@ def test_legalize_dynamic_begin_inf_end():
@I.ir_module(s_tir=True)
class expected:
@T.prim_func(private=True, s_tir=True)
- def strided_slice(A: T.Buffer((T.int64(16), T.int64(16)), "float32"),
var_T_dynamic_strided_slice_with_axes: T.handle, index: T.int64):
+ def strided_slice(A: T.Buffer((T.int64(16), T.int64(16)), "float32"),
index: T.int64, var_T_dynamic_strided_slice_with_axes: T.handle):
T.func_attr({"tirx.noalias": True})
T_dynamic_strided_slice_with_axes =
T.match_buffer(var_T_dynamic_strided_slice_with_axes, (T.max(T.int64(16) -
T.max(T.if_then_else(index < T.int64(0), index + T.int64(16), index),
T.int64(0)), T.int64(0)), T.int64(16)))
# with T.sblock("root"):
@@ -963,7 +962,7 @@ def test_legalize_dynamic_begin_inf_end():
def main(A: R.Tensor((16, 16), dtype="float32"), B:
R.Shape(["index"])) -> R.Tensor(("T.max(16 - T.max(T.if_then_else(index < 0,
index + 16, index), 0), 0)", 16), dtype="float32"):
index = T.int64()
cls = expected
- gv = R.call_tir(cls.strided_slice, (A,), out_ty=R.Tensor((T.max(16
- T.max(T.if_then_else(index < 0, index + 16, index), 0), 0), 16),
dtype="float32"), tir_vars=R.shape([index]))
+ gv = R.call_tir(cls.strided_slice, (A, index),
out_ty=R.Tensor((T.max(16 - T.max(T.if_then_else(index < 0, index + 16, index),
0), 0), 16), dtype="float32"))
return gv
# fmt: on
diff --git a/tests/python/relax/test_transform.py
b/tests/python/relax/test_transform.py
index 746ac5d858..d32caa69d5 100644
--- a/tests/python/relax/test_transform.py
+++ b/tests/python/relax/test_transform.py
@@ -178,6 +178,42 @@ def test_call_tir_rewrite():
assert s2.op.name_hint == "exp"
+def test_call_tir_rewrite_with_interspersed_primitive_argument():
+ @I.ir_module(s_tir=True)
+ class Module:
+ @T.prim_func(s_tir=True)
+ def scale_add(
+ A: T.Buffer((16,), "float32"),
+ scale: T.float32,
+ C: T.Buffer((16,), "float32"),
+ B: T.Buffer((16,), "float32"),
+ ):
+ for i in range(16):
+ B[i] = A[i] + scale * C[i]
+
+ @R.function
+ def main(
+ A: R.Tensor((16,), "float32"),
+ scale: R.Prim("float32"),
+ C: R.Tensor((16,), "float32"),
+ ) -> R.Tensor((16,), "float32"):
+ R.func_attr({"relax.force_pure": True})
+ B = R.call_tir(Module.scale_add, (A, scale, C), R.Tensor((16,),
"float32"))
+ return B
+
+ after = relax.transform.CallTIRRewrite()(Module)
+ func = after["main"]
+ bindings = func.body.blocks[0].bindings
+ output_buffer = bindings[0].var
+ call = bindings[1].value
+
+ assert call.op.name_hint == "scale_add"
+ tvm.ir.assert_structural_equal(
+ call.args,
+ [func.params[0], func.params[1], func.params[2], output_buffer],
+ )
+
+
def test_transform_remove_purity_checking():
@tvm.script.ir_module
class Before:
diff --git a/tests/python/relax/test_transform_fold_constant.py
b/tests/python/relax/test_transform_fold_constant.py
index f6720131c0..f580924329 100644
--- a/tests/python/relax/test_transform_fold_constant.py
+++ b/tests/python/relax/test_transform_fold_constant.py
@@ -585,13 +585,13 @@ def test_fold_large_op_with_tensor_input():
tvm.ir.assert_structural_equal(after, expected)
-def test_call_tir_with_tir_vars_not_folded():
- """call_tir with symbolic tir_vars cannot be const-evaluated."""
+def test_call_tir_with_primitive_args_not_folded():
+ """call_tir with symbolic primitive arguments cannot be const-evaluated."""
@tvm.script.ir_module
class Module:
@T.prim_func(private=True, s_tir=True)
- def shape_to_tensor(out: T.Buffer((T.int64(1),), "int64"), m: T.int64):
+ def shape_to_tensor(m: T.int64, out: T.Buffer((T.int64(1),), "int64")):
for i in range(T.int64(1)):
with T.sblock("out"):
vi = T.axis.remap("S", [i])
@@ -601,9 +601,7 @@ def test_call_tir_with_tir_vars_not_folded():
def main(x: R.Tensor(("m",), "float32")):
m = T.int64()
cls = Module
- gv = relax.call_tir(
- cls.shape_to_tensor, R.tuple(), R.Tensor((1,), "int64"),
tir_vars=R.shape([m])
- )
+ gv = relax.call_tir(cls.shape_to_tensor, (m,), R.Tensor((1,),
"int64"))
return gv
after = relax.transform.FoldConstant()(Module)
diff --git a/tests/python/relax/test_transform_fuse_tir.py
b/tests/python/relax/test_transform_fuse_tir.py
index 96aa496e5e..006621e4a4 100644
--- a/tests/python/relax/test_transform_fuse_tir.py
+++ b/tests/python/relax/test_transform_fuse_tir.py
@@ -959,8 +959,8 @@ def test_symbolic_var_in_call_tir_args():
def foo(
X: T.Buffer((T.int64(1), T.int64(1), T.int64(32), T.int64(128)),
"float32"),
Y: T.Buffer((T.int64(2048), T.int64(128)), "float32"),
- rotary: T.Buffer((T.int64(1), T.int64(1), T.int64(32),
T.int64(128)), "float32"),
m: T.int64,
+ rotary: T.Buffer((T.int64(1), T.int64(1), T.int64(32),
T.int64(128)), "float32"),
):
for i0, i1, i2, i3 in T.grid(T.int64(1), T.int64(1), T.int64(32),
T.int64(128)):
with T.sblock("rotary"):
@@ -980,9 +980,8 @@ def test_symbolic_var_in_call_tir_args():
lv1 = R.emit_te(topi.add, x, x)
gv = R.call_tir(
cls.foo,
- [lv1, y],
+ [lv1, y, m],
out_ty=R.Tensor((1, 1, 32, 128), dtype="float32"),
- tir_vars=R.shape([m]),
)
R.output(gv)
return gv
@@ -1005,8 +1004,8 @@ def test_symbolic_var_in_call_tir_args():
def fused(
X: T.Buffer((T.int64(1), T.int64(1), T.int64(32), T.int64(128)),
"float32"),
Y: T.Buffer((T.int64(2048), T.int64(128)), "float32"),
- rotary: T.Buffer((T.int64(1), T.int64(1), T.int64(32),
T.int64(128)), "float32"),
m: T.int64,
+ rotary: T.Buffer((T.int64(1), T.int64(1), T.int64(32),
T.int64(128)), "float32"),
):
T.func_attr({"tirx.noalias": True})
T_add = T.sblock_alloc_buffer((T.int64(1), T.int64(1),
T.int64(32), T.int64(128)))
@@ -1032,9 +1031,8 @@ def test_symbolic_var_in_call_tir_args():
with R.dataflow():
gv = R.call_tir(
cls.fused,
- (x, y),
+ (x, y, m),
out_ty=R.Tensor([1, 1, 32, 128], "float32"),
- tir_vars=R.shape([m]),
)
R.output(gv)
return gv
@@ -1196,8 +1194,8 @@ def test_tir_expression_in_shape():
def fused_transpose_matmul(
x: T.Buffer((T.int64(3), T.int64(4)), "float32"),
p_y: T.handle,
- p_output0: T.handle,
n: T.int64,
+ p_output0: T.handle,
):
T.func_attr({"tirx.noalias": True})
y = T.match_buffer(p_y, (n - T.int64(1), T.int64(4)))
@@ -1228,9 +1226,8 @@ def test_tir_expression_in_shape():
with R.dataflow():
lv = R.call_tir(
cls.fused_transpose_matmul,
- (x, y),
+ (x, y, n),
out_ty=R.Tensor((n - 1, 3), dtype="float32"),
- tir_vars=R.shape([n]),
)
R.output(lv)
return lv
@@ -1466,8 +1463,8 @@ def test_symbolic_var_in_buffer_shape():
def foo(
X_handle: T.handle,
Y: T.Buffer((T.int64(2048), T.int64(128)), "float32"),
- rotary_handle: T.handle,
m: T.int64,
+ rotary_handle: T.handle,
):
sequence_length = T.int64()
@@ -1497,9 +1494,8 @@ def test_symbolic_var_in_buffer_shape():
lv1 = R.emit_te(topi.add, x, x)
gv = R.call_tir(
cls.foo,
- [lv1, y],
+ [lv1, y, m],
out_ty=R.Tensor((1, sequence_length, 32, 128),
dtype="float32"),
- tir_vars=R.shape([m]),
)
R.output(gv)
return gv
@@ -1522,8 +1518,8 @@ def test_symbolic_var_in_buffer_shape():
def fused(
X_handle: T.handle,
Y: T.Buffer((T.int64(2048), T.int64(128)), "float32"),
- rotary_handle: T.handle,
m: T.int64,
+ rotary_handle: T.handle,
):
T.func_attr({"tirx.noalias": True})
@@ -1562,9 +1558,8 @@ def test_symbolic_var_in_buffer_shape():
with R.dataflow():
gv = R.call_tir(
cls.fused,
- (x, y),
+ (x, y, m),
out_ty=R.Tensor([1, sequence_length, 32, 128], "float32"),
- tir_vars=R.shape([m]),
)
R.output(gv)
return gv
@@ -1765,10 +1760,9 @@ def
test_symbolic_var_called_with_multiple_static_shapes():
def test_symbolic_var_called_with_static_argument():
"""A dynamic PrimFunc may accept a static argument
- The `tir_vars` parameter in `R.call_tir` contains definitions for
- all TIR variables explicitly listed in the function signature, and
- contains the TIR expression to be passed as the argument for for
- each parameter.
+ Primitive arguments in `R.call_tir` contain definitions for all TIR
+ variables explicitly listed in the function signature, and contain
+ the TIR expression to be passed for each parameter.
This test is identical to the earlier test named
"test_symbolic_var_called_with_static_shape", except for the
@@ -1780,8 +1774,8 @@ def test_symbolic_var_called_with_static_argument():
@T.prim_func(private=True, s_tir=True)
def sum_1d(
X_handle: T.handle,
- Y: T.Buffer([T.int64(1)], "float32"),
num_elements: T.int64,
+ Y: T.Buffer([T.int64(1)], "float32"),
):
X = T.match_buffer(X_handle, [num_elements], "float32")
@@ -1801,9 +1795,8 @@ def test_symbolic_var_called_with_static_argument():
with R.dataflow():
gv = R.call_tir(
cls.sum_1d,
- [x],
+ [x, 64],
out_ty=R.Tensor([1], dtype="float32"),
- tir_vars=R.shape([64]),
)
R.output(gv)
return gv
@@ -2524,7 +2517,7 @@ def test_primitive_scalar_parameter_preserves_identity():
@I.ir_module(s_tir=True)
class Before:
@T.prim_func(private=True, s_tir=True)
- def add_scalar(x: T.Buffer((4,), "int64"), y: T.Buffer((1,), "int64"),
p: T.int64):
+ def add_scalar(x: T.Buffer((4,), "int64"), p: T.int64, y:
T.Buffer((1,), "int64")):
for i in range(1):
with T.sblock("add"):
vi = T.axis.spatial(1, i)
@@ -2536,9 +2529,8 @@ def test_primitive_scalar_parameter_preserves_identity():
cls = Before
out = R.call_tir(
cls.add_scalar,
- (x,),
+ (x, p),
out_ty=R.Tensor((1,), "int64"),
- tir_vars=R.shape([p]),
)
return out
@@ -2553,5 +2545,38 @@ def test_primitive_scalar_parameter_preserves_identity():
assert tvm.tirx.analysis.verify_well_formed(after["fused"])
+def test_inplace_argument_after_primitive_scalar():
+ @I.ir_module(s_tir=True)
+ class Before:
+ @T.prim_func(private=True, s_tir=True)
+ def add_scalar_inplace(p: T.int64, x: T.Buffer((4,), "int64")):
+ for i in range(4):
+ with T.sblock("add"):
+ vi = T.axis.spatial(4, i)
+ x[vi] = x[vi] + p
+
+ @R.function(private=True)
+ def fused(p: R.Prim("int64"), x: R.Tensor((4,), "int64")) ->
R.Tensor((4,), "int64"):
+ R.func_attr({"Primitive": True})
+ cls = Before
+ out = R.call_tir_inplace(
+ cls.add_scalar_inplace,
+ (p, x),
+ inplace_indices=[1],
+ out_ty=R.Tensor((4,), "int64"),
+ )
+ return out
+
+ @R.function
+ def main(p: R.Prim("int64"), x: R.Tensor((4,), "int64")) ->
R.Tensor((4,), "int64"):
+ cls = Before
+ out = cls.fused(p, x)
+ return out
+
+ after = relax.transform.FuseTIR()(Before)
+ assert relax.analysis.check_well_formed(after)
+ assert tvm.tirx.analysis.verify_well_formed(after["fused"])
+
+
if __name__ == "__main__":
tvm.testing.main()
diff --git a/tests/python/relax/test_transform_lazy_transform_params.py
b/tests/python/relax/test_transform_lazy_transform_params.py
index 0ff259b948..5c1e602cad 100644
--- a/tests/python/relax/test_transform_lazy_transform_params.py
+++ b/tests/python/relax/test_transform_lazy_transform_params.py
@@ -422,8 +422,7 @@ def test_lazy_transform_params_with_symbolic_vars():
param = params[0]
transformed = R.call_tir(
cls.slice_buffer,
- (param,),
- tir_vars=[slice_index],
+ (param, slice_index),
out_ty=R.Tensor((16,), dtype="float32"),
)
output = (transformed,)
@@ -432,8 +431,8 @@ def test_lazy_transform_params_with_symbolic_vars():
@T.prim_func(private=True, s_tir=True)
def slice_buffer(
Input: T.Buffer((16, 16), "float32"),
- Output: T.Buffer(16, "float32"),
slice_index: T.int64,
+ Output: T.Buffer(16, "float32"),
):
for i in T.grid(16):
with T.sblock("slice_buffer"):
@@ -455,8 +454,7 @@ def test_lazy_transform_params_with_symbolic_vars():
param_m: R.Tensor((16, 16), dtype="float32") = gv
transformed = R.call_tir(
cls.slice_buffer,
- (param_m,),
- tir_vars=[slice_index],
+ (param_m, slice_index),
out_ty=R.Tensor((16,), dtype="float32"),
)
unused_1_ = R.vm.kill_object(param_m)
@@ -468,8 +466,8 @@ def test_lazy_transform_params_with_symbolic_vars():
@T.prim_func(private=True, s_tir=True)
def slice_buffer(
Input: T.Buffer((16, 16), "float32"),
- Output: T.Buffer(16, "float32"),
slice_index: T.int64,
+ Output: T.Buffer(16, "float32"),
):
for i in T.grid(16):
with T.sblock("slice_buffer"):
diff --git a/tests/python/relax/test_transform_legalize_ops_create_datatype.py
b/tests/python/relax/test_transform_legalize_ops_create_datatype.py
index 255da3671d..c76726fffd 100644
--- a/tests/python/relax/test_transform_legalize_ops_create_datatype.py
+++ b/tests/python/relax/test_transform_legalize_ops_create_datatype.py
@@ -600,11 +600,11 @@ def test_arange_symbolic():
def main(x: R.Tensor(["n"], "float32")):
cls = Expected
n = T.int64()
- gv = R.call_tir(cls.arange, R.tuple(), out_ty=R.Tensor((n // 2,),
dtype="int64"), tir_vars=R.shape([n]))
+ gv = R.call_tir(cls.arange, (n,), out_ty=R.Tensor((n // 2,),
dtype="int64"))
return gv
@T.prim_func(private=True, s_tir=True)
- def arange(var_T_arange: T.handle, n: T.int64):
+ def arange(n: T.int64, var_T_arange: T.handle):
T.func_attr({"tirx.noalias": True})
T_arange = T.match_buffer(var_T_arange, (n // T.int64(2),),
"int64")
for ax0 in range(n // T.int64(2)):
@@ -665,11 +665,11 @@ def test_shape_to_tensor_symbolic():
n = T.int64()
cls = Expected
gv: R.Shape([m, n]) = R.shape_of(x)
- gv_1 = R.call_tir(cls.shape_to_tensor, R.tuple(),
out_ty=R.Tensor((2,), dtype="int64"), tir_vars=R.shape([m, n]))
+ gv_1 = R.call_tir(cls.shape_to_tensor, (m, n),
out_ty=R.Tensor((2,), dtype="int64"))
return gv_1
@T.prim_func(private=True, s_tir=True)
- def shape_to_tensor(shape_to_tensor: T.Buffer((T.int64(2),), "int64"),
m: T.int64, n: T.int64):
+ def shape_to_tensor(m: T.int64, n: T.int64, shape_to_tensor:
T.Buffer((T.int64(2),), "int64")):
T.func_attr({"tirx.noalias": True})
for i in range(T.int64(2)):
with T.sblock("shape_to_tensor"):
@@ -697,11 +697,11 @@ def test_shape_to_tensor_mixed():
m = T.int64()
cls = Expected
gv: R.Shape([m, 3]) = R.shape_of(x)
- gv_1 = R.call_tir(cls.shape_to_tensor, R.tuple(),
out_ty=R.Tensor((2,), dtype="int64"), tir_vars=R.shape([m]))
+ gv_1 = R.call_tir(cls.shape_to_tensor, (m,), out_ty=R.Tensor((2,),
dtype="int64"))
return gv_1
@T.prim_func(private=True, s_tir=True)
- def shape_to_tensor(shape_to_tensor: T.Buffer((T.int64(2),), "int64"),
m: T.int64):
+ def shape_to_tensor(m: T.int64, shape_to_tensor:
T.Buffer((T.int64(2),), "int64")):
T.func_attr({"tirx.noalias": True})
for i in range(T.int64(2)):
with T.sblock("shape_to_tensor"):
diff --git a/tests/python/relax/test_transform_legalize_ops_distributed.py
b/tests/python/relax/test_transform_legalize_ops_distributed.py
index 83338570c3..2c7deb039b 100644
--- a/tests/python/relax/test_transform_legalize_ops_distributed.py
+++ b/tests/python/relax/test_transform_legalize_ops_distributed.py
@@ -37,7 +37,7 @@ def test_redistribute_replica_to_shard():
@I.ir_module(s_tir=True)
class Expected:
@T.prim_func(private=True, s_tir=True)
- def strided_slice(A: T.Buffer((T.int64(10), T.int64(10)), "float32"),
redistribute_replica_to_shard: T.Buffer((T.int64(10), T.int64(5)), "float32"),
worker_id: T.int64):
+ def strided_slice(A: T.Buffer((T.int64(10), T.int64(10)), "float32"),
worker_id: T.int64, redistribute_replica_to_shard: T.Buffer((T.int64(10),
T.int64(5)), "float32")):
T.func_attr({"tirx.noalias": True})
# with T.sblock("root"):
for i0, i1 in T.grid(T.int64(10), T.int64(5)):
@@ -53,7 +53,7 @@ def test_redistribute_replica_to_shard():
cls = Expected
gv: R.Shape(ndim=-1) =
R.call_pure_packed("runtime.disco.worker_id", ty_args=(R.Shape(ndim=-1),))
gv1: R.Shape([worker_id]) = R.match_cast(gv, R.Shape([worker_id]))
- gv0 = R.call_tir(cls.strided_slice, (x,), out_ty=R.Tensor((10, 5),
dtype="float32"), tir_vars=R.shape([worker_id]))
+ gv0 = R.call_tir(cls.strided_slice, (x, worker_id),
out_ty=R.Tensor((10, 5), dtype="float32"))
return gv0
# fmt: on
diff --git
a/tests/python/relax/test_transform_legalize_ops_index_linear_algebra.py
b/tests/python/relax/test_transform_legalize_ops_index_linear_algebra.py
index 549e4e5d99..a026507ae9 100644
--- a/tests/python/relax/test_transform_legalize_ops_index_linear_algebra.py
+++ b/tests/python/relax/test_transform_legalize_ops_index_linear_algebra.py
@@ -71,11 +71,11 @@ def test_take_prim_value():
class Expected:
@R.function
def main(x: R.Tensor((2, 3, 4), "float32"), index: R.Prim("int64")) ->
R.Tensor((2, 4), "float32"):
- gv = R.call_tir(Expected.take, (x,), R.Tensor((2, 4),
dtype="float32"), tir_vars=R.shape([index]))
+ gv = R.call_tir(Expected.take, (x, index), R.Tensor((2, 4),
dtype="float32"))
return gv
@T.prim_func(private=True, s_tir=True)
- def take(rxplaceholder: T.Buffer((T.int64(2), T.int64(3), T.int64(4)),
"float32"), T_take: T.Buffer((T.int64(2), T.int64(4)), "float32"), index:
T.int64):
+ def take(rxplaceholder: T.Buffer((T.int64(2), T.int64(3), T.int64(4)),
"float32"), index: T.int64, T_take: T.Buffer((T.int64(2), T.int64(4)),
"float32")):
T.func_attr({"tirx.noalias": True})
for i0, i2 in T.grid(T.int64(2), T.int64(4)):
with T.sblock("T_take"):
diff --git a/tests/python/relax/test_transform_legalize_ops_manipulate.py
b/tests/python/relax/test_transform_legalize_ops_manipulate.py
index 7a09fd75da..250e953f64 100644
--- a/tests/python/relax/test_transform_legalize_ops_manipulate.py
+++ b/tests/python/relax/test_transform_legalize_ops_manipulate.py
@@ -881,11 +881,11 @@ def test_split_by_indices_n_section_divisible_symbolic():
def main(dumb_param: R.Tensor(("n",)), x: R.Tensor(("m", "(n * 3)"),
"float32")) -> R.Tuple(R.Tensor(("m", "((n * 3) // 3)"), "float32"),
R.Tensor(("m", "((((n * 3) // 3) * 2) - ((n * 3) // 3))"), "float32"),
R.Tensor(("m", "((n * 3) - (((n * 3) // 3) * 2))"), "float32")):
m = T.int64()
n = T.int64()
- gv = R.call_tir(Expected.split, (x,), [R.Tensor((m, ((n * 3 + 3 -
1) // 3)), "float32"), R.Tensor((m, ((((n * 3 + 3 - 1) // 3) * 2) - ((n * 3 + 3
- 1) // 3))), "float32"), R.Tensor((m, ((n * 3) - (((n * 3 + 3 - 1) // 3) *
2))), "float32")], tir_vars=R.shape([n]))
+ gv = R.call_tir(Expected.split, (x, n), [R.Tensor((m, ((n * 3 + 3
- 1) // 3)), "float32"), R.Tensor((m, ((((n * 3 + 3 - 1) // 3) * 2) - ((n * 3 +
3 - 1) // 3))), "float32"), R.Tensor((m, ((n * 3) - (((n * 3 + 3 - 1) // 3) *
2))), "float32")])
return gv
@T.prim_func(private=True, s_tir=True)
- def split(var_rxplaceholder: T.handle, var_T_split_sections: T.handle,
var_T_split_sections_1: T.handle, var_T_split_sections_2: T.handle, n: T.int64):
+ def split(var_rxplaceholder: T.handle, n: T.int64,
var_T_split_sections: T.handle, var_T_split_sections_1: T.handle,
var_T_split_sections_2: T.handle):
T.func_attr({"tirx.noalias": True})
m = T.int64()
rxplaceholder = T.match_buffer(var_rxplaceholder, [m, n *
T.int64(3)], dtype="float32")
diff --git a/tests/python/relax/test_transform_legalize_ops_nn.py
b/tests/python/relax/test_transform_legalize_ops_nn.py
index 058a4e6081..c70ea1b670 100644
--- a/tests/python/relax/test_transform_legalize_ops_nn.py
+++ b/tests/python/relax/test_transform_legalize_ops_nn.py
@@ -3186,7 +3186,7 @@ def test_group_norm_symbolic():
@tvm.script.ir_module
class Expected:
@T.prim_func(private=True, s_tir=True)
- def group_norm(var_rxplaceholder: T.handle, var_rxplaceholder_1:
T.handle, var_rxplaceholder_2: T.handle, var_T_reshape: T.handle, c: T.int64):
+ def group_norm(var_rxplaceholder: T.handle, var_rxplaceholder_1:
T.handle, var_rxplaceholder_2: T.handle, c: T.int64, var_T_reshape: T.handle):
T.func_attr({"tirx.noalias": True})
n = T.int64()
h = T.int64()
@@ -3251,7 +3251,7 @@ def test_group_norm_symbolic():
c = T.int64()
h = T.int64()
w = T.int64()
- gv = R.call_tir(Expected.group_norm, (x, gamma, beta),
out_ty=R.Tensor((n, 4 * c, h, w), dtype="float32"), tir_vars=R.shape([c]))
+ gv = R.call_tir(Expected.group_norm, (x, gamma, beta, c),
out_ty=R.Tensor((n, 4 * c, h, w), dtype="float32"))
return gv
# fmt: on
mod = LegalizeOps()(GroupNorm)
diff --git a/tests/python/relax/test_transform_lift_transform_params.py
b/tests/python/relax/test_transform_lift_transform_params.py
index 40fefd26a8..37b3516b60 100644
--- a/tests/python/relax/test_transform_lift_transform_params.py
+++ b/tests/python/relax/test_transform_lift_transform_params.py
@@ -1505,14 +1505,12 @@ def test_symbolic_var_from_shape():
with R.dataflow():
B_slice = R.call_tir(
cls.slice,
- [B],
- tir_vars=R.ShapeExpr([slice_index]),
+ [B, slice_index],
out_ty=R.Tensor([16], dtype="int32"),
)
A_slice = R.call_tir(
cls.slice,
- [A],
- tir_vars=R.ShapeExpr([slice_index]),
+ [A, slice_index],
out_ty=R.Tensor([16], dtype="int32"),
)
A_scale = R.multiply(A_slice, B_slice)
@@ -1522,8 +1520,8 @@ def test_symbolic_var_from_shape():
@T.prim_func(private=True, s_tir=True)
def slice(
Input_2d: T.Buffer(shape=[16, 16], dtype="int32"),
- Output_Slice: T.Buffer(shape=[16], dtype="int32"),
slice_index: T.int64,
+ Output_Slice: T.Buffer(shape=[16], dtype="int32"),
):
T.func_attr({"tirx.noalias": True})
for j in range(16):
@@ -1545,8 +1543,7 @@ def test_symbolic_var_from_shape():
with R.dataflow():
A_slice = R.call_tir(
cls.slice,
- [A],
- tir_vars=R.ShapeExpr([slice_index]),
+ [A, slice_index],
out_ty=R.Tensor([16], dtype="int32"),
)
A_scale = R.multiply(A_slice, B_slice)
@@ -1565,8 +1562,7 @@ def test_symbolic_var_from_shape():
# extra_symbolic_vars = params[1]
B_slice = R.call_tir(
cls.slice,
- [B],
- tir_vars=R.ShapeExpr([slice_index]),
+ [B, slice_index],
out_ty=R.Tensor([16], dtype="int32"),
)
output = (R.ShapeExpr([slice_index]), B_slice)
@@ -1576,8 +1572,8 @@ def test_symbolic_var_from_shape():
@T.prim_func(private=True, s_tir=True)
def slice(
Input_2d: T.Buffer(shape=[16, 16], dtype="int32"),
- Output_Slice: T.Buffer(shape=[16], dtype="int32"),
slice_index: T.int64,
+ Output_Slice: T.Buffer(shape=[16], dtype="int32"),
):
T.func_attr({"tirx.noalias": True})
for j in range(16):
diff --git a/tests/python/relax/test_transform_rewrite_dataflow_reshape.py
b/tests/python/relax/test_transform_rewrite_dataflow_reshape.py
index ef9ef115b1..bbe22389ac 100644
--- a/tests/python/relax/test_transform_rewrite_dataflow_reshape.py
+++ b/tests/python/relax/test_transform_rewrite_dataflow_reshape.py
@@ -659,8 +659,7 @@ def test_rewrite_static_reshape():
# y = R.reshape(x, R.shape([N // 4, 4]))
# z = R.call_tir(
# cls.add,
-# (y, y),
-# tir_vars=[N],
+# (y, y, N),
# out_ty=R.Tensor((N // 4, 4), dtype="float32"),
# )
# R.output(z)
@@ -670,8 +669,8 @@ def test_rewrite_static_reshape():
# def add(
# y1_handle: T.handle,
# y2_handle: T.handle,
-# z_handle: T.handle,
# N: T.int64,
+# z_handle: T.handle,
# ):
# y1 = T.match_buffer(y1_handle, [N // 4, 4], "float32")
@@ -724,8 +723,7 @@ def test_rewrite_dynamic_reshape():
y = R.reshape(x, R.shape([N * 4, T.int64(4)]))
z = R.call_tir(
cls.add,
- (y, y),
- tir_vars=[N],
+ (y, y, N),
out_ty=R.Tensor((N * 4, 4), dtype="float32"),
)
R.output(z)
@@ -735,8 +733,8 @@ def test_rewrite_dynamic_reshape():
def add(
y1_handle: T.handle,
y2_handle: T.handle,
- z_handle: T.handle,
N: T.int64,
+ z_handle: T.handle,
):
y1 = T.match_buffer(y1_handle, [N * 4, T.int64(4)], "float32")
y2 = T.match_buffer(y2_handle, [N * 4, T.int64(4)], "float32")
diff --git a/tests/python/relax/test_tvmscript_parser.py
b/tests/python/relax/test_tvmscript_parser.py
index 50628970e7..b91a1e4544 100644
--- a/tests/python/relax/test_tvmscript_parser.py
+++ b/tests/python/relax/test_tvmscript_parser.py
@@ -982,11 +982,11 @@ def test_call_tir_with_tir_var():
) -> R.Tensor(("n * 2",), "float32"):
n = T.int64()
cls = Module
- y = R.call_tir(cls.copy, x, R.Tensor((n * 2,), dtype="float32"),
tir_vars=(n,))
+ y = R.call_tir(cls.copy, (x, n), R.Tensor((n * 2,),
dtype="float32"))
return y
@T.prim_func(s_tir=True)
- def copy(var_x: T.handle, var_y: T.handle, n: T.int64):
+ def copy(var_x: T.handle, n: T.int64, var_y: T.handle):
X = T.match_buffer(var_x, (n * 2,), dtype="float32")
Y = T.match_buffer(var_y, (n * 2,), dtype="float32")
for i in T.grid(n * 2):
diff --git a/tests/python/relax/test_tvmscript_printer_relax.py
b/tests/python/relax/test_tvmscript_printer_relax.py
index c47d9847b0..f2aeaf9b1a 100644
--- a/tests/python/relax/test_tvmscript_printer_relax.py
+++ b/tests/python/relax/test_tvmscript_printer_relax.py
@@ -485,14 +485,14 @@ def test_shape_expr():
def test_call():
x = tirx.Var("x", "int64")
a = relax.Var("a", relax.TensorType([1, x, 3], "float32"))
- o0 = relax.call_tir(relax.GlobalVar("tir_func"), args=a, out_ty=a.ty,
tir_vars=[x])
+ o0 = relax.call_tir(relax.GlobalVar("tir_func"), args=(a, x), out_ty=a.ty)
o1 = relax.call_dps_packed("my_dps_func", args=a, out_ty=a.ty)
_assert_print(
o0,
"""
x = T.int64()
a: R.Tensor((1, x, 3), dtype="float32")
-R.call_tir(tir_func, (a,), out_ty=R.Tensor((1, x, 3), dtype="float32"),
tir_vars=R.shape([x]))
+R.call_tir(tir_func, (a, x), out_ty=R.Tensor((1, x, 3), dtype="float32"))
""",
)
_assert_print(
@@ -535,10 +535,10 @@ def test_call_tir_inplace():
(
x,
y,
+ t,
),
inplace_indices=[-1, 0],
out_ty=[R.Tensor((32, 32), dtype="int32"), R.Tensor((32, 32),
dtype="int32")],
- tir_vars=[t],
)
_assert_print(
call,
@@ -546,7 +546,7 @@ def test_call_tir_inplace():
x: R.Tensor((32, 32), dtype="int32")
y: R.Tensor((32, 32), dtype="int32")
t = T.int64()
-R.call_tir_inplace(tir_func, (x, y), out_ty=[R.Tensor((32, 32),
dtype="int32"), R.Tensor((32, 32), dtype="int32")], inplace_indices=[-1, 0],
tir_vars=R.shape([t]))
+R.call_tir_inplace(tir_func, (x, y, t), out_ty=[R.Tensor((32, 32),
dtype="int32"), R.Tensor((32, 32), dtype="int32")], inplace_indices=[-1, 0])
""",
)