aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-sra.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-sra.c')
-rw-r--r--gcc/tree-sra.c225
1 files changed, 137 insertions, 88 deletions
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 84d950f770f..fa567e54e8b 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -90,6 +90,7 @@ along with GCC; see the file COPYING3. If not see
#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 */
@@ -634,7 +635,7 @@ type_internals_preclude_sra_p (tree type)
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);
@@ -697,7 +698,7 @@ mark_parm_dereference (tree base, HOST_WIDE_INT dist, gimple stmt)
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);
@@ -751,7 +752,8 @@ create_access (tree expr, gimple stmt, bool write)
base = get_ref_base_and_extent (expr, &offset, &size, &max_size);
- if (sra_mode == SRA_MODE_EARLY_IPA && INDIRECT_REF_P (base))
+ if (sra_mode == SRA_MODE_EARLY_IPA
+ && TREE_CODE (base) == MEM_REF)
{
base = get_ssa_base_param (TREE_OPERAND (base, 0));
if (!base)
@@ -820,7 +822,7 @@ type_consists_of_records_p (tree type)
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);
@@ -848,7 +850,7 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset)
{
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);
@@ -885,15 +887,10 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset)
static void
disqualify_base_of_expr (tree t, const char *reason)
{
- while (handled_component_p (t))
- t = TREE_OPERAND (t, 0);
-
- if (sra_mode == SRA_MODE_EARLY_IPA)
- {
- if (INDIRECT_REF_P (t))
- t = TREE_OPERAND (t, 0);
- t = get_ssa_base_param (t);
- }
+ t = get_base_address (t);
+ if (sra_mode == SRA_MODE_EARLY_IPA
+ && TREE_CODE (t) == MEM_REF)
+ t = get_ssa_base_param (TREE_OPERAND (t, 0));
if (t && DECL_P (t))
disqualify_candidate (t, reason);
@@ -935,8 +932,9 @@ build_access_from_expr_1 (tree expr, gimple stmt, bool write)
switch (TREE_CODE (expr))
{
- case INDIRECT_REF:
- if (sra_mode != SRA_MODE_EARLY_IPA)
+ case MEM_REF:
+ if (TREE_CODE (TREE_OPERAND (expr, 0)) != ADDR_EXPR
+ && sra_mode != SRA_MODE_EARLY_IPA)
return NULL;
/* fall through */
case VAR_DECL:
@@ -1285,7 +1283,21 @@ make_fancy_name_1 (tree expr)
break;
sprintf (buffer, HOST_WIDE_INT_PRINT_DEC, TREE_INT_CST_LOW (index));
obstack_grow (&name_obstack, buffer, strlen (buffer));
+ break;
+
+ case ADDR_EXPR:
+ make_fancy_name_1 (TREE_OPERAND (expr, 0));
+ break;
+ case MEM_REF:
+ make_fancy_name_1 (TREE_OPERAND (expr, 0));
+ if (!integer_zerop (TREE_OPERAND (expr, 1)))
+ {
+ obstack_1grow (&name_obstack, '$');
+ sprintf (buffer, HOST_WIDE_INT_PRINT_DEC,
+ TREE_INT_CST_LOW (TREE_OPERAND (expr, 1)));
+ obstack_grow (&name_obstack, buffer, strlen (buffer));
+ }
break;
case BIT_FIELD_REF:
@@ -1308,7 +1320,11 @@ make_fancy_name (tree expr)
return XOBFINISH (&name_obstack, char *);
}
-/* Helper function for build_ref_for_offset. */
+/* Helper function for build_ref_for_offset.
+
+ FIXME: Eventually this should be rewritten to either re-use the
+ original access expression unshared (which is good for alias
+ analysis) or to build a MEM_REF expression. */
static bool
build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset,
@@ -1329,7 +1345,7 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset,
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;
@@ -1406,12 +1422,7 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset,
type TYPE at the given OFFSET of the type EXP_TYPE. If EXPR is NULL, the
function only determines whether it can build such a reference without
actually doing it, otherwise, the tree it points to is unshared first and
- then used as a base for furhter sub-references.
-
- FIXME: Eventually this should be replaced with
- maybe_fold_offset_to_reference() from tree-ssa-ccp.c but that requires a
- minor rewrite of fold_stmt.
- */
+ then used as a base for furhter sub-references. */
bool
build_ref_for_offset (tree *expr, tree type, HOST_WIDE_INT offset,
@@ -1426,7 +1437,7 @@ build_ref_for_offset (tree *expr, tree type, HOST_WIDE_INT offset,
{
type = TREE_TYPE (type);
if (expr)
- *expr = fold_build1_loc (loc, INDIRECT_REF, type, *expr);
+ *expr = build_simple_mem_ref_loc (loc, *expr);
}
return build_ref_for_offset_1 (expr, type, offset, exp_type);
@@ -2406,9 +2417,11 @@ handle_unscalarized_data_in_subtree (struct access *top_racc, tree lhs,
(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,
@@ -2530,12 +2543,12 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
}
}
-/* 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;
@@ -2548,7 +2561,7 @@ replace_uses_with_default_def_ssa_name (tree ssa, struct access *racc)
set_default_def (decl, repl);
}
- replace_uses_by (ssa, repl);
+ return repl;
}
/* Examine both sides of the assignment statement pointed to by STMT, replace
@@ -2712,9 +2725,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
&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++;
@@ -2727,18 +2738,33 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
{
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,
@@ -2765,11 +2791,13 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
}
/* 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)
@@ -2832,12 +2860,16 @@ sra_modify_function_body (void)
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
@@ -2852,7 +2884,7 @@ initialize_parameter_reductions (void)
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;
@@ -2897,7 +2929,10 @@ perform_intra_sra (void)
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",
@@ -2911,8 +2946,6 @@ perform_intra_sra (void)
statistics_counter_event (cfun, "Separate LHS and RHS handling",
sra_stats.separate_lhs_rhs_handling);
- ret = TODO_update_ssa;
-
out:
sra_deinitialize ();
return ret;
@@ -3026,8 +3059,11 @@ ptr_parm_has_direct_uses (tree parm)
tree lhs = gimple_get_lhs (stmt);
while (handled_component_p (lhs))
lhs = TREE_OPERAND (lhs, 0);
- if (INDIRECT_REF_P (lhs)
- && TREE_OPERAND (lhs, 0) == name)
+ if (TREE_CODE (lhs) == MEM_REF
+ && TREE_OPERAND (lhs, 0) == name
+ && integer_zerop (TREE_OPERAND (lhs, 1))
+ && types_compatible_p (TREE_TYPE (lhs),
+ TREE_TYPE (TREE_TYPE (name))))
uses_ok++;
}
if (gimple_assign_single_p (stmt))
@@ -3035,8 +3071,11 @@ ptr_parm_has_direct_uses (tree parm)
tree rhs = gimple_assign_rhs1 (stmt);
while (handled_component_p (rhs))
rhs = TREE_OPERAND (rhs, 0);
- if (INDIRECT_REF_P (rhs)
- && TREE_OPERAND (rhs, 0) == name)
+ if (TREE_CODE (rhs) == MEM_REF
+ && TREE_OPERAND (rhs, 0) == name
+ && integer_zerop (TREE_OPERAND (rhs, 1))
+ && types_compatible_p (TREE_TYPE (rhs),
+ TREE_TYPE (TREE_TYPE (name))))
uses_ok++;
}
else if (is_gimple_call (stmt))
@@ -3047,8 +3086,11 @@ ptr_parm_has_direct_uses (tree parm)
tree arg = gimple_call_arg (stmt, i);
while (handled_component_p (arg))
arg = TREE_OPERAND (arg, 0);
- if (INDIRECT_REF_P (arg)
- && TREE_OPERAND (arg, 0) == name)
+ if (TREE_CODE (arg) == MEM_REF
+ && TREE_OPERAND (arg, 0) == name
+ && integer_zerop (TREE_OPERAND (arg, 1))
+ && types_compatible_p (TREE_TYPE (arg),
+ TREE_TYPE (TREE_TYPE (name))))
uses_ok++;
}
}
@@ -3082,7 +3124,7 @@ find_param_candidates (void)
for (parm = DECL_ARGUMENTS (current_function_decl);
parm;
- parm = TREE_CHAIN (parm))
+ parm = DECL_CHAIN (parm))
{
tree type = TREE_TYPE (parm);
@@ -3574,7 +3616,7 @@ splice_all_param_accesses (VEC (access_p, heap) **representatives)
for (parm = DECL_ARGUMENTS (current_function_decl);
parm;
- parm = TREE_CHAIN (parm))
+ parm = DECL_CHAIN (parm))
{
if (is_unused_scalar_param (parm))
{
@@ -3659,7 +3701,7 @@ turn_representatives_into_adjustments (VEC (access_p, heap) *representatives,
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);
@@ -3917,8 +3959,11 @@ sra_ipa_modify_expr (tree *expr, bool convert,
if (!base || size == -1 || max_size == -1)
return false;
- if (INDIRECT_REF_P (base))
- base = TREE_OPERAND (base, 0);
+ if (TREE_CODE (base) == MEM_REF)
+ {
+ offset += mem_ref_offset (base).low * BITS_PER_UNIT;
+ base = TREE_OPERAND (base, 0);
+ }
base = get_ssa_base_param (base);
if (!base || TREE_CODE (base) != PARM_DECL)
@@ -3939,14 +3984,7 @@ sra_ipa_modify_expr (tree *expr, bool convert,
return false;
if (cand->by_ref)
- {
- tree folded;
- src = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (cand->reduction)),
- cand->reduction);
- folded = gimple_fold_indirect_ref (src);
- if (folded)
- src = folded;
- }
+ src = build_simple_mem_ref (cand->reduction);
else
src = cand->reduction;
@@ -4033,17 +4071,17 @@ sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi,
}
/* 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);
@@ -4105,15 +4143,16 @@ ipa_sra_modify_function_body (ipa_parm_adjustment_vec 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
@@ -4229,13 +4268,14 @@ convert_callers (struct cgraph_node *node, tree old_decl,
}
/* 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;
@@ -4256,11 +4296,11 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
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
@@ -4270,6 +4310,13 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
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)
@@ -4280,7 +4327,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
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;
}
@@ -4377,9 +4424,11 @@ ipa_early_sra (void)
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);