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]

Re: Fix analysis stage of ipa-reference


On Mon, 15 Sep 2008, Jan Hubicka wrote:

> 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?

Ok with me.  Please wait some minutes for comments from others.

Thanks,
Richard.

> 	* 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;
>   }
>   
> 
> 

-- 
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex


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