333 lines
11 KiB
C++
333 lines
11 KiB
C++
/*
|
|
* 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 <tvm/ffi/reflection/registry.h>
|
|
#include <tvm/relax/block_builder.h>
|
|
#include <tvm/relax/expr.h>
|
|
#include <tvm/script/ir_builder/base.h>
|
|
#include <tvm/script/ir_builder/ir/frame.h>
|
|
#include <tvm/script/ir_builder/ir/ir.h>
|
|
|
|
#include <utility>
|
|
|
|
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<RelaxFrameNode>();
|
|
}
|
|
TVM_FFI_DECLARE_OBJECT_INFO("script.ir_builder.relax.RelaxFrame", RelaxFrameNode,
|
|
IRBuilderFrameNode);
|
|
};
|
|
|
|
class RelaxFrame : public IRBuilderFrame {
|
|
public:
|
|
explicit RelaxFrame(ffi::ObjectPtr<RelaxFrameNode> 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<tvm::relax::BindingBlock> binding_blocks;
|
|
/*! \brief The frame output expr. `std::nullopt` when undefined. */
|
|
ffi::Optional<tvm::relax::Expr> output;
|
|
|
|
static void RegisterReflection() {
|
|
namespace refl = tvm::ffi::reflection;
|
|
refl::ObjectDef<SeqExprFrameNode>()
|
|
.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<SeqExprFrameNode> 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<ffi::String> name;
|
|
/*! \brief The function params. */
|
|
ffi::Array<tvm::relax::Var> 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<tvm::Type> ret_ty;
|
|
/*! \brief Whether the function is annotated as pure */
|
|
ffi::Optional<bool> is_pure;
|
|
/*! \brief Whether the function is annotated as private */
|
|
ffi::Optional<bool> is_private;
|
|
/*! \brief The function attributes. */
|
|
ffi::Map<ffi::String, Any> attrs;
|
|
/*! \brief The block builder to create Relax function. */
|
|
tvm::relax::BlockBuilder block_builder;
|
|
|
|
static void RegisterReflection() {
|
|
namespace refl = tvm::ffi::reflection;
|
|
refl::ObjectDef<FunctionFrameNode>()
|
|
.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<FunctionFrameNode> 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<tvm::relax::Var> 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<tvm::relax::Var> output_vars;
|
|
|
|
static void RegisterReflection() {
|
|
namespace refl = tvm::ffi::reflection;
|
|
refl::ObjectDef<BindingBlockFrameNode>()
|
|
.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<BindingBlockFrameNode> 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<tvm::relax::Expr> then_expr;
|
|
/*! \brief The Bindings in the false branch. */
|
|
ffi::Optional<tvm::relax::Expr> 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<IfFrameNode>()
|
|
.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<IfFrameNode> 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<ThenFrameNode>();
|
|
}
|
|
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<ThenFrameNode> 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<ElseFrameNode>();
|
|
}
|
|
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<ElseFrameNode> 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_
|