ipa-split.c (struct split_point): Add split_part_set_retval.
* ipa-split.c (struct split_point): Add split_part_set_retval. (find_retval): Forward declare. (test_nonssa_use, mark_nonssa_use): Special case return by reference. (consider_split): Compute current->split_part_set_retval. (visit_bb): Do not look into return value. (split_function): Handle !split_part_set_retval From-SVN: r162842
This commit is contained in:
parent
fc734382d1
commit
241a2b9ec2
|
@ -1,3 +1,12 @@
|
||||||
|
2010-08-03 Jan Hubicka <jh@suse.cz>
|
||||||
|
|
||||||
|
* ipa-split.c (struct split_point): Add split_part_set_retval.
|
||||||
|
(find_retval): Forward declare.
|
||||||
|
(test_nonssa_use, mark_nonssa_use): Special case return by reference.
|
||||||
|
(consider_split): Compute current->split_part_set_retval.
|
||||||
|
(visit_bb): Do not look into return value.
|
||||||
|
(split_function): Handle !split_part_set_retval
|
||||||
|
|
||||||
2010-08-03 Martin Jambor <mjambor@suse.cz>
|
2010-08-03 Martin Jambor <mjambor@suse.cz>
|
||||||
|
|
||||||
* tree-sra.c (completely_scalarize_record): New parameter REF, create
|
* tree-sra.c (completely_scalarize_record): New parameter REF, create
|
||||||
|
|
139
gcc/ipa-split.c
139
gcc/ipa-split.c
|
@ -120,12 +120,18 @@ struct split_point
|
||||||
|
|
||||||
/* Basic blocks we are splitting away. */
|
/* Basic blocks we are splitting away. */
|
||||||
bitmap split_bbs;
|
bitmap split_bbs;
|
||||||
|
|
||||||
|
/* True when return value is computed on split part and thus it needs
|
||||||
|
to be returned. */
|
||||||
|
bool split_part_set_retval;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Best split point found. */
|
/* Best split point found. */
|
||||||
|
|
||||||
struct split_point best_split_point;
|
struct split_point best_split_point;
|
||||||
|
|
||||||
|
static tree find_retval (basic_block return_bb);
|
||||||
|
|
||||||
/* Callback for walk_stmt_load_store_addr_ops. If T is non-ssa automatic
|
/* Callback for walk_stmt_load_store_addr_ops. If T is non-ssa automatic
|
||||||
variable, check it if it is present in bitmap passed via DATA. */
|
variable, check it if it is present in bitmap passed via DATA. */
|
||||||
|
|
||||||
|
@ -141,6 +147,14 @@ test_nonssa_use (gimple stmt ATTRIBUTE_UNUSED, tree t,
|
||||||
|| (TREE_CODE (t) == RESULT_DECL)
|
|| (TREE_CODE (t) == RESULT_DECL)
|
||||||
|| (TREE_CODE (t) == PARM_DECL)))
|
|| (TREE_CODE (t) == PARM_DECL)))
|
||||||
return bitmap_bit_p ((bitmap)data, DECL_UID (t));
|
return bitmap_bit_p ((bitmap)data, DECL_UID (t));
|
||||||
|
|
||||||
|
/* For DECL_BY_REFERENCE, the return value is actually pointer. We want to pretend
|
||||||
|
that the value pointed to is actual result decl. */
|
||||||
|
if (t && (TREE_CODE (t) == MEM_REF || INDIRECT_REF_P (t))
|
||||||
|
&& TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME
|
||||||
|
&& TREE_CODE (SSA_NAME_VAR (TREE_OPERAND (t, 0))) == RESULT_DECL
|
||||||
|
&& DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
|
||||||
|
return bitmap_bit_p ((bitmap)data, DECL_UID (DECL_RESULT (current_function_decl)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +274,7 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
|
||||||
gimple_stmt_iterator bsi;
|
gimple_stmt_iterator bsi;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int incomming_freq = 0;
|
int incomming_freq = 0;
|
||||||
|
tree retval;
|
||||||
|
|
||||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||||
dump_split_point (dump_file, current);
|
dump_split_point (dump_file, current);
|
||||||
|
@ -388,6 +403,43 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
|
||||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||||
fprintf (dump_file, " Accepted!\n");
|
fprintf (dump_file, " Accepted!\n");
|
||||||
|
|
||||||
|
/* See if retval used by return bb is computed by header or split part.
|
||||||
|
When it is computed by split part, we need to produce return statement
|
||||||
|
in the split part and add code to header to pass it around.
|
||||||
|
|
||||||
|
This is bit tricky to test:
|
||||||
|
1) When there is no return_bb or no return value, we always pass
|
||||||
|
value around.
|
||||||
|
2) Invariants are always computed by caller.
|
||||||
|
3) For SSA we need to look if defining statement is in header or split part
|
||||||
|
4) For non-SSA we need to look where the var is computed. */
|
||||||
|
retval = find_retval (return_bb);
|
||||||
|
if (!retval)
|
||||||
|
current->split_part_set_retval = true;
|
||||||
|
else if (is_gimple_min_invariant (retval))
|
||||||
|
current->split_part_set_retval = false;
|
||||||
|
/* Special case is value returned by reference we record as if it was non-ssa
|
||||||
|
set to result_decl. */
|
||||||
|
else if (TREE_CODE (retval) == SSA_NAME
|
||||||
|
&& TREE_CODE (SSA_NAME_VAR (retval)) == RESULT_DECL
|
||||||
|
&& DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
|
||||||
|
current->split_part_set_retval
|
||||||
|
= bitmap_bit_p (non_ssa_vars, DECL_UID (SSA_NAME_VAR (retval)));
|
||||||
|
else if (TREE_CODE (retval) == SSA_NAME)
|
||||||
|
current->split_part_set_retval
|
||||||
|
= (!SSA_NAME_IS_DEFAULT_DEF (retval)
|
||||||
|
&& (bitmap_bit_p (current->split_bbs,
|
||||||
|
gimple_bb (SSA_NAME_DEF_STMT (retval))->index)
|
||||||
|
|| gimple_bb (SSA_NAME_DEF_STMT (retval)) == return_bb));
|
||||||
|
else if (TREE_CODE (retval) == PARM_DECL)
|
||||||
|
current->split_part_set_retval = false;
|
||||||
|
else if (TREE_CODE (retval) == VAR_DECL
|
||||||
|
|| TREE_CODE (retval) == RESULT_DECL)
|
||||||
|
current->split_part_set_retval
|
||||||
|
= bitmap_bit_p (non_ssa_vars, DECL_UID (retval));
|
||||||
|
else
|
||||||
|
current->split_part_set_retval = true;
|
||||||
|
|
||||||
/* At the moment chose split point with lowest frequency and that leaves
|
/* At the moment chose split point with lowest frequency and that leaves
|
||||||
out smallest size of header.
|
out smallest size of header.
|
||||||
In future we might re-consider this heuristics. */
|
In future we might re-consider this heuristics. */
|
||||||
|
@ -516,6 +568,14 @@ mark_nonssa_use (gimple stmt ATTRIBUTE_UNUSED, tree t,
|
||||||
if ((TREE_CODE (t) == VAR_DECL && auto_var_in_fn_p (t, current_function_decl))
|
if ((TREE_CODE (t) == VAR_DECL && auto_var_in_fn_p (t, current_function_decl))
|
||||||
|| (TREE_CODE (t) == RESULT_DECL))
|
|| (TREE_CODE (t) == RESULT_DECL))
|
||||||
bitmap_set_bit ((bitmap)data, DECL_UID (t));
|
bitmap_set_bit ((bitmap)data, DECL_UID (t));
|
||||||
|
|
||||||
|
/* For DECL_BY_REFERENCE, the return value is actually pointer. We want to pretend
|
||||||
|
that the value pointed to is actual result decl. */
|
||||||
|
if (t && (TREE_CODE (t) == MEM_REF || INDIRECT_REF_P (t))
|
||||||
|
&& TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME
|
||||||
|
&& TREE_CODE (SSA_NAME_VAR (TREE_OPERAND (t, 0))) == RESULT_DECL
|
||||||
|
&& DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
|
||||||
|
return bitmap_bit_p ((bitmap)data, DECL_UID (DECL_RESULT (current_function_decl)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,7 +690,6 @@ visit_bb (basic_block bb, basic_block return_bb,
|
||||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||||
if (e->dest == return_bb)
|
if (e->dest == return_bb)
|
||||||
{
|
{
|
||||||
bool found_phi = false;
|
|
||||||
for (bsi = gsi_start_phis (return_bb); !gsi_end_p (bsi); gsi_next (&bsi))
|
for (bsi = gsi_start_phis (return_bb); !gsi_end_p (bsi); gsi_next (&bsi))
|
||||||
{
|
{
|
||||||
gimple stmt = gsi_stmt (bsi);
|
gimple stmt = gsi_stmt (bsi);
|
||||||
|
@ -640,25 +699,11 @@ visit_bb (basic_block bb, basic_block return_bb,
|
||||||
continue;
|
continue;
|
||||||
if (!is_gimple_reg (gimple_phi_result (stmt)))
|
if (!is_gimple_reg (gimple_phi_result (stmt)))
|
||||||
continue;
|
continue;
|
||||||
found_phi = true;
|
|
||||||
if (TREE_CODE (op) == SSA_NAME)
|
if (TREE_CODE (op) == SSA_NAME)
|
||||||
bitmap_set_bit (used_ssa_names, SSA_NAME_VERSION (op));
|
bitmap_set_bit (used_ssa_names, SSA_NAME_VERSION (op));
|
||||||
else
|
else
|
||||||
can_split &= !mark_nonssa_use (stmt, op, non_ssa_vars);
|
can_split &= !mark_nonssa_use (stmt, op, non_ssa_vars);
|
||||||
}
|
}
|
||||||
if (!gsi_end_p (gsi_last_bb (return_bb)))
|
|
||||||
{
|
|
||||||
ssa_op_iter iter;
|
|
||||||
gimple stmt = gsi_stmt (gsi_last_bb (return_bb));
|
|
||||||
tree op;
|
|
||||||
if (!found_phi)
|
|
||||||
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
|
|
||||||
bitmap_set_bit (used_ssa_names, SSA_NAME_VERSION (op));
|
|
||||||
can_split &= !walk_stmt_load_store_addr_ops (stmt, non_ssa_vars,
|
|
||||||
mark_nonssa_use,
|
|
||||||
mark_nonssa_use,
|
|
||||||
mark_nonssa_use);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return can_split;
|
return can_split;
|
||||||
}
|
}
|
||||||
|
@ -905,8 +950,55 @@ split_function (struct split_point *split_point)
|
||||||
if (e)
|
if (e)
|
||||||
split_part_return_p = true;
|
split_part_return_p = true;
|
||||||
|
|
||||||
/* If we return, we will need the return block. */
|
/* Add return block to what will become the split function.
|
||||||
if (return_bb != EXIT_BLOCK_PTR && split_part_return_p)
|
We do not return; no return block is needed. */
|
||||||
|
if (!split_part_return_p)
|
||||||
|
;
|
||||||
|
/* We have no return block, so nothing is needed. */
|
||||||
|
else if (return_bb == EXIT_BLOCK_PTR)
|
||||||
|
;
|
||||||
|
/* When we do not want to return value, we need to construct
|
||||||
|
new return block with empty return statement.
|
||||||
|
FIXME: Once we are able to change return type, we should change function
|
||||||
|
to return void instead of just outputting function with undefined return
|
||||||
|
value. For structures this affects quality of codegen. */
|
||||||
|
else if (!split_point->split_part_set_retval
|
||||||
|
&& find_retval (return_bb))
|
||||||
|
{
|
||||||
|
bool redirected = true;
|
||||||
|
basic_block new_return_bb = create_basic_block (NULL, 0, return_bb);
|
||||||
|
gimple_stmt_iterator gsi = gsi_start_bb (new_return_bb);
|
||||||
|
gsi_insert_after (&gsi, gimple_build_return (NULL), GSI_NEW_STMT);
|
||||||
|
while (redirected)
|
||||||
|
{
|
||||||
|
redirected = false;
|
||||||
|
FOR_EACH_EDGE (e, ei, return_bb->preds)
|
||||||
|
if (bitmap_bit_p (split_point->split_bbs, e->src->index))
|
||||||
|
{
|
||||||
|
new_return_bb->count += e->count;
|
||||||
|
new_return_bb->frequency += EDGE_FREQUENCY (e);
|
||||||
|
redirect_edge_and_branch (e, new_return_bb);
|
||||||
|
redirected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e = make_edge (new_return_bb, EXIT_BLOCK_PTR, 0);
|
||||||
|
e->probability = REG_BR_PROB_BASE;
|
||||||
|
e->count = new_return_bb->count;
|
||||||
|
bitmap_set_bit (split_point->split_bbs, new_return_bb->index);
|
||||||
|
/* We change CFG in a way tree-inline is not able to compensate on while
|
||||||
|
updating PHIs. There are only virtuals in return_bb, so recompute
|
||||||
|
them. */
|
||||||
|
for (gsi = gsi_start_phis (return_bb); !gsi_end_p (gsi);)
|
||||||
|
{
|
||||||
|
gimple stmt = gsi_stmt (gsi);
|
||||||
|
gcc_assert (!is_gimple_reg (gimple_phi_result (stmt)));
|
||||||
|
mark_sym_for_renaming (SSA_NAME_VAR (PHI_RESULT (stmt)));
|
||||||
|
gsi_remove (&gsi, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* When we pass aorund the value, use existing return block. */
|
||||||
|
else
|
||||||
bitmap_set_bit (split_point->split_bbs, return_bb->index);
|
bitmap_set_bit (split_point->split_bbs, return_bb->index);
|
||||||
|
|
||||||
/* Now create the actual clone. */
|
/* Now create the actual clone. */
|
||||||
|
@ -974,15 +1066,7 @@ split_function (struct split_point *split_point)
|
||||||
{
|
{
|
||||||
real_retval = retval = find_retval (return_bb);
|
real_retval = retval = find_retval (return_bb);
|
||||||
|
|
||||||
/* See if return value is computed by split part;
|
if (real_retval && split_point->split_part_set_retval)
|
||||||
function might just return its argument, invariant or undefined
|
|
||||||
value. In this case we don't need to do any updating. */
|
|
||||||
if (real_retval
|
|
||||||
&& !is_gimple_min_invariant (retval)
|
|
||||||
&& (TREE_CODE (retval) != SSA_NAME
|
|
||||||
|| (!SSA_NAME_IS_DEFAULT_DEF (retval)
|
|
||||||
|| DECL_BY_REFERENCE
|
|
||||||
(DECL_RESULT (current_function_decl)))))
|
|
||||||
{
|
{
|
||||||
gimple_stmt_iterator psi;
|
gimple_stmt_iterator psi;
|
||||||
|
|
||||||
|
@ -1038,7 +1122,8 @@ split_function (struct split_point *split_point)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gimple ret;
|
gimple ret;
|
||||||
if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
|
if (split_point->split_part_set_retval
|
||||||
|
&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
|
||||||
{
|
{
|
||||||
retval = DECL_RESULT (current_function_decl);
|
retval = DECL_RESULT (current_function_decl);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2010-08-03 Jan Hubicka <jh@suse.cz>
|
||||||
|
|
||||||
|
* gcc.c-torture/compile/pr45085.c: New testcase.
|
||||||
|
|
||||||
2010-08-03 Janus Weil <janus@gcc.gnu.org>
|
2010-08-03 Janus Weil <janus@gcc.gnu.org>
|
||||||
|
|
||||||
PR fortran/44584
|
PR fortran/44584
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* { dg-options "-O2 -Wuninitialized" } */
|
||||||
|
struct S { char *s1; long s2; };
|
||||||
|
struct T { int t1; long t2; long t3; };
|
||||||
|
extern int fn2 (void);
|
||||||
|
extern int fn3 (struct T);
|
||||||
|
extern struct T fn4 ();
|
||||||
|
extern int fn5 (char **, long *, int);
|
||||||
|
extern void fn6 (void);
|
||||||
|
extern void fn7 (void *);
|
||||||
|
struct S *fn10 ();
|
||||||
|
static int p;
|
||||||
|
static void *q;
|
||||||
|
extern struct T r;
|
||||||
|
|
||||||
|
static struct T
|
||||||
|
fn8 (struct T x, int y)
|
||||||
|
{
|
||||||
|
struct S *u = fn10 ();
|
||||||
|
int v = fn5 (&u->s1, &u->s2, 0);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
fn6 ();
|
||||||
|
if (fn3 (x))
|
||||||
|
return fn4 ();
|
||||||
|
if (y & 1)
|
||||||
|
return r;
|
||||||
|
v = fn5 (&u->s1, &u->s2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct T
|
||||||
|
fn9 (struct T x, int y)
|
||||||
|
{
|
||||||
|
struct T t = fn8 (x, y);
|
||||||
|
if (fn2 ())
|
||||||
|
fn7 (q);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
fn1 (void)
|
||||||
|
{
|
||||||
|
return fn9;
|
||||||
|
}
|
Loading…
Reference in New Issue