tensorflow/compiler/tf2xla/const_analysis.cc
// Backwards dataflow analysis that finds arguments to a graph that must be
// compile-time constants.
Backwards dataflow analysis that finds arguments to a graph that must be
compile-time constants.
Backwards dataflow analysis that finds arguments to a graph that must be compile - time constants .
Status BackwardsConstAnalysis(
    const Graph& g, std::vector<bool>* compile_time_const_arg_indices,
    std::vector<bool>* compile_time_const_nodes,
    FunctionLibraryRuntime* flib_runtime,
    std::function<bool(const Edge&)> edge_filter_input) {
  if (!compile_time_const_nodes && g.GetConstArgIndicesCache().has_value() &&
      !edge_filter_input) {
    VLOG(5) << "Using cached argument indices on graph " << &g;
    *compile_time_const_arg_indices = g.GetConstArgIndicesCache().value();
    return Status::OK();
  }
  auto edge_filter = [&](const Edge& e) {
    return edge_filter_input ? edge_filter_input(e) : true;
  };
  std::vector<bool> compile_time_const_nodes_impl;
  if (compile_time_const_nodes) {
    CHECK_EQ(compile_time_const_nodes->size(), g.num_node_ids());
  } else {
    compile_time_const_nodes_impl.resize(g.num_node_ids());
    compile_time_const_nodes = &compile_time_const_nodes_impl;
  }
  Status status;
  auto visit = [&](Node* node) {
    if (!status.ok()) return;
    if (XlaOpRegistry::IsMetadataOp(node->type_string())) {
      VLOG(3) << "must-be-const node is metadata op: " << node->name();
      return;
    }
    if ((*compile_time_const_nodes)[node->id()]) {
      VLOG(3) << "marking consts for must-be-const node " << node->name();
      if (node->type_string() == "_Arg") {
        int index;
        status = GetNodeAttr(node->attrs(), "index", &index);
        if (!status.ok()) return;
        if (compile_time_const_arg_indices) {
          (*compile_time_const_arg_indices)[index] = true;
        }
        VLOG(3) << "  const _Arg " << index << ": " << node->name();
        return;
      }
      for (const Edge* pred : node->in_edges()) {
        if (!pred->IsControlEdge() && edge_filter(*pred)) {
          while (edge_filter(*pred) && IsConstTraversableOpType(pred->src())) {
            status = pred->src()->input_edge(pred->src_output(), &pred);
            if (!status.ok()) return;
          }
          if (edge_filter(*pred)) {
            VLOG(4) << "  " << pred->src()->name() << " must be const (is "
                    << pred->src()->type_string() << ")";
            (*compile_time_const_nodes)[pred->src()->id()] = true;
          }
        }
      }
      return;
    }
    std::vector<int> const_input_idxs;
    status = GetCompileTimeConstInputs(node, &const_input_idxs, flib_runtime);
    if (!status.ok() || const_input_idxs.empty()) {
      return;
    }
    VLOG(3) << "marking consts for must-be-const inputs of " << node->name();
    for (Edge const* edge : node->in_edges()) {
      if (!edge->IsControlEdge() &&
          absl::c_binary_search(const_input_idxs, edge->dst_input()) &&
          edge_filter(*edge)) {
         its
        while (edge_filter(*edge) && IsConstTraversableOpType(edge->src())) {
          status = edge->src()->input_edge(edge->src_output(), &edge);
          if (!status.ok()) return;
        }
        if (edge_filter(*edge)) {
          VLOG(4) << "  input " << edge->dst_input() << ": "
                  << edge->src()->name() << " must be const (is "
                  << edge->src()->type_string() << ")";
          (*compile_time_const_nodes)[edge->src()->id()] = true;
        }
      }
    }
  };
  DFS(g, {}, visit, NodeComparatorName{},
      [](const Edge& edge) { return !edge.src()->IsNextIteration(); });
  if (compile_time_const_arg_indices && !edge_filter_input) {
    VLOG(5) << "Setting the cache on the graph: " << &g;
    g.GetConstArgIndicesCache() = *compile_time_const_arg_indices;
  }
  return status;
}
Status BackwardsConstAnalysis ( const Graph & g , std :: vector < bool > * compile_time_const_arg_indices , std :: vector < bool > * compile_time_const_nodes , FunctionLibraryRuntime * flib_runtime , std :: function < bool ( const Edge & ) > edge_filter_input ) { if ( ! compile_time_const_nodes && g . GetConstArgIndicesCache ( ) . has_value ( ) && ! edge_filter_input ) { VLOG ( 5 ) << " " << & g ; * compile_time_const_arg_indices = g . GetConstArgIndicesCache ( ) . value ( ) ; return Status :: OK ( ) ; } auto edge_filter = [ & ] ( const Edge & e ) { return edge_filter_input ? edge_filter_input ( e ) : true ; } ; std :: vector < bool > compile_time_const_nodes_impl ; if ( compile_time_const_nodes ) { CHECK_EQ ( compile_time_const_nodes -> size ( ) , g . num_node_ids ( ) ) ; } else { compile_time_const_nodes_impl . resize ( g . num_node_ids ( ) ) ; compile_time_const_nodes = & compile_time_const_nodes_impl ; } Status status ; auto visit = [ & ] ( Node * node ) { if ( ! status . ok ( ) ) return ; if ( XlaOpRegistry :: IsMetadataOp ( node -> type_string ( ) ) ) { VLOG ( 3 ) << " " << node -> name ( ) ; return ; } if ( ( * compile_time_const_nodes ) [ node -> id ( ) ] ) { VLOG ( 3 ) << " " << node -> name ( ) ; if ( node -> type_string ( ) == " " ) { int index ; status = GetNodeAttr ( node -> attrs ( ) , " " , & index ) ; if ( ! status . ok ( ) ) return ; if ( compile_time_const_arg_indices ) { ( * compile_time_const_arg_indices ) [ index ] = true ; } VLOG ( 3 ) << " " << index << " " << node -> name ( ) ; return ; } for ( const Edge * pred : node -> in_edges ( ) ) { if ( ! pred -> IsControlEdge ( ) && edge_filter ( * pred ) ) { while ( edge_filter ( * pred ) && IsConstTraversableOpType ( pred -> src ( ) ) ) { status = pred -> src ( ) -> input_edge ( pred -> src_output ( ) , & pred ) ; if ( ! status . ok ( ) ) return ; } if ( edge_filter ( * pred ) ) { VLOG ( 4 ) << " " << pred -> src ( ) -> name ( ) << " " << pred -> src ( ) -> type_string ( ) << " " ; ( * compile_time_const_nodes ) [ pred -> src ( ) -> id ( ) ] = true ; } } } return ; } std :: vector < int > const_input_idxs ; status = GetCompileTimeConstInputs ( node , & const_input_idxs , flib_runtime ) ; if ( ! status . ok ( ) || const_input_idxs . empty ( ) ) { return ; } VLOG ( 3 ) << " " << node -> name ( ) ; for ( Edge const * edge : node -> in_edges ( ) ) { if ( ! edge -> IsControlEdge ( ) && absl :: c_binary_search ( const_input_idxs , edge -> dst_input ( ) ) && edge_filter ( * edge ) ) { while ( edge_filter ( * edge ) && IsConstTraversableOpType ( edge -> src ( ) ) ) { status = edge -> src ( ) -> input_edge ( edge -> src_output ( ) , & edge ) ; if ( ! status . ok ( ) ) return ; } if ( edge_filter ( * edge ) ) { VLOG ( 4 ) << " " << edge -> dst_input ( ) << " " << edge -> src ( ) -> name ( ) << " " << edge -> src ( ) -> type_string ( ) << " " ; ( * compile_time_const_nodes ) [ edge -> src ( ) -> id ( ) ] = true ; } } } } ; DFS ( g , { } , visit , NodeComparatorName { } , [ ] ( const Edge & edge ) { return ! edge . src ( ) -> IsNextIteration ( ) ; } ) ; if ( compile_time_const_arg_indices && ! edge_filter_input ) { VLOG ( 5 ) << " " << & g ; g . GetConstArgIndicesCache ( ) = * compile_time_const_arg_indices ; } return status ; }
Backwards dataflow analysis that finds arguments to a graph that must be
compile-time constants.
Backwards dataflow analysis that finds arguments to a graph that must be compile - time constants .
// If this is a metadata-only op, don't propagate the const requirement. // If this node must be const, and it isn't a metadata op, then all of its // parents must be const. // If the src node of the `pred` is an IdentityN/While do not mark it // as a compile-time const. Only mark the corresponding input to the // IdentityN/While node as a const. XLA IdentityN op simply forwards // its inputs so this is safe; loop-invariance is checked elsewhere. // Mark any compile-time constant operator arguments as const. // Do not mark IdentityN / While nodes as compile-time const. // If the src node of the `pred` is an IdentityN do not mark it as a // compile-time const. Only mark the corresponding input to the // IdentityN/While node as a const. XLA IdentityN op simply forwards its // inputs so this is safe; loop invariance is checked elsewhere. // Post-order traversal visits nodes in reverse topological order for an // acyclic graph. /*enter=*/ /*leave=*/