This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Fix analysis stage of ipa-reference
- From: Richard Guenther <rguenther at suse dot de>
- To: Jan Hubicka <jh at suse dot cz>
- Cc: gcc-patches at gcc dot gnu dot org, dnovillo at google dot com
- Date: Mon, 15 Sep 2008 10:17:35 +0200 (CEST)
- Subject: Re: Fix analysis stage of ipa-reference
- References: <20080915072017.GA27668@kam.mff.cuni.cz>
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