This is an automated email from the ASF dual-hosted git repository.
csullivan 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 0c09547c76 [TIR][CodeGen] Define PackedFunc error code in
MakePackedAPI (#15076)
0c09547c76 is described below
commit 0c09547c7610bd1bfde3e53d1ac87baad11b6026
Author: Eric Lunderberg <[email protected]>
AuthorDate: Thu Jun 15 14:50:51 2023 -0400
[TIR][CodeGen] Define PackedFunc error code in MakePackedAPI (#15076)
* [TIR][CodeGen] Define PackedFunc error code in MakePackedAPI
Previously, the return value of a PackedFunc was hard-coded as the
string `"return 0;"` in `CodeGenCHost`, which could cause compilation
errors for `PrimFunc` returning `DataType::Void()`. This PR removes
this explicit return statement from `CodeGenCHost`, replacing it with
`tir::ret(Integer(0))` in the `MakePackedAPI` and `MakeUnpackedAPI`
transforms.
This is related to https://github.com/apache/tvm/pull/15073, which
performs an analogous change for the function signature.
* Handle builtin::ret() in CodeGenC
* Place T.ret(0) inside asserts, rather than outside
This causes fewer unit tests to break, and has more readable
TVMScript.
* Update unit tests to look inside SeqStmt
* Handle T.ret(0) in CodeGenStackVM
* Update MakeUnpackedAPI tests to expect T.ret
---
src/target/source/codegen_c.cc | 6 +++---
src/target/source/codegen_c.h | 4 ----
src/target/source/codegen_c_host.cc | 5 -----
src/target/source/codegen_c_host.h | 1 -
src/target/stackvm/codegen_stackvm.cc | 6 ++++++
src/tir/transforms/make_packed_api.cc | 9 +++++++--
src/tir/transforms/make_unpacked_api.cc | 4 +++-
.../unittest/test_tir_transform_lower_tvm_builtin.py | 9 +++++++--
.../python/unittest/test_tir_transform_make_packed_api.py | 15 ++++++++++++---
.../unittest/test_tir_transform_make_unpacked_api.py | 6 ++++++
10 files changed, 44 insertions(+), 21 deletions(-)
diff --git a/src/target/source/codegen_c.cc b/src/target/source/codegen_c.cc
index bcdd0bfea0..a7cc320562 100644
--- a/src/target/source/codegen_c.cc
+++ b/src/target/source/codegen_c.cc
@@ -123,7 +123,6 @@ void CodeGenC::AddFunction(const PrimFunc& f) {
this->PreFunctionBody(f);
int func_scope = this->BeginScope();
this->PrintStmt(f->body);
- this->PrintFinalReturn();
this->EndScope(func_scope);
this->PrintIndent();
this->stream << "}\n\n";
@@ -133,8 +132,6 @@ void CodeGenC::PrintFuncPrefix(std::ostream& os) {}
void CodeGenC::PrintExtraAttrs(const PrimFunc& f) {}
-void CodeGenC::PrintFinalReturn() {}
-
std::string CodeGenC::Finish() { return decl_stream.str() + stream.str(); }
void CodeGenC::PrintExpr(const PrimExpr& n, std::ostream& os) { // NOLINT(*)
@@ -538,6 +535,9 @@ void CodeGenC::VisitExpr_(const CallNode* op, std::ostream&
os) { // NOLINT(*)
PrintExpr(op->args[0], os);
os << " ) return ";
PrintExpr(op->args[1], os);
+ } else if (op->op.same_as(builtin::ret())) {
+ os << "return ";
+ PrintExpr(op->args[0], os);
} else if (op->op.same_as(builtin_call_extern_) ||
op->op.same_as(builtin_call_pure_extern_)) {
ICHECK_GE(op->args.size(), 1U);
auto func = Downcast<StringImm>(op->args[0]);
diff --git a/src/target/source/codegen_c.h b/src/target/source/codegen_c.h
index de9c2f1745..93f9ea519c 100644
--- a/src/target/source/codegen_c.h
+++ b/src/target/source/codegen_c.h
@@ -110,10 +110,6 @@ class CodeGenC : public ExprFunctor<void(const PrimExpr&,
std::ostream&)>,
* Example: __launch_bounds__(256) for CUDA functions
*/
virtual void PrintExtraAttrs(const PrimFunc& f);
- /*!
- * \brief Print the final return at the end the function.
- */
- virtual void PrintFinalReturn(); // NOLINT(*)
/*!
* \brief Insert statement before function body.
* \param f The function to be compiled.
diff --git a/src/target/source/codegen_c_host.cc
b/src/target/source/codegen_c_host.cc
index e98852c270..3255e11c5d 100644
--- a/src/target/source/codegen_c_host.cc
+++ b/src/target/source/codegen_c_host.cc
@@ -128,11 +128,6 @@ void CodeGenCHost::PrintFuncPrefix(std::ostream& os) { //
NOLINT(*)
<< "TVM_DLL ";
}
-void CodeGenCHost::PrintFinalReturn() { // NOLINT(*)
- this->PrintIndent();
- stream << "return 0;\n";
-}
-
std::string CodeGenCHost::Finish() { // NOLINT(*)
std::string ret = decl_stream.str();
if (emit_fwd_func_decl_) {
diff --git a/src/target/source/codegen_c_host.h
b/src/target/source/codegen_c_host.h
index 9c71f197f0..c4db634705 100644
--- a/src/target/source/codegen_c_host.h
+++ b/src/target/source/codegen_c_host.h
@@ -58,7 +58,6 @@ class CodeGenCHost : public CodeGenC {
using CodeGenC::PrintType;
void PrintType(DataType t, std::ostream& os) final; // NOLINT(*)
void PrintFuncPrefix(std::ostream& os) final; // NOLINT(*)
- void PrintFinalReturn() final; // NOLINT(*)
// overload visitor functions
void VisitExpr_(const BroadcastNode* op, std::ostream& os) final; //
NOLINT(*)
diff --git a/src/target/stackvm/codegen_stackvm.cc
b/src/target/stackvm/codegen_stackvm.cc
index db6e32d65f..fa2cd6b09d 100644
--- a/src/target/stackvm/codegen_stackvm.cc
+++ b/src/target/stackvm/codegen_stackvm.cc
@@ -284,6 +284,12 @@ void CodeGenStackVM::VisitExpr_(const CallNode* op) {
this->Push(op->args[0]);
this->PushOp(StackVM::PUSH_I64, 0);
this->PushOp(StackVM::EQ_HANDLE);
+ } else if (op->op.same_as(builtin::ret())) {
+ CHECK(op->args.size() == 1 && op->args[0]->IsInstance<IntImmNode>() &&
+ op->args[0].as<IntImmNode>()->value == 0)
+ << "StackVM does not support return values, "
+ << "and the return value " << op->args
+ << " is not special case of returning an error code of zero.";
} else {
LOG(FATAL) << "unknown function call " << op->op;
}
diff --git a/src/tir/transforms/make_packed_api.cc
b/src/tir/transforms/make_packed_api.cc
index a6673a19ad..e387204045 100644
--- a/src/tir/transforms/make_packed_api.cc
+++ b/src/tir/transforms/make_packed_api.cc
@@ -353,11 +353,16 @@ PrimFunc MakePackedAPI(PrimFunc func) {
}
}
+ // Return error code of zero on success
+ body = SeqStmt({body, Evaluate(ret(Integer(0)))});
+
+ // Apply all argument assertions
std::ostringstream num_args_error;
num_args_error << name_hint << ": num_args should be " << num_args;
std::vector<Stmt> arg_assert = {MakeAssertEQ(v_num_packed_args, num_args,
num_args_error.str())};
- func_ptr->body =
- MergeNest({arg_assert, seq_init, binder.init_nest(), seq_check,
binder.asserts()}, body);
+ body = MergeNest({arg_assert, seq_init, binder.init_nest(), seq_check,
binder.asserts()}, body);
+
+ func_ptr->body = body;
func_ptr->params = args;
Array<Var> undefined = UndefinedVars(func_ptr->body, func_ptr->params);
diff --git a/src/tir/transforms/make_unpacked_api.cc
b/src/tir/transforms/make_unpacked_api.cc
index 4b1b3bf517..2646b5baea 100644
--- a/src/tir/transforms/make_unpacked_api.cc
+++ b/src/tir/transforms/make_unpacked_api.cc
@@ -147,7 +147,9 @@ PrimFunc MakeUnpackedAPI(PrimFunc func) {
device_init.push_back(AttrStmt(node, attr::device_type, device_type, nop));
}
- func_ptr->body = MergeNest(device_init, func_ptr->body);
+ Stmt body = MergeNest(device_init, SeqStmt({func_ptr->body,
Evaluate(ret(Integer(0)))}));
+
+ func_ptr->body = body;
func_ptr->params = args;
func_ptr->ret_type = PrimType(DataType::Int(32));
func_ptr->buffer_map = Map<Var, Buffer>();
diff --git a/tests/python/unittest/test_tir_transform_lower_tvm_builtin.py
b/tests/python/unittest/test_tir_transform_lower_tvm_builtin.py
index 2e0784cc31..6eac5e90b5 100644
--- a/tests/python/unittest/test_tir_transform_lower_tvm_builtin.py
+++ b/tests/python/unittest/test_tir_transform_lower_tvm_builtin.py
@@ -70,8 +70,13 @@ def check_packed_func(target="llvm"):
node = prim_func.body
# Recursively visit PrimFunc until we meet the for-loop:
- while isinstance(node, (tvm.tir.AssertStmt, tvm.tir.LetStmt,
tvm.tir.AttrStmt)):
- node = node.body
+ while True:
+ if isinstance(node, (tvm.tir.AssertStmt, tvm.tir.LetStmt,
tvm.tir.AttrStmt)):
+ node = node.body
+ elif isinstance(node, tvm.tir.SeqStmt):
+ node = node[0]
+ else:
+ break
# For-loop:
assert isinstance(node, tvm.tir.stmt.For)
diff --git a/tests/python/unittest/test_tir_transform_make_packed_api.py
b/tests/python/unittest/test_tir_transform_make_packed_api.py
index 34adcbb9ae..6f84b6f6d4 100644
--- a/tests/python/unittest/test_tir_transform_make_packed_api.py
+++ b/tests/python/unittest/test_tir_transform_make_packed_api.py
@@ -60,9 +60,18 @@ def _find_assignment(stmt, var_name):
def _find_next(stmt, type):
- while not isinstance(stmt, type):
- stmt = stmt.body
- return stmt
+ search_stack = [stmt]
+
+ while search_stack:
+ stmt = search_stack.pop()
+ if isinstance(stmt, type):
+ return stmt
+ elif isinstance(stmt, tvm.tir.SeqStmt):
+ search_stack.extend(reversed(stmt))
+ else:
+ search_stack.append(stmt.body)
+
+ return None
def _find_compute_scope(func):
diff --git a/tests/python/unittest/test_tir_transform_make_unpacked_api.py
b/tests/python/unittest/test_tir_transform_make_unpacked_api.py
index 1931f7aef3..868d30db36 100644
--- a/tests/python/unittest/test_tir_transform_make_unpacked_api.py
+++ b/tests/python/unittest/test_tir_transform_make_unpacked_api.py
@@ -172,6 +172,7 @@ class TestTargetHostRemoved(tvm.testing.CompareBeforeAfter):
T.attr("default", "device_id", 0)
T.attr("default", "device_type", 2)
mod.subroutine(A_data)
+ T.ret(T.int32(0))
@T.prim_func
def subroutine(A_data: T.handle("float32")):
@@ -215,6 +216,7 @@ class
TestInternalSubroutineCall(tvm.testing.CompareBeforeAfter):
T.attr("default", "device_id", 0)
T.attr("default", "device_type", 1)
mod.subroutine(A_data)
+ T.ret(T.int32(0))
@T.prim_func
def subroutine(A_data: T.handle("float32")):
@@ -259,11 +261,13 @@ class
TestSubroutineCallToExternallyVisibleSubroutine(tvm.testing.CompareBeforeA
T.attr("default", "device_id", 0)
T.attr("default", "device_type", 1)
mod.subroutine(A_data)
+ T.ret(T.int32(0))
@T.prim_func
def subroutine(A_data: T.handle("float32")) -> T.int32:
T.func_attr({"global_symbol": "subroutine", "target":
T.target("llvm")})
T.evaluate(A_data)
+ T.ret(T.int32(0))
return mod
@@ -316,6 +320,7 @@ class
TestCallExternallyVisibleSubroutineWithDLTensor(tvm.testing.CompareBeforeA
T.attr("default", "device_id", 0)
T.attr("default", "device_type", 1)
mod.subroutine(A_data)
+ T.ret(T.int32(0))
@T.prim_func
def subroutine(A_data: T.handle("float32")) -> T.int32:
@@ -323,6 +328,7 @@ class
TestCallExternallyVisibleSubroutineWithDLTensor(tvm.testing.CompareBeforeA
T.attr("default", "device_id", 0)
T.attr("default", "device_type", 1)
T.evaluate(A_data)
+ T.ret(T.int32(0))
return mod