| 84 | } // namespace |
| 85 | |
| 86 | Status BuildControlFlowInfo(const Graph* g, std::vector<ControlFlowInfo>* info, |
| 87 | std::vector<string>* unreachable_nodes) { |
| 88 | info->clear(); |
| 89 | info->resize(g->num_node_ids()); |
| 90 | |
| 91 | std::vector<const Node*> parent_nodes; |
| 92 | parent_nodes.resize(g->num_node_ids()); |
| 93 | |
| 94 | const Node* src_node = g->source_node(); |
| 95 | ControlFlowInfo& src_info = (*info)[src_node->id()]; |
| 96 | src_info.frame = src_node; |
| 97 | src_info.parent_frame = src_node; |
| 98 | |
| 99 | string frame_name; |
| 100 | std::deque<const Node*> ready; |
| 101 | ready.push_back(src_node); |
| 102 | while (!ready.empty()) { |
| 103 | const Node* curr_node = ready.front(); |
| 104 | ready.pop_front(); |
| 105 | const ControlFlowInfo& curr_info = (*info)[curr_node->id()]; |
| 106 | const Node* frame = curr_info.frame; |
| 107 | const Node* parent = curr_info.parent_frame; |
| 108 | frame_name = curr_info.frame_name; |
| 109 | |
| 110 | if (IsExit(curr_node)) { |
| 111 | // Exit to the parent frame. |
| 112 | const ControlFlowInfo& parent_info = (*info)[parent->id()]; |
| 113 | frame = parent_info.frame; |
| 114 | parent = parent_info.parent_frame; |
| 115 | frame_name = parent_info.frame_name; |
| 116 | } |
| 117 | |
| 118 | for (const Edge* out_edge : curr_node->out_edges()) { |
| 119 | const Node* out = out_edge->dst(); |
| 120 | int out_id = out->id(); |
| 121 | ControlFlowInfo* out_info = &(*info)[out_id]; |
| 122 | const Node* out_parent = out_info->parent_frame; |
| 123 | bool is_visited = (parent_nodes[out_id] != nullptr); |
| 124 | |
| 125 | // Skip Sink/Source nodes. |
| 126 | if (!out->IsOp()) continue; |
| 127 | |
| 128 | // Add to ready queue if not seen. |
| 129 | if (!is_visited) { |
| 130 | parent_nodes[out->id()] = curr_node; |
| 131 | ready.push_back(out); |
| 132 | } |
| 133 | |
| 134 | // Process the node 'out'. |
| 135 | if (IsEnter(out)) { |
| 136 | if (is_visited) { |
| 137 | const string& parent_frame = (*info)[out_parent->id()].frame_name; |
| 138 | if (parent_frame != frame_name) { |
| 139 | return errors::InvalidArgument( |
| 140 | FormatNodeForError(*out), |
| 141 | " has inputs from different frames. The input ", |
| 142 | FormatNodeForError(*curr_node), " is in frame '", frame_name, |
| 143 | "'. The input ", FormatNodeForError(*parent_nodes[out->id()]), |