mindspore2022/mindspore/core/ir/anf.h

1169 lines
40 KiB
C++

/**
* This is the C++ adaptation and derivative work of Myia (https://github.com/mila-iqia/myia/).
*
* Copyright 2019-2021 Huawei Technologies Co., Ltd
*
* Licensed 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 MINDSPORE_CORE_IR_ANF_H_
#define MINDSPORE_CORE_IR_ANF_H_
#include <functional>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <set>
#include "base/base.h"
#include "base/user_data.h"
#include "base/effect_info.h"
#include "ir/kernel_info_dev.h"
#include "ir/scope.h"
#include "ir/primal_attr.h"
#include "ir/primal_debug_info.h"
#include "utils/info.h"
#include "utils/ms_utils.h"
// A MindSpore ANF IR defined here.
// with BNF followed:
// <ANode> ::= Scalar | Named | Tensor | Var |
// Prim | MetaFuncGraph | FuncGraph | Type|
// Shape | Param
// <CNode> ::= (<ANode> ...)
// <AnfNode> ::= <CNode> | <ANode>
// ANode: Atomic Node
// CNode: Complex Node
namespace mindspore {
namespace abstract {
class BaseShape;
class AbstractBase;
} // namespace abstract
using BaseShapePtr = std::shared_ptr<abstract::BaseShape>;
using AbstractBasePtr = std::shared_ptr<abstract::AbstractBase>;
using AbstractBasePtrList = std::vector<AbstractBasePtr>;
class Value;
using ValuePtr = std::shared_ptr<Value>;
using ValuePtrList = std::vector<ValuePtr>;
class ValueNode;
using ValueNodePtr = std::shared_ptr<ValueNode>;
class CNode;
using CNodePtr = std::shared_ptr<CNode>;
using CNodePtrList = std::vector<CNodePtr>;
using CNodeWeakPtr = std::weak_ptr<CNode>;
class FuncGraph;
using FuncGraphSet = OrderedSet<FuncGraphPtr>;
using FuncGraphVector = std::vector<FuncGraphPtr>;
class Primitive;
using PrimitivePtr = std::shared_ptr<Primitive>;
struct PrimitiveHasher;
struct PrimitiveEqual;
using PrimitiveSet = std::unordered_set<PrimitivePtr, PrimitiveHasher, PrimitiveEqual>;
class BaseRef;
class Var;
using VarPtr = std::shared_ptr<Var>;
class AnfIrVisitor;
class ParamInfo;
using ParamInfoPtr = std::shared_ptr<ParamInfo>;
// AnfNode is the basic class of the IR definition derived from Base.
// Only two types of nodes are derived: CNode and ANode.
// Methods:
// func_graph: return FuncGraph that this AnfNode belongs to.
// scope: return the scope namespace of this AnfNode. Set it using set_scope.
// abstract: return the cached inferred abstract value. It contains type, shape
// value. Set New cache using set_abstract.
// intermediate_abstract: return the cached inferring abstract value.
// Type/Shape: return the related info of this AnfNode. When this AnfNode is an
// input of other CNodes, you can get the related info by this method.
// debug_info: return the information retrieved from parser. Set it using set_debug_info.
// fullname_with_scope: return the detailed debug info.
/// \brief AnfNode is the basic class of the IR definition derived from Base.
class MS_CORE_API AnfNode : public Base {
public:
/// \brief Constructor.
///
/// \param[in] func_graph The FuncGraph to which this AnfNode belongs.
/// \param[in] debug_info The debug info to be used for this AnfNode.
AnfNode(const FuncGraphPtr &func_graph, NodeDebugInfoPtr &&debug_info)
: func_graph_(FuncGraphWeakPtr(func_graph)),
abstract_(nullptr),
intermediate_abstract_(nullptr),
debug_info_(std::move(debug_info)),
fullname_with_scope_(""),
hash_(std::hash<const AnfNode *>()),
scope_(ScopeManager::GetInstance().GetCurrentScope()),
kernel_info_(nullptr),
interpret_(false),
interpreted_node_(nullptr) {}
/// \brief Constructor.
///
/// \param[in] func_graph The FuncGraph to which this AnfNode belongs.
explicit AnfNode(const FuncGraphPtr &func_graph) : AnfNode(func_graph, std::make_shared<NodeDebugInfo>()) {}
/// \brief Destructor.
~AnfNode() override = default;
MS_DECLARE_PARENT(AnfNode, Base);
/// \brief Use the method of the AnfIrVisitor class to process the node.
virtual void accept(AnfIrVisitor *) {}
/// \brief Obtain the FuncGraph to which this AnfNode belongs.
///
/// \return The FuncGraph to which this AnfNode belongs.
FuncGraphPtr func_graph() const { return func_graph_.lock(); }
/// \brief Set the FuncGraph to which this AnfNode belongs.
///
/// \param[in] func_graph The input FuncGraph.
virtual void set_func_graph(const FuncGraphPtr &func_graph) { func_graph_ = FuncGraphWeakPtr(func_graph); }
/// \brief Obtain the scope namespace of this AnfNode.
///
/// \return The scope namespace.
ScopePtr scope() { return scope_; }
/// \brief Set the scope namespace of this AnfNode.
///
/// \param[in] scope New scope namespace.
void set_scope(const ScopePtr &scope) { scope_ = scope; }
/// \brief Obtain device kernel program information.
///
/// \return Device kernel program information.
const KernelInfoDevice *kernel_info() const { return kernel_info_.get(); }
/// \brief Obtain device kernel program information.
///
/// \return Device kernel program information.
KernelInfoDevice *kernel_info() { return kernel_info_.get(); }
/// \brief Obtain the pointer of KernelInfoDevice.
///
/// \return The pointer of KernelInfoDevice.
const KernelInfoDevicePtr &kernel_info_ptr() { return kernel_info_; }
/// \brief Set device kernel program information.
///
/// \param[in] kernel_info New device kernel program information.
void set_kernel_info(const KernelInfoDevicePtr &kernel_info) { kernel_info_ = kernel_info; }
/// \brief Obtain the inferred abstract value of this AnfNode.
///
/// \return The inferred abstract value.
const AbstractBasePtr &abstract() const { return abstract_; }
/// \brief Set the abstract value of this AnfNode.
///
/// \param[in] abs New abstract value.
void set_abstract(const AbstractBasePtr &abs) { abstract_ = abs; }
/// \brief Obtain the intermediate abstract value of this AnfNode.
///
/// \return The intermediate abstract value.
AbstractBasePtr intermediate_abstract() { return intermediate_abstract_; }
/// \brief Set the intermediate abstract value of this AnfNode.
///
/// \param[in] abs New intermediate abstract value.
void set_intermediate_abstract(const AbstractBasePtr &abs) { intermediate_abstract_ = abs; }
/// \brief Obtain the debugging information of this AnfNode.
///
/// \return The debugging information of this AnfNode.
NodeDebugInfoPtr debug_info() {
MS_EXCEPTION_IF_NULL(debug_info_);
if (debug_info_->get_node() == nullptr) {
debug_info_->set_node(shared_from_base<AnfNode>());
}
return debug_info_;
}
/// \brief Set the debugging information of this AnfNode.
///
/// \return New debugging information.
void set_debug_info(const NodeDebugInfoPtr &debug_info) {
MS_EXCEPTION_IF_NULL(debug_info);
debug_info_ = debug_info;
if (debug_info_->get_node() == nullptr) {
debug_info_->set_node(shared_from_base<AnfNode>());
}
}
/// \brief Obtain the type of the element in this AnfNode.
///
/// \return The type of the element.
TypePtr Type() const;
/// \brief Obtain the shape of the element in this AnfNode.
///
/// \return The shape of the element.
BaseShapePtr Shape() const;
std::size_t hash() const override { return this->hash_(this); }
/// \brief Obtain detailed information about scope namespace.
///
/// \return Detailed information about scope namespace.
virtual std::string fullname_with_scope() { return ""; }
/// \brief Obtain the unique name of this AnfNode.
///
/// \return The unique name of this AnfNode.
std::string UniqueName() { return fullname_with_scope() + "_" + UniqueId(); }
/// \brief Obtain the display information of this AnfNode.
///
/// \param[in] recursive_level Recursion level when displayed.
/// \return Information to be displayed.
virtual std::string DebugString(int recursive_level = 1) const { return ToString(); }
/// \brief Obtain the display information of this AnfNode.
///
/// \param[in] recursive Whether to display AnfNode recursively.
/// \return Information to be displayed.
virtual std::string DebugString(bool recursive) const { return DebugString(recursive ? 1 : 0); }
std::string ToString() const override;
void dump() const override { std::cout << DebugString() << std::endl; }
/// \brief Obtain the unique id of the debug information of this AnfNode.
///
/// \return Unique id.
std::string UniqueId() { return std::to_string(debug_info()->unique_id()); }
/// \brief Obtain the unique id through copied traced information.
///
/// \return Unique id.
std::string UniqueIdThroughCopy() { return std::to_string(debug_info()->unique_id_through_copy()); }
/// \brief Determine whether two AnfNodes are the same.
///
/// \param[in] other Another ANfNode.
/// \return True if the same, otherwise False.
virtual bool operator==(const AnfNode &other) const { return &other == this; }
/// \brief Obtain the display information of this AnfNode.
///
/// \param[in] os Output stream.
/// \param[in] node AnfNode to be displayed.
/// \return Output stream.
friend std::ostream &operator<<(std::ostream &os, const AnfNode &node) {
os << node.ToString();
return os;
}
size_t seen_{0};
size_t extra_seen_{0};
/// \brief Set user data.
///
/// \param[in] key The key of user data.
/// \param[in] value The value of user data.
template <typename T>
void set_user_data(const std::string &key, const std::shared_ptr<T> &value) {
user_data_.set<T>(key, value);
}
/// \brief Set user data.
///
/// \param[in] value The value of user data.
template <typename T>
void set_user_data(const std::shared_ptr<T> &value) {
user_data_.set<T>(T::key, value);
}
/// \brief Set user data.
///
/// \param[in] key The key of user data.
/// \return Pointer to user data.
template <typename T>
std::shared_ptr<T> user_data(const std::string &key) const {
return user_data_.get<T>(key);
}
/// \brief Set user data.
///
/// \return Pointer to user data.
template <typename T>
std::shared_ptr<T> user_data() const {
return user_data_.get<T>(T::key);
}
/// \brief Check whether there is corresponding user data by the given key.
///
/// \param[in] key The key of user data.
/// \return True if it exists, otherwise false.
bool has_user_data(const std::string &key) const { return user_data_.has(key); }
/// \brief Check if there is user data.
///
/// \return True if it exists, otherwise false.
template <typename T>
bool has_user_data() const {
return user_data_.has(T::key);
}
/// \brief Clone user data.
///
/// \param[in] node Node used to copy user data.
void CloneUserData(const AnfNodePtr &node) { user_data_ = node->user_data_; }
/// \brief Check if there is an interpret node.
///
/// \return True if there is an interpret node, otherwise false.
bool interpret() { return interpret_; }
/// \brief Whether to use interpretation
///
/// \param[in] interpret Boolean.
void set_interpret(const bool &interpret) { interpret_ = interpret; }
/// \brief Get interpreted node.
///
/// \return Interpreted node.
AnfNodePtr interpreted_node() { return interpreted_node_; }
/// \brief Set interpreted node.
///
/// \param[in] Interpreted node.
void set_interpreted_node(const AnfNodePtr &node) { interpreted_node_ = node; }
protected:
// Hold a weak ref to Graph as Graph also hold ref to AnfNode.
// Otherwise, func_graph_ and AnfNode will make a reference cycle.
FuncGraphWeakPtr func_graph_;
AbstractBasePtr abstract_;
AbstractBasePtr intermediate_abstract_;
NodeDebugInfoPtr debug_info_;
std::string fullname_with_scope_;
private:
std::hash<const AnfNode *> hash_;
ScopePtr scope_;
KernelInfoDevicePtr kernel_info_;
UserData user_data_;
bool interpret_;
AnfNodePtr interpreted_node_;
};
// CNode represents the complex node with a set of arguments.
// Fields:
// inputs_: represents all of the inputs for this CNode.
// Using input(i) to get the index i input.
// Using inputs() to get all the inputs as a vector.
// Using add_input(input) to append a new input for a CNode.
// Using set_input(i, input) to change some input of these inputs.
// Using set_inputs(inputs) to refresh all of the inputs of a CNode.
// func_graph_as_var_: used in opt pattern matching to match a real FuncGraph.
// stop_gradient_: a flag used to stop gradient.
// Using stop_gradient() to get this flag, mainly used in ad.
// Using set_stop_gradient() to set this flag.
class MS_CORE_API CNode final : public AnfNode, public EffectInfoHolder {
public:
/// \brief Constructor.
///
/// \param[in] inputs Input nodes of this Cnode.
/// \param[in] func_graph The FuncGraph to which this CNode belongs.
CNode(std::vector<AnfNodePtr> &&inputs, const FuncGraphPtr &func_graph);
/// \brief Constructor.
///
/// \param[in] inputs Input nodes of this Cnode.
/// \param[in] func_graph The FuncGraph to which this CNode belongs.
CNode(const std::vector<AnfNodePtr> &inputs, const FuncGraphPtr &func_graph);
/// \brief Constructor.
///
/// \param[in] inputs Input nodes of this Cnode.
/// \param[in] func_graph_as_var The FuncGraph of type VarPtr to which this CNode belongs,
CNode(const std::vector<AnfNodePtr> &inputs, const VarPtr &func_graph_as_var)
: AnfNode(nullptr),
inputs_(inputs),
func_graph_as_var_(func_graph_as_var),
stop_gradient_(false),
input_tensor_num_(-1) {
primal_attrs_ = PrimalAttrManager::GetInstance().GetCurrentPrimalAttr();
primal_debug_infos_ = PrimalDebugInfoManager::GetInstance().GetCurrentPrimalDebugInfo();
}
/// \brief Constructor.
///
/// \param[in] inputs Input nodes of this Cnode.
/// \param[in] func_graph The FuncGraph to which this CNode belongs.
/// \param[in] debug_info The debug info to be used for this CNode.
CNode(std::vector<AnfNodePtr> &&inputs, const FuncGraphPtr &func_graph, NodeDebugInfoPtr &&debug_info);
/// \brief Destructor.
~CNode() override = default;
MS_DECLARE_PARENT(CNode, AnfNode);
void accept(AnfIrVisitor *v) override;
/// \brief Check whether this cnode has the same primitive value as the first input.
///
/// \return True if they have the same primitive value, otherwise false.
bool IsApply(const PrimitivePtr &) const;
/// \brief Obtain the size of input nodes of this CNode.
///
/// \return Size of input nodes.
const size_t size() const { return inputs_.size(); }
/// \brief Get the input node of the given index.
///
/// \param[in] i The given index.
/// \return The input node of the given index.
const AnfNodePtr &input(size_t i) const;
/// \brief Get the input nodes.
///
/// \return The input nodes of this CNode.
const std::vector<AnfNodePtr> &inputs() const { return inputs_; }
/// \brief Add the input node to this CNode.
///
/// \param[in] input Node.
void add_input(const AnfNodePtr &input);
/// \brief Set the input node of the given index.
///
/// \param[in] i The given index.
/// \param[in] input Node.
void set_input(size_t i, const AnfNodePtr &input);
/// \brief Set the input nodes for this CNode.
///
/// \param[in] inputs Input nodes.
void set_inputs(const std::vector<AnfNodePtr> &inputs);
/// \brief Record the cnode input value and id to inputs_value_.
///
/// \param[in] input_value Input value.
/// \param[in] id The id.
void add_input_value(const ValuePtr &input_value, const std::string &id) {
inputs_value_.push_back(std::make_pair(input_value, id));
}
/// \brief Clear the record of cnode input value in inputs_value_.
void clear_inputs_value() { inputs_value_.clear(); }
/// \brief Set the record of cnode input value.
///
/// \param[in] values New record.
void set_inputs_value(const std::vector<std::pair<ValuePtr, std::string>> &values) { inputs_value_ = values; }
/// \brief Get the record of input value of this CNode.
///
/// \return The input values of this CNode.
const std::vector<std::pair<ValuePtr, std::string>> &inputs_value() const { return inputs_value_; }
/// \brief Record the cnode value and id to output_value_.
///
/// \param[in] forward The cnode value.
/// \param[in] id The id.
void set_forward(const ValueNodePtr &forward, const std::string &id) { output_value_ = std::make_pair(forward, id); }
/// \brief Get the record of output value of this CNode.
///
/// \return The output value of this CNode.
const std::pair<ValueNodePtr, std::string> &forward() const { return output_value_; }
/// \brief Check if stop_gradient is set.
///
/// \return True if stop_gradient is set, otherwise false.
bool stop_gradient() const { return stop_gradient_; }
/// \brief Set stop_gradient.
///
/// \param[in] stop_gradient Boolean.
void set_stop_gradient(bool stop_gradient) { stop_gradient_ = stop_gradient; }
std::string fullname_with_scope() override;
/// \brief Set fullname_with_scope for this CNode.
///
/// \param[in] full_name The fullname_with_scope.
void set_fullname_with_scope(const std::string full_name) { fullname_with_scope_ = full_name; }
std::string DebugString(int recursive_level = 1) const override;
std::string DebugString(bool recursive) const override { return DebugString(recursive ? 1 : 0); }
/// \brief Set in_forward_flag for this CNode.
///
/// \param[in] flag Boolean.
void set_in_forward_flag(bool flag) { in_forward_flag_ = flag; }
/// \brief Check if in_forward_flag is set.
///
/// \return True if in_forward_flag is set, otherwise false.
bool in_forward_flag() const { return in_forward_flag_; }
/// \brief Check if the primitive of this CNode is load.
///
/// \param[in] is_load Boolean.
void set_load_flag(bool is_load) { is_load_ = is_load; }
/// \brief Check if is_load_ is set.
///
/// \return True if is_load_ is set, otherwise false.
bool get_load_flag() { return is_load_; }
/// \brief Get func_graph_as_var of this CNode.
///
/// \return func_graph_as_var.
VarPtr func_graph_as_var() const { return func_graph_as_var_; }
/// \brief Get all attributes of this CNode.
///
/// \return Attributes of this CNode.
const std::unordered_map<std::string, ValuePtr> &attrs() const { return attrs_; }
void set_attrs(const std::unordered_map<std::string, ValuePtr> &attrs) {
attrs_.insert(attrs.cbegin(), attrs.cend());
}
/// \brief Add a new attribute to this CNode.
///
/// \param[in] name The name of the new attribute.
/// \param[in] attr The value of the new attribute.
void AddAttr(const std::string &name, const ValuePtr &attr) { attrs_[name] = attr; }
/// \brief Erase the attribute with the given name.
///
/// \param[in] name The name of attribute.
void EraseAttr(const std::string &name) { (void)attrs_.erase(name); }
/// \brief Get the attribute with the given name.
///
/// \param[in] name The name of attribute.
/// \return Attribute.
ValuePtr GetAttr(const std::string &name) const {
auto iter = attrs_.find(name);
return iter == attrs_.cend() ? nullptr : iter->second;
}
/// \brief Check whether this CNode has an attribute with the given name.
///
/// \param[in] name The name of attribute.
/// \return Boolean.
bool HasAttr(const std::string &name) const { return attrs_.find(name) != attrs_.cend(); }
/// \brief Get the number of input tensors.
///
/// \return The number of input tensors.
ssize_t input_tensor_num() const { return input_tensor_num_; }
/// \brief Get the primal attributes of this CNode.
///
/// \return The primal attributes.
const std::unordered_map<std::string, ValuePtr> &primal_attrs() const { return primal_attrs_; }
/// \brief Set the primal attributes of this CNode.
///
/// \param[in] attrs The primal attributes.
void set_primal_attrs(const std::unordered_map<std::string, ValuePtr> &attrs) {
primal_attrs_.insert(attrs.cbegin(), attrs.cend());
}
/// \brief Add the primal attribute to this CNode.
///
/// \param[in] name The name of the attribute.
/// \param[in] attr The attribute.
void AddPrimalAttr(const std::string &name, const ValuePtr &attr) { primal_attrs_[name] = attr; }
/// \brief Erase the primal attribute with the given name.
///
/// \param[in] name The name of the attribute.
void ErasePrimalAttr(const std::string &name) { (void)primal_attrs_.erase(name); }
/// \brief Get the primal attribute with the given name.
///
/// \param[in] name The name of the attribute.
/// \return The primal attribute with the given name.
ValuePtr GetPrimalAttr(const std::string &name) const {
auto iter = primal_attrs_.find(name);
return iter == primal_attrs_.cend() ? nullptr : iter->second;
}
/// \brief Check whether this CNode has an attribute with the given name.
///
/// \param[in] name The name of the attribute.
/// \return True if it exists, otherwise false.
bool HasPrimalAttr(const std::string &name) const { return primal_attrs_.find(name) != attrs_.cend(); }
/// \brief Get primal debug information.
///
/// \return The primal debug information.
std::vector<NodeDebugInfoPtr> primal_debug_infos() { return primal_debug_infos_; }
/// \brief Set primal debug information.
///
/// \param[in] debug_infos Debug information of this CNode.
void set_primal_debug_infos(const std::vector<NodeDebugInfoPtr> &debug_infos) {
primal_debug_infos_.insert(primal_debug_infos_.end(), debug_infos.begin(), debug_infos.end());
}
/// \brief Add primal debug information to this CNode.
///
/// \param[in] debug_infos The primal debug information.
void AddPrimalDebugInfo(const NodeDebugInfoPtr debug_info) {
if (std::find(primal_debug_infos_.begin(), primal_debug_infos_.end(), debug_info) != primal_debug_infos_.end()) {
MS_LOG(EXCEPTION) << "Debug_info already in primal_debug_infos_ vector";
}
primal_debug_infos_.push_back(debug_info);
}
/// \brief Clone node information from a given Cnode.
///
/// \param[in] node Another node.
void CloneCNodeInfo(const CNodePtr &node) {
MS_EXCEPTION_IF_NULL(node);
set_abstract(node->abstract());
set_forward(node->forward().first, node->forward().second);
set_inputs_value(node->inputs_value());
set_attrs(node->attrs());
set_primal_attrs(node->primal_attrs());
set_load_flag(node->get_load_flag());
CloneUserData(node);
set_kernel_info(node->kernel_info_ptr());
set_primal_debug_infos(node->primal_debug_infos());
set_fused_debug_infos(node->fused_debug_infos());
}
/// \brief Set the number of input tensors.
///
/// \param[in] The number of input tensors.
void set_input_tensor_num(ssize_t input_tensor_num) { input_tensor_num_ = input_tensor_num; }
/// \brief Is effect have been handled.
///
/// \return True if effect have been handled, otherwise false.
bool IsEffectHandled() const { return effect_handled_; }
/// \brief Set effect handled or not.
///
/// \param[in] handled Boolean.
void SetEffectHandled(bool handled) { effect_handled_ = handled; }
/// \brief Get the debug infos of fused nodes.
///
/// \return A vector of debug infos.
std::vector<NodeDebugInfoPtr> fused_debug_infos() const { return fused_debug_infos_; }
/// \brief Set the debug infos for CNode.
///
/// \param fused_debug_infos The debuf infos to be set.
void set_fused_debug_infos(const std::vector<NodeDebugInfoPtr> &fused_debug_infos) {
fused_debug_infos_ = fused_debug_infos;
}
/// \brief Add a node's debug info or fused debug info.
///
/// \param node An anf node.
void AddFusedDebugInfo(const AnfNodePtr &node) {}
/// \brief Add a vector of nodes' debug info or fused debug info.
///
/// \param nodes A vector of anf nodes.
void AddFusedDebugInfoList(const std::vector<AnfNodePtr> &nodes) {}
private:
std::vector<AnfNodePtr> inputs_;
VarPtr func_graph_as_var_;
bool stop_gradient_;
bool in_forward_flag_ = false;
bool effect_handled_ = false;
bool is_load_ = false;
// inputs_value_ store cnode input value and id in pynative mode
// output_value_ store cnode value and id in pynative mode
std::vector<std::pair<ValuePtr, std::string>> inputs_value_;
std::pair<ValueNodePtr, std::string> output_value_;
std::unordered_map<std::string, ValuePtr> attrs_;
std::unordered_map<std::string, ValuePtr> primal_attrs_;
std::vector<NodeDebugInfoPtr> primal_debug_infos_;
std::vector<NodeDebugInfoPtr> fused_debug_infos_;
ssize_t input_tensor_num_ = -1;
};
// ANode represents the atomic node. It's derived Parameter and ValueNode.
class MS_CORE_API ANode : public AnfNode {
public:
ANode() : AnfNode(nullptr) {}
/// \brief Constructor.
///
/// \param[in] func_graph The FuncGraph to which this ANode belongs.
explicit ANode(const FuncGraphPtr &func_graph) : AnfNode(func_graph) {}
/// \brief Constructor.
///
/// \param[in] func_graph The FuncGraph to which this ANode belongs.
/// \param[in] debug_info The debug info to be used for this ANode.
ANode(const FuncGraphPtr &func_graph, NodeDebugInfoPtr &&debug_info) : AnfNode(func_graph, std::move(debug_info)) {}
/// \brief Destructor.
virtual ~ANode() = default;
MS_DECLARE_PARENT(ANode, AnfNode);
};
// Parameter represents the parameter inputs of a function. They have no value.
// Attributes:
// default_param_value_: used to hold the inputting tensor of the model.
class MS_CORE_API Parameter final : public ANode {
public:
/// \brief Constructor.
///
/// \param[in] func_graph The FuncGraph to which this Parameter belongs.
explicit Parameter(const FuncGraphPtr &func_graph)
: ANode(func_graph), name_(""), has_default_(false), default_param_(nullptr), used_graph_count_(0) {}
/// \brief Constructor.
///
/// \param[in] func_graph The FuncGraph to which this Parameter belongs.
/// \param[in] debug_info The debug info to be used for this Parameter.
Parameter(const FuncGraphPtr &func_graph, NodeDebugInfoPtr &&debug_info)
: ANode(func_graph, std::move(debug_info)),
name_(""),
has_default_(false),
default_param_(nullptr),
used_graph_count_(0) {}
/// \brief Destructor.
~Parameter() override = default;
MS_DECLARE_PARENT(Parameter, ANode);
void accept(AnfIrVisitor *v) override;
std::string DebugString(int recursive_level = 1) const override;
/// \brief Get the name of this Parameter.
///
/// \return The name.
std::string name() const { return name_; }
/// \brief Set the name of this Parameter.
///
/// \param[in] The name.
void set_name(const std::string &name) { name_ = name; }
std::string fullname_with_scope() override { return name(); }
/// \brief Check if there is a default parameter.
///
/// \return True if this Parameter has a default parameter, otherwise false.
bool has_default() const { return has_default_; }
/// \brief Set the default parameter.
///
/// \param[in] param The default parameter.
void set_default_param(ValuePtr param) {
default_param_ = param;
has_default_ = true;
}
/// \brief Get the default parameter.
///
/// \return The default parameter.
ValuePtr default_param() const { return default_param_; }
/// \brief Get the parameter information.
///
/// \return The parameter information.
ParamInfoPtr param_info() const;
/// \brief Increase used_graph_count_.
void IncreaseUsedGraphCount() { used_graph_count_++; }
/// \brief Decrease used_graph_count_.
void DecreaseUsedGraphCount() { used_graph_count_--; }
/// \brief Get used_graph_count_.
///
/// \return used_graph_count_.
int used_graph_count() const { return used_graph_count_; }
bool is_top_graph_param() const { return is_top_graph_param_; }
void set_is_top_graph_param(bool flag) { is_top_graph_param_ = flag; }
bool operator==(const AnfNode &other) const override {
if (!other.isa<Parameter>()) {
return false;
}
auto p = static_cast<const Parameter &>(other);
if (name_.length() > 0 && p.name_.length() > 0) {
return p.name_ == name_;
}
return shared_from_this() == other.shared_from_this();
}
/// \brief This parameter is not used in graph with id.
///
/// \param[in] graph_id The graph id.
void SetNotUsedByRealKernelInGraph(uint32_t graph_id) { (void)not_used_in_graphs_.insert(graph_id); }
/// \brief Check if this Parameter is used in graph with id.
///
/// \param[in] graph_id True if used, otherwise false.
bool IsUsedByRealKernelInGraph(uint32_t graph_id) const {
if (not_used_in_graphs_.find(graph_id) != not_used_in_graphs_.end()) {
return false;
}
return true;
}
/// \brief Set whether this Parameter has a dynamic shape.
///
/// \param[in] flag Boolean.
void set_has_dynamic_shape(bool flag) { has_dynamic_shape_ = flag; }
/// \brief Check whether this Parameter has a dynamic shape.
///
/// \return True if this Parameter has a dynamic shape, otherwise false.
bool has_dynamic_shape() const { return has_dynamic_shape_; }
/// \brief Set groups attr in FracZ format.
///
/// \param[in] fracz_group Groups attr in FracZ format.
void set_fracz_group(int64_t fracz_group) { fracz_group_ = fracz_group; }
/// \brief Get groups attr in FracZ format.
///
/// \return Groups attr in FracZ format.
int64_t fracz_group() { return fracz_group_; }
private:
std::string name_;
bool has_default_;
std::set<uint32_t> not_used_in_graphs_;
bool has_dynamic_shape_ = false;
ValuePtr default_param_;
// The count of graphs using the parameter.
int used_graph_count_;
// groups attr in FracZ format
int64_t fracz_group_ = 1;
bool is_top_graph_param_ = false;
};
using ParameterPtr = std::shared_ptr<Parameter>;
// Value is used to represent the atomic expression mentioned in BNF.
// It mainly be stored in ValueNode. Value and ValueNode is related definition.
class MS_CORE_API Value : public Base {
public:
/// \brief Default constructor.
Value() = default;
/// \brief Constructor of Value.
///
/// \param[in] t The type of this Value.
explicit Value(const TypePtr t) : type_(t) {}
/// \brief Constructor of Value.
///
/// \param[in] other Another Value.
Value(const Value &other) : Base(other) { this->type_ = other.type_; }
/// \brief Destructor.
~Value() override = default;
MS_DECLARE_PARENT(Value, Base)
/// \brief Get the type of this Value.
///
/// \return The type.
TypePtr type() const { return type_; }
/// \brief Get the abstract value of Value.
///
/// \return Abstract value of Value.
virtual abstract::AbstractBasePtr ToAbstract() {
MS_LOG(EXCEPTION) << "ToAbstract error";
abstract::AbstractBasePtr result;
return result;
}
/// \brief Check whether the input is the current Value object.
///
/// \param[in] rhs The Value object to be compared.
/// \return Whether the input is the current Value object.
virtual bool operator==(const Value &rhs) const = 0;
/// \brief Check whether the input is the current Value object.
///
/// \param[in] other The Value object to be compared.
/// \return Whether the input is the current Value object.
virtual Value &operator=(const Value &other) {
if (&other == this) {
return *this;
}
this->type_ = other.type_;
return *this;
}
protected:
TypePtr type_{nullptr};
};
// ValueNode is used to hold value. Unlike CNode and Parameter, ValueNode
// does not belong to any particular function graph.
class MS_CORE_API ValueNode final : public ANode {
public:
/// \brief Constructor of ValueNode.
///
/// \param[in] value The value of this ValueNode.
explicit ValueNode(const ValuePtr &value) : value_(value) {}
/// \brief Constructor of ValueNode.
///
/// \param[in] value The value of this ValueNode.
/// \param[in] debug_info The debug info to be used for this ValueNode.
ValueNode(const ValuePtr &value, NodeDebugInfoPtr &&debug_info)
: ANode(nullptr, std::move(debug_info)), value_(value) {}
/// \brief Destructor.
~ValueNode() override = default;
MS_DECLARE_PARENT(ValueNode, ANode);
void set_func_graph(const FuncGraphPtr &func_graph) override {
MS_EXCEPTION(ValueError) << "ValueNode should not set its func_graph.";
}
void accept(AnfIrVisitor *v) override;
/// \brief Set the value of this ValueNode.
///
/// \param[in] value The value.
void set_value(const ValuePtr &value) { value_ = value; }
/// \brief Get the value of this ValueNode.
///
/// \return The value.
const ValuePtr &value() const { return value_; }
std::string fullname_with_scope() override;
/// \brief Set whether this ValueNode has a new value.
///
/// \param[in] flag Whether this ValueNode has a new value.
void set_has_new_value(bool flag) { has_new_value_ = flag; }
/// \brief Check whether this ValueNode has a new value.
///
/// \return Whether this ValueNode has a new value.
bool has_new_value() const { return has_new_value_; }
/// \brief Get the count of graphs using this ValueNode.
///
/// \return The count of graphs using this ValueNode.
size_t used_graph_count() const { return used_graph_count_; }
/// \brief Set the count of graphs using this ValueNode.
///
/// \param[in] used_graph_count The count of graphs using this ValueNode.
void set_used_graph_count(size_t used_graph_count) { used_graph_count_ = used_graph_count; }
std::string ToString() const override;
std::string DebugString(int recursive_level = 1) const override;
std::string DebugString(bool recursive) const override { return DebugString(recursive ? 1 : 0); }
bool operator==(const AnfNode &other) const override {
if (!other.isa<ValueNode>()) {
return false;
}
auto v = static_cast<const ValueNode &>(other);
return *v.value() == *value();
}
friend std::ostream &operator<<(std::ostream &os, const ValueNodePtr &node) {
MS_EXCEPTION_IF_NULL(node);
os << node->ToString();
return os;
}
private:
ValuePtr value_;
bool has_new_value_ = false;
size_t used_graph_count_{0};
};
template <typename T>
struct ImmTraits {};
#define IMM_TRAITS(typeimm, prototype) \
template <> \
struct ImmTraits<prototype> { \
using type = typeimm; \
};
inline ValuePtr MakeValue(const ValuePtr &value) { return value; }
template <typename S, typename U = typename ImmTraits<S>::type::element_type>
inline ValuePtr MakeValue(S v) {
return std::make_shared<U>(v);
}
template <typename S, typename U = typename ImmTraits<S>::type>
static S GetValue(const ValuePtr &value) {
MS_EXCEPTION_IF_NULL(value);
U imm = value->cast<U>();
if (imm == nullptr) {
MS_LOG(EXCEPTION) << "Cast failed, original value: " << value->ToString() << ", type: " << value->type_name();
}
return imm->value();
}
template <typename S,
typename std::enable_if<is_shared_ptr<S>::value && std::is_base_of<Value, typename S::element_type>::value,
S>::type * = nullptr>
static S GetValue(const ValuePtr &value) {
MS_EXCEPTION_IF_NULL(value);
S v = value->cast<S>();
if (v == nullptr) {
MS_LOG(EXCEPTION) << "Cast failed, original value: " << value->ToString() << ", type: " << value->type_name();
}
return v;
}
std::string GetCNodeFuncName(CNodePtr cnode);
// used to get FuncGraphPtr from a cnode first input
FuncGraphPtr GetCNodeFuncGraph(const AnfNodePtr &node);
// used to check whether an AnfNode is a cnode with a kind of Primitive as first input
bool IsPrimitiveCNode(const AnfNodePtr &node, const PrimitivePtr &value = nullptr);
// used to get PrimitivePtr from a cnode first input
PrimitivePtr GetCNodePrimitive(const AnfNodePtr &node);
/// \brief Used to check whether the given node is a ValueNode with some Primitive value.
///
/// \param[in] node The input node.
/// \param[in] value Primitive value.
/// \return Whether the given node is a ValueNode with some Primitive value.
MS_CORE_API bool IsPrimitive(const AnfNodePtr &node, const PrimitivePtr &value);
// Check whether the given node is a ValueNode belonging to a primitive set.
bool IsOneOfPrimitive(const AnfNodePtr &node, const PrimitiveSet &prim_set);
/// \brief Used to check whether the given node is a CNode belonging to a primitive set.
///
/// \param[in] node The input node.
/// \param[in] prim_set Primitive set.
/// \return Whether the given node is a CNode belonging to a primitive set.
MS_CORE_API bool IsOneOfPrimitiveCNode(const AnfNodePtr &node, const PrimitiveSet &prim_set);
// Check whether two primitives are same.
bool IsPrimitiveEquals(const PrimitivePtr &prim1, const PrimitivePtr &prim2);
// Get number of AbstractMonad
size_t GetAbstractMonadNum(const AbstractBasePtrList &args);
// Check whether the given node has monad abstract.
bool HasAbstractMonad(const AnfNodePtr &node);
// Check whether the given node has U monad abstract.
bool HasAbstractUMonad(const AnfNodePtr &node);
// Check whether the given node has IO monad abstract.
bool HasAbstractIOMonad(const AnfNodePtr &node);
// Gets primitive attribute value as a bool flag.
bool GetPrimitiveFlag(const PrimitivePtr &prim, const std::string &attr);
// Gets effect info from a primitive by its attributes.
EffectInfo GetPrimEffectInfo(const PrimitivePtr &prim);
struct MonadState {
AnfNodePtr u{nullptr};
AnfNodePtr io{nullptr};
};
// Get Memory/IO monad state from node.
MonadState GetMonadState(const AnfNodePtr &node, const AnfNodePtr &skip_input = nullptr);
// Check if two state is equivalent.
bool IsStateEquivalent(const MonadState &state1, const MonadState &state2);
// Check if monad state is strict equivalent for the connected two nodes.
bool IsStateStrictEquivalent(const AnfNodePtr &outer, const AnfNodePtr &inner);
// Check if monad state is equivalent for the connected two nodes, not strict but more faster.
bool IsStateEquivalent(const AnfNodePtr &outer, const AnfNodePtr &inner);
// used to check whether a ValueNode has some kind of value
template <typename T>
static bool IsValueNode(const AnfNodePtr &node) {
MS_EXCEPTION_IF_NULL(node);
auto anode = node->cast<ValueNodePtr>();
if (anode != nullptr) {
auto value = anode->value();
if (value == nullptr) {
MS_LOG(EXCEPTION) << "Const value is nullptr.";
}
return value->isa<T>();
}
return false;
}
inline ValuePtr GetValueNode(const AnfNodePtr &node) {
MS_EXCEPTION_IF_NULL(node);
if (!node->isa<ValueNode>()) {
return nullptr;
}
return node->cast<ValueNodePtr>()->value();
}
template <typename S,
typename std::enable_if<is_shared_ptr<S>::value && std::is_base_of<Value, typename S::element_type>::value,
S>::type * = nullptr>
inline S GetValueNode(const AnfNodePtr &node) {
auto value = GetValueNode(node);
if (value == nullptr) {
return nullptr;
}
auto s = value->cast<S>();
return s;
}
size_t NewSeenGeneration();
namespace id_generator {
std::string get_id(const AnfNodePtr &node);
void reset_id();
} // namespace id_generator
using TaggedNodeMap = std::unordered_map<AnfNodePtr, size_t>;
using TaggedGraph = std::pair<FuncGraphPtr, TaggedNodeMap>;
std::string GetCNodeTarget(const AnfNodePtr &node);
std::string GetOriginNodeTarget(const AnfNodePtr &node);
bool ContainMultiTarget(const std::vector<AnfNodePtr> &nodes);
struct GraphSegment {
GraphSegment(const std::vector<AnfNodePtr> &nodes, bool is_cut) : nodes_(nodes), is_cut_(is_cut) {}
void AddPreSegment(const std::shared_ptr<GraphSegment> &segment) { (void)pre_segments_.insert(segment); }
std::vector<AnfNodePtr> nodes_;
std::set<std::shared_ptr<GraphSegment>> pre_segments_;
bool is_cut_{false};
uint32_t graph_id_{0};
};
using GraphSegmentPtr = std::shared_ptr<GraphSegment>;
} // namespace mindspore
#endif // MINDSPORE_CORE_IR_ANF_H_