#include "flags.h"
#include "dbgcnt.h"
#include "tree-inline.h"
+#include "gimple-pretty-print.h"
/* Enumeration of all aggregate reductions we can do. */
enum sra_mode { SRA_MODE_EARLY_IPA, /* early call regularization */
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
- for (fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
+ for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
if (TREE_CODE (fld) == FIELD_DECL)
{
tree ft = TREE_TYPE (fld);
for (parm = DECL_ARGUMENTS (current_function_decl);
parm && parm != base;
- parm = TREE_CHAIN (parm))
+ parm = DECL_CHAIN (parm))
parm_index++;
gcc_assert (parm_index < func_param_count);
if (TREE_CODE (type) != RECORD_TYPE)
return false;
- for (fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
+ for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
if (TREE_CODE (fld) == FIELD_DECL)
{
tree ft = TREE_TYPE (fld);
{
tree fld, decl_type = TREE_TYPE (decl);
- for (fld = TYPE_FIELDS (decl_type); fld; fld = TREE_CHAIN (fld))
+ for (fld = TYPE_FIELDS (decl_type); fld; fld = DECL_CHAIN (fld))
if (TREE_CODE (fld) == FIELD_DECL)
{
HOST_WIDE_INT pos = offset + int_bit_position (fld);
case UNION_TYPE:
case QUAL_UNION_TYPE:
case RECORD_TYPE:
- for (fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
+ for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
{
HOST_WIDE_INT pos, size;
tree expr, *expr_ptr;
(sub)tree. If that is not possible, refresh the TOP_RACC base aggregate and
load the accesses from it. LEFT_OFFSET is the offset of the left whole
subtree being copied, RIGHT_OFFSET is the same thing for the right subtree.
- GSI is stmt iterator used for statement insertions. *REFRESHED is true iff
- the rhs top aggregate has already been refreshed by contents of its scalar
- reductions and is set to true if this function has to do it. */
+ NEW_GSI is stmt iterator used for statement insertions after the original
+ assignment, OLD_GSI is used to insert statements before the assignment.
+ *REFRESHED keeps the information whether we have needed to refresh
+ replacements of the LHS and from which side of the assignments this takes
+ place. */
static void
load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
}
}
-/* Create a new suitable default definition SSA_NAME and replace all uses of
- SSA with it, RACC is access describing the uninitialized part of an
- aggregate that is being loaded. */
+/* Create and return a new suitable default definition SSA_NAME for RACC which
+ is an access describing an uninitialized part of an aggregate that is being
+ loaded. */
-static void
-replace_uses_with_default_def_ssa_name (tree ssa, struct access *racc)
+static tree
+get_repl_default_def_ssa_name (struct access *racc)
{
tree repl, decl;
set_default_def (decl, repl);
}
- replace_uses_by (ssa, repl);
+ return repl;
}
/* Examine both sides of the assignment statement pointed to by STMT, replace
&orig_gsi, gsi, &refreshed, lhs);
if (refreshed != SRA_UDH_RIGHT)
{
- if (*stmt == gsi_stmt (*gsi))
- gsi_next (gsi);
-
+ gsi_next (gsi);
unlink_stmt_vdef (*stmt);
gsi_remove (&orig_gsi, true);
sra_stats.deleted++;
{
if (!racc->grp_to_be_replaced && !racc->grp_unscalarized_data)
{
- if (racc->first_child)
- generate_subtree_copies (racc->first_child, lhs,
- racc->offset, 0, 0, gsi,
- false, false);
- gcc_assert (*stmt == gsi_stmt (*gsi));
- if (TREE_CODE (lhs) == SSA_NAME)
- replace_uses_with_default_def_ssa_name (lhs, racc);
+ if (dump_file)
+ {
+ fprintf (dump_file, "Removing load: ");
+ print_gimple_stmt (dump_file, *stmt, 0, 0);
+ }
- unlink_stmt_vdef (*stmt);
- gsi_remove (gsi, true);
- sra_stats.deleted++;
- return SRA_AM_REMOVED;
+ if (TREE_CODE (lhs) == SSA_NAME)
+ {
+ rhs = get_repl_default_def_ssa_name (racc);
+ if (!useless_type_conversion_p (TREE_TYPE (lhs),
+ TREE_TYPE (rhs)))
+ rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
+ TREE_TYPE (lhs), rhs);
+ }
+ else
+ {
+ if (racc->first_child)
+ generate_subtree_copies (racc->first_child, lhs,
+ racc->offset, 0, 0, gsi,
+ false, false);
+
+ gcc_assert (*stmt == gsi_stmt (*gsi));
+ unlink_stmt_vdef (*stmt);
+ gsi_remove (gsi, true);
+ sra_stats.deleted++;
+ return SRA_AM_REMOVED;
+ }
}
else if (racc->first_child)
generate_subtree_copies (racc->first_child, lhs,
}
/* Traverse the function body and all modifications as decided in
- analyze_all_variable_accesses. */
+ analyze_all_variable_accesses. Return true iff the CFG has been
+ changed. */
-static void
+static bool
sra_modify_function_body (void)
{
+ bool cfg_changed = false;
basic_block bb;
FOR_EACH_BB (bb)
if (modified)
{
update_stmt (stmt);
- maybe_clean_eh_stmt (stmt);
+ if (maybe_clean_eh_stmt (stmt)
+ && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
+ cfg_changed = true;
}
if (!deleted)
gsi_next (&gsi);
}
}
+
+ return cfg_changed;
}
/* Generate statements initializing scalar replacements of parts of function
for (parm = DECL_ARGUMENTS (current_function_decl);
parm;
- parm = TREE_CHAIN (parm))
+ parm = DECL_CHAIN (parm))
{
VEC (access_p, heap) *access_vec;
struct access *access;
if (!analyze_all_variable_accesses ())
goto out;
- sra_modify_function_body ();
+ if (sra_modify_function_body ())
+ ret = TODO_update_ssa | TODO_cleanup_cfg;
+ else
+ ret = TODO_update_ssa;
initialize_parameter_reductions ();
statistics_counter_event (cfun, "Scalar replacements created",
statistics_counter_event (cfun, "Separate LHS and RHS handling",
sra_stats.separate_lhs_rhs_handling);
- ret = TODO_update_ssa;
-
out:
sra_deinitialize ();
return ret;
for (parm = DECL_ARGUMENTS (current_function_decl);
parm;
- parm = TREE_CHAIN (parm))
+ parm = DECL_CHAIN (parm))
{
tree type = TREE_TYPE (parm);
for (parm = DECL_ARGUMENTS (current_function_decl);
parm;
- parm = TREE_CHAIN (parm))
+ parm = DECL_CHAIN (parm))
{
if (is_unused_scalar_param (parm))
{
parms = ipa_get_vector_of_formal_parms (current_function_decl);
adjustments = VEC_alloc (ipa_parm_adjustment_t, heap, adjustments_count);
parm = DECL_ARGUMENTS (current_function_decl);
- for (i = 0; i < func_param_count; i++, parm = TREE_CHAIN (parm))
+ for (i = 0; i < func_param_count; i++, parm = DECL_CHAIN (parm))
{
struct access *repr = VEC_index (access_p, representatives, i);
}
/* Traverse the function body and all modifications as described in
- ADJUSTMENTS. */
+ ADJUSTMENTS. Return true iff the CFG has been changed. */
-static void
+static bool
ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments)
{
+ bool cfg_changed = false;
basic_block bb;
FOR_EACH_BB (bb)
{
gimple_stmt_iterator gsi;
- bool bb_changed = false;
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
replace_removed_params_ssa_names (gsi_stmt (gsi), adjustments);
if (modified)
{
- bb_changed = true;
update_stmt (stmt);
- maybe_clean_eh_stmt (stmt);
+ if (maybe_clean_eh_stmt (stmt)
+ && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
+ cfg_changed = true;
}
gsi_next (&gsi);
}
- if (bb_changed)
- gimple_purge_dead_eh_edges (bb);
}
+
+ return cfg_changed;
}
/* Call gimple_debug_bind_reset_value on all debug statements describing
}
/* Perform all the modification required in IPA-SRA for NODE to have parameters
- as given in ADJUSTMENTS. */
+ as given in ADJUSTMENTS. Return true iff the CFG has been changed. */
-static void
+static bool
modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
{
struct cgraph_node *new_node;
struct cgraph_edge *cs;
+ bool cfg_changed;
VEC (cgraph_edge_p, heap) * redirect_callers;
int node_callers;
push_cfun (DECL_STRUCT_FUNCTION (new_node->decl));
ipa_modify_formal_parameters (current_function_decl, adjustments, "ISRA");
- ipa_sra_modify_function_body (adjustments);
+ cfg_changed = ipa_sra_modify_function_body (adjustments);
sra_ipa_reset_debug_stmts (adjustments);
convert_callers (new_node, node->decl, adjustments);
cgraph_make_node_local (new_node);
- return;
+ return cfg_changed;
}
/* Return false the function is apparently unsuitable for IPA-SRA based on it's
static bool
ipa_sra_preliminary_function_checks (struct cgraph_node *node)
{
+ if (!tree_versionable_function_p (current_function_decl))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Function isn't allowed to be versioned.\n");
+ return false;
+ }
+
if (!cgraph_node_can_be_local_p (node))
{
if (dump_file)
if (!tree_versionable_function_p (node->decl))
{
if (dump_file)
- fprintf (dump_file, "Function not local to this compilation unit.\n");
+ fprintf (dump_file, "Function is not versionable.\n");
return false;
}
if (dump_file)
ipa_dump_param_adjustments (dump_file, adjustments, current_function_decl);
- modify_function (node, adjustments);
+ if (modify_function (node, adjustments))
+ ret = TODO_update_ssa | TODO_cleanup_cfg;
+ else
+ ret = TODO_update_ssa;
VEC_free (ipa_parm_adjustment_t, heap, adjustments);
- ret = TODO_update_ssa;
statistics_counter_event (cfun, "Unused parameters deleted",
sra_stats.deleted_unused_parameters);