| 1348 | } |
| 1349 | |
| 1350 | Status ConstantFolding::FoldMergeNode(NodeDef* node, GraphDef* output_graph) { |
| 1351 | // Merge nodes are special, in the sense that they execute as soon as one of |
| 1352 | // their input is ready. We can therefore fold a merge node iff it has at |
| 1353 | // least one constant input without control dependency. |
| 1354 | // We still need to ensure that the nodes in the fanin of the merge node are |
| 1355 | // scheduled. We'll therefore add a control dependency from the merge node |
| 1356 | // to the folded constant. We end up with: |
| 1357 | // * the merge node and its inputs are preserved as is |
| 1358 | // * a new constant node C1, driven by the merge node through a control |
| 1359 | // dependency, initialized to the value of the folded input |
| 1360 | // * a new constant node C2, driven by the merge node through a control |
| 1361 | // dependency, initialized to the index of the folded input |
| 1362 | // * the fanout of the merge nodes is rewired to be driven by either C1 or |
| 1363 | // C2. |
| 1364 | for (int input_index = 0; input_index < node->input_size(); ++input_index) { |
| 1365 | const auto& input = node->input(input_index); |
| 1366 | if (IsControlInput(input)) { |
| 1367 | // Try the next input. |
| 1368 | continue; |
| 1369 | } |
| 1370 | NodeDef* input_node = node_map_->GetNode(input); |
| 1371 | if (!IsReallyConstant(*input_node)) { |
| 1372 | continue; |
| 1373 | } |
| 1374 | bool valid_input = true; |
| 1375 | for (const string& fanin_of_input : input_node->input()) { |
| 1376 | if (IsControlInput(fanin_of_input)) { |
| 1377 | valid_input = false; |
| 1378 | break; |
| 1379 | } |
| 1380 | } |
| 1381 | if (!valid_input) { |
| 1382 | // Try the next input |
| 1383 | continue; |
| 1384 | } |
| 1385 | |
| 1386 | string const_out_name = OptimizedNodeName(*node, "_const"); |
| 1387 | string const_index_name = OptimizedNodeName(*node, "_index"); |
| 1388 | if (node_map_->GetNode(const_out_name) || |
| 1389 | node_map_->GetNode(const_index_name)) { |
| 1390 | // Intended name already exists. |
| 1391 | return errors::AlreadyExists( |
| 1392 | strings::StrCat(const_out_name, " or ", const_index_name, |
| 1393 | " already present in the graph")); |
| 1394 | } |
| 1395 | |
| 1396 | NodeDef* const_out = output_graph->add_node(); |
| 1397 | *const_out = *input_node; |
| 1398 | const_out->set_name(const_out_name); |
| 1399 | const_out->set_device(node->device()); |
| 1400 | *const_out->add_input() = AsControlDependency(*node); |
| 1401 | node_map_->AddNode(const_out->name(), const_out); |
| 1402 | node_map_->AddOutput(node->name(), const_out->name()); |
| 1403 | |
| 1404 | NodeDef* const_index = output_graph->add_node(); |
| 1405 | const_index->set_op("Const"); |
| 1406 | Tensor index(DT_INT32, TensorShape({})); |
| 1407 | index.flat<int32>()(0) = input_index; |
nothing calls this directly
no test coverage detected