## Introduction
[TVM Object system]([https://tvm.apache.org/docs/dev/runtime.html#tvm-object-and-compiler-stack](https://tvm.apache.org/docs/dev/runtime.html#tvm-object-and-compiler-stack)) provides a convenient and decent way to share objects between backend (C++) and frontend (Python/Java/Rust/etc.). For example, one can construct a variable in Python and pass it to functions written in C++, and vice versa. However, adding one object node into TVM stack requires manually adding lines of code to different places in both Python and C++. For example, here’s how `tvm::tir::IntImm` is implemented and registered, - Definition for Node and its Reference: [https://github.com/apache/incubator-tvm/blob/master/include/tvm/ir/expr.h#L228-L270](https://github.com/apache/incubator-tvm/blob/master/include/tvm/ir/expr.h#L228-L270) - Implement functionality: [https://github.com/apache/incubator-tvm/blob/master/src/ir/expr.cc#L58-L68](https://github.com/apache/incubator-tvm/blob/master/src/ir/expr.cc#L58-L68) - Node registry in C++: [https://github.com/apache/incubator-tvm/blob/master/src/ir/expr.cc#L70-L84](https://github.com/apache/incubator-tvm/blob/master/src/ir/expr.cc#L70-L84) - Node registry in Frontend (Python): [https://github.com/apache/incubator-tvm/blob/master/python/tvm/tir/expr.py#L275-L290](https://github.com/apache/incubator-tvm/blob/master/python/tvm/tir/expr.py#L275-L290) This RFC advocates the approach to generate C++ implement directly from Python class definition and registry. Moreover, as we still allow users to write C++ code manually in order to bring in more complex features, the object transpiler will provide basic validation for these manually written C++ code. Here is an example of how an object can be described in Python and how the generated C++ code looks like: ```python @declare class BaseExprNode(Object): """ Base type of all the expression. See Also -------- BaseExpr """ type_key = "BaseExpr" default_visit_attrs = False default_sequal_reduce = False default_shash_reduce = False @declare class IntImmNode(PrimExprNode): """ Constant integer literals in the program. See Also -------- IntImm Attributes ---------- value The internal value. """ type_key = "IntImm" value: ty.int64_t ``` ```cpp /*! * \brief Base type of all the expressions. * \sa Expr */ class BaseExprNode : public Object { public: TVM_DECLARE_BASE_OBJECT_INFO(BaseExprNode, Object); }; /*! * \brief Managed reference to BaseExprNode. * \sa BaseExprNode */ class BaseExpr : public ObjectRef { public: TVM_DEFINE_OBJECT_REF_METHODS(BaseExpr, ObjectRef, BaseExprNode); }; /*! * \brief Constant integer literals in the program. */ class IntImmNode : public PrimExprNode { public: /*! \brief The internal value. */ int64_t value; void VisitAttrs(AttrVisitor* v) { v->Visit("dtype", &dtype); v->Visit("value", &value); } void SEqualReduce(const IntImmNode* other, SEqualReducer equal) const { return equal(dtype, other->dtype) && equal(value, other->value) } void SHashReduce(SHashReducer hash_reducer) const { hash_reducer(dtype); hash_reducer(value); } static constexpr const char* _type_key = "IntImm"; TVM_DECLARE_BASE_OBJECT_INFO(IntImmNode, PrimExprNode); }; /*! * \brief Managed reference class to IntImmNode. * * \sa IntImmNode */ class IntImm : public PrimExpr { public: TVM_DEFINE_OBJECT_REF_METHODS(IntImm, PrimExpr, IntImmNode); }; ``` We name it as TVM Object Schema DSL, or tschema. In summary, tschema will bring several benefits for the TVM architecture: - Reduce boilerplate code; - Verify to avoid missing some definition like `TVM_REGISTER(...)`; - Enable deployment on all kinds environment even without C++; - Fields like `type_child_slots` can be automatically generate for optimizing; - Allow users to define Objects in Python, build and export them to a .o/.so file; - Have more type information during runtime, enable some optimizations in TIR compilation; ## High-level Object Compilation Pipeline - Define TVM Object in Python. This object definition Python file is in a seperate directory (which will not be a part of PYTHONPATH) other than python/tvm/ - Run python class parser to generate related .h, .cc files. This step can be triggered manually or via cmake. The generated files will be checked into the code base so that code completion tools can locate them. - Compile TVM using cmake as usual. Notice that the second step happens during (or before) compiling TVM itself. We provide a standalone tool to parse the Python code. ## TSchema DSL Take `IntImm` as an example, the ```python @declare class IntImmNode(PrimExprNode): """ Constant integer literals in the program. See Also -------- IntImm Attributes ---------- value The internal value. """ type_key = "IntImm" value: ty.int64_t ``` There are several things require to be parsed, - Object name. In the above example it is `IntImmNode`, therefore `class IntImmNode` (extends Object) will be generated. - Type key. In the above example it is `IntImm`, therefore `class IntImm` (extends ObjectRef) will be generated. - Parent class. In the above example it is `PrimExprNode` - Member variables. In the above example they are, - `value` and its type annotation `int64_t` - The constructor arguments in C++ will be generated as the same order of the arguments in Python class definition. - We also will generate default `VisitAttrs`, `SEqualReduce`, `SHashReduce` methods unless user specify `default_visit_attrs` as `False`. ## **Inplace C++ Source File Modification** As we mentioned before, there are cases where users need to implement complex functions manually. To leverage the convenience of Python declaration and automatic code generation in such cases, we provide an option to modify the C++ source file in-place, and give users the control to specify which part of the file can be modified. We provide comment parser for .h and .cc file, in which users can wrap the auto-generated section by comments, e.g., ``` // tschema: ObjectName The lines between tschema: ObjectName and tschema: end will be manipulated by tschema // tschema: custom-begin User can also mark sections which should be left unchanged by objgen This section will be inserted at the end of the class definition, right before the close brace // tschema: custom-end // tschema: end ``` Here is also an example for it: **Before generation** ```cpp // tschema: GlobalVarNode // tschema: custom-begin bool SEqualReduce(const GlobalVarNode* other, SEqualReducer equal) const { return equal(name_hint, other->name_hint) && equal.FreeVarEqualImpl(this, other) } bool SHashReduce(SHashReducer hash_reducer) const { hash_reduce(name_hint); hash_reduce.FreeVarHashImpl(this); } // tschema: custom-end // tschema: end ``` **TSchema Definition** ```cpp @declare class GlobalVarNode(RelayExprNode): """ Global variable that lives in the top-level module. A GlobalVar only refers to function definitions. This is used to enable recursive calls between function. See Also -------- GlobalVarNode Attributes ---------- name_hint The name of the variable, this only acts as a hint. """ type_key = "GlobalVar" default_sequal_reduce = False default_shash_reduce = False name_hint: ty.String ``` **Generated Code** ```cpp // tschema: GlobalVarNode class GlobalVarNode : public RelayExprNode { public: String name_hint; void VisitAttrs(AttrVisitor* v) { v->Visit("span", &span); v->Visit("checked_type_", &checked_type_); v->Visit("name_hint", &name_hint); } static constexpr const char* _type_key = "GlobalVar"; TVM_DECLARE_BASE_OBJECT_INFO(GlobalVarNode, RelayExprNode); // tschema: custom-begin bool SEqualReduce(const GlobalVarNode* other, SEqualReducer equal) const { return equal(name_hint, other->name_hint) && equal.FreeVarEqualImpl(this, other) } bool SHashReduce(SHashReducer hash_reducer) const { hash_reduce(name_hint); hash_reduce.FreeVarHashImpl(this); } // tschema: custom-end }; // tschema: end ``` @tqchen @yzhliu @jwfromm @jroesch @junrushao1994 , also thanks Yizhi for the initial idea and RFC writing. --- [Visit Topic](https://discuss.tvm.apache.org/t/rfc-tvm-object-schema-dsl/7930/1) to respond. You are receiving this because you enabled mailing list mode. To unsubscribe from these emails, [click here](https://discuss.tvm.apache.org/email/unsubscribe/d4b6f75d7c462a948da56217a1f4878c25e48f1262c2d3d4c6ffecfe01fac5a3).