• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * This is the C++ adaptation and derivative work of Myia (https://github.com/mila-iqia/myia/).
3  *
4  * Copyright 2019-2021 Huawei Technologies Co., Ltd
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #ifndef MINDSPORE_CCSRC_PIPELINE_JIT_PARSE_FUNCTION_BLOCK_H_
20 #define MINDSPORE_CCSRC_PIPELINE_JIT_PARSE_FUNCTION_BLOCK_H_
21 
22 #include <vector>
23 #include <string>
24 #include <map>
25 #include <set>
26 #include <unordered_map>
27 #include <memory>
28 #include <utility>
29 #include <tuple>
30 #include "pipeline/jit/parse/parse_base.h"
31 #include "utils/log_adapter.h"
32 #include "utils/ordered_set.h"
33 
34 namespace mindspore {
35 namespace parse {
36 class Parser;
37 class NameSpace;
38 class Symbol;
39 class Script;
40 class FunctionBlock;
41 using FunctionBlockPtr = std::shared_ptr<FunctionBlock>;
42 
43 // A function block is a straight-line code sequence with no branches, every block has one one exit point
44 // which is return. When parsing function, loop or branch , we use function block to track the structure of
45 // the original source code.
46 class FunctionBlock : public std::enable_shared_from_this<FunctionBlock> {
47  public:
48   explicit FunctionBlock(const Parser &parser);
49   virtual ~FunctionBlock() = default;
50 
func_graph()51   FuncGraphPtr func_graph() { return func_graph_; }
ToString()52   std::string ToString() const { return func_graph_->ToString(); }
53   void WriteVariable(const std::string &var_name, const AnfNodePtr &node);
54   AnfNodePtr ReadVariable(const std::string &var_name);
55   void AddPrevBlock(const FunctionBlockPtr &block);
56   void SetPhiArgument(const ParameterPtr &phi);
57   bool CollectRemovablePhi(const ParameterPtr &phi);
58   // A block is matured if all its predecessors is generated
59   void Mature();
60   CNodePtr ForceToBoolNode(const AnfNodePtr &cond);
61   CNodePtr ForceToWhileCond(const AnfNodePtr &cond);
62   void Jump(const FunctionBlockPtr &block, const std::vector<AnfNodePtr> &args);
63   AnfNodePtr SearchReplaceNode(const std::string &var, const ParameterPtr &phi);
64   void ConditionalJump(AnfNodePtr condNode, const FunctionBlockPtr &trueBlock, const FunctionBlockPtr &falseBlock,
65                        bool unroll_loop = true);
66   // Create cnode for the assign statement like self.target = source.
67   void SetStateAssign(const AnfNodePtr &target, const AnfNodePtr &source);
AddGlobalVar(const std::string & var_name)68   void AddGlobalVar(const std::string &var_name) { (void)global_vars_.insert(var_name); }
IsGlobalVar(const std::string & var_name)69   bool IsGlobalVar(const std::string &var_name) { return global_vars_.find(var_name) != global_vars_.end(); }
70   AnfNodePtr MakeResolveAstOp(const py::object &op);
71   AnfNodePtr MakeResolveClassMember(const std::string &attr);
72   AnfNodePtr MakeResolveSymbol(const std::string &value);
73   AnfNodePtr MakeResolveOperation(const std::string &value);
74   AnfNodePtr MakeResolve(const std::shared_ptr<NameSpace> &name_space, const std::shared_ptr<Symbol> &resolve_symbol);
75   AnfNodePtr HandleNamespaceInfo(const py::tuple &namespace_info);
76   AnfNodePtr MakeInterpret(const std::string &script_text, const AnfNodePtr &global_dict_node,
77                            const AnfNodePtr &local_dict_node, const AnfNodePtr &orig_node);
removable_phis()78   const std::unordered_map<ParameterPtr, AnfNodePtr> &removable_phis() const { return removable_phis_; }
79   void FindIsolatedNodes();
80   void AddIsolatedNode(const AnfNodePtr &target);
81   void AttachIsolatedNodesBeforeReturn();
prev_blocks()82   const std::vector<FunctionBlock *> &prev_blocks() const { return prev_blocks_; }
is_dead_block()83   bool is_dead_block() const { return is_dead_block_; }
84   void SetAsDeadBlock();
85 
global_py_params()86   py::dict &global_py_params() { return global_py_params_; }
set_global_py_params(const py::dict & symbols)87   void set_global_py_params(const py::dict &symbols) { global_py_params_ = symbols; }
AddGlobalPyParam(const std::string & name,const py::object & obj)88   void AddGlobalPyParam(const std::string &name, const py::object &obj) { global_py_params_[py::str(name)] = obj; }
CopyGlobalPyParam(const py::dict & symbols)89   void CopyGlobalPyParam(const py::dict &symbols) {
90     for (auto &param : symbols) {
91       if (!global_py_params_.contains(param.first)) {
92         global_py_params_[param.first] = param.second;
93       }
94     }
95   }
96 
local_py_params()97   std::tuple<std::vector<AnfNodePtr>, std::vector<AnfNodePtr>> local_py_params() {
98     return {local_py_params_keys_, local_py_params_values_};
99   }
AddLocalPyParam(const std::string & name,const AnfNodePtr & node)100   void AddLocalPyParam(const std::string &name, const AnfNodePtr &node) {
101     local_py_params_keys_.emplace_back(NewValueNode(name));
102     local_py_params_values_.emplace_back(node);
103   }
104 
105  private:
106   // Block graph
107   FuncGraphPtr func_graph_;
108 
109   // Block parser
110   const Parser &parser_;
111 
112   // A block is matured if all its prev_blocks is processed
113   bool matured_;
114 
115   // Store the nest-level block.
116   // Refer to comments in Parser::func_block_list_;
117   std::vector<FunctionBlock *> prev_blocks_;
118 
119   // Store args and variable's node, use a bool flag to indicate if the variable is used.
120   std::map<std::string, std::pair<AnfNodePtr, bool>> assigned_vars_;
121 
122   // Map the parameter node to variable, it can be resolved if the block's predecessors are processed
123   std::map<ParameterPtr, std::string> phi_nodes_;
124 
125   // Jumps map the successor block and the function call that perform jump
126   // Refer to comments in Parser::func_block_list_ that how to break the cyclic reference
127   std::map<FunctionBlock *, CNodePtr> jumps_;
128 
129   // Keep all removable phis which will be removed in one pass.
130   std::unordered_map<ParameterPtr, AnfNodePtr> removable_phis_;
131 
132   // Keep the map for the resolve node to the removable phi node.
133   // For the case that ReadVariable returns a phi node although this phi node
134   // generated in the prev block is identified as removable. The other blocks
135   // should find this phi node.
136   std::unordered_map<AnfNodePtr, ParameterPtr> resolve_to_removable_phis_;
137 
138   // Hold declared global variables in function
139   std::set<std::string> global_vars_;
140 
141   // Keep new made resolve symbol for the variable not found in vars_.
142   std::unordered_map<std::string, AnfNodePtr> var_to_resolve_;
143 
144   // Collect all python symbols in the block.
145   // We treat both global symbols and local symbols declared previously as global symbols.
146   py::dict global_py_params_;
147   std::vector<AnfNodePtr> local_py_params_keys_;
148   std::vector<AnfNodePtr> local_py_params_values_;
149 
150   // Isolated nodes.
151   OrderedSet<AnfNodePtr> isolated_nodes_;
152 
153   // If a block can never be executed, it's prev blocks will be empty, so this block is a dead block.
154   // while x > 5:
155   //    x = x - 2
156   //    if x > 7 :
157   //         break
158   //    else :
159   //         break
160   //    x = x - 1   #This after block is a dead block
161   bool is_dead_block_{false};
162 };
163 
164 class ScriptInfo {
165  public:
ScriptInfo(const py::object & obj)166   explicit ScriptInfo(const py::object &obj) : py_obj_(obj) {}
167   ~ScriptInfo() = default;
168   // Key for user data.
169   constexpr static char key[] = "ScriptInfo";
170 
171   py::object py_obj_;
172 };
173 }  // namespace parse
174 }  // namespace mindspore
175 
176 #endif  // MINDSPORE_CCSRC_PIPELINE_JIT_PARSE_FUNCTION_BLOCK_H_
177