Commit eb270950 by Feng Xue Committed by Feng Xue

Support extended aggregate jump function in ipa-cp

2019-11-14  Feng Xue  <fxue@os.amperecomputing.com>

	PR ipa/91682
	* ipa-prop.h (jump_func_type): New value IPA_JF_LOAD_AGG.
	(ipa_load_agg_data, ipa_agg_value, ipa_agg_value_set): New structs.
	(ipa_agg_jf_item): Add new field jftype and type, redefine field value.
	(ipa_agg_jump_function): Remove member function equal_to.
	(ipa_agg_jump_function_p): Remove typedef.
	(ipa_copy_agg_values, ipa_release_agg_values): New functions.
	* ipa-prop.c (ipa_print_node_jump_functions_for_edge): Dump
	information for aggregate jump function.
	(get_ssa_def_if_simple_copy): Add new parameter rhs_stmt to
	record last definition statement.
	(load_from_unmodified_param_or_agg): New function.
	(ipa_known_agg_contents_list): Add new field type and value, remove
	field constant.
	(build_agg_jump_func_from_list): Rename parameter const_count to
	value_count, build aggregate jump function from ipa_load_agg_data.
	(analyze_agg_content_value): New function.
	(extract_mem_content): Analyze memory store assignment to prepare
	information for aggregate jump function generation.
	(determine_known_aggregate_parts): Add new parameter fbi, remove
	parameter aa_walk_budeget_p.
	(update_jump_functions_after_inlining): Update aggregate jump function.
	(ipa_find_agg_cst_for_param): Change type of parameter agg.
	(try_make_edge_direct_simple_call): Add new parameter new_root.
	(try_make_edge_direct_virtual_call): Add new parameter new_root and
	new_root_info.
	(update_indirect_edges_after_inlining): Pass new argument to
	try_make_edge_direct_simple_call and try_make_edge_direct_virtual_call.
	(ipa_write_jump_function): Write aggregate jump function to file.
	(ipa_read_jump_function): Read aggregate jump function from file.
	(ipa_agg_value::equal_to): Migrate from ipa_agg_jf_item::equal_to.
	* ipa-cp.c (ipa_get_jf_arith_result): New function.
	(ipa_agg_value_from_node): Likewise.
	(ipa_agg_value_set_from_jfunc): Likewise.
	(propagate_vals_across_arith_jfunc): Likewise.
	(propagate_aggregate_lattice): Likewise.
	(ipa_get_jf_pass_through_result): Call ipa_get_jf_arith_result.
	(propagate_vals_across_pass_through): Call
	propagate_vals_across_arith_jfunc.
	(get_clone_agg_value): Move forward.
	(propagate_aggs_across_jump_function): Handle value propagation for
	aggregate jump function.
	(agg_jmp_p_vec_for_t_vec): Remove.
	(context_independent_aggregate_values): Replace vec<ipa_agg_jf_item>
	with vec<ipa_agg_value>.
	(copy_plats_to_inter, intersect_with_plats): Likewise.
	(agg_replacements_to_vector, intersect_with_agg_replacements): Likewise.
	(intersect_aggregate_with_edge): Likewise.
	(find_aggregate_values_for_callers_subset): Likewise.
	(cgraph_edge_brings_all_agg_vals_for_node): Likewise.
	(estimate_local_effects): Replace vec<ipa_agg_jump_function> and
	vec<ipa_agg_jump_function_p> with vec<ipa_agg_value_set>.
	(gather_context_independent_values): Likewise.
	(perform_estimation_of_a_value, decide_whether_version_node): Likewise.
	* ipa-fnsummary.c (evaluate_conditions_for_known_args): Replace
	vec<ipa_agg_jump_function_p> with vec<ipa_agg_value_set>.
	(evaluate_properties_for_edge): Likewise.
	(estimate_edge_devirt_benefit): Likewise.
	(estimate_edge_size_and_time):  Likewise.
	(estimate_calls_size_and_time): Likewise.
	(ipa_call_context::ipa_call_context): Likewise.
	(estimate_ipcp_clone_size_and_time):  Likewise.
	* ipa-fnsummary.h (ipa_call_context): Replace
	vec<ipa_agg_jump_function_p> with vec<ipa_agg_value_set>.
	* ipa-inline-analysis.c (do_estimate_edge_time): Replace
	vec<ipa_agg_jump_function_p> with vec<ipa_agg_value_set>.
	(do_estimate_edge_size): Likewise.
	(do_estimate_edge_hints): Likewise.

2019-11-14  Feng Xue  <fxue@os.amperecomputing.com>

        PR ipa/91682
        * gcc.dg/ipa/ipcp-agg-10.c: Change dg-scan string.
        * gcc.dg/ipa/ipcp-agg-11.c: New test.

From-SVN: r278193
parent 3e7cf2e6
2019-11-14 Feng Xue <fxue@os.amperecomputing.com>
PR ipa/91682
* ipa-prop.h (jump_func_type): New value IPA_JF_LOAD_AGG.
(ipa_load_agg_data, ipa_agg_value, ipa_agg_value_set): New structs.
(ipa_agg_jf_item): Add new field jftype and type, redefine field value.
(ipa_agg_jump_function): Remove member function equal_to.
(ipa_agg_jump_function_p): Remove typedef.
(ipa_copy_agg_values, ipa_release_agg_values): New functions.
* ipa-prop.c (ipa_print_node_jump_functions_for_edge): Dump
information for aggregate jump function.
(get_ssa_def_if_simple_copy): Add new parameter rhs_stmt to
record last definition statement.
(load_from_unmodified_param_or_agg): New function.
(ipa_known_agg_contents_list): Add new field type and value, remove
field constant.
(build_agg_jump_func_from_list): Rename parameter const_count to
value_count, build aggregate jump function from ipa_load_agg_data.
(analyze_agg_content_value): New function.
(extract_mem_content): Analyze memory store assignment to prepare
information for aggregate jump function generation.
(determine_known_aggregate_parts): Add new parameter fbi, remove
parameter aa_walk_budeget_p.
(update_jump_functions_after_inlining): Update aggregate jump function.
(ipa_find_agg_cst_for_param): Change type of parameter agg.
(try_make_edge_direct_simple_call): Add new parameter new_root.
(try_make_edge_direct_virtual_call): Add new parameter new_root and
new_root_info.
(update_indirect_edges_after_inlining): Pass new argument to
try_make_edge_direct_simple_call and try_make_edge_direct_virtual_call.
(ipa_write_jump_function): Write aggregate jump function to file.
(ipa_read_jump_function): Read aggregate jump function from file.
(ipa_agg_value::equal_to): Migrate from ipa_agg_jf_item::equal_to.
* ipa-cp.c (ipa_get_jf_arith_result): New function.
(ipa_agg_value_from_node): Likewise.
(ipa_agg_value_set_from_jfunc): Likewise.
(propagate_vals_across_arith_jfunc): Likewise.
(propagate_aggregate_lattice): Likewise.
(ipa_get_jf_pass_through_result): Call ipa_get_jf_arith_result.
(propagate_vals_across_pass_through): Call
propagate_vals_across_arith_jfunc.
(get_clone_agg_value): Move forward.
(propagate_aggs_across_jump_function): Handle value propagation for
aggregate jump function.
(agg_jmp_p_vec_for_t_vec): Remove.
(context_independent_aggregate_values): Replace vec<ipa_agg_jf_item>
with vec<ipa_agg_value>.
(copy_plats_to_inter, intersect_with_plats): Likewise.
(agg_replacements_to_vector, intersect_with_agg_replacements): Likewise.
(intersect_aggregate_with_edge): Likewise.
(find_aggregate_values_for_callers_subset): Likewise.
(cgraph_edge_brings_all_agg_vals_for_node): Likewise.
(estimate_local_effects): Replace vec<ipa_agg_jump_function> and
vec<ipa_agg_jump_function_p> with vec<ipa_agg_value_set>.
(gather_context_independent_values): Likewise.
(perform_estimation_of_a_value, decide_whether_version_node): Likewise.
* ipa-fnsummary.c (evaluate_conditions_for_known_args): Replace
vec<ipa_agg_jump_function_p> with vec<ipa_agg_value_set>.
(evaluate_properties_for_edge): Likewise.
(estimate_edge_devirt_benefit): Likewise.
(estimate_edge_size_and_time): Likewise.
(estimate_calls_size_and_time): Likewise.
(ipa_call_context::ipa_call_context): Likewise.
(estimate_ipcp_clone_size_and_time): Likewise.
* ipa-fnsummary.h (ipa_call_context): Replace
vec<ipa_agg_jump_function_p> with vec<ipa_agg_value_set>.
* ipa-inline-analysis.c (do_estimate_edge_time): Replace
vec<ipa_agg_jump_function_p> with vec<ipa_agg_value_set>.
(do_estimate_edge_size): Likewise.
(do_estimate_edge_hints): Likewise.
2019-11-13 Jan Hubicka <hubicka@ucw.cz> 2019-11-13 Jan Hubicka <hubicka@ucw.cz>
* ipa-cp.c (propagate_vr_across_jump_function): Propagate also across * ipa-cp.c (propagate_vr_across_jump_function): Propagate also across
...@@ -306,9 +306,9 @@ set_hint_predicate (predicate **p, predicate new_predicate) ...@@ -306,9 +306,9 @@ set_hint_predicate (predicate **p, predicate new_predicate)
the fact that parameter is indeed a constant. the fact that parameter is indeed a constant.
KNOWN_VALS is partial mapping of parameters of NODE to constant values. KNOWN_VALS is partial mapping of parameters of NODE to constant values.
KNOWN_AGGS is a vector of aggreggate jump functions for each parameter. KNOWN_AGGS is a vector of aggreggate known offset/value set for each
Return clause of possible truths. When INLINE_P is true, assume that we are parameter. Return clause of possible truths. When INLINE_P is true, assume
inlining. that we are inlining.
ERROR_MARK means compile time invariant. */ ERROR_MARK means compile time invariant. */
...@@ -316,8 +316,7 @@ static void ...@@ -316,8 +316,7 @@ static void
evaluate_conditions_for_known_args (struct cgraph_node *node, evaluate_conditions_for_known_args (struct cgraph_node *node,
bool inline_p, bool inline_p,
vec<tree> known_vals, vec<tree> known_vals,
vec<ipa_agg_jump_function_p> vec<ipa_agg_value_set> known_aggs,
known_aggs,
clause_t *ret_clause, clause_t *ret_clause,
clause_t *ret_nonspec_clause) clause_t *ret_nonspec_clause)
{ {
...@@ -349,7 +348,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -349,7 +348,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
if (c->agg_contents) if (c->agg_contents)
{ {
struct ipa_agg_jump_function *agg; struct ipa_agg_value_set *agg;
if (c->code == predicate::changed if (c->code == predicate::changed
&& !c->by_ref && !c->by_ref
...@@ -358,7 +357,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, ...@@ -358,7 +357,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
if (known_aggs.exists ()) if (known_aggs.exists ())
{ {
agg = known_aggs[c->operand_num]; agg = &known_aggs[c->operand_num];
val = ipa_find_agg_cst_for_param (agg, known_vals[c->operand_num], val = ipa_find_agg_cst_for_param (agg, known_vals[c->operand_num],
c->offset, c->by_ref); c->offset, c->by_ref);
} }
...@@ -445,12 +444,12 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -445,12 +444,12 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
vec<tree> *known_vals_ptr, vec<tree> *known_vals_ptr,
vec<ipa_polymorphic_call_context> vec<ipa_polymorphic_call_context>
*known_contexts_ptr, *known_contexts_ptr,
vec<ipa_agg_jump_function_p> *known_aggs_ptr) vec<ipa_agg_value_set> *known_aggs_ptr)
{ {
struct cgraph_node *callee = e->callee->ultimate_alias_target (); struct cgraph_node *callee = e->callee->ultimate_alias_target ();
class ipa_fn_summary *info = ipa_fn_summaries->get (callee); class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
vec<tree> known_vals = vNULL; vec<tree> known_vals = vNULL;
vec<ipa_agg_jump_function_p> known_aggs = vNULL; vec<ipa_agg_value_set> known_aggs = vNULL;
class ipa_edge_args *args; class ipa_edge_args *args;
if (clause_ptr) if (clause_ptr)
...@@ -465,14 +464,16 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -465,14 +464,16 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
&& ((clause_ptr && info->conds) || known_vals_ptr || known_contexts_ptr) && ((clause_ptr && info->conds) || known_vals_ptr || known_contexts_ptr)
&& (args = IPA_EDGE_REF (e)) != NULL) && (args = IPA_EDGE_REF (e)) != NULL)
{ {
struct cgraph_node *caller;
class ipa_node_params *caller_parms_info, *callee_pi; class ipa_node_params *caller_parms_info, *callee_pi;
class ipa_call_summary *es = ipa_call_summaries->get (e); class ipa_call_summary *es = ipa_call_summaries->get (e);
int i, count = ipa_get_cs_argument_count (args); int i, count = ipa_get_cs_argument_count (args);
if (e->caller->inlined_to) if (e->caller->inlined_to)
caller_parms_info = IPA_NODE_REF (e->caller->inlined_to); caller = e->caller->inlined_to;
else else
caller_parms_info = IPA_NODE_REF (e->caller); caller = e->caller;
caller_parms_info = IPA_NODE_REF (caller);
callee_pi = IPA_NODE_REF (callee); callee_pi = IPA_NODE_REF (callee);
if (count && (info->conds || known_vals_ptr)) if (count && (info->conds || known_vals_ptr))
...@@ -508,10 +509,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -508,10 +509,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
if (known_contexts_ptr) if (known_contexts_ptr)
(*known_contexts_ptr)[i] (*known_contexts_ptr)[i]
= ipa_context_from_jfunc (caller_parms_info, e, i, jf); = ipa_context_from_jfunc (caller_parms_info, e, i, jf);
/* TODO: When IPA-CP starts propagating and merging aggregate jump
functions, use its knowledge of the caller too, just like the known_aggs[i] = ipa_agg_value_set_from_jfunc (caller_parms_info,
scalar case above. */ caller, &jf->agg);
known_aggs[i] = &jf->agg;
} }
else else
gcc_assert (callee->thunk.thunk_p); gcc_assert (callee->thunk.thunk_p);
...@@ -545,7 +545,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, ...@@ -545,7 +545,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
if (known_aggs_ptr) if (known_aggs_ptr)
*known_aggs_ptr = known_aggs; *known_aggs_ptr = known_aggs;
else else
known_aggs.release (); ipa_release_agg_values (known_aggs);
} }
...@@ -2838,7 +2838,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie, ...@@ -2838,7 +2838,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
int *size, int *time, int *size, int *time,
vec<tree> known_vals, vec<tree> known_vals,
vec<ipa_polymorphic_call_context> known_contexts, vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs) vec<ipa_agg_value_set> known_aggs)
{ {
tree target; tree target;
struct cgraph_node *callee; struct cgraph_node *callee;
...@@ -2887,7 +2887,7 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size, ...@@ -2887,7 +2887,7 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size,
int prob, int prob,
vec<tree> known_vals, vec<tree> known_vals,
vec<ipa_polymorphic_call_context> known_contexts, vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs, vec<ipa_agg_value_set> known_aggs,
ipa_hints *hints) ipa_hints *hints)
{ {
class ipa_call_summary *es = ipa_call_summaries->get (e); class ipa_call_summary *es = ipa_call_summaries->get (e);
...@@ -2923,7 +2923,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, ...@@ -2923,7 +2923,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size,
clause_t possible_truths, clause_t possible_truths,
vec<tree> known_vals, vec<tree> known_vals,
vec<ipa_polymorphic_call_context> known_contexts, vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs) vec<ipa_agg_value_set> known_aggs)
{ {
struct cgraph_edge *e; struct cgraph_edge *e;
for (e = node->callees; e; e = e->next_callee) for (e = node->callees; e; e = e->next_callee)
...@@ -2983,7 +2983,7 @@ ipa_call_context::ipa_call_context (cgraph_node *node, ...@@ -2983,7 +2983,7 @@ ipa_call_context::ipa_call_context (cgraph_node *node,
vec<tree> known_vals, vec<tree> known_vals,
vec<ipa_polymorphic_call_context> vec<ipa_polymorphic_call_context>
known_contexts, known_contexts,
vec<ipa_agg_jump_function_p> known_aggs, vec<ipa_agg_value_set> known_aggs,
vec<inline_param_summary> vec<inline_param_summary>
inline_param_summary) inline_param_summary)
: m_node (node), m_possible_truths (possible_truths), : m_node (node), m_possible_truths (possible_truths),
...@@ -3057,9 +3057,9 @@ ipa_call_context::duplicate_from (const ipa_call_context &ctx) ...@@ -3057,9 +3057,9 @@ ipa_call_context::duplicate_from (const ipa_call_context &ctx)
for (unsigned int i = 0; i < n; i++) for (unsigned int i = 0; i < n; i++)
if (ipa_is_param_used_by_indirect_call (params_summary, i) if (ipa_is_param_used_by_indirect_call (params_summary, i)
&& ctx.m_known_aggs[i]) && !ctx.m_known_aggs[i].is_empty ())
{ {
m_known_aggs = ctx.m_known_aggs.copy (); m_known_aggs = ipa_copy_agg_values (ctx.m_known_aggs);
break; break;
} }
} }
...@@ -3078,7 +3078,7 @@ ipa_call_context::release (bool all) ...@@ -3078,7 +3078,7 @@ ipa_call_context::release (bool all)
return; return;
m_known_vals.release (); m_known_vals.release ();
m_known_contexts.release (); m_known_contexts.release ();
m_known_aggs.release (); ipa_release_agg_values (m_known_aggs);
if (all) if (all)
m_inline_param_summary.release (); m_inline_param_summary.release ();
} }
...@@ -3179,19 +3179,22 @@ ipa_call_context::equal_to (const ipa_call_context &ctx) ...@@ -3179,19 +3179,22 @@ ipa_call_context::equal_to (const ipa_call_context &ctx)
{ {
if (!ipa_is_param_used_by_indirect_call (params_summary, i)) if (!ipa_is_param_used_by_indirect_call (params_summary, i))
continue; continue;
if (i >= m_known_aggs.length () || !m_known_aggs[i]) if (i >= m_known_aggs.length () || m_known_aggs[i].is_empty ())
{ {
if (i < ctx.m_known_aggs.length () && ctx.m_known_aggs[i]) if (i < ctx.m_known_aggs.length ()
&& !ctx.m_known_aggs[i].is_empty ())
return false; return false;
continue; continue;
} }
if (i >= ctx.m_known_aggs.length () || !ctx.m_known_aggs[i]) if (i >= ctx.m_known_aggs.length ()
|| ctx.m_known_aggs[i].is_empty ())
{ {
if (i < m_known_aggs.length () && m_known_aggs[i]) if (i < m_known_aggs.length ()
&& !m_known_aggs[i].is_empty ())
return false; return false;
continue; continue;
} }
if (m_known_aggs[i] != ctx.m_known_aggs[i]) if (!m_known_aggs[i].equal_to (ctx.m_known_aggs[i]))
return false; return false;
} }
} }
...@@ -3348,7 +3351,7 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node, ...@@ -3348,7 +3351,7 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
vec<tree> known_vals, vec<tree> known_vals,
vec<ipa_polymorphic_call_context> vec<ipa_polymorphic_call_context>
known_contexts, known_contexts,
vec<ipa_agg_jump_function_p> known_aggs, vec<ipa_agg_value_set> known_aggs,
int *ret_size, sreal *ret_time, int *ret_size, sreal *ret_time,
sreal *ret_nonspec_time, sreal *ret_nonspec_time,
ipa_hints *hints) ipa_hints *hints)
......
...@@ -293,7 +293,7 @@ public: ...@@ -293,7 +293,7 @@ public:
clause_t nonspec_possible_truths, clause_t nonspec_possible_truths,
vec<tree> known_vals, vec<tree> known_vals,
vec<ipa_polymorphic_call_context> known_contexts, vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs, vec<ipa_agg_value_set> known_aggs,
vec<inline_param_summary> m_inline_param_summary); vec<inline_param_summary> m_inline_param_summary);
ipa_call_context () ipa_call_context ()
: m_node(NULL) : m_node(NULL)
...@@ -329,7 +329,7 @@ private: ...@@ -329,7 +329,7 @@ private:
/* Vector describing known polymorphic call contexts. */ /* Vector describing known polymorphic call contexts. */
vec<ipa_polymorphic_call_context> m_known_contexts; vec<ipa_polymorphic_call_context> m_known_contexts;
/* Vector describing known aggregate values. */ /* Vector describing known aggregate values. */
vec<ipa_agg_jump_function_p> m_known_aggs; vec<ipa_agg_value_set> m_known_aggs;
}; };
extern fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries; extern fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries;
...@@ -345,7 +345,7 @@ void inline_analyze_function (struct cgraph_node *node); ...@@ -345,7 +345,7 @@ void inline_analyze_function (struct cgraph_node *node);
void estimate_ipcp_clone_size_and_time (struct cgraph_node *, void estimate_ipcp_clone_size_and_time (struct cgraph_node *,
vec<tree>, vec<tree>,
vec<ipa_polymorphic_call_context>, vec<ipa_polymorphic_call_context>,
vec<ipa_agg_jump_function_p>, vec<ipa_agg_value_set>,
int *, sreal *, sreal *, int *, sreal *, sreal *,
ipa_hints *); ipa_hints *);
void ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge); void ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge);
...@@ -360,7 +360,7 @@ void evaluate_properties_for_edge (struct cgraph_edge *e, ...@@ -360,7 +360,7 @@ void evaluate_properties_for_edge (struct cgraph_edge *e,
vec<tree> *known_vals_ptr, vec<tree> *known_vals_ptr,
vec<ipa_polymorphic_call_context> vec<ipa_polymorphic_call_context>
*known_contexts_ptr, *known_contexts_ptr,
vec<ipa_agg_jump_function_p> *); vec<ipa_agg_value_set> *);
void ipa_fnsummary_c_finalize (void); void ipa_fnsummary_c_finalize (void);
HOST_WIDE_INT ipa_get_stack_frame_offset (struct cgraph_node *node); HOST_WIDE_INT ipa_get_stack_frame_offset (struct cgraph_node *node);
......
...@@ -188,7 +188,7 @@ do_estimate_edge_time (struct cgraph_edge *edge) ...@@ -188,7 +188,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
clause_t clause, nonspec_clause; clause_t clause, nonspec_clause;
vec<tree> known_vals; vec<tree> known_vals;
vec<ipa_polymorphic_call_context> known_contexts; vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function_p> known_aggs; vec<ipa_agg_value_set> known_aggs;
class ipa_call_summary *es = ipa_call_summaries->get (edge); class ipa_call_summary *es = ipa_call_summaries->get (edge);
int min_size = -1; int min_size = -1;
...@@ -308,7 +308,7 @@ do_estimate_edge_size (struct cgraph_edge *edge) ...@@ -308,7 +308,7 @@ do_estimate_edge_size (struct cgraph_edge *edge)
clause_t clause, nonspec_clause; clause_t clause, nonspec_clause;
vec<tree> known_vals; vec<tree> known_vals;
vec<ipa_polymorphic_call_context> known_contexts; vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function_p> known_aggs; vec<ipa_agg_value_set> known_aggs;
/* When we do caching, use do_estimate_edge_time to populate the entry. */ /* When we do caching, use do_estimate_edge_time to populate the entry. */
...@@ -347,7 +347,7 @@ do_estimate_edge_hints (struct cgraph_edge *edge) ...@@ -347,7 +347,7 @@ do_estimate_edge_hints (struct cgraph_edge *edge)
clause_t clause, nonspec_clause; clause_t clause, nonspec_clause;
vec<tree> known_vals; vec<tree> known_vals;
vec<ipa_polymorphic_call_context> known_contexts; vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function_p> known_aggs; vec<ipa_agg_value_set> known_aggs;
/* When we do caching, use do_estimate_edge_time to populate the entry. */ /* When we do caching, use do_estimate_edge_time to populate the entry. */
......
...@@ -39,6 +39,15 @@ along with GCC; see the file COPYING3. If not see ...@@ -39,6 +39,15 @@ along with GCC; see the file COPYING3. If not see
argument. argument.
Unknown - neither of the above. Unknown - neither of the above.
IPA_JF_LOAD_AGG is a compound pass-through jump function, in which primary
operation on formal parameter is memory dereference that loads a value from
a part of an aggregate, which is represented or pointed to by the formal
parameter. Moreover, an additional unary/binary operation can be applied on
the loaded value, and final result is passed as actual argument of callee
(e.g. *(param_1(D) + 4) op 24 ). It is meant to describe usage of aggregate
parameter or by-reference parameter referenced in argument passing, commonly
found in C++ and Fortran.
IPA_JF_ANCESTOR is a special pass-through jump function, which means that IPA_JF_ANCESTOR is a special pass-through jump function, which means that
the result is an address of a part of the object pointed to by the formal the result is an address of a part of the object pointed to by the formal
parameter to which the function refers. It is mainly intended to represent parameter to which the function refers. It is mainly intended to represent
...@@ -60,6 +69,7 @@ enum jump_func_type ...@@ -60,6 +69,7 @@ enum jump_func_type
IPA_JF_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */ IPA_JF_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */
IPA_JF_CONST, /* represented by field costant */ IPA_JF_CONST, /* represented by field costant */
IPA_JF_PASS_THROUGH, /* represented by field pass_through */ IPA_JF_PASS_THROUGH, /* represented by field pass_through */
IPA_JF_LOAD_AGG, /* represented by field load_agg */
IPA_JF_ANCESTOR /* represented by field ancestor */ IPA_JF_ANCESTOR /* represented by field ancestor */
}; };
...@@ -97,6 +107,26 @@ struct GTY(()) ipa_pass_through_data ...@@ -97,6 +107,26 @@ struct GTY(()) ipa_pass_through_data
unsigned agg_preserved : 1; unsigned agg_preserved : 1;
}; };
/* Structure holding data required to describe a load-value-from-aggregate
jump function. */
struct GTY(()) ipa_load_agg_data
{
/* Inherit from pass through jump function, describing unary/binary
operation on the value loaded from aggregate that is represented or
pointed to by the formal parameter, specified by formal_id in this
pass_through jump function data structure. */
struct ipa_pass_through_data pass_through;
/* Type of the value loaded from the aggregate. */
tree type;
/* Offset at which the value is located within the aggregate. */
HOST_WIDE_INT offset;
/* True if loaded by reference (the aggregate is pointed to by the formal
parameter) or false if loaded by value (the aggregate is represented
by the formal parameter). */
bool by_ref;
};
/* Structure holding data required to describe an ancestor pass-through /* Structure holding data required to describe an ancestor pass-through
jump function. */ jump function. */
...@@ -110,58 +140,139 @@ struct GTY(()) ipa_ancestor_jf_data ...@@ -110,58 +140,139 @@ struct GTY(()) ipa_ancestor_jf_data
unsigned agg_preserved : 1; unsigned agg_preserved : 1;
}; };
/* An element in an aggegate part of a jump function describing a known value /* A jump function for an aggregate part at a given offset, which describes how
at a given offset. When it is part of a pass-through jump function with it content value is generated. All unlisted positions are assumed to have a
agg_preserved set or an ancestor jump function with agg_preserved set, all value defined in an unknown way. */
unlisted positions are assumed to be preserved but the value can be a type
node, which means that the particular piece (starting at offset and having
the size of the type) is clobbered with an unknown value. When
agg_preserved is false or the type of the containing jump function is
different, all unlisted parts are assumed to be unknown and all values must
fulfill is_gimple_ip_invariant. */
struct GTY(()) ipa_agg_jf_item struct GTY(()) ipa_agg_jf_item
{ {
/* The offset at which the known value is located within the aggregate. */ /* The offset for the aggregate part. */
HOST_WIDE_INT offset; HOST_WIDE_INT offset;
/* The known constant or type if this is a clobber. */ /* Data type of the aggregate part. */
tree value; tree type;
/* Return true if OTHER describes same agg item. */ /* Jump function type. */
bool equal_to (const ipa_agg_jf_item &other); enum jump_func_type jftype;
};
/* Represents a value of jump function. constant represents the actual constant
in constant jump function content. pass_through is used only in simple pass
through jump function context. load_agg is for load-value-from-aggregate
jump function context. */
union jump_func_agg_value
{
tree GTY ((tag ("IPA_JF_CONST"))) constant;
struct ipa_pass_through_data GTY ((tag ("IPA_JF_PASS_THROUGH"))) pass_through;
struct ipa_load_agg_data GTY ((tag ("IPA_JF_LOAD_AGG"))) load_agg;
} GTY ((desc ("%1.jftype"))) value;
};
/* Aggregate jump function - i.e. description of contents of aggregates passed /* Jump functions describing a set of aggregate contents. */
either by reference or value. */
struct GTY(()) ipa_agg_jump_function struct GTY(()) ipa_agg_jump_function
{ {
/* Description of the individual items. */ /* Description of the individual jump function item. */
vec<ipa_agg_jf_item, va_gc> *items; vec<ipa_agg_jf_item, va_gc> *items;
/* True if the data was passed by reference (as opposed to by value). */ /* True if the data was passed by reference (as opposed to by value). */
bool by_ref; bool by_ref;
};
/* An element in an aggregate part describing a known value at a given offset.
All unlisted positions are assumed to be unknown and all listed values must
fulfill is_gimple_ip_invariant. */
struct ipa_agg_value
{
/* The offset at which the known value is located within the aggregate. */
HOST_WIDE_INT offset;
/* Return true if OTHER describes same agg items. */ /* The known constant. */
bool equal_to (const ipa_agg_jump_function &other) tree value;
/* Return true if OTHER describes same agg value. */
bool equal_to (const ipa_agg_value &other);
};
/* Structure describing a set of known offset/value for aggregate. */
struct ipa_agg_value_set
{
/* Description of the individual item. */
vec<ipa_agg_value> items;
/* True if the data was passed by reference (as opposed to by value). */
bool by_ref;
/* Return true if OTHER describes same agg values. */
bool equal_to (const ipa_agg_value_set &other)
{ {
if (by_ref != other.by_ref) if (by_ref != other.by_ref)
return false; return false;
if (items != NULL && other.items == NULL) if (items.length () != other.items.length ())
return false;
if (!items)
return other.items == NULL;
if (items->length () != other.items->length ())
return false; return false;
for (unsigned int i = 0; i < items->length (); i++) for (unsigned int i = 0; i < items.length (); i++)
if (!(*items)[i].equal_to ((*other.items)[i])) if (!items[i].equal_to (other.items[i]))
return false; return false;
return true; return true;
} }
/* Return true if there is any value for aggregate. */
bool is_empty () const
{
return items.is_empty ();
}
ipa_agg_value_set copy () const
{
ipa_agg_value_set new_copy;
new_copy.items = items.copy ();
new_copy.by_ref = by_ref;
return new_copy;
}
void release ()
{
items.release ();
}
}; };
typedef struct ipa_agg_jump_function *ipa_agg_jump_function_p; /* Return copy of a vec<ipa_agg_value_set>. */
static inline vec<ipa_agg_value_set>
ipa_copy_agg_values (const vec<ipa_agg_value_set> &aggs)
{
vec<ipa_agg_value_set> aggs_copy = vNULL;
if (!aggs.is_empty ())
{
ipa_agg_value_set *agg;
int i;
aggs_copy.reserve_exact (aggs.length ());
FOR_EACH_VEC_ELT (aggs, i, agg)
aggs_copy.quick_push (agg->copy ());
}
return aggs_copy;
}
/* For vec<ipa_agg_value_set>, DO NOT call release(), use below function
instead. Because ipa_agg_value_set contains a field of vector type, we
should release this child vector in each element before reclaiming the
whole vector. */
static inline void
ipa_release_agg_values (vec<ipa_agg_value_set> &aggs)
{
ipa_agg_value_set *agg;
int i;
FOR_EACH_VEC_ELT (aggs, i, agg)
agg->release ();
aggs.release ();
}
/* Information about zero/non-zero bits. */ /* Information about zero/non-zero bits. */
class GTY(()) ipa_bits class GTY(()) ipa_bits
...@@ -193,8 +304,8 @@ public: ...@@ -193,8 +304,8 @@ public:
types of jump functions supported. */ types of jump functions supported. */
struct GTY (()) ipa_jump_func struct GTY (()) ipa_jump_func
{ {
/* Aggregate contants description. See struct ipa_agg_jump_function and its /* Aggregate jump function description. See struct ipa_agg_jump_function
description. */ and its description. */
struct ipa_agg_jump_function agg; struct ipa_agg_jump_function agg;
/* Information about zero/non-zero bits. The pointed to structure is shared /* Information about zero/non-zero bits. The pointed to structure is shared
...@@ -857,9 +968,9 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, ...@@ -857,9 +968,9 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
/* Indirect edge and binfo processing. */ /* Indirect edge and binfo processing. */
tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
vec<tree> , vec<tree>,
vec<ipa_polymorphic_call_context>, vec<ipa_polymorphic_call_context>,
vec<ipa_agg_jump_function_p>, vec<ipa_agg_value_set>,
bool *); bool *);
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree, struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree,
bool speculative = false); bool speculative = false);
...@@ -872,7 +983,7 @@ ipa_bits *ipa_get_ipa_bits_for_value (const widest_int &value, ...@@ -872,7 +983,7 @@ ipa_bits *ipa_get_ipa_bits_for_value (const widest_int &value,
void ipa_analyze_node (struct cgraph_node *); void ipa_analyze_node (struct cgraph_node *);
/* Aggregate jump function related functions. */ /* Aggregate jump function related functions. */
tree ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg, tree scalar, tree ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
HOST_WIDE_INT offset, bool by_ref, HOST_WIDE_INT offset, bool by_ref,
bool *from_global_constant = NULL); bool *from_global_constant = NULL);
bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi, bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
...@@ -918,6 +1029,9 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *, ...@@ -918,6 +1029,9 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
cgraph_edge *, cgraph_edge *,
int, int,
ipa_jump_func *); ipa_jump_func *);
ipa_agg_value_set ipa_agg_value_set_from_jfunc (ipa_node_params *,
cgraph_node *,
ipa_agg_jump_function *);
void ipa_dump_param (FILE *, class ipa_node_params *info, int i); void ipa_dump_param (FILE *, class ipa_node_params *info, int i);
void ipa_release_body_info (struct ipa_func_body_info *); void ipa_release_body_info (struct ipa_func_body_info *);
tree ipa_get_callee_param_type (struct cgraph_edge *e, int i); tree ipa_get_callee_param_type (struct cgraph_edge *e, int i);
......
2019-11-14 Feng Xue <fxue@os.amperecomputing.com>
PR ipa/91682
* gcc.dg/ipa/ipcp-agg-10.c: Change dg-scan string.
* gcc.dg/ipa/ipcp-agg-11.c: New test.
2019-11-14 Jakub Jelinek <jakub@redhat.com> 2019-11-14 Jakub Jelinek <jakub@redhat.com>
PR ipa/92421 PR ipa/92421
......
...@@ -72,7 +72,7 @@ int caller2(void) ...@@ -72,7 +72,7 @@ int caller2(void)
return sum; return sum;
} }
/* { dg-final { scan-ipa-dump-times "offset: 0, cst: 1" 1 "cp" } } */ /* { dg-final { scan-ipa-dump-times "offset: 0, type: int, CONST: 1" 1 "cp" } } */
/* { dg-final { scan-ipa-dump-times "offset: 0, cst: 2" 1 "cp" } } */ /* { dg-final { scan-ipa-dump-times "offset: 0, type: int, CONST: 2" 1 "cp" } } */
/* { dg-final { scan-ipa-dump-times "offset: 0, cst: 3" 1 "cp" } } */ /* { dg-final { scan-ipa-dump-times "offset: 0, type: int, CONST: 3" 1 "cp" } } */
/* { dg-final { scan-ipa-dump-times "offset: 64, cst: 4" 1 "cp" } } */ /* { dg-final { scan-ipa-dump-times "offset: 64, type: int, CONST: 4" 1 "cp" } } */
/* { dg-do compile } */
/* { dg-options "-O3 -fno-ipa-sra -fdump-ipa-cp-details -fno-early-inlining" } */
/* { dg-add-options bind_pic_locally } */
struct S
{
int a, b, c;
};
void *blah(int, void *);
#define foo_body(p)\
{ \
int i, c = (p)->c; \
int b = (p)->b; \
void *v = (void *) (p); \
\
for (i= 0; i< c; i++) \
v = blah(b + i, v); \
}
static void __attribute__ ((noinline))
foo_v (struct S s)
{
foo_body (&s);
}
static void __attribute__ ((noinline))
foo_r (struct S *p)
{
foo_body (p);
}
static void
goo_v (int a, int *p)
{
struct S s;
s.a = 101;
s.b = a % 7;
s.c = *p + 6;
foo_v (s);
}
static void
goo_r (int a, struct S n)
{
struct S s;
s.a = 1;
s.b = a + 5;
s.c = -n.b;
foo_r (&s);
}
void
entry ()
{
int a;
int v;
struct S s;
a = 9;
v = 3;
goo_v (a, &v);
a = 100;
s.b = 18;
goo_r (a, s);
}
/* { dg-final { scan-ipa-dump "offset: 0, type: int, CONST: 1" "cp" } } */
/* { dg-final { scan-ipa-dump "offset: 32, type: int, PASS THROUGH: 0, op plus_expr 5" "cp" } } */
/* { dg-final { scan-ipa-dump "offset: 64, type: int, LOAD AGG: 1 \\\[offset: 32, by value], op negate_expr" "cp" } } */
/* { dg-final { scan-ipa-dump "offset: 0, type: int, CONST: 101" "cp" } } */
/* { dg-final { scan-ipa-dump "offset: 32, type: int, PASS THROUGH: 0, op trunc_mod_expr 7" "cp" } } */
/* { dg-final { scan-ipa-dump "offset: 64, type: int, LOAD AGG: 1 \\\[offset: 0, by reference], op plus_expr 6" "cp" } } */
/* { dg-final { scan-ipa-dump "Aggregate replacements: 0\\\[0]=1, 0\\\[32]=105, 0\\\[64]=-18" "cp" } } */
/* { dg-final { scan-ipa-dump "Aggregate replacements: 0\\\[0]=101, 0\\\[32]=2, 0\\\[64]=9" "cp" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment