/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef TVM_RELAX_SCRIPT_BUILDER_FRAME_H_ #define TVM_RELAX_SCRIPT_BUILDER_FRAME_H_ #include #include #include #include #include #include #include namespace tvm { namespace script { namespace ir_builder { namespace relax { /*! \brief The base ir_builder frame for the relax dialect. */ class RelaxFrameNode : public IRBuilderFrameNode { public: static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef(); } TVM_FFI_DECLARE_OBJECT_INFO("script.ir_builder.relax.RelaxFrame", RelaxFrameNode, IRBuilderFrameNode); }; class RelaxFrame : public IRBuilderFrame { public: explicit RelaxFrame(ffi::ObjectPtr data) : IRBuilderFrame(ffi::UnsafeInit{}) { TVM_FFI_ICHECK(data != nullptr); data_ = std::move(data); } TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(RelaxFrame, IRBuilderFrame, RelaxFrameNode); protected: RelaxFrame() = default; }; /*! \brief The base ir_builder frame for frames with SeqExpr i.e. Functions, If branches */ class SeqExprFrameNode : public RelaxFrameNode { public: /*! \brief The binding blocks inside the frame. */ ffi::Array binding_blocks; /*! \brief The frame output expr. `std::nullopt` when undefined. */ ffi::Optional output; static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef() .def_ro("binding_blocks", &SeqExprFrameNode::binding_blocks) .def_ro("output", &SeqExprFrameNode::output); } TVM_FFI_DECLARE_OBJECT_INFO("script.ir_builder.relax.SeqExprFrame", SeqExprFrameNode, RelaxFrameNode); public: void EnterWithScope() override; void ExitWithScope() override; }; class SeqExprFrame : public RelaxFrame { public: explicit SeqExprFrame(ffi::ObjectPtr data) : RelaxFrame(data) { TVM_FFI_ICHECK(data != nullptr); } TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(SeqExprFrame, RelaxFrame, SeqExprFrameNode); }; /*! \brief The ir_builder frame for the relax function. */ class FunctionFrameNode : public SeqExprFrameNode { public: /*! * \brief The function name. * \note The name will not be specified in constructor, so it is "Optional", * However, we must specify the name by `R.func_name` before exit this frame. */ ffi::Optional name; /*! \brief The function params. */ ffi::Array params; /*! * \brief The function return type. * \note Usually the function return type can be deduced by the function body. * But we can use this field to specify a more "accurate" return type. * i.e. If the `ret_ty` is None, try to use the deduced type from body * If the `ret_ty` is not None, we can still take body.ty * if we ret_ty is base of body.ty. If not, we will * take the specified `ret_ty`. */ ffi::Optional ret_ty; /*! \brief Whether the function is annotated as pure */ ffi::Optional is_pure; /*! \brief Whether the function is annotated as private */ ffi::Optional is_private; /*! \brief The function attributes. */ ffi::Map attrs; /*! \brief The block builder to create Relax function. */ tvm::relax::BlockBuilder block_builder; static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef() .def_ro("name", &FunctionFrameNode::name) .def_ro("params", &FunctionFrameNode::params) .def_ro("ret_ty", &FunctionFrameNode::ret_ty) .def_ro("is_pure", &FunctionFrameNode::is_pure) .def_ro("attrs", &FunctionFrameNode::attrs); // `binding_blocks` and `output` are inherited from SeqExprFrameNode. // `block_builder` is not registered as it's not visited. } TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.ir_builder.relax.FunctionFrame", FunctionFrameNode, SeqExprFrameNode); public: void EnterWithScope() final; void ExitWithScope() final; }; class FunctionFrame : public SeqExprFrame { public: explicit FunctionFrame(ffi::ObjectPtr data) : SeqExprFrame(data) { TVM_FFI_ICHECK(data != nullptr); } TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(FunctionFrame, SeqExprFrame, FunctionFrameNode); }; /*! \brief The ir_builder frame for relax binding blocks. */ class BindingBlockFrameNode : public RelaxFrameNode { public: /*! \brief The flag that indicates whether the block is a dataflow block. */ bool is_dataflow; /*! \brief The variables emitted in this block. */ ffi::Array emitted_vars; /*! * \brief A boolean indicating if the dataflow block is ended of construction. * If it is true, any new binding trying to be emitted into this block will cause an error. * \note Only used for a dataflow block. */ bool block_ended; /*! * \brief The output vars of the dataflow block. * \note Only used for a dataflow block. */ ffi::Array output_vars; static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef() .def_ro("is_dataflow", &BindingBlockFrameNode::is_dataflow) .def_ro("emitted_vars", &BindingBlockFrameNode::emitted_vars) .def_ro("output_vars", &BindingBlockFrameNode::output_vars); // `block_ended` is not registered as it's not visited. } TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.ir_builder.relax.BindingBlockFrame", BindingBlockFrameNode, RelaxFrameNode); public: void EnterWithScope() final; void ExitWithScope() final; }; class BindingBlockFrame : public RelaxFrame { public: explicit BindingBlockFrame(ffi::ObjectPtr data) : RelaxFrame(data) { TVM_FFI_ICHECK(data != nullptr); } TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(BindingBlockFrame, RelaxFrame, BindingBlockFrameNode); }; /*! * \brief A frame that represents if statement. * * \sa IfFrame */ class IfFrameNode : public RelaxFrameNode { public: /*! \brief The condition of the if statement. */ tvm::relax::Expr condition; /*! \brief The Bindings in the true branch. */ ffi::Optional then_expr; /*! \brief The Bindings in the false branch. */ ffi::Optional else_expr; /*! \brief The Binding var. */ tvm::relax::Var var; /*! \brief The binding var name. */ ffi::String var_name; static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef() .def_ro("condition", &IfFrameNode::condition) .def_ro("then_expr", &IfFrameNode::then_expr) .def_ro("else_expr", &IfFrameNode::else_expr) .def_ro("var", &IfFrameNode::var) .def_ro("var_name", &IfFrameNode::var_name); } TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.ir_builder.relax.IfFrame", IfFrameNode, RelaxFrameNode); public: /*! * \brief The method called when entering RAII scope. * \sa tvm::support::With */ void EnterWithScope() final; /*! * \brief The method called when exiting RAII scope. * \sa tvm::support::With */ void ExitWithScope() final; }; /*! * \brief Managed reference to IfFrameNode. * * \sa IfFrameNode */ class IfFrame : public RelaxFrame { public: explicit IfFrame(ffi::ObjectPtr data) : RelaxFrame(data) { TVM_FFI_ICHECK(data != nullptr); } TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(IfFrame, RelaxFrame, IfFrameNode); }; /*! * \brief A frame that represents then. * * \sa ThenFrame */ class ThenFrameNode : public SeqExprFrameNode { public: static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef(); } TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.ir_builder.relax.ThenFrame", ThenFrameNode, SeqExprFrameNode); public: /*! * \brief The method called when entering RAII scope. * \sa tvm::support::With */ void EnterWithScope() final; /*! * \brief The method called when exiting RAII scope. * \sa tvm::support::With */ void ExitWithScope() final; }; /*! * \brief Managed reference to ThenFrameNode. * * \sa ThenFrameNode */ class ThenFrame : public SeqExprFrame { public: explicit ThenFrame(ffi::ObjectPtr data) : SeqExprFrame(data) { TVM_FFI_ICHECK(data != nullptr); } TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(ThenFrame, SeqExprFrame, ThenFrameNode); }; /*! * \brief A frame that represents else. * * \sa ElseFrame */ class ElseFrameNode : public SeqExprFrameNode { public: static void RegisterReflection() { namespace refl = tvm::ffi::reflection; refl::ObjectDef(); } TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.ir_builder.relax.ElseFrame", ElseFrameNode, SeqExprFrameNode); public: /*! * \brief The method called when entering RAII scope. * \sa tvm::support::With */ void EnterWithScope() final; /*! * \brief The method called when exiting RAII scope. * \sa tvm::support::With */ void ExitWithScope() final; }; /*! * \brief Managed reference to ElseFrameNode. * * \sa ElseFrameNode */ class ElseFrame : public SeqExprFrame { public: explicit ElseFrame(ffi::ObjectPtr data) : SeqExprFrame(data) { TVM_FFI_ICHECK(data != nullptr); } TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(ElseFrame, SeqExprFrame, ElseFrameNode); }; } // namespace relax } // namespace ir_builder } // namespace script } // namespace tvm #endif // TVM_RELAX_SCRIPT_BUILDER_FRAME_H_