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 8680c39c33 [Relax] Handle presence of R.call_tir in
MergeCompositeFunctions (#17220)
8680c39c33 is described below
commit 8680c39c33b41b3ce18d3c6562a89a9b8355bb50
Author: Eric Lunderberg <[email protected]>
AuthorDate: Wed Jul 31 14:16:14 2024 -0500
[Relax] Handle presence of R.call_tir in MergeCompositeFunctions (#17220)
Prior to this commit, use of `R.call_tir` in the input to
`MergeCompositeFunctions` would result in a segfault, when attempting
to determine the `Group*` that contains the `relax::GlobalVar` of the
callee.
This commit updates `MergeCompositeFunctions` to check for
`relax::GlobalVar` and `relax::Tuple` instances.
Closes https://github.com/apache/tvm/issues/17120
---
src/relax/transform/merge_composite_functions.cc | 22 +++-
.../test_transform_merge_composite_functions.py | 119 +++++++++++++++++++++
2 files changed, 138 insertions(+), 3 deletions(-)
diff --git a/src/relax/transform/merge_composite_functions.cc
b/src/relax/transform/merge_composite_functions.cc
index 0dd14f5bb1..0a3c4ff0a1 100644
--- a/src/relax/transform/merge_composite_functions.cc
+++ b/src/relax/transform/merge_composite_functions.cc
@@ -234,19 +234,35 @@ class CompositeGroupsBuilder : public
MemoizedExprTranslator<Group*> {
void UpdateGroupDependencies(Group* group, const Array<Expr>& args) {
Group* group_root = group->FindRoot();
- for (const auto& arg : args) {
- auto arg_group_root = memo_[arg]->FindRoot();
+ std::function<void(Expr)> visit_expr = [&](Expr expr) {
+ if (expr.as<GlobalVarNode>()) return;
+ if (auto tuple = expr.as<TupleNode>()) {
+ for (const auto& field : tuple->fields) {
+ visit_expr(field);
+ }
+ return;
+ }
+
+ ICHECK(memo_.count(expr)) << "Could not find memo-ized group for
expression of type "
+ << expr->GetTypeKey();
+ auto arg_group_root = memo_[expr]->FindRoot();
+
if (arg_group_root == group_root) {
// If arg and the current node are in the same group,
// there is nothing to update.
- continue;
+ return;
}
+
// Add the group of arg as dependency
group_deps_[group_root].insert(arg_group_root);
// Propagate dependencies of arg
for (auto dep : group_deps_[arg_group_root]) {
group_deps_[group_root].insert(dep);
}
+ };
+
+ for (const auto& arg : args) {
+ visit_expr(arg);
}
}
diff --git a/tests/python/relax/test_transform_merge_composite_functions.py
b/tests/python/relax/test_transform_merge_composite_functions.py
index cff832a21f..27537edd9e 100644
--- a/tests/python/relax/test_transform_merge_composite_functions.py
+++ b/tests/python/relax/test_transform_merge_composite_functions.py
@@ -20,6 +20,7 @@ import tvm
from tvm import relax
from tvm.script import relax as R
from tvm.script import ir as I
+from tvm.script import tir as T
@tvm.script.ir_module
@@ -1106,5 +1107,123 @@ def test_reshape():
check(Module, Expected)
+def test_handle_existence_of_call_tir():
+ """MergeCompositeFunctions should accept R.call_tir as input
+
+ No merging is required in this case, since the two composite
+ functions have `R.call_tir` between them. This is a regression
+ test, as previously the `Tuple` used to express of `R.call_tir`
+ caused a segfault.
+
+ """
+
+ @I.ir_module
+ class Before:
+ @R.function
+ def main(A: R.Tensor([10], dtype="float32")) -> R.Tensor([10],
dtype="float32"):
+ cls = Before
+ with R.dataflow():
+ B = cls.fused_relax_nn_relu(A)
+ C = R.call_tir(cls.relu, (B,), out_sinfo=R.Tensor([10],
dtype="float32"))
+ D = cls.fused_relax_nn_gelu(C)
+ R.output(D)
+ return D
+
+ @R.function(private=True)
+ def fused_relax_nn_relu(
+ Input: R.Tensor([10], dtype="float32")
+ ) -> R.Tensor([10], dtype="float32"):
+ R.func_attr({"Composite": "compiler_A.relu", "Primitive": 1})
+ with R.dataflow():
+ Output = R.nn.relu(Input)
+ R.output(Output)
+ return Output
+
+ @T.prim_func(private=True)
+ def relu(
+ Input: T.Buffer(T.int64(10), "float32"),
+ Output: T.Buffer(T.int64(10), "float32"),
+ ):
+ T.func_attr({"tir.noalias": T.bool(True)})
+ for i in range(T.int64(10)):
+ with T.block("compute"):
+ vi = T.axis.remap("S", [i])
+ Output[vi] = T.max(Input[vi], T.float32(0))
+
+ @R.function(private=True)
+ def fused_relax_nn_gelu(
+ Input: R.Tensor([10], dtype="float32")
+ ) -> R.Tensor([10], dtype="float32"):
+ R.func_attr({"Composite": "compiler_A.gelu", "Primitive": 1})
+ with R.dataflow():
+ Output = R.nn.gelu(Input)
+ R.output(Output)
+ return Output
+
+ @I.ir_module
+ class Expected:
+ @R.function
+ def main(A: R.Tensor([10], dtype="float32")) -> R.Tensor([10],
dtype="float32"):
+ cls = Expected
+ with R.dataflow():
+ B = cls.fused_relax_nn_relu1_compiler_A(A)
+ C = R.call_tir(cls.relu, (B,), out_sinfo=R.Tensor([10],
dtype="float32"))
+ D = cls.fused_relax_nn_gelu1_compiler_A(C)
+ R.output(D)
+ return D
+
+ @R.function
+ def fused_relax_nn_relu1_compiler_A(
+ Input: R.Tensor([10], dtype="float32")
+ ) -> R.Tensor([10], dtype="float32"):
+ R.func_attr({"Codegen": "compiler_A"})
+
+ @R.function
+ def composite_lambda(
+ Input: R.Tensor([10], dtype="float32")
+ ) -> R.Tensor([10], dtype="float32"):
+ R.func_attr({"Composite": "compiler_A.relu"})
+ with R.dataflow():
+ Output = R.nn.relu(Input)
+ R.output(Output)
+ return Output
+
+ Output = composite_lambda(Input)
+ return Output
+
+ @T.prim_func(private=True)
+ def relu(
+ Input: T.Buffer(T.int64(10), "float32"),
+ Output: T.Buffer(T.int64(10), "float32"),
+ ):
+ T.func_attr({"tir.noalias": T.bool(True)})
+ for i in range(T.int64(10)):
+ with T.block("compute"):
+ vi = T.axis.remap("S", [i])
+ Output[vi] = T.max(Input[vi], T.float32(0))
+
+ @R.function
+ def fused_relax_nn_gelu1_compiler_A(
+ Input: R.Tensor([10], dtype="float32")
+ ) -> R.Tensor([10], dtype="float32"):
+ R.func_attr({"Codegen": "compiler_A"})
+
+ @R.function
+ def composite_lambda(
+ Input: R.Tensor([10], dtype="float32")
+ ) -> R.Tensor([10], dtype="float32"):
+ R.func_attr({"Composite": "compiler_A.gelu"})
+ with R.dataflow():
+ Output = R.nn.gelu(Input)
+ R.output(Output)
+ return Output
+
+ Output = composite_lambda(Input)
+ return Output
+
+ After = relax.transform.MergeCompositeFunctions()(Before)
+ tvm.ir.assert_structural_equal(Expected, After)
+
+
if __name__ == "__main__":
pytest.main([__file__])