This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix analysis stage of ipa-reference


Hi,
while looking into infinite loop in ipa-reference caused by the fibonaci
testcase, I noticed that local analyzis give wrong results, including
FUNCTION_DECLs being read and such.  It seems more sane to actually rewrite it
to the SSA infrastructure then try to fix bugs as the gimple and initializer
walking seems confused in various ways.

There is little problem that we don't include function in addresses_taken list,
while the pass is trying to figure out what functions are called indirectly.
Result of this analyzis was never used (sicne we rely on cgraph needed flag
that will need to be decoupled based on different reasons function is needed),
so I dropped the code for now.  For cgraph we will need more cureful analyzis
to be handle e.g. references eliminated completely by indirect call inlining.
This also save a lot of memory on jonas.jar testcase so I can now get under
10GB of compilation (ipa-refernece used previously over 4GB of data making GCC
to be killed on my setup)

To avoid memory leaks I also placed local analysis to obstack that is freed
after IPA propagation is run.

Still IPA porpagation needs to be fixed since it is confused about
inline clones, I will try to do that in separate patch.

There are many things that can be improved on ipa-reference
implementation.  In particular I think it should be able to figure out
what builtins will never call back to unit and avoid them from being
considered as reading everything.  Inline clones are also not all
equivalent now, since indirect call inlining can propagate direct calls
to them.  This ought to be realized by the analysis to give sane results
on this kind of constructs.

Bootstrapped/regtested i686-linux, OK for mainline?

	* ipa-reference.c (ipa_obstack): Remove.
	(local_info_obstack, global_info_obstack): New.
	(add_static_var): We now handle variables only.
	(mark_address_taken, mark_load, mark_store): New functions based on ...
	(check_operand): ... remove.
	(get_asm_stmt_operands): Rename to ...
	(check_asm_memory_clobber): ... this. Look only for memory clobber.
	(check_call): Simplify; const functions are not touching
	anything.
	(scan_stmt_for_static_refs): Rewrite.
	(scan_op_for_static_refs): Rename to ...
	(scan_initializer_for_static_refs): do not look for VAR_DECL
	initializers; stop recursion on types and decls.
	(ipa_init): Use proper obstacks.
	(analyze_variable): Use scan_initializer_for_static_refs.
	(init_function_info): Use local obstack.
	(analyze_function): Simplify.
	(add_new_function): We don't need visited_nodes obstack.
	(generate_summary): Use proper obstacks; cleanup after propagation.
Index: ipa-reference.c
===================================================================
*** ipa-reference.c	(revision 140362)
--- ipa-reference.c	(working copy)
*************** static bitmap all_module_statics;
*** 93,99 ****
  
  static struct pointer_set_t *visited_nodes;
  
! static bitmap_obstack ipa_obstack;
  
  /* Holders of ipa cgraph hooks: */
  static struct cgraph_node_hook_list *function_insertion_hook_holder;
--- 93,103 ----
  
  static struct pointer_set_t *visited_nodes;
  
! /* Obstack holding bitmaps of local analysis (live from analysis to
!    propagation)  */
! static bitmap_obstack local_info_obstack;
! /* Obstack holding global analysis live forever.  */
! static bitmap_obstack global_info_obstack;
  
  /* Holders of ipa cgraph hooks: */
  static struct cgraph_node_hook_list *function_insertion_hook_holder;
*************** static inline void
*** 238,243 ****
--- 242,248 ----
  add_static_var (tree var) 
  {
    int uid = DECL_UID (var);
+   gcc_assert (TREE_CODE (var) == VAR_DECL);
    if (!bitmap_bit_p (all_module_statics, uid))
      {
        splay_tree_insert (reference_vars_to_consider,
*************** has_proper_scope_for_analysis (tree t)
*** 281,427 ****
    return true;
  }
  
! /* If T is a VAR_DECL for a static that we are interested in, add the
!    uid to the bitmap.  */
  
  static void
! check_operand (ipa_reference_local_vars_info_t local, 
! 	       tree t, bool checking_write)
  {
!   if (!t) return;
! 
!   if ((TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
!       && (has_proper_scope_for_analysis (t))) 
!     {
!       if (checking_write)
! 	{
! 	  if (local)
! 	    bitmap_set_bit (local->statics_written, DECL_UID (t));
! 	  /* Mark the write so we can tell which statics are
! 	     readonly.  */
! 	  if (module_statics_written)
! 	    bitmap_set_bit (module_statics_written, DECL_UID (t));
! 	}
!       else if (local)
! 	bitmap_set_bit (local->statics_read, DECL_UID (t));
!     }
  }
  
! /* Examine tree T for references to static variables. All internal
!    references like array references or indirect references are added
!    to the READ_BM. Direct references are added to either READ_BM or
!    WRITE_BM depending on the value of CHECKING_WRITE.   */
  
  static void
! check_tree (ipa_reference_local_vars_info_t local, tree t, bool checking_write)
  {
!   if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
!     return;
! 
!   while (TREE_CODE (t) == REALPART_EXPR 
! 	 || TREE_CODE (t) == IMAGPART_EXPR
! 	 || handled_component_p (t))
!     {
!       if (TREE_CODE (t) == ARRAY_REF)
! 	check_operand (local, TREE_OPERAND (t, 1), false);
!       t = TREE_OPERAND (t, 0);
!     }
! 
!   /* The bottom of an indirect reference can only be read, not
!      written.  So just recurse and whatever we find, check it against
!      the read bitmaps.  */
! 
!   /*  if (INDIRECT_REF_P (t) || TREE_CODE (t) == MEM_REF) */
!   /* FIXME when we have array_ref's of pointers.  */
!   if (INDIRECT_REF_P (t))
!     check_tree (local, TREE_OPERAND (t, 0), false);
! 
!   if (SSA_VAR_P (t))
!     check_operand (local, t, checking_write);
  }
  
! /* Scan tree T to see if there are any addresses taken in within T.  */
  
! static void 
! look_for_address_of (tree t)
  {
!   if (TREE_CODE (t) == ADDR_EXPR)
      {
!       tree x = get_base_var (t);
!       if (TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == FUNCTION_DECL) 
! 	if (has_proper_scope_for_analysis (x) && module_statics_escape)
! 	  bitmap_set_bit (module_statics_escape, DECL_UID (x));
      }
  }
  
! /* Check to see if T is a read or address of operation on a static var
!    we are interested in analyzing.  LOCAL is passed in to get access
!    to its bit vectors.  Local is NULL if this is called from a static
!    initializer.  */
! 
! static void
! check_rhs_var (ipa_reference_local_vars_info_t local, tree t)
! {
!   look_for_address_of (t);
! 
!   if (local == NULL) 
!     return;
! 
!   check_tree(local, t, false);
! }
! 
! /* Check to see if T is an assignment to a static var we are
!    interested in analyzing.  LOCAL is passed in to get access to its bit
!    vectors.  */
! 
! static void
! check_lhs_var (ipa_reference_local_vars_info_t local, tree t)
! {
!   if (local == NULL) 
!     return;
!    
!   check_tree(local, t, true);
! }
! 
! /* This is a scaled down version of get_asm_expr_operands from
!    tree_ssa_operands.c.  The version there runs much later and assumes
!    that aliasing information is already available. Here we are just
!    trying to find if the set of inputs and outputs contain references
!    or address of operations to local static variables.  FN is the
!    function being analyzed and STMT is the actual asm statement.  */
  
  static void
! get_asm_stmt_operands (ipa_reference_local_vars_info_t local, gimple stmt)
  {
-   size_t noutputs = gimple_asm_noutputs (stmt);
-   const char **oconstraints
-     = (const char **) alloca ((noutputs) * sizeof (const char *));
    size_t i;
    tree op;
-   const char *constraint;
-   bool allows_mem, allows_reg, is_inout;
-   
-   for (i = 0; i < noutputs; i++)
-     {
-       op = gimple_asm_output_op (stmt, i);
-       oconstraints[i] = constraint
- 	= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
-       parse_output_constraint (&constraint, i, 0, 0,
- 			       &allows_mem, &allows_reg, &is_inout);
-       
-       check_lhs_var (local, TREE_VALUE (op));
-     }
- 
-   for (i = 0; i < gimple_asm_ninputs (stmt); i++)
-     {
-       op = gimple_asm_input_op (stmt, i);
-       constraint
- 	= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
-       parse_input_constraint (&constraint, 0, 0, noutputs, 0,
- 			      oconstraints, &allows_mem, &allows_reg);
-       
-       check_rhs_var (local, TREE_VALUE (op));
-     }
    
    for (i = 0; i < gimple_asm_nclobbers (stmt); i++)
      {
--- 286,337 ----
    return true;
  }
  
! /* Mark tree T as having address taken.  */
  
  static void
! mark_address_taken (tree x)
  {
!   if (TREE_CODE (x) == VAR_DECL
!       && module_statics_escape && has_proper_scope_for_analysis (x))
!     bitmap_set_bit (module_statics_escape, DECL_UID (x));
  }
  
! /* Mark load of T.  */
  
  static void
! mark_load (ipa_reference_local_vars_info_t local, 
! 	   tree t)
  {
!   if (TREE_CODE (t) == VAR_DECL
!       && has_proper_scope_for_analysis (t))
!     bitmap_set_bit (local->statics_read, DECL_UID (t));
  }
  
! /* Mark store of T.  */
  
! static void
! mark_store (ipa_reference_local_vars_info_t local, 
! 	   tree t)
  {
!   if (TREE_CODE (t) == VAR_DECL
!       && has_proper_scope_for_analysis (t))
      {
!       if (local)
! 	bitmap_set_bit (local->statics_written, DECL_UID (t));
!       /* Mark the write so we can tell which statics are
! 	 readonly.  */
!       if (module_statics_written)
! 	bitmap_set_bit (module_statics_written, DECL_UID (t));
      }
  }
  
! /* Look for memory clobber and set read_all/write_all if present.  */
  
  static void
! check_asm_memory_clobber (ipa_reference_local_vars_info_t local, gimple stmt)
  {
    size_t i;
    tree op;
    
    for (i = 0; i < gimple_asm_nclobbers (stmt); i++)
      {
*************** get_asm_stmt_operands (ipa_reference_loc
*** 435,461 ****
      }
  }
  
! /* Check the parameters of a function call from CALLER to CALL_EXPR to
!    see if any of them are static vars.  Also check to see if this is
!    either an indirect call, a call outside the compilation unit, or
!    has special attributes that effect the clobbers.  The caller
!    parameter is the tree node for the caller and the second operand is
!    the tree node for the entire call expression.  */
  
  static void
  check_call (ipa_reference_local_vars_info_t local, gimple stmt)
  {
    int flags = gimple_call_flags (stmt);
-   tree operand;
    tree callee_t = gimple_call_fndecl (stmt);
    enum availability avail = AVAIL_NOT_AVAILABLE;
-   size_t i;
- 
-   if ((operand = gimple_call_lhs (stmt)) != NULL)
-     check_lhs_var (local, operand);
- 
-   for (i = 0; i < gimple_call_num_args (stmt); i++)
-     check_rhs_var (local, gimple_call_arg (stmt, i));
  
    if (callee_t)
      {
--- 345,358 ----
      }
  }
  
! /* Look for external calls and set read_all/write_all correspondingly.  */
  
  static void
  check_call (ipa_reference_local_vars_info_t local, gimple stmt)
  {
    int flags = gimple_call_flags (stmt);
    tree callee_t = gimple_call_fndecl (stmt);
    enum availability avail = AVAIL_NOT_AVAILABLE;
  
    if (callee_t)
      {
*************** check_call (ipa_reference_local_vars_inf
*** 466,472 ****
    if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
      if (local) 
        {
! 	if (flags & ECF_PURE) 
  	  local->calls_read_all = true;
  	else 
  	  {
--- 363,371 ----
    if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
      if (local) 
        {
! 	if (flags & ECF_CONST) 
! 	  ;
! 	else if (flags & ECF_PURE)
  	  local->calls_read_all = true;
  	else 
  	  {
*************** check_call (ipa_reference_local_vars_inf
*** 474,603 ****
  	    local->calls_write_all = true;
  	  }
        }
  }
  
  /* TP is the part of the tree currently under the microscope.
     WALK_SUBTREES is part of the walk_tree api but is unused here.
     DATA is cgraph_node of the function being walked.  */
  
- /* FIXME: When this is converted to run over SSA form, this code
-    should be converted to use the operand scanner.  */
- 
  static tree
! scan_stmt_for_static_refs (gimple_stmt_iterator *gsip, bool *handled_ops_p,
! 			   struct walk_stmt_info *data)
  {
-   struct cgraph_node *fn = (struct cgraph_node *) data->info;
    gimple stmt = gsi_stmt (*gsip);
    ipa_reference_local_vars_info_t local = NULL;
    if (fn)
      local = get_reference_vars_info_from_cgraph (fn)->local;
  
    switch (gimple_code (stmt))
      {
-     case GIMPLE_ASSIGN:
-       {
- 	/* First look on the lhs and see what variable is stored to */
- 	tree lhs = gimple_assign_lhs (stmt);
- 	tree rhs1 = gimple_assign_rhs1 (stmt);
- 	tree rhs2 = gimple_assign_rhs2 (stmt);
- 	enum tree_code code = gimple_assign_rhs_code (stmt);
- 
- 	check_lhs_var (local, lhs);
- 
- 	/* For the purposes of figuring out what the cast affects */
- 
- 	/* Next check the operands on the rhs to see if they are ok. */
- 	switch (TREE_CODE_CLASS (code))
- 	  {
- 	  case tcc_binary:	    
- 	  case tcc_comparison:	    
-  	    check_rhs_var (local, rhs1);
-  	    check_rhs_var (local, rhs2);
- 	    break;
- 
- 	  case tcc_unary:
- 	  case tcc_reference:
- 	  case tcc_declaration:
- 	    check_rhs_var (local, rhs1);
- 	    break;
- 
- 	  case tcc_expression:
- 	    switch (code)
- 	      {
- 	      case ADDR_EXPR:
- 		check_rhs_var (local, rhs1);
- 		break;
- 	      default:
- 		break;
- 	      }
- 	    break;
- 	  default:
- 	    break;
- 	  }
- 	*handled_ops_p = true;
-       }
-       break;
- 
-     case GIMPLE_LABEL:
-       if (DECL_NONLOCAL (gimple_label_label (stmt)))
- 	{
- 	  /* Target of long jump. */
- 	  local->calls_read_all = true;
- 	  local->calls_write_all = true;
- 	}
-       break;
- 
      case GIMPLE_CALL:
        check_call (local, stmt);
-       *handled_ops_p = true;
        break;
        
      case GIMPLE_ASM:
!       get_asm_stmt_operands (local, stmt);
!       *handled_ops_p = true;
        break;
!       
      default:
        break;
      }
    return NULL;
  }
  
! /* Call-back to scan GIMPLE operands for static references.  This is supposed
!    to work with scan_stmt_for_static_refs so the real call-back data is stored
!    inside a walk_stmt_info struct.  Callers using the walk_tree interface must
!    also wrap the call-back data in a walk_stmt_info struct.  */
  
  static tree
! scan_op_for_static_refs (tree *tp, int *walk_subtrees, void *data)
  {
-   struct walk_stmt_info *wi = (struct walk_stmt_info*) data;
-   struct cgraph_node *fn = (struct cgraph_node *) wi->info;
    tree t = *tp;
-   ipa_reference_local_vars_info_t local = NULL;
-   if (fn)
-     local = get_reference_vars_info_from_cgraph (fn)->local;
  
!   switch (TREE_CODE (t))  
      {
!     case VAR_DECL:
!       if (DECL_INITIAL (t))
! 	walk_tree (&DECL_INITIAL (t), scan_op_for_static_refs, data,
! 		   wi->pset);
!       *walk_subtrees = 0;
!       break;
! 
!     case ADDR_EXPR:
!       /* This case is here to find addresses on rhs of constructors in
! 	 decl_initial of static variables. */
!       check_rhs_var (local, t);
        *walk_subtrees = 0;
-       break;
- 
-     default:
-       break;
      }
    return NULL;
  }
  
--- 373,450 ----
  	    local->calls_write_all = true;
  	  }
        }
+    /* TODO: To be able to produce sane results, we should also handle
+       common builtins, in particular throw.
+       Indirect calls hsould be only counted and as inliner is replacing them
+       by direct calls, we can conclude if any indirect calls are left in body */
  }
  
  /* TP is the part of the tree currently under the microscope.
     WALK_SUBTREES is part of the walk_tree api but is unused here.
     DATA is cgraph_node of the function being walked.  */
  
  static tree
! scan_stmt_for_static_refs (gimple_stmt_iterator *gsip,
! 			   struct cgraph_node *fn)
  {
    gimple stmt = gsi_stmt (*gsip);
    ipa_reference_local_vars_info_t local = NULL;
+   unsigned int i;
+   bitmap_iterator bi;
+ 
    if (fn)
      local = get_reference_vars_info_from_cgraph (fn)->local;
  
+   if (gimple_loaded_syms (stmt))
+     EXECUTE_IF_SET_IN_BITMAP (gimple_loaded_syms (stmt), 0, i, bi)
+       mark_load (local, referenced_var_lookup (i));
+   if (gimple_stored_syms (stmt))
+     EXECUTE_IF_SET_IN_BITMAP (gimple_stored_syms (stmt), 0, i, bi)
+       mark_store (local, referenced_var_lookup (i));
+   if (gimple_addresses_taken (stmt))
+     EXECUTE_IF_SET_IN_BITMAP (gimple_addresses_taken (stmt), 0, i, bi)
+       mark_address_taken (referenced_var_lookup (i));
+ 
    switch (gimple_code (stmt))
      {
      case GIMPLE_CALL:
        check_call (local, stmt);
        break;
        
      case GIMPLE_ASM:
!       check_asm_memory_clobber (local, stmt);
        break;
! 
!     /* We used to check nonlocal labels here and set them as potentially modifying
!        everything.  This is not needed, since we can get to nonlocal label only
!        from callee and thus we will get info propagated.  */
! 
      default:
        break;
      }
+   
    return NULL;
  }
  
! /* Call-back to scan variable initializers for static references.  
!    Called using walk_tree.  */
  
  static tree
! scan_initializer_for_static_refs (tree *tp, int *walk_subtrees,
! 				  void *data ATTRIBUTE_UNUSED)
  {
    tree t = *tp;
  
!   if (TREE_CODE (t) == ADDR_EXPR)
      {
!       mark_address_taken (get_base_var (t));
        *walk_subtrees = 0;
      }
+   /* Save some cycles by not walking types and declaration as we
+      won't find anything useful there anyway.  */
+   else if (IS_TYPE_OR_DECL_P (*tp))
+     *walk_subtrees = 0;
+  
    return NULL;
  }
  
*************** propagate_bits (struct cgraph_node *x)
*** 687,695 ****
  		}
  	    }
  	  else 
! 	    {
! 	      gcc_unreachable ();
! 	    }
  	}
      }
  }
--- 534,540 ----
  		}
  	    }
  	  else 
! 	    gcc_unreachable ();
  	}
      }
  }
*************** merge_callee_local_info (struct cgraph_n
*** 763,782 ****
  static void 
  ipa_init (void) 
  {
-   struct cgraph_node *node;
    memory_identifier_string = build_string(7, "memory");
  
    reference_vars_to_consider =
      splay_tree_new_ggc (splay_tree_compare_ints);
  
!   bitmap_obstack_initialize (&ipa_obstack);
!   module_statics_escape = BITMAP_ALLOC (&ipa_obstack);
!   module_statics_written = BITMAP_ALLOC (&ipa_obstack);
!   all_module_statics = BITMAP_ALLOC (&ipa_obstack);
! 
!   /* This will add NODE->DECL to the splay trees.  */
!   for (node = cgraph_nodes; node; node = node->next)
!     has_proper_scope_for_analysis (node->decl);
  
    /* There are some shared nodes, in particular the initializers on
       static declarations.  We do not need to scan them more than once
--- 608,623 ----
  static void 
  ipa_init (void) 
  {
    memory_identifier_string = build_string(7, "memory");
  
    reference_vars_to_consider =
      splay_tree_new_ggc (splay_tree_compare_ints);
  
!   bitmap_obstack_initialize (&local_info_obstack);
!   bitmap_obstack_initialize (&global_info_obstack);
!   module_statics_escape = BITMAP_ALLOC (&local_info_obstack);
!   module_statics_written = BITMAP_ALLOC (&local_info_obstack);
!   all_module_statics = BITMAP_ALLOC (&global_info_obstack);
  
    /* There are some shared nodes, in particular the initializers on
       static declarations.  We do not need to scan them more than once
*************** analyze_variable (struct varpool_node *v
*** 799,805 ****
  
    memset (&wi, 0, sizeof (wi));
    wi.pset = visited_nodes;
!   walk_tree (&DECL_INITIAL (global), scan_op_for_static_refs,
               &wi, wi.pset);
  }
  
--- 640,646 ----
  
    memset (&wi, 0, sizeof (wi));
    wi.pset = visited_nodes;
!   walk_tree (&DECL_INITIAL (global), scan_initializer_for_static_refs,
               &wi, wi.pset);
  }
  
*************** init_function_info (struct cgraph_node *
*** 818,825 ****
    get_function_ann (decl)->reference_vars_info = info;
  
    info->local = l;
!   l->statics_read = BITMAP_ALLOC (&ipa_obstack);
!   l->statics_written = BITMAP_ALLOC (&ipa_obstack);
  
    return l;
  }
--- 659,666 ----
    get_function_ann (decl)->reference_vars_info = info;
  
    info->local = l;
!   l->statics_read = BITMAP_ALLOC (&local_info_obstack);
!   l->statics_written = BITMAP_ALLOC (&local_info_obstack);
  
    return l;
  }
*************** init_function_info (struct cgraph_node *
*** 830,844 ****
  static void
  analyze_function (struct cgraph_node *fn)
  {
-   ipa_reference_local_vars_info_t l = init_function_info (fn);
    tree decl = fn->decl;
-   struct walk_stmt_info wi;
    struct function *this_cfun = DECL_STRUCT_FUNCTION (decl);
    basic_block this_block;
  
    if (dump_file)
      fprintf (dump_file, "\n local analysis of %s\n", cgraph_node_name (fn));
    
    FOR_EACH_BB_FN (this_block, this_cfun)
      {
        gimple_stmt_iterator gsi;
--- 671,688 ----
  static void
  analyze_function (struct cgraph_node *fn)
  {
    tree decl = fn->decl;
    struct function *this_cfun = DECL_STRUCT_FUNCTION (decl);
    basic_block this_block;
+   tree step;
  
    if (dump_file)
      fprintf (dump_file, "\n local analysis of %s\n", cgraph_node_name (fn));
+ 
+   push_cfun (DECL_STRUCT_FUNCTION (decl));
+   current_function_decl = decl;
    
+   init_function_info (fn);
    FOR_EACH_BB_FN (this_block, this_cfun)
      {
        gimple_stmt_iterator gsi;
*************** analyze_function (struct cgraph_node *fn
*** 857,895 ****
  	    {
  	      op = USE_FROM_PTR (use);
  	      if (TREE_CODE (op) == ADDR_EXPR)
! 		check_rhs_var (l, op);
  	    }
  	}
  
-       memset (&wi, 0, sizeof (wi));
-       wi.info = fn;
-       wi.pset = visited_nodes;
        for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi))
! 	walk_gimple_stmt (&gsi, scan_stmt_for_static_refs,
! 			  scan_op_for_static_refs, &wi);
      }
  
!   /* There may be const decls with interesting right hand sides.  */
!   if (DECL_STRUCT_FUNCTION (decl))
!     {
!       tree step;
!       for (step = DECL_STRUCT_FUNCTION (decl)->local_decls;
! 	   step;
! 	   step = TREE_CHAIN (step))
! 	{
! 	  tree var = TREE_VALUE (step);
! 	  if (TREE_CODE (var) == VAR_DECL 
! 	      && DECL_INITIAL (var)
! 	      && !TREE_STATIC (var))
! 	    {
! 	      memset (&wi, 0, sizeof (wi));
! 	      wi.info = fn;
! 	      wi.pset = visited_nodes;
! 	      walk_tree (&DECL_INITIAL (var), scan_op_for_static_refs,
! 		         &wi, wi.pset);
! 	    }
! 	}
!     }
  }
  
  /* If FN is avail == AVAIL_OVERWRITABLE, replace the effects bit
--- 701,729 ----
  	    {
  	      op = USE_FROM_PTR (use);
  	      if (TREE_CODE (op) == ADDR_EXPR)
! 		mark_address_taken (get_base_var (op));
  	    }
  	}
  
        for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi))
! 	scan_stmt_for_static_refs (&gsi, fn);
      }
  
! #ifdef ENABLE_CHECKING
!   /* Verify that all local initializers was expanded by gimplifier.  */
!   for (step = DECL_STRUCT_FUNCTION (decl)->local_decls;
!        step;
!        step = TREE_CHAIN (step))
!     {
!       tree var = TREE_VALUE (step);
!       if (TREE_CODE (var) == VAR_DECL 
! 	  && DECL_INITIAL (var)
! 	  && !TREE_STATIC (var))
! 	gcc_unreachable ();
!     }
! #endif
!   pop_cfun ();
!   current_function_decl = NULL;
  }
  
  /* If FN is avail == AVAIL_OVERWRITABLE, replace the effects bit
*************** add_new_function (struct cgraph_node *no
*** 947,955 ****
       static declarations.  We do not need to scan them more than once
       since all we would be interested in are the addressof
       operations.  */
-   visited_nodes = pointer_set_create ();
    analyze_function (node);
-   pointer_set_destroy (visited_nodes);
    visited_nodes = NULL;
  }
  
--- 781,787 ----
*************** generate_summary (void)
*** 969,976 ****
    function_insertion_hook_holder =
        cgraph_add_function_insertion_hook (&add_new_function, NULL);
    ipa_init ();
!   module_statics_readonly = BITMAP_ALLOC (&ipa_obstack);
!   bm_temp = BITMAP_ALLOC (&ipa_obstack);
  
    /* Process all of the variables first.  */
    FOR_EACH_STATIC_INITIALIZER (vnode)
--- 801,808 ----
    function_insertion_hook_holder =
        cgraph_add_function_insertion_hook (&add_new_function, NULL);
    ipa_init ();
!   module_statics_readonly = BITMAP_ALLOC (&local_info_obstack);
!   bm_temp = BITMAP_ALLOC (&local_info_obstack);
  
    /* Process all of the variables first.  */
    FOR_EACH_STATIC_INITIALIZER (vnode)
*************** generate_summary (void)
*** 1031,1041 ****
      {
        tree var = get_static_decl (index);
        
-       /* Readonly on a function decl is very different from the
- 	 variable.  */
-       if (TREE_CODE (var) == FUNCTION_DECL)
- 	continue;
-       
        /* Ignore variables in named sections - changing TREE_READONLY
  	 changes the section flags, potentially causing conflicts with
  	 other variables in the same named section.  */
--- 863,868 ----
*************** propagate (void)
*** 1186,1192 ****
  	node_g->statics_read = all_module_statics;
        else 
  	{
! 	  node_g->statics_read = BITMAP_ALLOC (&ipa_obstack);
  	  bitmap_copy (node_g->statics_read, 
  		       node_l->statics_read);
  	}
--- 1013,1019 ----
  	node_g->statics_read = all_module_statics;
        else 
  	{
! 	  node_g->statics_read = BITMAP_ALLOC (&global_info_obstack);
  	  bitmap_copy (node_g->statics_read, 
  		       node_l->statics_read);
  	}
*************** propagate (void)
*** 1195,1201 ****
  	node_g->statics_written = all_module_statics;
        else
  	{
! 	  node_g->statics_written = BITMAP_ALLOC (&ipa_obstack);
  	  bitmap_copy (node_g->statics_written, 
  		       node_l->statics_written);
  	}
--- 1022,1028 ----
  	node_g->statics_written = all_module_statics;
        else
  	{
! 	  node_g->statics_written = BITMAP_ALLOC (&global_info_obstack);
  	  bitmap_copy (node_g->statics_written, 
  		       node_l->statics_written);
  	}
*************** propagate (void)
*** 1346,1353 ****
        
        /* Create the complimentary sets.  These are more useful for
  	 certain apis.  */
!       node_g->statics_not_read = BITMAP_ALLOC (&ipa_obstack);
!       node_g->statics_not_written = BITMAP_ALLOC (&ipa_obstack);
  
        if (node_g->statics_read != all_module_statics) 
  	{
--- 1173,1180 ----
        
        /* Create the complimentary sets.  These are more useful for
  	 certain apis.  */
!       node_g->statics_not_read = BITMAP_ALLOC (&global_info_obstack);
!       node_g->statics_not_written = BITMAP_ALLOC (&global_info_obstack);
  
        if (node_g->statics_read != all_module_statics) 
  	{
*************** propagate (void)
*** 1361,1372 ****
--- 1188,1201 ----
  	bitmap_and_compl (node_g->statics_not_written, 
  			  all_module_statics,
  			  node_g->statics_written);
     }
  
    free (order);
  
    for (node = cgraph_nodes; node; node = node->next)
      {
+       ipa_reference_vars_info_t node_info;
+       node_info = get_reference_vars_info_from_cgraph (node);
        /* Get rid of the aux information.  */
        
        if (node->aux)
*************** propagate (void)
*** 1378,1384 ****
--- 1208,1225 ----
        if (node->analyzed 
  	  && (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE))
  	clean_function (node);
+       else if (node_info)
+ 	{
+ 	  /* Remove local info we no longer need.  */
+ 	  if (node_info->local->statics_read
+ 	      && node_info->local->statics_read != all_module_statics)
+ 	    BITMAP_FREE (node_info->local->statics_read);
+ 	  if (node_info->local->statics_written
+ 	      && node_info->local->statics_written != all_module_statics)
+ 	    BITMAP_FREE (node_info->local->statics_written);
+ 	}
      }
+   bitmap_obstack_release (&local_info_obstack);
    return 0;
  }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]