The Relax IR requires the FunctionNode::body
, IfNode::true_branch
, and IfNode::false_branch
to be instances of relax::SeqExpr
. If these Relax requirements are violated, correctly-implemented transformations may raise an exception (e.g. from Downcast
in Downcast<SeqExpr>(func->body)->blocks
), or even segfault (e.g. when .as
returns a nullptr in func->body.as<SeqExprNode>()->blocks
). Debugging these failure modes is also difficult, as even the TVMScript printer relies on the body of the function being a SeqExprNode
. As such, I wanted to experiment with ways to improve the developer experience around these requirements.
I have a draft PR open at [QoL][Relax] Use SeqExpr in IR types when SeqExpr is required by Lunderberg · Pull Request #16859 · apache/tvm · GitHub that would update the C++ type of FunctionNode::body
, IfNode::true_branch
, and IfNode::false_branch
to be relax::SeqExpr
instead of relax::Expr
. This does not impact any well-formed Relax IR, and allows this type of ill-formed Relax IR type to be checked at compile-time. A large number of checks applied during TVM runtime can now be removed, as they duplicate the new compile-time check.
To maintain backwards compatibility, this PR would also add a new constructor to relax::SeqExpr
, which accepts a single Expr body
argument. This constructor provides either an additional reference to the same underlying relax::SeqExprNode
, if body
already contains a relax::SeqExprNode
, and otherwise wraps the body in a relax::SeqExpr
. For implementations that previously produced well-formed Relax IR, this change has no effect. For implementations that previously produced ill-formed Relax IR, this change results in the equivalent well-formed Relax IR.
Alternate implementations considered:
-
Perform the backwards-compatibility wrapping within the
relax::Function
andrelax::If
constructors. While this would provide the intended conversion when these constructors are used, Relax transforms make frequent use of copy-on-write (e.g.func.CopyOnWrite()->body = new_body
), which does not use the constructor. Maintaining backwards compatibility for this usage requires the implicit conversion constructor that was chosen for this PR. -
Remove the Relax IR requirement for these expressions to be
SeqExpr
. While this would make Relax more internally consistent, such a change would break backwards compatibility that relies onSeqExpr
being present. While the callsites within TVM could be updated to resolve this breakage, callsites outside of TVM (e.g. MLC-LLM) could not. Exposing the special case within the C++ type, as done in this PR, maintains backwards compatibility.
Since this does impact the Relax IR, the PR is currently marked as a draft, to allow time for discussion. I think this is a useful change to make, as it moves the well-formed check from TVM’s execution time to the C++ compile-time.