@@ -1541,9 +1541,10 @@ build_agg_jump_func_from_list (struct ipa_known_agg_contents_list *list,
in ARG is filled in with constant values. ARG can either be an aggregate
expression or a pointer to an aggregate. ARG_TYPE is the type of the
aggregate. JFUNC is the jump function into which the constants are
- subsequently stored. */
+ subsequently stored. Return true if any known aggregate value has been
+ discovered. */
-static void
+static bool
determine_locally_known_aggregate_parts (gcall *call, tree arg,
tree arg_type,
struct ipa_jump_func *jfunc)
@@ -1557,7 +1558,7 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
ao_ref r;
if (PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS) == 0)
- return;
+ return false;
/* The function operates in three stages. First, we prepare check_ref, r,
arg_base and arg_offset based on what is actually passed as an actual
@@ -1571,7 +1572,7 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
tree type_size;
if (!tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (arg_type)))
|| !POINTER_TYPE_P (TREE_TYPE (arg)))
- return;
+ return false;
check_ref = true;
arg_base = arg;
arg_offset = 0;
@@ -1587,17 +1588,17 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
arg_base = get_ref_base_and_extent_hwi (arg, &arg_offset,
&arg_size, &reverse);
if (!arg_base)
- return;
+ return false;
if (DECL_P (arg_base))
{
check_ref = false;
ao_ref_init (&r, arg_base);
}
else
- return;
+ return false;
}
else
- return;
+ return false;
}
else
{
@@ -1610,7 +1611,7 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
arg_base = get_ref_base_and_extent_hwi (arg, &arg_offset,
&arg_size, &reverse);
if (!arg_base)
- return;
+ return false;
ao_ref_init (&r, arg);
}
@@ -1697,7 +1698,9 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
{
jfunc->agg.by_ref = by_ref;
build_agg_jump_func_from_list (list, const_count, arg_offset, jfunc);
+ return true;
}
+ return false;
}
/* Return the Ith param type of callee associated with call graph
@@ -1827,18 +1830,24 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
struct ipa_edge_args *args = IPA_EDGE_REF (cs);
gcall *call = cs->call_stmt;
int n, arg_num = gimple_call_num_args (call);
+ bool useful_value = false;
bool useful_context = false;
- if (arg_num == 0 || args->jump_functions)
+ if (arg_num == 0
+ || gimple_call_internal_p (call)
+ || ipa_func_spec_opts_forbid_analysis_p (cs->caller))
return;
- vec_safe_grow_cleared (args->jump_functions, arg_num);
- if (flag_devirtualize)
- vec_safe_grow_cleared (args->polymorphic_call_contexts, arg_num);
+ gcc_checking_assert (!args->jump_functions
+ && !args->polymorphic_call_contexts);
- if (gimple_call_internal_p (call))
- return;
- if (ipa_func_spec_opts_forbid_analysis_p (cs->caller))
- return;
+ vec_safe_reserve_exact (args->jump_functions, arg_num);
+ args->jump_functions->quick_grow_cleared (arg_num);
+
+ if (flag_devirtualize)
+ {
+ vec_safe_reserve_exact (args->polymorphic_call_contexts, arg_num);
+ vec_safe_grow_cleared (args->polymorphic_call_contexts, arg_num);
+ }
for (n = 0; n < arg_num; n++)
{
@@ -1873,6 +1882,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
{
tree z = build_int_cst (TREE_TYPE (arg), 0);
ipa_set_jfunc_vr (jfunc, VR_ANTI_RANGE, z, z);
+ useful_value = true;
}
else
gcc_assert (!jfunc->m_vr);
@@ -1893,7 +1903,10 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
extract_range_from_unary_expr (&resvr, NOP_EXPR, param_type,
&tmpvr, TREE_TYPE (arg));
if (!resvr.undefined_p () && !resvr.varying_p ())
- ipa_set_jfunc_vr (jfunc, &resvr);
+ {
+ ipa_set_jfunc_vr (jfunc, &resvr);
+ useful_value = true;
+ }
else
gcc_assert (!jfunc->m_vr);
}
@@ -1905,11 +1918,20 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
&& (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) == INTEGER_CST))
{
if (TREE_CODE (arg) == SSA_NAME)
- ipa_set_jfunc_bits (jfunc, 0,
- widest_int::from (get_nonzero_bits (arg),
- TYPE_SIGN (TREE_TYPE (arg))));
+ {
+ widest_int nonzero_bits
+ = widest_int::from (get_nonzero_bits (arg),
+ TYPE_SIGN (TREE_TYPE (arg)));
+ ipa_set_jfunc_bits (jfunc, 0, nonzero_bits);
+ if (SSA_NAME_RANGE_INFO (arg)
+ && nonzero_bits != -1)
+ useful_value = true;
+ }
else
- ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0);
+ {
+ ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0);
+ useful_value = true;
+ }
}
else if (POINTER_TYPE_P (TREE_TYPE (arg)))
{
@@ -1917,6 +1939,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
unsigned align;
get_pointer_alignment_1 (arg, &align, &bitpos);
+ if (align != BITS_PER_UNIT)
+ useful_value = true;
widest_int mask = wi::bit_and_not
(wi::mask<widest_int> (TYPE_PRECISION (TREE_TYPE (arg)), false),
align / BITS_PER_UNIT - 1);
@@ -1930,7 +1954,10 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
|| (VAR_P (arg)
&& is_global_var (arg)
&& TREE_READONLY (arg)))
- ipa_set_jf_constant (jfunc, arg, cs);
+ {
+ ipa_set_jf_constant (jfunc, arg, cs);
+ useful_value = true;
+ }
else if (!is_gimple_reg_type (TREE_TYPE (arg))
&& TREE_CODE (arg) == PARM_DECL)
{
@@ -1943,6 +1970,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
if (parm_preserved_before_stmt_p (fbi, index, call, arg))
{
ipa_set_jf_simple_pass_through (jfunc, index, false);
+ useful_value = true;
continue;
}
}
@@ -1956,6 +1984,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
bool agg_p;
agg_p = parm_ref_data_pass_through_p (fbi, index, call, arg);
ipa_set_jf_simple_pass_through (jfunc, index, agg_p);
+ useful_value = true;
}
}
else
@@ -1969,14 +1998,17 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
call,
as_a <gphi *> (stmt));
}
+ if (jfunc->type != IPA_JF_UNKNOWN)
+ useful_value = true;
}
- /* If ARG is pointer, we can not use its type to determine the type of aggregate
- passed (because type conversions are ignored in gimple). Usually we can
- safely get type from function declaration, but in case of K&R prototypes or
- variadic functions we can try our luck with type of the pointer passed.
- TODO: Since we look for actual initialization of the memory object, we may better
- work out the type based on the memory stores we find. */
+ /* If ARG is pointer, we can not use its type to determine the type of
+ aggregate passed (because type conversions are ignored in gimple).
+ Usually we can safely get type from function declaration, but in case
+ of K&R prototypes or variadic functions we can try our luck with type
+ of the pointer passed.
+ TODO: Since we look for actual initialization of the memory object, we
+ may better work out the type based on the memory stores we find. */
if (!param_type)
param_type = TREE_TYPE (arg);
@@ -1986,8 +2018,16 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
|| !ipa_get_jf_ancestor_agg_preserved (jfunc))
&& (AGGREGATE_TYPE_P (TREE_TYPE (arg))
|| POINTER_TYPE_P (param_type)))
- determine_locally_known_aggregate_parts (call, arg, param_type, jfunc);
+ {
+ if (determine_locally_known_aggregate_parts (call, arg, param_type,
+ jfunc))
+ useful_value = true;
+ }
}
+
+ if (!useful_value)
+ vec_free (args->jump_functions);
+
if (!useful_context)
vec_free (args->polymorphic_call_contexts);
}