1f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
3f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlowerLicensed under the Apache License, Version 2.0 (the "License");
4f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFloweryou may not use this file except in compliance with the License.
5f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlowerYou may obtain a copy of the License at
6f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
7f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    http://www.apache.org/licenses/LICENSE-2.0
8f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
9f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlowerUnless required by applicable law or agreed to in writing, software
10f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlowerdistributed under the License is distributed on an "AS IS" BASIS,
11f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlowerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlowerSee the License for the specific language governing permissions and
13f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlowerlimitations under the License.
14f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower==============================================================================*/
15f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
16f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower#include "tensorflow/core/graph/control_flow.h"
17f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
18f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower#include <deque>
19f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower#include <vector>
20f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
21f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower#include "tensorflow/core/framework/types.h"
22f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower#include "tensorflow/core/graph/node_builder.h"
23f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower#include "tensorflow/core/lib/core/errors.h"
24f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
25f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlowernamespace tensorflow {
26f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
27f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlowerStatus BuildControlFlowInfo(Graph* g, std::vector<ControlFlowInfo>* info) {
28f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  info->clear();
29f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  info->resize(g->num_node_ids());
30f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
31f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  std::vector<const Node*> parent_nodes;
32f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  parent_nodes.resize(g->num_node_ids());
33f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
34f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  Node* src_node = g->source_node();
35f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  ControlFlowInfo& src_info = (*info)[src_node->id()];
36f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  src_info.frame = src_node;
37f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  src_info.parent_frame = src_node;
38f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
39f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  string frame_name;
40f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  std::deque<Node*> ready;
41f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  ready.push_back(src_node);
42f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  while (!ready.empty()) {
43f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    Node* curr_node = ready.front();
44f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    ready.pop_front();
45f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    const ControlFlowInfo& curr_info = (*info)[curr_node->id()];
46f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    const Node* frame = curr_info.frame;
47f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    const Node* parent = curr_info.parent_frame;
48f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    frame_name = curr_info.frame_name;
49f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
50f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    if (IsExit(curr_node)) {
51f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      // Exit to the parent frame.
52f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      const ControlFlowInfo& parent_info = (*info)[parent->id()];
53f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      frame = parent_info.frame;
54f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      parent = parent_info.parent_frame;
55f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      frame_name = parent_info.frame_name;
56f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    }
57f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
58f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    for (const Edge* out_edge : curr_node->out_edges()) {
59f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      Node* out = out_edge->dst();
60f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      int out_id = out->id();
61f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      ControlFlowInfo* out_info = &(*info)[out_id];
62f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      const Node* out_parent = out_info->parent_frame;
63f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      bool is_visited = (parent_nodes[out_id] != nullptr);
64f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
65f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      // Skip Sink/Source nodes.
66f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      if (!out->IsOp()) continue;
67f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
68f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      // Add to ready queue if not seen.
69f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      if (!is_visited) {
70f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower        parent_nodes[out->id()] = curr_node;
71f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower        ready.push_back(out);
72f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      }
73f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
74f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      // Process the node 'out'.
75f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      if (IsEnter(out)) {
76f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower        if (is_visited) {
77f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          const string& parent_frame = (*info)[out_parent->id()].frame_name;
78f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          if (parent_frame != frame_name) {
79f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower            return errors::InvalidArgument(
80f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "The node '", out->name(),
81f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "' has inputs from different "
82f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "frames. The input '",
83f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                curr_node->name(), "' is in frame '", frame_name,
84f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "'. The input '", parent_nodes[out->id()]->name(),
85f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "' is in frame '", parent_frame, "'.");
86f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          }
87f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower        } else {
88f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          out_info->frame = out;
89f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          out_info->parent_frame = frame;
90f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          TF_RETURN_IF_ERROR(
9173882f257ffb1bc9e1a828571c085d080b1d9266Geoffrey Irving              GetNodeAttr(out->attrs(), "frame_name", &out_info->frame_name));
92f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          if (out_info->frame_name.empty()) {
93f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower            return errors::InvalidArgument("The Enter node ", out->name(),
94f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                                           " must have a frame name.");
95f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          }
96f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower        }
97f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      } else {
98f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower        if (is_visited) {
99f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          if (out_info->frame_name != frame_name) {
100f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower            return errors::InvalidArgument(
101f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "The node '", out->name(),
102f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "' has inputs from different "
103f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "frames. The input '",
104f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                curr_node->name(), "' is in frame '", frame_name,
105f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "'. The input '", parent_nodes[out->id()]->name(),
106f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower                "' is in frame '", out_info->frame_name, "'.");
107f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          }
108f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower        } else {
109f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          out_info->frame = frame;
110f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          out_info->parent_frame = parent;
111f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower          out_info->frame_name = frame_name;
112f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower        }
113f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower      }
114f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower    }
115f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  }
116f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower  return Status::OK();
117f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower}
118f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower
119f26dcdc819e903267cb03c33c2f09876d0003f52A. Unique TensorFlower}  // namespace tensorflow
120