!22946 Handle if break else break situation of control flow

Merge pull request !22946 from chenfei_mindspore/pr_dead_block
This commit is contained in:
i-robot 2021-09-08 12:32:23 +00:00 committed by Gitee
commit 7978aae666
3 changed files with 43 additions and 10 deletions

View File

@ -97,6 +97,7 @@ void FunctionBlock::WriteVariable(const std::string &var_name, const AnfNodePtr
// Read variable from predecessors
AnfNodePtr FunctionBlock::ReadVariable(const std::string &var) {
MS_LOG(DEBUG) << "Read begin, var: " << var << ", block id: " << func_graph_->debug_info()->debug_id();
// Get var node if it is found
auto found = assigned_vars_.find(var);
if (found != assigned_vars_.end()) {
@ -202,6 +203,7 @@ AnfNodePtr FunctionBlock::HandleNamespaceInfo(const py::tuple &namespace_info) {
// Make a resolve node for symbol string
AnfNodePtr FunctionBlock::MakeResolveSymbol(const std::string &value) {
MS_LOG(DEBUG) << "value: " << value;
if (value.compare(0, strlen("self"), "self") == 0) {
auto start = value.find_first_of('.') + 1;
if (start >= value.size()) {
@ -287,12 +289,11 @@ void FunctionBlock::SetPhiArgument(const ParameterPtr &phi) {
AnfNodePtr FunctionBlock::SearchReplaceNode(const std::string &var, const ParameterPtr &phi) {
AnfNodePtr arg_node = nullptr;
MS_LOG(DEBUG) << "Prev_blocks size: " << prev_blocks_.size();
for (auto &prev : prev_blocks_) {
MS_EXCEPTION_IF_NULL(prev);
AnfNodePtr temp_node = prev->ReadVariable(var);
MS_EXCEPTION_IF_NULL(temp_node);
MS_LOG(DEBUG) << "graph " << (prev->func_graph_ ? prev->func_graph_->ToString() : "FG(Null)") << " phi "
<< (phi ? phi->ToString() : "null") << " for var " << var << " is " << temp_node->DebugString();
if (temp_node != phi) {
if (arg_node == nullptr) {
arg_node = temp_node;
@ -401,7 +402,14 @@ CNodePtr FunctionBlock::ForceToWhileCond(const AnfNodePtr &cond) {
// Perform a jump from this block to target block
void FunctionBlock::Jump(const FunctionBlockPtr &target_block, const std::vector<AnfNodePtr> &args) {
MS_LOG(DEBUG) << "Jump from " << func_graph_->debug_info()->debug_id() << " to "
<< target_block->func_graph()->debug_info()->debug_id();
MS_EXCEPTION_IF_NULL(target_block);
if (is_dead_block_) {
MS_LOG(DEBUG) << "Dead code block should not jump to other block! Block id:"
<< func_graph_->debug_info()->debug_id();
return;
}
if (func_graph_->get_return() != nullptr) {
MS_LOG(EXCEPTION) << "Failure: have return node! NodeInfo: "
<< trace::GetDebugInfo(func_graph_->get_return()->debug_info());
@ -536,5 +544,7 @@ void FunctionBlock::AttachIsolatedNodesBeforeReturn() {
<< ", state: " << state->DebugString(2);
func_graph_->set_output(depend_node, true);
}
void FunctionBlock::SetAsDeadBlock() { is_dead_block_ = true; }
} // namespace parse
} // namespace mindspore

View File

@ -46,7 +46,7 @@ using FunctionBlockPtr = std::shared_ptr<FunctionBlock>;
class FunctionBlock : public std::enable_shared_from_this<FunctionBlock> {
public:
explicit FunctionBlock(const Parser &parser);
virtual ~FunctionBlock() {}
virtual ~FunctionBlock() = default;
FuncGraphPtr func_graph() { return func_graph_; }
void WriteVariable(const std::string &var_name, const AnfNodePtr &node);
@ -78,6 +78,9 @@ class FunctionBlock : public std::enable_shared_from_this<FunctionBlock> {
void FindIsolatedNodes();
void AddIsolatedNode(const AnfNodePtr &target);
void AttachIsolatedNodesBeforeReturn();
const std::vector<FunctionBlock *> &prev_blocks() const { return prev_blocks_; }
bool is_dead_block() const { return is_dead_block_; }
void SetAsDeadBlock();
py::dict &global_py_params() { return global_py_params_; }
void set_global_py_params(const py::dict &symbols) { global_py_params_ = symbols; }
@ -138,6 +141,16 @@ class FunctionBlock : public std::enable_shared_from_this<FunctionBlock> {
// Isolated nodes.
OrderedSet<AnfNodePtr> isolated_nodes_;
// If a block can never be executed, it's prev blocks will be empty, so this block is a dead block.
// while x > 5:
// x = x - 2
// if x > 7 :
// break
// else :
// break
// x = x - 1 #This after block is a dead block
bool is_dead_block_{false};
};
class ScriptInfo {

View File

@ -166,7 +166,8 @@ void CheckFuncReturn(const FuncGraphPtr &fn, const std::shared_ptr<ParseFunction
}
py::str desc =
python_adapter::CallPyModFn(ast->module(), PYTHON_MOD_GET_OBJECT_DESCRIPTION, ast->function(), ret[0], ret[1]);
MS_EXCEPTION(TypeError) << "Missing return statement in " << desc.cast<std::string>() << ".";
MS_EXCEPTION(TypeError) << "Missing return statement in " << desc.cast<std::string>() << ". "
<< "Func graph id: " << func_graph->debug_info()->debug_id();
}
}
@ -325,11 +326,17 @@ FunctionBlockPtr Parser::ParseStatements(FunctionBlockPtr block, const py::objec
size_t count = py::len(node_list);
MS_LOG(DEBUG) << "The nodes count is " << count;
for (size_t i = 0; i < count; ++i) {
MS_LOG(DEBUG) << "Start parse statement[" << i << "]: " << py::str(node_list[i]);
auto node = node_list[i];
block = ParseStatement(block, node);
MS_EXCEPTION_IF_NULL(block);
// Insert appropriate depended items for the function block if it has a return node
if (block->func_graph()->get_return() != nullptr) {
if (block->func_graph()->get_return() != nullptr || block->is_dead_block()) {
// If break is not the last expr.
if (i != count - 1) {
TraceGuard trace_guard(GetLocation(node_list[i + 1]));
MS_LOG(EXCEPTION) << "Dead code exist, please remove it.";
}
// Skip statements after 'return' (or 'break', 'continue').
break;
}
@ -361,7 +368,7 @@ FunctionBlockPtr Parser::ParseStatement(const FunctionBlockPtr &block, const py:
}
AnfNodePtr Parser::ParseExprNode(const FunctionBlockPtr &block, const py::object &node) {
MS_LOG(DEBUG) << "Process ast expr";
MS_LOG(DEBUG) << "Process ast expr.";
TraceGuard trace_guard(GetLocation(node));
auto node_type = ast_->GetNodeType(node);
// Check the node type
@ -1063,7 +1070,6 @@ FunctionBlockPtr Parser::ParseAugAssign(const FunctionBlockPtr &block, const py:
MS_LOG(DEBUG) << "Process ast AugAssign";
MS_EXCEPTION_IF_NULL(block);
MS_EXCEPTION_IF_NULL(ast_);
py::object target_obj = python_adapter::GetPyObjAttr(node, "target");
py::object op_obj = python_adapter::GetPyObjAttr(node, "op");
py::object value_obj = python_adapter::GetPyObjAttr(node, "value");
@ -1086,6 +1092,7 @@ FunctionBlockPtr Parser::ParseAugAssign(const FunctionBlockPtr &block, const py:
}
CNodePtr augassign_app = block->func_graph()->NewCNodeInOrder({op_node, target_node, value_node});
WriteAssignVars(block, target_obj, augassign_app);
return block;
}
// Process global declaration such as 'global x';
@ -1139,6 +1146,7 @@ FunctionBlockPtr Parser::ParseIf(const FunctionBlockPtr &block, const py::object
// If the return_ is set, it has its own continuation block
if (true_end->func_graph()->get_return() == nullptr) {
MS_LOG(DEBUG) << "true end jump to after.";
true_end->Jump(after_block, {});
}
@ -1148,10 +1156,14 @@ FunctionBlockPtr Parser::ParseIf(const FunctionBlockPtr &block, const py::object
// If the return_ is set, it has its own continuation block
if (false_end->func_graph()->get_return() == nullptr) {
MS_LOG(DEBUG) << "false_end jump to after.";
false_end->Jump(after_block, {});
}
block->ConditionalJump(bool_node, true_block, false_block);
if (after_block->prev_blocks().empty()) {
after_block->SetAsDeadBlock();
}
after_block->Mature();
return after_block;
}
@ -1159,7 +1171,6 @@ FunctionBlockPtr Parser::ParseIf(const FunctionBlockPtr &block, const py::object
FunctionBlockPtr Parser::ParseWhile(const FunctionBlockPtr &block, const py::object &node) {
MS_LOG(DEBUG) << "Process ast While";
MS_EXCEPTION_IF_NULL(block);
MS_LOG(INFO) << "Parse while statement";
FunctionBlockPtr header_block = nullptr;
FunctionBlockPtr body_block = nullptr;
FunctionBlockPtr after_block = nullptr;
@ -1193,12 +1204,11 @@ FunctionBlockPtr Parser::ParseWhile(const FunctionBlockPtr &block, const py::obj
if (after_body->func_graph()->get_return() == nullptr) {
after_body->Jump(header_block, {});
}
header_block->Mature();
after_block->Mature();
auto &end_block = loop_context.EndBlock();
// end_block exists if we encounter 'break' in loop body.
if (end_block) {
// end_block exists if we encounter 'break' in loop body.
after_block->Jump(end_block, {});
end_block->Mature();
return end_block;