tree-sra.c (build_access_from_expr_1): The first parameter type changed to simple tree.

2010-05-04  Martin Jambor  <mjambor@suse.cz>

	* tree-sra.c (build_access_from_expr_1): The first parameter type
	changed to simple tree.
	(build_access_from_expr): Likewise, gsi parameter was eliminated.
	(scan_assign_result): Renamed to assignment_mod_result, enum elements
	renamed as well.
	(build_accesses_from_assign): Removed all parameters except for a
	simple gimple statement.  Now returns a simple bool.
	(scan_function): All non-analysis parts moved to separate functions
	sra_modify_function_body and ipa_sra_modify_function_body.  Removed all
	parameters and updated both callers.
	(sra_modify_expr): Removed parameter data.
	(sra_modify_function_body): New function.
	(perform_intra_sra): Call sra_modify_function_body to modify the
	function body.
	(replace_removed_params_ssa_names): Parameter data changed into
	adjustments vector.
	(sra_ipa_modify_expr): Likewise.  Also removed unused parameter gsi and
	changed the parameter dont_convert to convert with the opposite
	meaning.
	(sra_ipa_modify_assign): Parameter data changed into adjustments
	vector, return value changed to bool.
	(ipa_sra_modify_function_body): New function.
	(sra_ipa_reset_debug_stmts): Updated a comment.
	(modify_function): Use ipa_sra_modify_function_body to modify function
	body.

From-SVN: r159038
This commit is contained in:
Martin Jambor 2010-05-04 19:34:01 +02:00 committed by Martin Jambor
parent ed24bfdf68
commit 6cbd3b6a69
2 changed files with 303 additions and 193 deletions

View File

@ -1,3 +1,31 @@
2010-05-04 Martin Jambor <mjambor@suse.cz>
* tree-sra.c (build_access_from_expr_1): The first parameter type
changed to simple tree.
(build_access_from_expr): Likewise, gsi parameter was eliminated.
(scan_assign_result): Renamed to assignment_mod_result, enum elements
renamed as well.
(build_accesses_from_assign): Removed all parameters except for a
simple gimple statement. Now returns a simple bool.
(scan_function): All non-analysis parts moved to separate functions
sra_modify_function_body and ipa_sra_modify_function_body. Removed all
parameters and updated both callers.
(sra_modify_expr): Removed parameter data.
(sra_modify_function_body): New function.
(perform_intra_sra): Call sra_modify_function_body to modify the
function body.
(replace_removed_params_ssa_names): Parameter data changed into
adjustments vector.
(sra_ipa_modify_expr): Likewise. Also removed unused parameter gsi and
changed the parameter dont_convert to convert with the opposite
meaning.
(sra_ipa_modify_assign): Parameter data changed into adjustments
vector, return value changed to bool.
(ipa_sra_modify_function_body): New function.
(sra_ipa_reset_debug_stmts): Updated a comment.
(modify_function): Use ipa_sra_modify_function_body to modify function
body.
2010-05-04 H.J. Lu <hongjiu.lu@intel.com>
PR middle-end/43671

View File

@ -903,10 +903,9 @@ disqualify_base_of_expr (tree t, const char *reason)
created. */
static struct access *
build_access_from_expr_1 (tree *expr_ptr, gimple stmt, bool write)
build_access_from_expr_1 (tree expr, gimple stmt, bool write)
{
struct access *ret = NULL;
tree expr = *expr_ptr;
bool partial_ref;
if (TREE_CODE (expr) == BIT_FIELD_REF
@ -958,18 +957,17 @@ build_access_from_expr_1 (tree *expr_ptr, gimple stmt, bool write)
return ret;
}
/* Callback of scan_function. Scan expression EXPR and create access
structures for all accesses to candidates for scalarization. Return true if
any access has been inserted. */
/* Scan expression EXPR and create access structures for all accesses to
candidates for scalarization. Return true if any access has been inserted.
STMT must be the statement from which the expression is taken, WRITE must be
true if the expression is a store and false otherwise. */
static bool
build_access_from_expr (tree *expr_ptr,
gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, bool write,
void *data ATTRIBUTE_UNUSED)
build_access_from_expr (tree expr, gimple stmt, bool write)
{
struct access *access;
access = build_access_from_expr_1 (expr_ptr, gsi_stmt (*gsi), write);
access = build_access_from_expr_1 (expr, stmt, write);
if (access)
{
/* This means the aggregate is accesses as a whole in a way other than an
@ -1001,39 +999,28 @@ disqualify_ops_if_throwing_stmt (gimple stmt, tree lhs, tree rhs)
return false;
}
/* Result code for scan_assign callback for scan_function. */
enum scan_assign_result { SRA_SA_NONE, /* nothing done for the stmt */
SRA_SA_PROCESSED, /* stmt analyzed/changed */
SRA_SA_REMOVED }; /* stmt redundant and eliminated */
/* Callback of scan_function. Scan expressions occuring in the statement
pointed to by STMT_EXPR, create access structures for all accesses to
candidates for scalarization and remove those candidates which occur in
/* Scan expressions occuring in STMT, create access structures for all accesses
to candidates for scalarization and remove those candidates which occur in
statements or expressions that prevent them from being split apart. Return
true if any access has been inserted. */
static enum scan_assign_result
build_accesses_from_assign (gimple *stmt_ptr,
gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
static bool
build_accesses_from_assign (gimple stmt)
{
gimple stmt = *stmt_ptr;
tree *lhs_ptr, *rhs_ptr;
tree lhs, rhs;
struct access *lacc, *racc;
if (!gimple_assign_single_p (stmt))
return SRA_SA_NONE;
return false;
lhs_ptr = gimple_assign_lhs_ptr (stmt);
rhs_ptr = gimple_assign_rhs1_ptr (stmt);
lhs = gimple_assign_lhs (stmt);
rhs = gimple_assign_rhs1 (stmt);
if (disqualify_ops_if_throwing_stmt (stmt, *lhs_ptr, *rhs_ptr))
return SRA_SA_NONE;
if (disqualify_ops_if_throwing_stmt (stmt, lhs, rhs))
return false;
racc = build_access_from_expr_1 (rhs_ptr, stmt, false);
lacc = build_access_from_expr_1 (lhs_ptr, stmt, true);
racc = build_access_from_expr_1 (rhs, stmt, false);
lacc = build_access_from_expr_1 (lhs, stmt, true);
if (racc)
{
@ -1047,7 +1034,7 @@ build_accesses_from_assign (gimple *stmt_ptr,
&& (sra_mode == SRA_MODE_EARLY_INTRA || sra_mode == SRA_MODE_INTRA)
&& !lacc->grp_unscalarizable_region
&& !racc->grp_unscalarizable_region
&& AGGREGATE_TYPE_P (TREE_TYPE (*lhs_ptr))
&& AGGREGATE_TYPE_P (TREE_TYPE (lhs))
/* FIXME: Turn the following line into an assert after PR 40058 is
fixed. */
&& lacc->size == racc->size
@ -1064,7 +1051,7 @@ build_accesses_from_assign (gimple *stmt_ptr,
add_link_to_rhs (racc, link);
}
return (lacc || racc) ? SRA_SA_PROCESSED : SRA_SA_NONE;
return lacc || racc;
}
/* Callback of walk_stmt_load_store_addr_ops visit_addr used to determine
@ -1091,76 +1078,46 @@ callsite_has_enough_arguments_p (gimple call)
return gimple_call_num_args (call) >= (unsigned) func_param_count;
}
/* Scan function and look for interesting statements. Return true if any has
been found or processed, as indicated by callbacks. SCAN_EXPR is a callback
called on all expressions within statements except assign statements and
those deemed entirely unsuitable for some reason (all operands in such
statements and expression are removed from candidate_bitmap). SCAN_ASSIGN
is a callback called on all assign statements, HANDLE_SSA_DEFS is a callback
called on assign statements and those call statements which have a lhs, it
can be NULL. ANALYSIS_STAGE is true when running in the analysis stage of a
pass and thus no statement is being modified. DATA is a pointer passed to
all callbacks. If any single callback returns true, this function also
returns true, otherwise it returns false. */
/* Scan function and look for interesting expressions and create access
structures for them. Return true iff any access is created. */
static bool
scan_function (bool (*scan_expr) (tree *, gimple_stmt_iterator *, bool, void *),
enum scan_assign_result (*scan_assign) (gimple *,
gimple_stmt_iterator *,
void *),
bool (*handle_ssa_defs)(gimple, void *),
bool analysis_stage, void *data)
scan_function (void)
{
gimple_stmt_iterator gsi;
basic_block bb;
unsigned i;
tree *t;
bool ret = false;
FOR_EACH_BB (bb)
{
bool bb_changed = false;
if (handle_ssa_defs)
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
ret |= handle_ssa_defs (gsi_stmt (gsi), data);
gsi = gsi_start_bb (bb);
while (!gsi_end_p (gsi))
gimple_stmt_iterator gsi;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
enum scan_assign_result assign_result;
bool any = false, deleted = false;
tree t;
unsigned i;
if (analysis_stage && final_bbs && stmt_can_throw_external (stmt))
if (final_bbs && stmt_can_throw_external (stmt))
bitmap_set_bit (final_bbs, bb->index);
switch (gimple_code (stmt))
{
case GIMPLE_RETURN:
t = gimple_return_retval_ptr (stmt);
if (*t != NULL_TREE)
any |= scan_expr (t, &gsi, false, data);
if (analysis_stage && final_bbs)
t = gimple_return_retval (stmt);
if (t != NULL_TREE)
ret |= build_access_from_expr (t, stmt, false);
if (final_bbs)
bitmap_set_bit (final_bbs, bb->index);
break;
case GIMPLE_ASSIGN:
assign_result = scan_assign (&stmt, &gsi, data);
any |= assign_result == SRA_SA_PROCESSED;
deleted = assign_result == SRA_SA_REMOVED;
if (handle_ssa_defs && assign_result != SRA_SA_REMOVED)
any |= handle_ssa_defs (stmt, data);
ret |= build_accesses_from_assign (stmt);
break;
case GIMPLE_CALL:
/* Operands must be processed before the lhs. */
for (i = 0; i < gimple_call_num_args (stmt); i++)
{
tree *argp = gimple_call_arg_ptr (stmt, i);
any |= scan_expr (argp, &gsi, false, data);
}
ret |= build_access_from_expr (gimple_call_arg (stmt, i),
stmt, false);
if (analysis_stage && sra_mode == SRA_MODE_EARLY_IPA)
if (sra_mode == SRA_MODE_EARLY_IPA)
{
tree dest = gimple_call_fndecl (stmt);
int flags = gimple_call_flags (stmt);
@ -1184,65 +1141,33 @@ scan_function (bool (*scan_expr) (tree *, gimple_stmt_iterator *, bool, void *),
bitmap_set_bit (final_bbs, bb->index);
}
if (gimple_call_lhs (stmt))
{
tree *lhs_ptr = gimple_call_lhs_ptr (stmt);
if (!analysis_stage
|| !disqualify_ops_if_throwing_stmt (stmt,
*lhs_ptr, NULL))
{
any |= scan_expr (lhs_ptr, &gsi, true, data);
if (handle_ssa_defs)
any |= handle_ssa_defs (stmt, data);
}
}
t = gimple_call_lhs (stmt);
if (t && !disqualify_ops_if_throwing_stmt (stmt, t, NULL))
ret |= build_access_from_expr (t, stmt, true);
break;
case GIMPLE_ASM:
if (analysis_stage)
{
walk_stmt_load_store_addr_ops (stmt, NULL, NULL, NULL,
asm_visit_addr);
if (final_bbs)
bitmap_set_bit (final_bbs, bb->index);
}
walk_stmt_load_store_addr_ops (stmt, NULL, NULL, NULL,
asm_visit_addr);
if (final_bbs)
bitmap_set_bit (final_bbs, bb->index);
for (i = 0; i < gimple_asm_ninputs (stmt); i++)
{
tree *op = &TREE_VALUE (gimple_asm_input_op (stmt, i));
any |= scan_expr (op, &gsi, false, data);
t = TREE_VALUE (gimple_asm_input_op (stmt, i));
ret |= build_access_from_expr (t, stmt, false);
}
for (i = 0; i < gimple_asm_noutputs (stmt); i++)
{
tree *op = &TREE_VALUE (gimple_asm_output_op (stmt, i));
any |= scan_expr (op, &gsi, true, data);
t = TREE_VALUE (gimple_asm_output_op (stmt, i));
ret |= build_access_from_expr (t, stmt, true);
}
break;
default:
break;
}
if (any)
{
ret = true;
if (!analysis_stage)
{
bb_changed = true;
update_stmt (stmt);
maybe_clean_eh_stmt (stmt);
}
}
if (deleted)
bb_changed = true;
else
{
gsi_next (&gsi);
ret = true;
}
}
if (!analysis_stage && bb_changed && sra_mode == SRA_MODE_EARLY_IPA)
gimple_purge_dead_eh_edges (bb);
}
return ret;
@ -2300,15 +2225,14 @@ get_access_for_expr (tree expr)
return get_var_base_offset_size_access (base, offset, max_size);
}
/* Callback for scan_function. Replace the expression EXPR with a scalar
replacement if there is one and generate other statements to do type
conversion or subtree copying if necessary. GSI is used to place newly
created statements, WRITE is true if the expression is being written to (it
is on a LHS of a statement or output in an assembly statement). */
/* Replace the expression EXPR with a scalar replacement if there is one and
generate other statements to do type conversion or subtree copying if
necessary. GSI is used to place newly created statements, WRITE is true if
the expression is being written to (it is on a LHS of a statement or output
in an assembly statement). */
static bool
sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write,
void *data ATTRIBUTE_UNUSED)
sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
{
struct access *access;
tree type, bfr;
@ -2510,11 +2434,17 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
while (lacc);
}
/* Result code for SRA assignment modification. */
enum assignment_mod_result { SRA_AM_NONE, /* nothing done for the stmt */
SRA_AM_MODIFIED, /* stmt changed but not
removed */
SRA_AM_REMOVED }; /* stmt eliminated */
/* Modify assignments with a CONSTRUCTOR on their RHS. STMT contains a pointer
to the assignment and GSI is the statement iterator pointing at it. Returns
the same values as sra_modify_assign. */
static enum scan_assign_result
static enum assignment_mod_result
sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
{
tree lhs = gimple_assign_lhs (*stmt);
@ -2522,7 +2452,7 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
acc = get_access_for_expr (lhs);
if (!acc)
return SRA_SA_NONE;
return SRA_AM_NONE;
if (VEC_length (constructor_elt,
CONSTRUCTOR_ELTS (gimple_assign_rhs1 (*stmt))) > 0)
@ -2532,7 +2462,7 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
if (access_has_children_p (acc))
generate_subtree_copies (acc->first_child, acc->base, 0, 0, 0, gsi,
true, true);
return SRA_SA_PROCESSED;
return SRA_AM_MODIFIED;
}
if (acc->grp_covered)
@ -2540,12 +2470,12 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
init_subtree_with_zero (acc, gsi, false);
unlink_stmt_vdef (*stmt);
gsi_remove (gsi, true);
return SRA_SA_REMOVED;
return SRA_AM_REMOVED;
}
else
{
init_subtree_with_zero (acc, gsi, true);
return SRA_SA_PROCESSED;
return SRA_AM_MODIFIED;
}
}
@ -2578,16 +2508,14 @@ replace_uses_with_default_def_ssa_name (tree ssa)
replace_uses_by (ssa, repl);
}
/* Callback of scan_function to process assign statements. It examines both
sides of the statement, replaces them with a scalare replacement if there is
one and generating copying of replacements if scalarized aggregates have been
used in the assignment. STMT is a pointer to the assign statement, GSI is
used to hold generated statements for type conversions and subtree
/* Examine both sides of the assignment statement pointed to by STMT, replace
them with a scalare replacement if there is one and generate copying of
replacements if scalarized aggregates have been used in the assignment. GSI
is used to hold generated statements for type conversions and subtree
copying. */
static enum scan_assign_result
sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
void *data ATTRIBUTE_UNUSED)
static enum assignment_mod_result
sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
{
struct access *lacc, *racc;
tree lhs, rhs;
@ -2597,7 +2525,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
gimple_stmt_iterator orig_gsi = *gsi;
if (!gimple_assign_single_p (*stmt))
return SRA_SA_NONE;
return SRA_AM_NONE;
lhs = gimple_assign_lhs (*stmt);
rhs = gimple_assign_rhs1 (*stmt);
@ -2609,16 +2537,16 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
|| TREE_CODE (rhs) == BIT_FIELD_REF || TREE_CODE (lhs) == BIT_FIELD_REF)
{
modify_this_stmt = sra_modify_expr (gimple_assign_rhs1_ptr (*stmt),
gsi, false, data);
gsi, false);
modify_this_stmt |= sra_modify_expr (gimple_assign_lhs_ptr (*stmt),
gsi, true, data);
return modify_this_stmt ? SRA_SA_PROCESSED : SRA_SA_NONE;
gsi, true);
return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
}
lacc = get_access_for_expr (lhs);
racc = get_access_for_expr (rhs);
if (!lacc && !racc)
return SRA_SA_NONE;
return SRA_AM_NONE;
if (lacc && lacc->grp_to_be_replaced)
{
@ -2747,7 +2675,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
unlink_stmt_vdef (*stmt);
gsi_remove (&orig_gsi, true);
sra_stats.deleted++;
return SRA_SA_REMOVED;
return SRA_AM_REMOVED;
}
}
else
@ -2767,7 +2695,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
unlink_stmt_vdef (*stmt);
gsi_remove (gsi, true);
sra_stats.deleted++;
return SRA_SA_REMOVED;
return SRA_AM_REMOVED;
}
else if (racc->first_child)
generate_subtree_copies (racc->first_child, lhs,
@ -2790,7 +2718,83 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
gcc_assert (*stmt == gsi_stmt (orig_gsi));
}
return modify_this_stmt ? SRA_SA_PROCESSED : SRA_SA_NONE;
return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
}
/* Traverse the function body and all modifications as decided in
analyze_all_variable_accesses. */
static void
sra_modify_function_body (void)
{
basic_block bb;
FOR_EACH_BB (bb)
{
gimple_stmt_iterator gsi = gsi_start_bb (bb);
while (!gsi_end_p (gsi))
{
gimple stmt = gsi_stmt (gsi);
enum assignment_mod_result assign_result;
bool modified = false, deleted = false;
tree *t;
unsigned i;
switch (gimple_code (stmt))
{
case GIMPLE_RETURN:
t = gimple_return_retval_ptr (stmt);
if (*t != NULL_TREE)
modified |= sra_modify_expr (t, &gsi, false);
break;
case GIMPLE_ASSIGN:
assign_result = sra_modify_assign (&stmt, &gsi);
modified |= assign_result == SRA_AM_MODIFIED;
deleted = assign_result == SRA_AM_REMOVED;
break;
case GIMPLE_CALL:
/* Operands must be processed before the lhs. */
for (i = 0; i < gimple_call_num_args (stmt); i++)
{
t = gimple_call_arg_ptr (stmt, i);
modified |= sra_modify_expr (t, &gsi, false);
}
if (gimple_call_lhs (stmt))
{
t = gimple_call_lhs_ptr (stmt);
modified |= sra_modify_expr (t, &gsi, true);
}
break;
case GIMPLE_ASM:
for (i = 0; i < gimple_asm_ninputs (stmt); i++)
{
t = &TREE_VALUE (gimple_asm_input_op (stmt, i));
modified |= sra_modify_expr (t, &gsi, false);
}
for (i = 0; i < gimple_asm_noutputs (stmt); i++)
{
t = &TREE_VALUE (gimple_asm_output_op (stmt, i));
modified |= sra_modify_expr (t, &gsi, true);
}
break;
default:
break;
}
if (modified)
{
update_stmt (stmt);
maybe_clean_eh_stmt (stmt);
}
if (!deleted)
gsi_next (&gsi);
}
}
}
/* Generate statements initializing scalar replacements of parts of function
@ -2844,14 +2848,13 @@ perform_intra_sra (void)
if (!find_var_candidates ())
goto out;
if (!scan_function (build_access_from_expr, build_accesses_from_assign, NULL,
true, NULL))
if (!scan_function ())
goto out;
if (!analyze_all_variable_accesses ())
goto out;
scan_function (sra_modify_expr, sra_modify_assign, NULL, false, NULL);
sra_modify_function_body ();
initialize_parameter_reductions ();
statistics_counter_event (cfun, "Scalar replacements created",
@ -3786,20 +3789,18 @@ get_adjustment_for_base (ipa_parm_adjustment_vec adjustments, tree base)
return NULL;
}
/* Callback for scan_function. If the statement STMT defines an SSA_NAME of a
parameter which is to be removed because its value is not used, replace the
SSA_NAME with a one relating to a created VAR_DECL and replace all of its
uses too and return true (update_stmt is then issued for the statement by
the caller). DATA is a pointer to an adjustments vector. */
/* If the statement STMT defines an SSA_NAME of a parameter which is to be
removed because its value is not used, replace the SSA_NAME with a one
relating to a created VAR_DECL together all of its uses and return true.
ADJUSTMENTS is a pointer to an adjustments vector. */
static bool
replace_removed_params_ssa_names (gimple stmt, void *data)
replace_removed_params_ssa_names (gimple stmt,
ipa_parm_adjustment_vec adjustments)
{
VEC (ipa_parm_adjustment_t, heap) *adjustments;
struct ipa_parm_adjustment *adj;
tree lhs, decl, repl, name;
adjustments = (VEC (ipa_parm_adjustment_t, heap) *) data;
if (gimple_code (stmt) == GIMPLE_PHI)
lhs = gimple_phi_result (stmt);
else if (is_gimple_assign (stmt))
@ -3842,27 +3843,22 @@ replace_removed_params_ssa_names (gimple stmt, void *data)
return true;
}
/* Callback for scan_function and helper to sra_ipa_modify_assign. If the
expression *EXPR should be replaced by a reduction of a parameter, do so.
DATA is a pointer to a vector of adjustments. DONT_CONVERT specifies
whether the function should care about type incompatibility the current and
new expressions. If it is true, the function will leave incompatibility
issues to the caller.
When called directly by scan_function, DONT_CONVERT is true when the EXPR is
a write (LHS) expression. */
/* If the expression *EXPR should be replaced by a reduction of a parameter, do
so. ADJUSTMENTS is a pointer to a vector of adjustments. CONVERT
specifies whether the function should care about type incompatibility the
current and new expressions. If it is false, the function will leave
incompatibility issues to the caller. Return true iff the expression
was modified. */
static bool
sra_ipa_modify_expr (tree *expr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
bool dont_convert, void *data)
sra_ipa_modify_expr (tree *expr, bool convert,
ipa_parm_adjustment_vec adjustments)
{
ipa_parm_adjustment_vec adjustments;
int i, len;
struct ipa_parm_adjustment *adj, *cand = NULL;
HOST_WIDE_INT offset, size, max_size;
tree base, src;
adjustments = (VEC (ipa_parm_adjustment_t, heap) *) data;
len = VEC_length (ipa_parm_adjustment_t, adjustments);
if (TREE_CODE (*expr) == BIT_FIELD_REF
@ -3870,7 +3866,7 @@ sra_ipa_modify_expr (tree *expr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
|| TREE_CODE (*expr) == REALPART_EXPR)
{
expr = &TREE_OPERAND (*expr, 0);
dont_convert = false;
convert = true;
}
base = get_ref_base_and_extent (*expr, &offset, &size, &max_size);
@ -3919,8 +3915,7 @@ sra_ipa_modify_expr (tree *expr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
fprintf (dump_file, "\n");
}
if (!dont_convert
&& !useless_type_conversion_p (TREE_TYPE (*expr), cand->type))
if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type))
{
tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src);
*expr = vce;
@ -3930,24 +3925,28 @@ sra_ipa_modify_expr (tree *expr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
return true;
}
/* Callback for scan_function to process assign statements. Performs
essentially the same function like sra_ipa_modify_expr. */
/* If the statement pointed to by STMT_PTR contains any expressions that need
to replaced with a different one as noted by ADJUSTMENTS, do so. Handle any
potential type incompatibilities (GSI is used to accommodate conversion
statements and must point to the statement). Return true iff the statement
was modified. */
static enum scan_assign_result
sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi, void *data)
static bool
sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi,
ipa_parm_adjustment_vec adjustments)
{
gimple stmt = *stmt_ptr;
tree *lhs_p, *rhs_p;
bool any;
if (!gimple_assign_single_p (stmt))
return SRA_SA_NONE;
return false;
rhs_p = gimple_assign_rhs1_ptr (stmt);
lhs_p = gimple_assign_lhs_ptr (stmt);
any = sra_ipa_modify_expr (rhs_p, gsi, true, data);
any |= sra_ipa_modify_expr (lhs_p, gsi, true, data);
any = sra_ipa_modify_expr (rhs_p, false, adjustments);
any |= sra_ipa_modify_expr (lhs_p, false, adjustments);
if (any)
{
tree new_rhs = NULL_TREE;
@ -3983,10 +3982,94 @@ sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi, void *data)
gimple_assign_set_rhs_from_tree (gsi, tmp);
}
return SRA_SA_PROCESSED;
return true;
}
return SRA_SA_NONE;
return false;
}
/* Traverse the function body and all modifications as described in
ADJUSTMENTS. */
static void
ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments)
{
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);
gsi = gsi_start_bb (bb);
while (!gsi_end_p (gsi))
{
gimple stmt = gsi_stmt (gsi);
bool modified = false;
tree *t;
unsigned i;
switch (gimple_code (stmt))
{
case GIMPLE_RETURN:
t = gimple_return_retval_ptr (stmt);
if (*t != NULL_TREE)
modified |= sra_ipa_modify_expr (t, true, adjustments);
break;
case GIMPLE_ASSIGN:
modified |= sra_ipa_modify_assign (&stmt, &gsi, adjustments);
modified |= replace_removed_params_ssa_names (stmt, adjustments);
break;
case GIMPLE_CALL:
/* Operands must be processed before the lhs. */
for (i = 0; i < gimple_call_num_args (stmt); i++)
{
t = gimple_call_arg_ptr (stmt, i);
modified |= sra_ipa_modify_expr (t, true, adjustments);
}
if (gimple_call_lhs (stmt))
{
t = gimple_call_lhs_ptr (stmt);
modified |= sra_ipa_modify_expr (t, false, adjustments);
modified |= replace_removed_params_ssa_names (stmt,
adjustments);
}
break;
case GIMPLE_ASM:
for (i = 0; i < gimple_asm_ninputs (stmt); i++)
{
t = &TREE_VALUE (gimple_asm_input_op (stmt, i));
modified |= sra_ipa_modify_expr (t, true, adjustments);
}
for (i = 0; i < gimple_asm_noutputs (stmt); i++)
{
t = &TREE_VALUE (gimple_asm_output_op (stmt, i));
modified |= sra_ipa_modify_expr (t, false, adjustments);
}
break;
default:
break;
}
if (modified)
{
bb_changed = true;
update_stmt (stmt);
maybe_clean_eh_stmt (stmt);
}
gsi_next (&gsi);
}
if (bb_changed)
gimple_purge_dead_eh_edges (bb);
}
}
/* Call gimple_debug_bind_reset_value on all debug statements describing
@ -4013,7 +4096,8 @@ sra_ipa_reset_debug_stmts (ipa_parm_adjustment_vec adjustments)
continue;
FOR_EACH_IMM_USE_STMT (stmt, ui, name)
{
/* All other users must have been removed by scan_function. */
/* All other users must have been removed by
ipa_sra_modify_function_body. */
gcc_assert (is_gimple_debug (stmt));
gimple_debug_bind_reset_value (stmt);
update_stmt (stmt);
@ -4131,8 +4215,7 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
as following functions will use what it computed. */
create_abstract_origin (current_function_decl);
ipa_modify_formal_parameters (current_function_decl, adjustments, "ISRA");
scan_function (sra_ipa_modify_expr, sra_ipa_modify_assign,
replace_removed_params_ssa_names, false, adjustments);
ipa_sra_modify_function_body (adjustments);
sra_ipa_reset_debug_stmts (adjustments);
convert_callers (node, adjustments);
cgraph_make_node_local (node);
@ -4224,8 +4307,7 @@ ipa_early_sra (void)
* last_basic_block_for_function (cfun));
final_bbs = BITMAP_ALLOC (NULL);
scan_function (build_access_from_expr, build_accesses_from_assign,
NULL, true, NULL);
scan_function ();
if (encountered_apply_args)
{
if (dump_file)