For a "While" node in graph `g`, if it has Const node inputs, rewrite its cond/body function to replace _Arg nodes with those Const inputs.
| 245 | // For a "While" node in graph `g`, if it has Const node inputs, rewrite its |
| 246 | // cond/body function to replace _Arg nodes with those Const inputs. |
| 247 | Status PropagateConstIntoWhileNode(Graph* g, Node* while_node, |
| 248 | const FunctionLibraryDefinition* lookup_fld, |
| 249 | FunctionLibraryDefinition* fld) { |
| 250 | // For "While" node, we should only replace _Arg nodes which are loop |
| 251 | // invariants. For such _Arg nodes, the return value's input will come |
| 252 | // directly from the corresponding arg. |
| 253 | std::unordered_map<int, const Node*> const_input_index_to_node; |
| 254 | NameAttrList body_attr; |
| 255 | TF_RETURN_IF_ERROR(GetNodeAttr(while_node->def(), "body", &body_attr)); |
| 256 | const FunctionDef* body_func = lookup_fld->Find(body_attr.name()); |
| 257 | if (!body_func) { |
| 258 | return errors::Internal("Cannot find body function ", body_attr.name(), |
| 259 | " for While node ", while_node->name()); |
| 260 | } |
| 261 | for (int i = 0; i < while_node->num_inputs(); i++) { |
| 262 | const Node* input_node; |
| 263 | TF_RETURN_IF_ERROR(while_node->input_node(i, &input_node)); |
| 264 | if (input_node->type_string() != "Const") { |
| 265 | continue; |
| 266 | } |
| 267 | |
| 268 | // Check if i-th retval's input comes from i-th arg directly. |
| 269 | // For resource variable input of While nodes, TF2XLA convention is to place |
| 270 | // them at the end of all inputs (after all data inputs), and *not* return |
| 271 | // them. So number of While node inputs might be larger than number of its |
| 272 | // outputs. |
| 273 | if (i >= body_func->signature().output_arg_size()) { |
| 274 | continue; |
| 275 | } |
| 276 | const OpDef_ArgDef& output_arg = body_func->signature().output_arg(i); |
| 277 | auto output_arg_input = body_func->ret().find(output_arg.name()); |
| 278 | if (output_arg_input == body_func->ret().end()) { |
| 279 | return errors::Internal("Cannot find input for output arg ", |
| 280 | output_arg.name(), " in function ", |
| 281 | body_attr.name()); |
| 282 | } |
| 283 | const OpDef_ArgDef& input_arg = body_func->signature().input_arg(i); |
| 284 | if (output_arg_input->second != input_arg.name()) { |
| 285 | continue; |
| 286 | } |
| 287 | |
| 288 | const_input_index_to_node[i] = input_node; |
| 289 | } |
| 290 | if (const_input_index_to_node.empty()) { |
| 291 | return Status::OK(); |
| 292 | } |
| 293 | |
| 294 | // Rewrite "cond" and "body" function, replace usage of those _Arg nodes with |
| 295 | // corresponding const node. |
| 296 | for (const auto& attr_name : std::vector<string>{"cond", "body"}) { |
| 297 | TF_RETURN_IF_ERROR(PropagateConstIntoFuncAttr( |
| 298 | while_node, attr_name, const_input_index_to_node, lookup_fld, fld)); |
| 299 | } |
| 300 | return Status::OK(); |
| 301 | } |
| 302 | |
| 303 | } // namespace |
| 304 |
no test coverage detected