diff options
author | Martin Jambor <mjambor@suse.cz> | 2013-05-13 12:16:09 +0200 |
---|---|---|
committer | Martin Jambor <jamborm@gcc.gnu.org> | 2013-05-13 12:16:09 +0200 |
commit | 4502fe8dfcb1cc2c59b50b868ac75fb5cdd742fc (patch) | |
tree | eb36587215072023d7faafc93b4cb03eb6f629f3 | |
parent | 0864bfc257a3d3198ba182c562b729ba1e96466d (diff) | |
download | gcc-4502fe8dfcb1cc2c59b50b868ac75fb5cdd742fc.zip gcc-4502fe8dfcb1cc2c59b50b868ac75fb5cdd742fc.tar.gz gcc-4502fe8dfcb1cc2c59b50b868ac75fb5cdd742fc.tar.bz2 |
re PR middle-end/42371 (dead code not eliminated during folding with whole-program)
2013-05-13 Martin Jambor <mjambor@suse.cz>
PR middle-end/42371
* ipa-prop.h (IPA_UNDESCRIBED_USE): New macro.
(ipa_constant_data): New type.
(ipa_jump_func): Use ipa_constant_data to hold information about
constant jump functions.
(ipa_get_jf_constant): Adjust to jump function type changes.
(ipa_get_jf_constant_rdesc): New function.
(ipa_param_descriptor): New field controlled_uses.
(ipa_get_controlled_uses): New function.
(ipa_set_controlled_uses): Likewise.
* ipa-ref.h (ipa_find_reference): Declare.
* ipa-prop.c (ipa_cst_ref_desc): New type.
(ipa_print_node_jump_functions_for_edge): Adjust for jump function type
changes.
(ipa_set_jf_constant): Likewise. Also create reference descriptions.
New parameter cs. Adjust all callers.
(ipa_analyze_params_uses): Detect uncontrolled and controlled uses.
(remove_described_reference): New function.
(jfunc_rdesc_usable): Likewise.
(try_make_edge_direct_simple_call): Decrement controlled use count,
attempt to remove reference if it hits zero.
(combine_controlled_uses_counters): New function.
(propagate_controlled_uses): Likewise.
(ipa_propagate_indirect_call_infos): Call propagate_controlled_uses.
(ipa_edge_duplication_hook): Duplicate reference descriptions.
(ipa_print_node_params): Print described use counter.
(ipa_write_jump_function): Adjust to jump function type changes.
(ipa_read_jump_function): New parameter CS, pass it to
ipa_set_jf_constant. Adjust caller.
(ipa_write_node_info): Stream controlled use count
(ipa_read_node_info): Likewise.
* cgraph.c (cgraph_mark_address_taken_node): Bail out instead of
asserting.
* ipa-cp.c (ipcp_discover_new_direct_edges): Decrement controlled use
count. Remove cloning-added reference if it reaches zero.
* ipa-ref.c (ipa_find_reference): New function.
testsuite/
* gcc.dg/ipa/remref-0.c: New test.
* gcc.dg/ipa/remref-1a.c: Likewise.
* gcc.dg/ipa/remref-1b.c: Likewise.
* gcc.dg/ipa/remref-2a.c: Likewise.
* gcc.dg/ipa/remref-2b.c: Likewise.
From-SVN: r198821
-rw-r--r-- | gcc/ChangeLog | 39 | ||||
-rw-r--r-- | gcc/cgraph.c | 9 | ||||
-rw-r--r-- | gcc/ipa-cp.c | 30 | ||||
-rw-r--r-- | gcc/ipa-prop.c | 327 | ||||
-rw-r--r-- | gcc/ipa-prop.h | 45 | ||||
-rw-r--r-- | gcc/ipa-ref.c | 17 | ||||
-rw-r--r-- | gcc/ipa-ref.h | 1 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/remref-0.c | 30 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/remref-1a.c | 34 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/remref-1b.c | 37 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/remref-2a.c | 90 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/remref-2b.c | 94 |
13 files changed, 740 insertions, 22 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b33e4f3..8a3a733 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,42 @@ +2013-05-13 Martin Jambor <mjambor@suse.cz> + + PR middle-end/42371 + * ipa-prop.h (IPA_UNDESCRIBED_USE): New macro. + (ipa_constant_data): New type. + (ipa_jump_func): Use ipa_constant_data to hold information about + constant jump functions. + (ipa_get_jf_constant): Adjust to jump function type changes. + (ipa_get_jf_constant_rdesc): New function. + (ipa_param_descriptor): New field controlled_uses. + (ipa_get_controlled_uses): New function. + (ipa_set_controlled_uses): Likewise. + * ipa-ref.h (ipa_find_reference): Declare. + * ipa-prop.c (ipa_cst_ref_desc): New type. + (ipa_print_node_jump_functions_for_edge): Adjust for jump function type + changes. + (ipa_set_jf_constant): Likewise. Also create reference descriptions. + New parameter cs. Adjust all callers. + (ipa_analyze_params_uses): Detect uncontrolled and controlled uses. + (remove_described_reference): New function. + (jfunc_rdesc_usable): Likewise. + (try_make_edge_direct_simple_call): Decrement controlled use count, + attempt to remove reference if it hits zero. + (combine_controlled_uses_counters): New function. + (propagate_controlled_uses): Likewise. + (ipa_propagate_indirect_call_infos): Call propagate_controlled_uses. + (ipa_edge_duplication_hook): Duplicate reference descriptions. + (ipa_print_node_params): Print described use counter. + (ipa_write_jump_function): Adjust to jump function type changes. + (ipa_read_jump_function): New parameter CS, pass it to + ipa_set_jf_constant. Adjust caller. + (ipa_write_node_info): Stream controlled use count + (ipa_read_node_info): Likewise. + * cgraph.c (cgraph_mark_address_taken_node): Bail out instead of + asserting. + * ipa-cp.c (ipcp_discover_new_direct_edges): Decrement controlled use + count. Remove cloning-added reference if it reaches zero. + * ipa-ref.c (ipa_find_reference): New function. + 2013-05-13 Ganesh Gopalasubramanian <Ganesh.Gopalasubramanian@amd.com> * config/i386/i386.c (processor_target_table): Modified default diff --git a/gcc/cgraph.c b/gcc/cgraph.c index a6a16e6..568486e 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1409,7 +1409,14 @@ cgraph_remove_node (struct cgraph_node *node) void cgraph_mark_address_taken_node (struct cgraph_node *node) { - gcc_assert (!node->global.inlined_to); + /* Indirect inlining can figure out that all uses of the address are + inlined. */ + if (node->global.inlined_to) + { + gcc_assert (cfun->after_inlining); + gcc_assert (node->callers->indirect_inlining_edge); + return; + } /* FIXME: address_taken flag is used both as a shortcut for testing whether IPA_REF_ADDR reference exists (and thus it should be set on node representing alias we take address of) and as a test whether address diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index f16bd1a..98c91ef 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -2276,8 +2276,36 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node, aggvals); if (target) { - ipa_make_edge_direct_to_target (ie, target); + struct cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target); found = true; + + if (cs && !ie->indirect_info->agg_contents + && !ie->indirect_info->polymorphic) + { + struct ipa_node_params *info = IPA_NODE_REF (node); + int param_index = ie->indirect_info->param_index; + int c = ipa_get_controlled_uses (info, param_index); + if (c != IPA_UNDESCRIBED_USE) + { + struct ipa_ref *to_del; + + c--; + ipa_set_controlled_uses (info, param_index, c); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " controlled uses count of param " + "%i bumped down to %i\n", param_index, c); + if (c == 0 + && (to_del = ipa_find_reference ((symtab_node) node, + (symtab_node) cs->callee, + NULL))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " and even removing its " + "cloning-created reference\n"); + ipa_remove_reference (to_del); + } + } + } } } /* Turning calls to direct calls will improve overall summary. */ diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index b98f9ad..76b3136 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -62,6 +62,22 @@ static struct cgraph_2edge_hook_list *edge_duplication_hook_holder; static struct cgraph_2node_hook_list *node_duplication_hook_holder; static struct cgraph_node_hook_list *function_insertion_hook_holder; +/* Description of a reference to an IPA constant. */ +struct ipa_cst_ref_desc +{ + /* Edge that corresponds to the statement which took the reference. */ + struct cgraph_edge *cs; + /* Linked list of duplicates created when call graph edges are cloned. */ + struct ipa_cst_ref_desc *next_duplicate; + /* Number of references in IPA structures, IPA_UNDESCRIBED_USE if the value + if out of control. */ + int refcount; +}; + +/* Allocation pool for reference descriptions. */ + +static alloc_pool ipa_refdesc_pool; + /* Return index of the formal whose tree is PTREE in function which corresponds to INFO. */ @@ -175,7 +191,7 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs) } else if (type == IPA_JF_CONST) { - tree val = jump_func->value.constant; + tree val = jump_func->value.constant.value; fprintf (f, "CONST: "); print_generic_expr (f, val, 0); if (TREE_CODE (val) == ADDR_EXPR @@ -309,13 +325,31 @@ ipa_set_jf_known_type (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset, /* Set JFUNC to be a constant jmp function. */ static void -ipa_set_jf_constant (struct ipa_jump_func *jfunc, tree constant) +ipa_set_jf_constant (struct ipa_jump_func *jfunc, tree constant, + struct cgraph_edge *cs) { constant = unshare_expr (constant); if (constant && EXPR_P (constant)) SET_EXPR_LOCATION (constant, UNKNOWN_LOCATION); jfunc->type = IPA_JF_CONST; - jfunc->value.constant = unshare_expr_without_location (constant); + jfunc->value.constant.value = unshare_expr_without_location (constant); + + if (TREE_CODE (constant) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (constant, 0)) == FUNCTION_DECL) + { + struct ipa_cst_ref_desc *rdesc; + if (!ipa_refdesc_pool) + ipa_refdesc_pool = create_alloc_pool ("IPA-PROP ref descriptions", + sizeof (struct ipa_cst_ref_desc), 32); + + rdesc = (struct ipa_cst_ref_desc *) pool_alloc (ipa_refdesc_pool); + rdesc->cs = cs; + rdesc->next_duplicate = NULL; + rdesc->refcount = 1; + jfunc->value.constant.rdesc = rdesc; + } + else + jfunc->value.constant.rdesc = NULL; } /* Set JFUNC to be a simple pass-through jump function. */ @@ -1404,7 +1438,7 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo, tree arg = gimple_call_arg (call, n); if (is_gimple_ip_invariant (arg)) - ipa_set_jf_constant (jfunc, arg); + ipa_set_jf_constant (jfunc, arg, cs); else if (!is_gimple_reg_type (TREE_TYPE (arg)) && TREE_CODE (arg) == PARM_DECL) { @@ -1891,14 +1925,35 @@ ipa_analyze_params_uses (struct cgraph_node *node, for (i = 0; i < ipa_get_param_count (info); i++) { tree parm = ipa_get_param (info, i); - tree ddef; + int controlled_uses = 0; + /* For SSA regs see if parameter is used. For non-SSA we compute the flag during modification analysis. */ - if (is_gimple_reg (parm) - && (ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->symbol.decl), - parm)) != NULL_TREE - && !has_zero_uses (ddef)) - ipa_set_param_used (info, i, true); + if (is_gimple_reg (parm)) + { + tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->symbol.decl), + parm); + if (ddef && !has_zero_uses (ddef)) + { + imm_use_iterator imm_iter; + use_operand_p use_p; + + ipa_set_param_used (info, i, true); + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, ddef) + if (!is_gimple_call (USE_STMT (use_p))) + { + controlled_uses = IPA_UNDESCRIBED_USE; + break; + } + else + controlled_uses++; + } + else + controlled_uses = 0; + } + else + controlled_uses = IPA_UNDESCRIBED_USE; + ipa_set_controlled_uses (info, i, controlled_uses); } func = DECL_STRUCT_FUNCTION (decl); @@ -2226,6 +2281,40 @@ ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg, return NULL; } +/* Remove a reference to SYMBOL from the list of references of a node given by + reference description RDESC. */ + +static void +remove_described_reference (symtab_node symbol, struct ipa_cst_ref_desc *rdesc) +{ + struct ipa_ref *to_del; + struct cgraph_edge *origin; + + origin = rdesc->cs; + to_del = ipa_find_reference ((symtab_node) origin->caller, symbol, + origin->call_stmt); + gcc_assert (to_del); + ipa_remove_reference (to_del); + if (dump_file) + fprintf (dump_file, "ipa-prop: Removed a reference from %s/%i to %s.\n", + xstrdup (cgraph_node_name (origin->caller)), + origin->caller->uid, xstrdup (symtab_node_name (symbol))); +} + +/* If JFUNC has a reference description with refcount different from + IPA_UNDESCRIBED_USE, return the reference description, otherwise return + NULL. JFUNC must be a constant jump function. */ + +static struct ipa_cst_ref_desc * +jfunc_rdesc_usable (struct ipa_jump_func *jfunc) +{ + struct ipa_cst_ref_desc *rdesc = ipa_get_jf_constant_rdesc (jfunc); + if (rdesc && rdesc->refcount != IPA_UNDESCRIBED_USE) + return rdesc; + else + return NULL; +} + /* Try to find a destination for indirect edge IE that corresponds to a simple call or a call of a member function pointer and where the destination is a pointer formal parameter described by jump function JFUNC. If it can be @@ -2237,6 +2326,8 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie, struct ipa_jump_func *jfunc, struct ipa_node_params *new_root_info) { + struct ipa_cst_ref_desc *rdesc; + struct cgraph_edge *cs; tree target; if (ie->indirect_info->agg_contents) @@ -2247,7 +2338,15 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie, target = ipa_value_from_jfunc (new_root_info, jfunc); if (!target) return NULL; - return ipa_make_edge_direct_to_target (ie, target); + cs = ipa_make_edge_direct_to_target (ie, target); + + if (cs && !ie->indirect_info->agg_contents + && jfunc->type == IPA_JF_CONST + && (rdesc = jfunc_rdesc_usable (jfunc)) + && --rdesc->refcount == 0) + remove_described_reference ((symtab_node) cs->callee, rdesc); + + return cs; } /* Try to find a destination for indirect edge IE that corresponds to a virtual @@ -2411,6 +2510,135 @@ propagate_info_to_inlined_callees (struct cgraph_edge *cs, return res; } +/* Combine two controlled uses counts as done during inlining. */ + +static int +combine_controlled_uses_counters (int c, int d) +{ + if (c == IPA_UNDESCRIBED_USE || d == IPA_UNDESCRIBED_USE) + return IPA_UNDESCRIBED_USE; + else + return c + d - 1; +} + +/* Propagate number of controlled users from CS->caleee to the new root of the + tree of inlined nodes. */ + +static void +propagate_controlled_uses (struct cgraph_edge *cs) +{ + struct ipa_edge_args *args = IPA_EDGE_REF (cs); + struct cgraph_node *new_root = cs->caller->global.inlined_to + ? cs->caller->global.inlined_to : cs->caller; + struct ipa_node_params *new_root_info = IPA_NODE_REF (new_root); + struct ipa_node_params *old_root_info = IPA_NODE_REF (cs->callee); + int count, i; + + count = MIN (ipa_get_cs_argument_count (args), + ipa_get_param_count (old_root_info)); + for (i = 0; i < count; i++) + { + struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i); + struct ipa_cst_ref_desc *rdesc; + + if (jf->type == IPA_JF_PASS_THROUGH) + { + int src_idx, c, d; + src_idx = ipa_get_jf_pass_through_formal_id (jf); + c = ipa_get_controlled_uses (new_root_info, src_idx); + d = ipa_get_controlled_uses (old_root_info, i); + + gcc_checking_assert (ipa_get_jf_pass_through_operation (jf) + == NOP_EXPR || c == IPA_UNDESCRIBED_USE); + c = combine_controlled_uses_counters (c, d); + ipa_set_controlled_uses (new_root_info, src_idx, c); + if (c == 0 && new_root_info->ipcp_orig_node) + { + struct cgraph_node *n; + struct ipa_ref *ref; + tree t = new_root_info->known_vals[src_idx]; + + if (t && TREE_CODE (t) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL + && (n = cgraph_get_node (TREE_OPERAND (t, 0))) + && (ref = ipa_find_reference ((symtab_node) new_root, + (symtab_node) n, NULL))) + { + if (dump_file) + fprintf (dump_file, "ipa-prop: Removing cloning-created " + "reference from %s/%i to %s/%i.\n", + xstrdup (cgraph_node_name (new_root)), + new_root->uid, + xstrdup (cgraph_node_name (n)), n->uid); + ipa_remove_reference (ref); + } + } + } + else if (jf->type == IPA_JF_CONST + && (rdesc = jfunc_rdesc_usable (jf))) + { + int d = ipa_get_controlled_uses (old_root_info, i); + int c = rdesc->refcount; + rdesc->refcount = combine_controlled_uses_counters (c, d); + if (rdesc->refcount == 0) + { + tree cst = ipa_get_jf_constant (jf); + struct cgraph_node *n; + gcc_checking_assert (TREE_CODE (cst) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (cst, 0)) + == FUNCTION_DECL); + n = cgraph_get_node (TREE_OPERAND (cst, 0)); + if (n) + { + struct cgraph_node *clone; + remove_described_reference ((symtab_node) n, rdesc); + + clone = cs->caller; + while (clone->global.inlined_to + && clone != rdesc->cs->caller + && IPA_NODE_REF (clone)->ipcp_orig_node) + { + struct ipa_ref *ref; + ref = ipa_find_reference ((symtab_node) clone, + (symtab_node) n, NULL); + if (ref) + { + if (dump_file) + fprintf (dump_file, "ipa-prop: Removing " + "cloning-created reference " + "from %s/%i to %s/%i.\n", + xstrdup (cgraph_node_name (clone)), + clone->uid, + xstrdup (cgraph_node_name (n)), + n->uid); + ipa_remove_reference (ref); + } + clone = clone->callers->caller; + } + } + } + } + } + + for (i = ipa_get_param_count (old_root_info); + i < ipa_get_cs_argument_count (args); + i++) + { + struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i); + + if (jf->type == IPA_JF_CONST) + { + struct ipa_cst_ref_desc *rdesc = jfunc_rdesc_usable (jf); + if (rdesc) + rdesc->refcount = IPA_UNDESCRIBED_USE; + } + else if (jf->type == IPA_JF_PASS_THROUGH) + ipa_set_controlled_uses (new_root_info, + jf->value.pass_through.formal_id, + IPA_UNDESCRIBED_USE); + } +} + /* Update jump functions and call note functions on inlining the call site CS. CS is expected to lead to a node already cloned by cgraph_clone_inline_nodes. Newly discovered indirect edges will be added to @@ -2428,6 +2656,7 @@ ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, return false; gcc_assert (ipa_edge_args_vector); + propagate_controlled_uses (cs); changed = propagate_info_to_inlined_callees (cs, cs->callee, new_edges); /* We do not keep jump functions of inlined edges up to date. Better to free @@ -2543,8 +2772,53 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst, new_args->jump_functions = vec_safe_copy (old_args->jump_functions); for (i = 0; i < vec_safe_length (old_args->jump_functions); i++) - (*new_args->jump_functions)[i].agg.items - = vec_safe_copy ((*old_args->jump_functions)[i].agg.items); + { + struct ipa_jump_func *src_jf = ipa_get_ith_jump_func (old_args, i); + struct ipa_jump_func *dst_jf = ipa_get_ith_jump_func (new_args, i); + + dst_jf->agg.items = vec_safe_copy (dst_jf->agg.items); + + if (src_jf->type == IPA_JF_CONST) + { + struct ipa_cst_ref_desc *src_rdesc = jfunc_rdesc_usable (src_jf); + + if (!src_rdesc) + dst_jf->value.constant.rdesc = NULL; + else if (src_rdesc->cs == src) + { + struct ipa_cst_ref_desc *dst_rdesc; + gcc_checking_assert (ipa_refdesc_pool); + dst_rdesc + = (struct ipa_cst_ref_desc *) pool_alloc (ipa_refdesc_pool); + dst_rdesc->cs = dst; + dst_rdesc->next_duplicate = src_rdesc->next_duplicate; + src_rdesc->next_duplicate = dst_rdesc; + dst_rdesc->refcount = src_rdesc->refcount; + dst_jf->value.constant.rdesc = dst_rdesc; + } + else + { + struct ipa_cst_ref_desc *dst_rdesc; + /* This can happen during inlining, when a JFUNC can refer to a + reference taken in a function up in the tree of inline clones. + We need to find the duplicate that refers to our tree of + inline clones. */ + + gcc_assert (dst->caller->global.inlined_to); + for (dst_rdesc = src_rdesc->next_duplicate; + dst_rdesc; + dst_rdesc = dst_rdesc->next_duplicate) + { + gcc_assert (dst_rdesc->cs->caller->global.inlined_to); + if (dst_rdesc->cs->caller->global.inlined_to + == dst->caller->global.inlined_to) + break; + } + + dst_jf->value.constant.rdesc = dst_rdesc; + } + } + } } /* Hook that is called by cgraph.c when a node is duplicated. */ @@ -2646,6 +2920,8 @@ ipa_free_all_structures_after_ipa_cp (void) free_alloc_pool (ipcp_values_pool); free_alloc_pool (ipcp_agg_lattice_pool); ipa_unregister_cgraph_hooks (); + if (ipa_refdesc_pool) + free_alloc_pool (ipa_refdesc_pool); } } @@ -2664,6 +2940,8 @@ ipa_free_all_structures_after_iinln (void) free_alloc_pool (ipcp_values_pool); if (ipcp_agg_lattice_pool) free_alloc_pool (ipcp_agg_lattice_pool); + if (ipa_refdesc_pool) + free_alloc_pool (ipa_refdesc_pool); } /* Print ipa_tree_map data structures of all functions in the @@ -2684,6 +2962,8 @@ ipa_print_node_params (FILE *f, struct cgraph_node *node) count = ipa_get_param_count (info); for (i = 0; i < count; i++) { + int c; + temp = ipa_get_param (info, i); if (TREE_CODE (temp) == PARM_DECL) fprintf (f, " param %d : %s", i, @@ -2692,6 +2972,11 @@ ipa_print_node_params (FILE *f, struct cgraph_node *node) : "(unnamed)")); if (ipa_is_param_used (info, i)) fprintf (f, " used"); + c = ipa_get_controlled_uses (info, i); + if (c == IPA_UNDESCRIBED_USE) + fprintf (f, " undescribed_use"); + else + fprintf (f, " controlled_uses=%i", c); fprintf (f, "\n"); } } @@ -3311,8 +3596,8 @@ ipa_write_jump_function (struct output_block *ob, break; case IPA_JF_CONST: gcc_assert ( - EXPR_LOCATION (jump_func->value.constant) == UNKNOWN_LOCATION); - stream_write_tree (ob, jump_func->value.constant, true); + EXPR_LOCATION (jump_func->value.constant.value) == UNKNOWN_LOCATION); + stream_write_tree (ob, jump_func->value.constant.value, true); break; case IPA_JF_PASS_THROUGH: streamer_write_uhwi (ob, jump_func->value.pass_through.operation); @@ -3360,6 +3645,7 @@ ipa_write_jump_function (struct output_block *ob, static void ipa_read_jump_function (struct lto_input_block *ib, struct ipa_jump_func *jump_func, + struct cgraph_edge *cs, struct data_in *data_in) { enum jump_func_type jftype; @@ -3382,7 +3668,7 @@ ipa_read_jump_function (struct lto_input_block *ib, break; } case IPA_JF_CONST: - ipa_set_jf_constant (jump_func, stream_read_tree (ib, data_in)); + ipa_set_jf_constant (jump_func, stream_read_tree (ib, data_in), cs); break; case IPA_JF_PASS_THROUGH: operation = (enum tree_code) streamer_read_uhwi (ib); @@ -3503,6 +3789,8 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node) for (j = 0; j < ipa_get_param_count (info); j++) bp_pack_value (&bp, ipa_is_param_used (info, j), 1); streamer_write_bitpack (&bp); + for (j = 0; j < ipa_get_param_count (info); j++) + streamer_write_hwi (ob, ipa_get_controlled_uses (info, j)); for (e = node->callees; e; e = e->next_callee) { struct ipa_edge_args *args = IPA_EDGE_REF (e); @@ -3540,6 +3828,8 @@ ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node, info->uses_analysis_done = true; info->node_enqueued = false; for (k = 0; k < ipa_get_param_count (info); k++) + ipa_set_controlled_uses (info, k, streamer_read_hwi (ib)); + for (k = 0; k < ipa_get_param_count (info); k++) ipa_set_param_used (info, k, bp_unpack_value (&bp, 1)); for (e = node->callees; e; e = e->next_callee) { @@ -3551,7 +3841,8 @@ ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node, vec_safe_grow_cleared (args->jump_functions, count); for (k = 0; k < ipa_get_cs_argument_count (args); k++) - ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), data_in); + ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e, + data_in); } for (e = node->indirect_calls; e; e = e->next_callee) { @@ -3562,7 +3853,7 @@ ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node, { vec_safe_grow_cleared (args->jump_functions, count); for (k = 0; k < ipa_get_cs_argument_count (args); k++) - ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), + ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e, data_in); } ipa_read_indirect_edge_info (ib, data_in, e); diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index e75826f..3399e82 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -29,6 +29,8 @@ along with GCC; see the file COPYING3. If not see /* The following definitions and interfaces are used by interprocedural analyses or parameters. */ +#define IPA_UNDESCRIBED_USE -1 + /* ipa-prop.c stuff (ipa-cp, indirect inlining): */ /* A jump function for a callsite represents the values passed as actual @@ -84,6 +86,17 @@ struct GTY(()) ipa_known_type_data tree component_type; }; +struct ipa_cst_ref_desc; + +/* Structure holding data required to describe a constant jump function. */ +struct GTY(()) ipa_constant_data +{ + /* THe value of the constant. */ + tree value; + /* Pointer to the structure that describes the reference. */ + struct ipa_cst_ref_desc GTY((skip)) *rdesc; +}; + /* Structure holding data required to describe a pass-through jump function. */ struct GTY(()) ipa_pass_through_data @@ -172,7 +185,7 @@ typedef struct GTY (()) ipa_jump_func union jump_func_value { struct ipa_known_type_data GTY ((tag ("IPA_JF_KNOWN_TYPE"))) known_type; - tree GTY ((tag ("IPA_JF_CONST"))) constant; + struct ipa_constant_data GTY ((tag ("IPA_JF_CONST"))) constant; struct ipa_pass_through_data GTY ((tag ("IPA_JF_PASS_THROUGH"))) pass_through; struct ipa_ancestor_jf_data GTY ((tag ("IPA_JF_ANCESTOR"))) ancestor; } GTY ((desc ("%1.type"))) value; @@ -213,7 +226,14 @@ static inline tree ipa_get_jf_constant (struct ipa_jump_func *jfunc) { gcc_checking_assert (jfunc->type == IPA_JF_CONST); - return jfunc->value.constant; + return jfunc->value.constant.value; +} + +static inline struct ipa_cst_ref_desc * +ipa_get_jf_constant_rdesc (struct ipa_jump_func *jfunc) +{ + gcc_checking_assert (jfunc->type == IPA_JF_CONST); + return jfunc->value.constant.rdesc; } /* Return the operand of a pass through jmp function JFUNC. */ @@ -296,6 +316,10 @@ struct ipa_param_descriptor { /* PARAM_DECL of this parameter. */ tree decl; + /* If all uses of the parameter are described by ipa-prop structures, this + says how many there are. If any use could not be described by means of + ipa-prop structures, this is IPA_UNDESCRIBED_USE. */ + int controlled_uses; /* The parameter is used. */ unsigned used : 1; }; @@ -365,6 +389,23 @@ ipa_set_param_used (struct ipa_node_params *info, int i, bool val) info->descriptors[i].used = val; } +/* Return how many uses described by ipa-prop a parameter has or + IPA_UNDESCRIBED_USE if there is a use that is not described by these + structures. */ +static inline int +ipa_get_controlled_uses (struct ipa_node_params *info, int i) +{ + return info->descriptors[i].controlled_uses; +} + +/* Set the controlled counter of a given parameter. */ + +static inline void +ipa_set_controlled_uses (struct ipa_node_params *info, int i, int val) +{ + info->descriptors[i].controlled_uses = val; +} + /* Return the used flag corresponding to the Ith formal parameter of the function associated with INFO. */ diff --git a/gcc/ipa-ref.c b/gcc/ipa-ref.c index 044e237..d6ac25f 100644 --- a/gcc/ipa-ref.c +++ b/gcc/ipa-ref.c @@ -198,3 +198,20 @@ ipa_ref_has_aliases_p (struct ipa_ref_list *ref_list) return true; return false; } + +/* Find the structure describing a reference in REFERRING_NODE to REFERRED_NODE + and associated with statement STMT. */ + +struct ipa_ref * +ipa_find_reference (symtab_node referring_node, symtab_node referred_node, + gimple stmt) +{ + struct ipa_ref *r = NULL; + int i; + + FOR_EACH_VEC_SAFE_ELT (referring_node->symbol.ref_list.references, i, r) + if (r->referred == referred_node + && (in_lto_p || r->stmt == stmt)) + return r; + return NULL; +} diff --git a/gcc/ipa-ref.h b/gcc/ipa-ref.h index 0b2fc50..972e973 100644 --- a/gcc/ipa-ref.h +++ b/gcc/ipa-ref.h @@ -71,3 +71,4 @@ void ipa_clone_references (symtab_node, struct ipa_ref_list *); void ipa_clone_referring (symtab_node, struct ipa_ref_list *); bool ipa_ref_cannot_lead_to_return (struct ipa_ref *); bool ipa_ref_has_aliases_p (struct ipa_ref_list *); +struct ipa_ref * ipa_find_reference (symtab_node, symtab_node, gimple); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1e59972..b4fc7f9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2013-05-13 Martin Jambor <mjambor@suse.cz> + + PR middle-end/42371 + * gcc.dg/ipa/remref-0.c: New test. + * gcc.dg/ipa/remref-1a.c: Likewise. + * gcc.dg/ipa/remref-1b.c: Likewise. + * gcc.dg/ipa/remref-2a.c: Likewise. + * gcc.dg/ipa/remref-2b.c: Likewise. + 2013-05-13 Marc Glisse <marc.glisse@inria.fr> * gcc.dg/vector-shift-2.c: New testcase. diff --git a/gcc/testsuite/gcc.dg/ipa/remref-0.c b/gcc/testsuite/gcc.dg/ipa/remref-0.c new file mode 100644 index 0000000..a9e434a --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/remref-0.c @@ -0,0 +1,30 @@ +/* Verify that indirect inlining machinery can remove references to functions + passed as parameters that are never used. */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-early-inlining -fno-ipa-sra -fno-ipa-cp -fdump-ipa-inline -fdump-tree-optimized" } */ + +extern int __attribute__ ((noinline, noclone, used)) +stuff (int i) +{ + return 0; +} + +static void hooray () +{ + stuff (1); +} + +static int hiphip (void (*f)()) +{ + return stuff (2); +} + +int main (void) +{ + return hiphip (hooray); +} + +/* { dg-final { scan-ipa-dump "ipa-prop: Removed a reference" "inline" } } */ +/* { dg-final { scan-tree-dump-not "hooray" "optimized" } } */ +/* { dg-final { cleanup-ipa-dump "inline" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/remref-1a.c b/gcc/testsuite/gcc.dg/ipa/remref-1a.c new file mode 100644 index 0000000..9db2bd6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/remref-1a.c @@ -0,0 +1,34 @@ +/* Verify that indirect inlining can also remove references of the functions it + discovers calls for. */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-early-inlining -fno-ipa-cp -fdump-ipa-inline -fdump-tree-optimized" } */ + +int global; + +void __attribute__ ((noinline, noclone, used)) +stuff (int i) +{ + global = i; +} + +static void hooray () +{ + stuff (1); +} + +static void hiphip (void (*f)()) +{ + stuff (2); + f (); +} + +int main (void) +{ + hiphip (hooray); + return 0; +} + +/* { dg-final { scan-ipa-dump "ipa-prop: Removed a reference" "inline" } } */ +/* { dg-final { scan-tree-dump-not "hooray" "optimized" } } */ +/* { dg-final { cleanup-ipa-dump "inline" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/remref-1b.c b/gcc/testsuite/gcc.dg/ipa/remref-1b.c new file mode 100644 index 0000000..a17cf48 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/remref-1b.c @@ -0,0 +1,37 @@ +/* Verify that indirect inlining can also remove references of the functions it + discovers calls for, even when nodes being inlined are virtual IPA-CP + clones. */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-early-inlining -fdump-ipa-cp-details -fdump-ipa-inline -fdump-tree-optimized" } */ + +int global; + +void __attribute__ ((noinline, noclone, used)) +stuff (int i) +{ + global = i; +} + +static void hooray () +{ + stuff (1); +} + +static void hiphip (void (*f)()) +{ + stuff (2); + f (); +} + +int main (void) +{ + hiphip (hooray); + return 0; +} + +/* { dg-final { scan-ipa-dump "removing its cloning-created reference" "cp" } } */ +/* { dg-final { scan-ipa-dump "ipa-prop: Removed a reference" "inline" } } */ +/* { dg-final { scan-tree-dump-not "hooray" "optimized" } } */ +/* { dg-final { cleanup-ipa-dump "cp" } } */ +/* { dg-final { cleanup-ipa-dump "inline" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/remref-2a.c b/gcc/testsuite/gcc.dg/ipa/remref-2a.c new file mode 100644 index 0000000..1e0df2e --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/remref-2a.c @@ -0,0 +1,90 @@ +/* Verify that indirect inlining can also remove references of the functions it + discovers calls for. */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-early-inlining -fno-ipa-cp -fdump-ipa-inline -fdump-tree-optimized" } */ + +int global; + +void __attribute__ ((noinline, noclone, used)) +stuff (int i) +{ + global = i; +} + +int __attribute__ ((noinline,noclone)) get_input(void) +{ + return 1; +} + +static void +hooray_1 () +{ + stuff (1); +} + +static inline void +hip2_1 (void (*g)()) +{ + int i; + g (); + /* Some stuff to make the function bigger so that hip1_1 gets inlined + fiorst. */ + for (i = 0; i < get_input (); i++) + { + stuff (2); + stuff (2+2); + } +} + +static inline void +hip1_1 (void (*g)()) +{ + hip2_1 (g); +} + +static void +hooray_2 () +{ + stuff (1); +} + +static inline void +hip2_2 (void (*g)()) +{ + g (); +} + +static inline void +hip1_2 (void (*g)()) +{ + int i; + + hip2_2 (g); + + /* Some stuff to make the function bigger so that hip2_2 gets inlined + fiorst. */ + for (i = 0; i < get_input (); i++) + { + stuff (2); + stuff (2+2); + } +} + + +int +main (int argc, int *argv[]) +{ + int i; + + for (i = 0; i < get_input (); i++) + { + hip1_1 (hooray_1); + hip1_2 (hooray_2); + } + return 0; +} + +/* { dg-final { scan-ipa-dump-times "ipa-prop: Removed a reference" 2 "inline" } } */ +/* { dg-final { scan-tree-dump-not "hooray" "optimized" } } */ +/* { dg-final { cleanup-ipa-dump "inline" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/remref-2b.c b/gcc/testsuite/gcc.dg/ipa/remref-2b.c new file mode 100644 index 0000000..554f306 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/remref-2b.c @@ -0,0 +1,94 @@ +/* Verify that indirect inlining can also remove references of the functions it + discovers calls for, even when nodes being inlined are virtual IPA-CP + clones. */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-early-inlining -fdump-ipa-cp-details -fdump-ipa-inline -fdump-tree-optimized" } */ + + +int global; + +void __attribute__ ((noinline, noclone, used)) +stuff (int i) +{ + global = i; +} + +int __attribute__ ((noinline,noclone)) get_input(void) +{ + return 1; +} + +static void +hooray_1 () +{ + stuff (1); +} + +static inline void +hip2_1 (void (*g)()) +{ + int i; + g (); + /* Some stuff to make the function bigger so that hip1_1 gets inlined + fiorst. */ + for (i = 0; i < get_input (); i++) + { + stuff (2); + stuff (2+2); + } +} + +static inline void +hip1_1 (void (*g)()) +{ + hip2_1 (g); +} + +static void +hooray_2 () +{ + stuff (1); +} + +static inline void +hip2_2 (void (*g)()) +{ + g (); +} + +static inline void +hip1_2 (void (*g)()) +{ + int i; + + hip2_2 (g); + + /* Some stuff to make the function bigger so that hip2_2 gets inlined + fiorst. */ + for (i = 0; i < get_input (); i++) + { + stuff (2); + stuff (2+2); + } +} + +int +main (int argc, int *argv[]) +{ + int i; + + for (i = 0; i < get_input (); i++) + { + hip1_1 (hooray_1); + hip1_2 (hooray_2); + } + return 0; +} + +/* { dg-final { scan-ipa-dump-times "removing its cloning-created reference" 2 "cp" } } */ +/* { dg-final { scan-ipa-dump "ipa-prop: Removed a reference" "inline" } } */ +/* { dg-final { scan-ipa-dump-times "ipa-prop: Removing cloning-created reference" 2 "inline" } } */ +/* { dg-final { scan-tree-dump-not "hooray" "optimized" } } */ +/* { dg-final { cleanup-ipa-dump "cp" } } */ +/* { dg-final { cleanup-ipa-dump "inline" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ |