@@ -46,7 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-phinodes.h"
#include "cfgexpand.h"
#include "attribs.h"
-
+#include "ipa-prop.h"
/* Actual prefixes of different newly synthetized parameters. Keep in sync
with IPA_PARAM_PREFIX_* defines. */
@@ -449,39 +449,6 @@ ipa_param_adjustments::get_updated_indices (vec<int> *new_indices)
}
}
-/* If a parameter with original INDEX has survived intact, return its new
- index. Otherwise return -1. In that case, if it has been split and there
- is a new parameter representing a portion at unit OFFSET for which a value
- of a TYPE can be substituted, store its new index into SPLIT_INDEX,
- otherwise store -1 there. */
-int
-ipa_param_adjustments::get_updated_index_or_split (int index,
- unsigned unit_offset,
- tree type, int *split_index)
-{
- unsigned adj_len = vec_safe_length (m_adj_params);
- for (unsigned i = 0; i < adj_len ; i++)
- {
- ipa_adjusted_param *apm = &(*m_adj_params)[i];
- if (apm->base_index != index)
- continue;
- if (apm->op == IPA_PARAM_OP_COPY)
- return i;
- if (apm->op == IPA_PARAM_OP_SPLIT
- && apm->unit_offset == unit_offset)
- {
- if (useless_type_conversion_p (apm->type, type))
- *split_index = i;
- else
- *split_index = -1;
- return -1;
- }
- }
-
- *split_index = -1;
- return -1;
-}
-
/* Return the original index for the given new parameter index. Return a
negative number if not available. */
@@ -1020,6 +987,21 @@ ipa_param_adjustments::debug ()
dump (stderr);
}
+/* Register a REPLACEMENT for accesses to BASE at UNIT_OFFSET. */
+
+void
+ipa_param_body_adjustments::register_replacement (tree base,
+ unsigned unit_offset,
+ tree replacement)
+{
+ ipa_param_body_replacement psr;
+ psr.base = base;
+ psr.repl = replacement;
+ psr.dummy = NULL_TREE;
+ psr.unit_offset = unit_offset;
+ m_replacements.safe_push (psr);
+}
+
/* Register that REPLACEMENT should replace parameter described in APM. */
void
@@ -1029,12 +1011,8 @@ ipa_param_body_adjustments::register_replacement (ipa_adjusted_param *apm,
gcc_checking_assert (apm->op == IPA_PARAM_OP_SPLIT
|| apm->op == IPA_PARAM_OP_NEW);
gcc_checking_assert (!apm->prev_clone_adjustment);
- ipa_param_body_replacement psr;
- psr.base = m_oparms[apm->prev_clone_index];
- psr.repl = replacement;
- psr.dummy = NULL_TREE;
- psr.unit_offset = apm->unit_offset;
- m_replacements.safe_push (psr);
+ register_replacement (m_oparms[apm->prev_clone_index], apm->unit_offset,
+ replacement);
}
/* Copy or not, as appropriate given m_id and decl context, a pre-existing
@@ -1386,23 +1364,73 @@ ipa_param_body_adjustments::common_initialization (tree old_fndecl,
gcc_unreachable ();
}
+ auto_vec <int, 16> index_mapping;
+ bool need_remap = false;
+ if (m_id)
+ {
+ clone_info *cinfo = clone_info::get (m_id->src_node);
+ if (cinfo && cinfo->param_adjustments)
+ {
+ cinfo->param_adjustments->get_updated_indices (&index_mapping);
+ need_remap = true;
+ }
+
+ if (ipcp_transformation *ipcp_ts
+ = ipcp_get_transformation_summary (m_id->src_node))
+ {
+ for (const ipa_argagg_value &av : ipcp_ts->m_agg_values)
+ {
+ int parm_num = av.index;
+
+ if (need_remap)
+ {
+ /* FIXME: We cannot handle the situation when IPA-CP
+ identified that a parameter is a pointer to a global
+ variable and at the same time the variable has some known
+ constant contents (PR 107640). The best place to make
+ sure we don't drop such constants on the floor probably is
+ not here, but we have to make sure that it does not
+ confuse the remapping. */
+ if (parm_num >= (int) index_mapping.length ())
+ continue;
+ parm_num = index_mapping[parm_num];
+ if (parm_num < 0)
+ continue;
+ }
+
+ if (!kept[parm_num])
+ {
+ /* IPA-CP has detected an aggregate constant in a parameter
+ that will not be kept, which means that IPA-SRA would have
+ split it if there wasn't a constant. Because we are about
+ to remove the original, this is the last chance where we
+ can substitute the uses with a constant (for values passed
+ by reference) or do the split but initialize the
+ replacement with a constant (for split aggregates passed
+ by value). */
+
+ tree repl;
+ if (av.by_ref)
+ repl = av.value;
+ else
+ {
+ repl = create_tmp_var (TREE_TYPE (av.value),
+ "removed_ipa_cp");
+ gimple *init_stmt = gimple_build_assign (repl, av.value);
+ m_split_agg_csts_inits.safe_push (init_stmt);
+ }
+ register_replacement (m_oparms[parm_num], av.unit_offset,
+ repl);
+ split[parm_num] = true;
+ }
+ }
+ }
+ }
+
if (tree_map)
{
/* Do not treat parameters which were replaced with a constant as
completely vanished. */
- auto_vec <int, 16> index_mapping;
- bool need_remap = false;
-
- if (m_id)
- {
- clone_info *cinfo = clone_info::get (m_id->src_node);
- if (cinfo && cinfo->param_adjustments)
- {
- cinfo->param_adjustments->get_updated_indices (&index_mapping);
- need_remap = true;
- }
- }
-
for (unsigned i = 0; i < tree_map->length (); i++)
{
int parm_num = (*tree_map)[i]->parm_num;
@@ -1473,8 +1501,9 @@ ipa_param_body_adjustments
: m_adj_params (adj_params), m_adjustments (NULL), m_reset_debug_decls (),
m_dead_stmts (), m_dead_ssas (), m_dead_ssa_debug_equiv (),
m_dead_stmt_debug_equiv (), m_fndecl (fndecl), m_id (NULL), m_oparms (),
- m_new_decls (), m_new_types (), m_replacements (), m_removed_decls (),
- m_removed_map (), m_method2func (false)
+ m_new_decls (), m_new_types (), m_replacements (),
+ m_split_agg_csts_inits (), m_removed_decls (), m_removed_map (),
+ m_method2func (false)
{
common_initialization (fndecl, NULL, NULL);
}
@@ -1491,7 +1520,8 @@ ipa_param_body_adjustments
m_reset_debug_decls (), m_dead_stmts (), m_dead_ssas (),
m_dead_ssa_debug_equiv (), m_dead_stmt_debug_equiv (), m_fndecl (fndecl),
m_id (NULL), m_oparms (), m_new_decls (), m_new_types (), m_replacements (),
- m_removed_decls (), m_removed_map (), m_method2func (false)
+ m_split_agg_csts_inits (), m_removed_decls (), m_removed_map (),
+ m_method2func (false)
{
common_initialization (fndecl, NULL, NULL);
}
@@ -1514,7 +1544,8 @@ ipa_param_body_adjustments
m_reset_debug_decls (), m_dead_stmts (), m_dead_ssas (),
m_dead_ssa_debug_equiv (), m_dead_stmt_debug_equiv (), m_fndecl (fndecl),
m_id (id), m_oparms (), m_new_decls (), m_new_types (), m_replacements (),
- m_removed_decls (), m_removed_map (), m_method2func (false)
+ m_split_agg_csts_inits (), m_removed_decls (), m_removed_map (),
+ m_method2func (false)
{
common_initialization (old_fndecl, vars, tree_map);
}
@@ -2383,6 +2414,16 @@ ipa_param_body_adjustments::perform_cfun_body_modifications ()
}
+/* If there are any initialization statements that need to be emitted into
+ the basic block BB right at ther start of the new function, do so. */
+void
+ipa_param_body_adjustments::append_init_stmts (basic_block bb)
+{
+ gimple_stmt_iterator si = gsi_last_bb (bb);
+ while (!m_split_agg_csts_inits.is_empty ())
+ gsi_insert_after (&si, m_split_agg_csts_inits.pop (), GSI_NEW_STMT);
+}
+
/* Deallocate summaries which otherwise stay alive until the end of
compilation. */
@@ -236,13 +236,6 @@ public:
void get_surviving_params (vec<bool> *surviving_params);
/* Fill a vector with new indices of surviving original parameters. */
void get_updated_indices (vec<int> *new_indices);
- /* If a parameter with original INDEX has survived intact, return its new
- index. Otherwise return -1. In that case, if it has been split and there
- is a new parameter representing a portion at UNIT_OFFSET for which a value
- of a TYPE can be substituted, store its new index into SPLIT_INDEX,
- otherwise store -1 there. */
- int get_updated_index_or_split (int index, unsigned unit_offset, tree type,
- int *split_index);
/* Return the original index for the given new parameter index. Return a
negative number if not available. */
int get_original_index (int newidx);
@@ -321,6 +314,8 @@ public:
/* Change the PARM_DECLs. */
void modify_formal_parameters ();
+ /* Register a REPLACEMENT for accesses to BASE at UNIT_OFFSET. */
+ void register_replacement (tree base, unsigned unit_offset, tree replacement);
/* Register a replacement decl for the transformation done in APM. */
void register_replacement (ipa_adjusted_param *apm, tree replacement);
/* Lookup a replacement for a given offset within a given parameter. */
@@ -340,6 +335,10 @@ public:
they are mapped to. */
void remap_with_debug_expressions (tree *t);
+ /* If there are any initialization statements that need to be emitted into
+ the basic block BB right at ther start of the new function, do so. */
+ void append_init_stmts (basic_block bb);
+
/* Pointers to data structures defining how the function should be
modified. */
vec<ipa_adjusted_param, va_gc> *m_adj_params;
@@ -405,6 +404,12 @@ private:
auto_vec<ipa_param_body_replacement, 16> m_replacements;
+ /* List of initialization assignments to be put at the beginning of the
+ cloned function to deal with split aggregates which however have known
+ constant value and so their PARM_DECL disappears. */
+
+ auto_vec<gimple *, 8> m_split_agg_csts_inits;
+
/* Vector for remapping SSA_BASES from old parameter declarations that are
being removed as a part of the transformation. Before a new VAR_DECL is
created, it holds the old PARM_DECL, once the variable is built it is
@@ -5516,29 +5516,21 @@ ipcp_read_transformation_summaries (void)
}
}
-/* Adjust the aggregate replacements in TS to reflect parameters skipped in
- NODE but also if any parameter was IPA-SRAed into a scalar go ahead with
- substitution of the default_definitions of that new param with the
- appropriate constant.
+/* Adjust the aggregate replacements in TS to reflect any parameter removals
+ which might have already taken place. If after adjustments there are no
+ aggregate replacements left, the m_agg_values will be set to NULL. In other
+ cases, it may be shrunk. */
- If after adjustments there are no aggregate replacements left, the
- m_agg_values will be set to NULL. In other cases, it may be shrunk.
-
- Return true if any values were already substituted for scalarized parameters
- and update_cfg shuld be run after replace_uses_by. */
-
-static bool
-adjust_agg_replacement_values (cgraph_node *node,
- ipcp_transformation *ts,
- const vec<ipa_param_descriptor, va_gc>
- &descriptors)
+static void
+adjust_agg_replacement_values (cgraph_node *node, ipcp_transformation *ts)
{
clone_info *cinfo = clone_info::get (node);
if (!cinfo || !cinfo->param_adjustments)
- return false;
+ return;
+ auto_vec<int, 16> new_indices;
+ cinfo->param_adjustments->get_updated_indices (&new_indices);
bool removed_item = false;
- bool done_replacement = false;
unsigned dst_index = 0;
unsigned count = ts->m_agg_values->length ();
for (unsigned i = 0; i < count; i++)
@@ -5546,13 +5538,10 @@ adjust_agg_replacement_values (cgraph_node *node,
ipa_argagg_value *v = &(*ts->m_agg_values)[i];
gcc_checking_assert (v->index >= 0);
- tree cst_type = TREE_TYPE (v->value);
- int split_idx;
- int new_idx
- = cinfo->param_adjustments->get_updated_index_or_split (v->index,
- v->unit_offset,
- cst_type,
- &split_idx);
+ int new_idx = -1;
+ if ((unsigned) v->index < new_indices.length ())
+ new_idx = new_indices[v->index];
+
if (new_idx >= 0)
{
v->index = new_idx;
@@ -5561,19 +5550,7 @@ adjust_agg_replacement_values (cgraph_node *node,
dst_index++;
}
else
- {
- removed_item = true;
- if (split_idx >= 0)
- {
- tree parm = ipa_get_param (descriptors, split_idx);
- tree ddef = ssa_default_def (cfun, parm);
- if (ddef)
- {
- replace_uses_by (ddef, v->value);
- done_replacement = true;
- }
- }
- }
+ removed_item = true;
}
if (dst_index == 0)
@@ -5584,7 +5561,7 @@ adjust_agg_replacement_values (cgraph_node *node,
else if (removed_item)
ts->m_agg_values->truncate (dst_index);
- return done_replacement;
+ return;
}
/* Dominator walker driving the ipcp modification phase. */
@@ -5953,7 +5930,6 @@ ipcp_update_vr (struct cgraph_node *node)
unsigned int
ipcp_transform_function (struct cgraph_node *node)
{
- vec<ipa_param_descriptor, va_gc> *descriptors = NULL;
struct ipa_func_body_info fbi;
int param_count;
@@ -5972,18 +5948,13 @@ ipcp_transform_function (struct cgraph_node *node)
param_count = count_formal_params (node->decl);
if (param_count == 0)
return 0;
- vec_safe_grow_cleared (descriptors, param_count, true);
- ipa_populate_param_decls (node, *descriptors);
- bool cfg_changed = adjust_agg_replacement_values (node, ts, *descriptors);
+ adjust_agg_replacement_values (node, ts);
if (vec_safe_is_empty (ts->m_agg_values))
{
- vec_free (descriptors);
if (dump_file)
fprintf (dump_file, " All affected aggregate parameters were either "
"removed or converted into scalars, phase done.\n");
- if (cfg_changed)
- delete_unreachable_blocks_update_callgraph (node, false);
return 0;
}
if (dump_file)
@@ -6000,12 +5971,15 @@ ipcp_transform_function (struct cgraph_node *node)
fbi.param_count = param_count;
fbi.aa_walk_budget = opt_for_fn (node->decl, param_ipa_max_aa_steps);
+ vec<ipa_param_descriptor, va_gc> *descriptors = NULL;
+ vec_safe_grow_cleared (descriptors, param_count, true);
+ ipa_populate_param_decls (node, *descriptors);
bool modified_mem_access = false;
calculate_dominance_info (CDI_DOMINATORS);
ipcp_modif_dom_walker walker (&fbi, descriptors, ts, &modified_mem_access);
walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
free_dominance_info (CDI_DOMINATORS);
- cfg_changed |= walker.cleanup_eh ();
+ bool cfg_changed = walker.cleanup_eh ();
int i;
struct ipa_bb_info *bi;
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see
#include "internal-fn.h"
#include "symtab-clones.h"
#include "attribs.h"
+#include "ipa-prop.h"
static void ipa_sra_summarize_function (cgraph_node *);
@@ -3608,13 +3609,16 @@ retval_used_p (cgraph_node *node, void *)
/* Push into NEW_PARAMS all required parameter adjustment entries to copy or
modify parameter which originally had index BASE_INDEX, in the adjustment
vector of parent clone (if any) had PREV_CLONE_INDEX and was described by
- PREV_ADJUSTMENT. If the parent clone is the original function,
- PREV_ADJUSTMENT is NULL and PREV_CLONE_INDEX is equal to BASE_INDEX. */
+ PREV_ADJUSTMENT. If IPA-CP has created a transformation summary for the
+ original node, it needs to be passed in IPCP_TS, otherwise it should be
+ NULL. If the parent clone is the original function, PREV_ADJUSTMENT is NULL
+ and PREV_CLONE_INDEX is equal to BASE_INDEX. */
static void
push_param_adjustments_for_index (isra_func_summary *ifs, unsigned base_index,
unsigned prev_clone_index,
ipa_adjusted_param *prev_adjustment,
+ ipcp_transformation *ipcp_ts,
vec<ipa_adjusted_param, va_gc> **new_params)
{
isra_param_desc *desc = &(*ifs->m_parameters)[base_index];
@@ -3655,6 +3659,23 @@ push_param_adjustments_for_index (isra_func_summary *ifs, unsigned base_index,
param_access *pa = (*desc->accesses)[j];
if (!pa->certain)
continue;
+
+ if (ipcp_ts)
+ {
+ ipa_argagg_value_list avl (ipcp_ts);
+ tree value = avl.get_value (base_index, pa->unit_offset);
+ if (value
+ && (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (value))) / BITS_PER_UNIT
+ == pa->unit_size))
+ {
+ if (dump_file)
+ fprintf (dump_file, " - omitting component at byte "
+ "offset %u which is known to have a constant value\n ",
+ pa->unit_offset);
+ continue;
+ }
+ }
+
if (dump_file)
fprintf (dump_file, " - component at byte offset %u, "
"size %u\n", pa->unit_offset, pa->unit_size);
@@ -3735,6 +3756,7 @@ process_isra_node_results (cgraph_node *node,
fprintf (dump_file, " Will remove return value.\n");
}
+ ipcp_transformation *ipcp_ts = ipcp_get_transformation_summary (node);
vec<ipa_adjusted_param, va_gc> *new_params = NULL;
if (ipa_param_adjustments *old_adjustments
= cinfo ? cinfo->param_adjustments : NULL)
@@ -3744,12 +3766,12 @@ process_isra_node_results (cgraph_node *node,
{
ipa_adjusted_param *old_adj = &(*old_adjustments->m_adj_params)[i];
push_param_adjustments_for_index (ifs, old_adj->base_index, i,
- old_adj, &new_params);
+ old_adj, ipcp_ts, &new_params);
}
}
else
for (unsigned i = 0; i < param_count; i++)
- push_param_adjustments_for_index (ifs, i, i, NULL, &new_params);
+ push_param_adjustments_for_index (ifs, i, i, NULL, ipcp_ts, &new_params);
ipa_param_adjustments *new_adjustments
= (new (ggc_alloc <ipa_param_adjustments> ())
new file mode 100644
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized-slim" } */
+
+struct S
+{
+ int a, b, c;
+};
+
+int ellide (int c);
+volatile short gi;
+
+void __attribute__((noipa))
+consume_s (struct S *p)
+{
+ gi = p->a;
+}
+
+static void __attribute__((noinline))
+foo (struct S *p, short *r)
+{
+ gi = *r;
+ if (!__builtin_constant_p (p->b))
+ ellide (1);
+ consume_s (p);
+}
+
+static void __attribute__((noinline))
+bar (short *r, struct S *p)
+{
+ gi = *r;
+ if (!__builtin_constant_p (p->c))
+ ellide (2);
+ consume_s (p);
+}
+
+struct S gs;
+
+int main (int argc, char *argv[])
+{
+ short i = 42;
+ gs.a = 10;
+ gs.b = 20;
+ foo (&gs, &i);
+ gs.b = 30;
+ gs.c = 40;
+ bar (&i, &gs);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "ellide" "optimized" { xfail *-*-* } } } */
@@ -6377,6 +6377,8 @@ tree_function_versioning (tree old_decl, tree new_decl,
bb = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
while (init_stmts.length ())
insert_init_stmt (&id, bb, init_stmts.pop ());
+ if (param_body_adjs)
+ param_body_adjs->append_init_stmts (bb);
update_clone_info (&id);
/* Remap the nonlocal_goto_save_area, if any. */