ipa-split.c (verify_non_ssa_vars): Break out from ......
* ipa-split.c (verify_non_ssa_vars): Break out from ...; perform DFS walk backwards from entry_bb to check only those basic block of header that might lead to execution of split part. (consider_split) ... here. (find_return_bb): Allow assignment in return BB. (find_retval): New. (split_function): Fix name of cloned function; take care of updating return value in return_bb containing move. * gcc.dg/tree-ssa/ipa-split-5.c: New function. From-SVN: r161744
This commit is contained in:
parent
c21ae2bfce
commit
2094f1fcd6
@ -1,3 +1,14 @@
|
||||
2010-07-02 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* ipa-split.c (verify_non_ssa_vars): Break out from ...; perform DFS walk
|
||||
backwards from entry_bb to check only those basic block of header
|
||||
that might lead to execution of split part.
|
||||
(consider_split) ... here.
|
||||
(find_return_bb): Allow assignment in return BB.
|
||||
(find_retval): New.
|
||||
(split_function): Fix name of cloned function; take care of updating return
|
||||
value in return_bb containing move.
|
||||
|
||||
2010-07-02 Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
PR target/44771
|
||||
|
233
gcc/ipa-split.c
233
gcc/ipa-split.c
@ -159,6 +159,91 @@ dump_split_point (FILE * file, struct split_point *current)
|
||||
dump_bitmap (file, current->ssa_names_to_pass);
|
||||
}
|
||||
|
||||
/* Look for all BBs in header that might lead to split part and verify that
|
||||
they are not defining any of SSA vars used by split part.
|
||||
Parameters are the same as for consider_split. */
|
||||
|
||||
static bool
|
||||
verify_non_ssa_vars (struct split_point *current, bitmap non_ssa_vars,
|
||||
basic_block return_bb)
|
||||
{
|
||||
bitmap seen = BITMAP_ALLOC (NULL);
|
||||
VEC (basic_block,heap) *worklist = NULL;
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
bool ok = true;
|
||||
|
||||
FOR_EACH_EDGE (e, ei, current->entry_bb->preds)
|
||||
if (e->src != ENTRY_BLOCK_PTR
|
||||
&& !bitmap_bit_p (current->split_bbs, e->src->index))
|
||||
{
|
||||
VEC_safe_push (basic_block, heap, worklist, e->src);
|
||||
bitmap_set_bit (seen, e->src->index);
|
||||
}
|
||||
|
||||
while (!VEC_empty (basic_block, worklist))
|
||||
{
|
||||
gimple_stmt_iterator bsi;
|
||||
basic_block bb = VEC_pop (basic_block, worklist);
|
||||
|
||||
FOR_EACH_EDGE (e, ei, bb->preds)
|
||||
if (e->src != ENTRY_BLOCK_PTR
|
||||
&& !bitmap_bit_p (seen, e->src->index))
|
||||
{
|
||||
gcc_checking_assert (!bitmap_bit_p (current->split_bbs,
|
||||
e->src->index));
|
||||
VEC_safe_push (basic_block, heap, worklist, e->src);
|
||||
bitmap_set_bit (seen, e->src->index);
|
||||
}
|
||||
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
|
||||
{
|
||||
if (is_gimple_debug (gsi_stmt (bsi)))
|
||||
continue;
|
||||
if (walk_stmt_load_store_addr_ops
|
||||
(gsi_stmt (bsi), non_ssa_vars, test_nonssa_use,
|
||||
test_nonssa_use, test_nonssa_use))
|
||||
{
|
||||
ok = false;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
|
||||
{
|
||||
if (walk_stmt_load_store_addr_ops
|
||||
(gsi_stmt (bsi), non_ssa_vars, test_nonssa_use,
|
||||
test_nonssa_use, test_nonssa_use))
|
||||
{
|
||||
ok = false;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
if (e->dest != return_bb)
|
||||
continue;
|
||||
for (bsi = gsi_start_phis (return_bb); !gsi_end_p (bsi);
|
||||
gsi_next (&bsi))
|
||||
{
|
||||
gimple stmt = gsi_stmt (bsi);
|
||||
tree op = gimple_phi_arg_def (stmt, e->dest_idx);
|
||||
|
||||
if (!is_gimple_reg (gimple_phi_result (stmt)))
|
||||
continue;
|
||||
if (TREE_CODE (op) != SSA_NAME
|
||||
&& test_nonssa_use (stmt, op, non_ssa_vars))
|
||||
{
|
||||
ok = false;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
BITMAP_FREE (seen);
|
||||
VEC_free (basic_block, heap, worklist);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* We found an split_point CURRENT. NON_SSA_VARS is bitmap of all non ssa
|
||||
variables used and RETURN_BB is return basic block.
|
||||
See if we can split function here. */
|
||||
@ -292,63 +377,12 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
|
||||
/* When there are non-ssa vars used in the split region, see if they
|
||||
are used in the header region. If so, reject the split.
|
||||
FIXME: we can use nested function support to access both. */
|
||||
if (!bitmap_empty_p (non_ssa_vars))
|
||||
if (!bitmap_empty_p (non_ssa_vars)
|
||||
&& !verify_non_ssa_vars (current, non_ssa_vars, return_bb))
|
||||
{
|
||||
basic_block bb;
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
gimple_stmt_iterator bsi;
|
||||
if (!bitmap_bit_p (current->split_bbs, bb->index))
|
||||
continue;
|
||||
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
|
||||
{
|
||||
if (is_gimple_debug (gsi_stmt (bsi)))
|
||||
continue;
|
||||
if (walk_stmt_load_store_addr_ops
|
||||
(gsi_stmt (bsi), non_ssa_vars, test_nonssa_use,
|
||||
test_nonssa_use, test_nonssa_use))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file,
|
||||
" Refused: split part has non-ssa uses\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
|
||||
{
|
||||
if (walk_stmt_load_store_addr_ops
|
||||
(gsi_stmt (bsi), non_ssa_vars, test_nonssa_use,
|
||||
test_nonssa_use, test_nonssa_use))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file,
|
||||
" Refused: split part has non-ssa uses\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
if (e->dest != return_bb)
|
||||
continue;
|
||||
for (bsi = gsi_start_phis (return_bb); !gsi_end_p (bsi);
|
||||
gsi_next (&bsi))
|
||||
{
|
||||
gimple stmt = gsi_stmt (bsi);
|
||||
tree op = gimple_phi_arg_def (stmt, e->dest_idx);
|
||||
|
||||
if (!is_gimple_reg (gimple_phi_result (stmt)))
|
||||
continue;
|
||||
if (TREE_CODE (op) != SSA_NAME
|
||||
&& test_nonssa_use (stmt, op, non_ssa_vars))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file,
|
||||
" Refused: split part has non-ssa uses\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file,
|
||||
" Refused: split part has non-ssa uses\n");
|
||||
return;
|
||||
}
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
@ -379,10 +413,20 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
|
||||
}
|
||||
}
|
||||
|
||||
/* Return basic block containing RETURN statement, or EXIT_BLOCK_PTR if none
|
||||
found.
|
||||
/* Return basic block containing RETURN statement. We allow basic blocks
|
||||
of the form:
|
||||
<retval> = tmp_var;
|
||||
return <retval>
|
||||
but return_bb can not be more complex than this.
|
||||
If nothing is found, return EXIT_BLOCK_PTR.
|
||||
|
||||
When there are multiple RETURN statement, chose one with return value,
|
||||
since that one is more likely shared by multiple code paths.
|
||||
|
||||
Return BB is special, because for function splitting it is the only
|
||||
basic block that is duplicated in between header and split part of the
|
||||
function.
|
||||
|
||||
TODO: We might support multiple return blocks. */
|
||||
|
||||
static basic_block
|
||||
@ -399,16 +443,29 @@ find_return_bb (void)
|
||||
bool found_return = false;
|
||||
tree retval = NULL_TREE;
|
||||
|
||||
for (bsi = gsi_start_bb (e->src); !gsi_end_p (bsi); gsi_next (&bsi))
|
||||
if (gimple_code (gsi_stmt (bsi)) != GIMPLE_RETURN
|
||||
&& gimple_code (gsi_stmt (bsi)) != GIMPLE_LABEL
|
||||
&& !is_gimple_debug (gsi_stmt (bsi)))
|
||||
break;
|
||||
else if (gimple_code (gsi_stmt (bsi)) == GIMPLE_RETURN)
|
||||
{
|
||||
found_return = true;
|
||||
retval = gimple_return_retval (gsi_stmt (bsi));
|
||||
}
|
||||
for (bsi = gsi_last_bb (e->src); !gsi_end_p (bsi); gsi_prev (&bsi))
|
||||
{
|
||||
gimple stmt = gsi_stmt (bsi);
|
||||
if (gimple_code (stmt) == GIMPLE_LABEL
|
||||
|| is_gimple_debug (stmt))
|
||||
;
|
||||
else if (gimple_code (stmt) == GIMPLE_ASSIGN
|
||||
&& found_return
|
||||
&& gimple_assign_single_p (stmt)
|
||||
&& (auto_var_in_fn_p (gimple_assign_rhs1 (stmt),
|
||||
current_function_decl)
|
||||
|| is_gimple_min_invariant
|
||||
(gimple_assign_rhs1 (stmt)))
|
||||
&& retval == gimple_assign_lhs (stmt))
|
||||
;
|
||||
else if (gimple_code (stmt) == GIMPLE_RETURN)
|
||||
{
|
||||
found_return = true;
|
||||
retval = gimple_return_retval (stmt);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (gsi_end_p (bsi) && found_return)
|
||||
{
|
||||
if (retval)
|
||||
@ -420,6 +477,20 @@ find_return_bb (void)
|
||||
return return_bb;
|
||||
}
|
||||
|
||||
/* Given return basicblock RETURN_BB, see where return value is really
|
||||
stored. */
|
||||
static tree
|
||||
find_retval (basic_block return_bb)
|
||||
{
|
||||
gimple_stmt_iterator bsi;
|
||||
for (bsi = gsi_start_bb (return_bb); !gsi_end_p (bsi); gsi_next (&bsi))
|
||||
if (gimple_code (gsi_stmt (bsi)) == GIMPLE_RETURN)
|
||||
return gimple_return_retval (gsi_stmt (bsi));
|
||||
else if (gimple_code (gsi_stmt (bsi)) == GIMPLE_ASSIGN)
|
||||
return gimple_assign_rhs1 (gsi_stmt (bsi));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Callback for walk_stmt_load_store_addr_ops. If T is non-ssa automatic
|
||||
variable, mark it as used in bitmap passed via DATA.
|
||||
Return true when access to T prevents splitting the function. */
|
||||
@ -844,7 +915,7 @@ split_function (struct split_point *split_point)
|
||||
NULL, NULL,
|
||||
args_to_skip,
|
||||
split_point->split_bbs,
|
||||
split_point->entry_bb, "_part");
|
||||
split_point->entry_bb, "part");
|
||||
/* For usual cloning it is enough to clear builtin only when signature
|
||||
changes. For partial inlining we however can not expect the part
|
||||
of builtin implementation to have same semantic as the whole. */
|
||||
@ -891,17 +962,15 @@ split_function (struct split_point *split_point)
|
||||
e->probability = REG_BR_PROB_BASE;
|
||||
if (return_bb != EXIT_BLOCK_PTR)
|
||||
{
|
||||
gimple return_stmt = gsi_stmt (gsi_last_bb (return_bb));
|
||||
gcc_assert (gimple_code (return_stmt) == GIMPLE_RETURN);
|
||||
|
||||
if ((real_retval = retval = gimple_return_retval (return_stmt))
|
||||
real_retval = retval = find_retval (return_bb);
|
||||
if (real_retval
|
||||
&& !is_gimple_min_invariant (retval)
|
||||
&& (TREE_CODE (retval) != SSA_NAME
|
||||
|| !SSA_NAME_IS_DEFAULT_DEF (retval)))
|
||||
{
|
||||
gimple_stmt_iterator psi;
|
||||
|
||||
/* See if there is PHI definind return value. */
|
||||
/* See if there is PHI defining return value. */
|
||||
for (psi = gsi_start_phis (return_bb);
|
||||
!gsi_end_p (psi); gsi_next (&psi))
|
||||
if (is_gimple_reg (gimple_phi_result (gsi_stmt (psi))))
|
||||
@ -917,8 +986,20 @@ split_function (struct split_point *split_point)
|
||||
add_phi_arg (gsi_stmt (psi), retval, e, UNKNOWN_LOCATION);
|
||||
else if (TREE_CODE (retval) == SSA_NAME)
|
||||
{
|
||||
gimple_return_set_retval (return_stmt, retval);
|
||||
update_stmt (return_stmt);
|
||||
gimple_stmt_iterator bsi;
|
||||
for (bsi = gsi_start_bb (return_bb); !gsi_end_p (bsi);
|
||||
gsi_next (&bsi))
|
||||
if (gimple_code (gsi_stmt (bsi)) == GIMPLE_RETURN)
|
||||
{
|
||||
gimple_return_set_retval (gsi_stmt (bsi), retval);
|
||||
break;
|
||||
}
|
||||
else if (gimple_code (gsi_stmt (bsi)) == GIMPLE_ASSIGN)
|
||||
{
|
||||
gimple_assign_set_rhs1 (gsi_stmt (bsi), retval);
|
||||
break;
|
||||
}
|
||||
update_stmt (gsi_stmt (bsi));
|
||||
}
|
||||
}
|
||||
gimple_call_set_lhs (call, retval);
|
||||
|
@ -1,3 +1,7 @@
|
||||
2010-07-02 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* gcc.dg/tree-ssa/ipa-split-5.c: New function.
|
||||
|
||||
2010-07-02 Iain Sandoe <iains@gcc.gnu.org>
|
||||
|
||||
* objc-obj-c++-shared/Object1.h: Correct Line endings.
|
||||
|
37
gcc/testsuite/gcc.dg/tree-ssa/ipa-split-5.c
Normal file
37
gcc/testsuite/gcc.dg/tree-ssa/ipa-split-5.c
Normal file
@ -0,0 +1,37 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -fdump-tree-fnsplit -fdump-tree-optimized" } */
|
||||
|
||||
struct a {int a,b;};
|
||||
struct a make_me_big (int a);
|
||||
struct a split_me (int a)
|
||||
{
|
||||
struct a retval;
|
||||
if (__builtin_expect (a!=0,1))
|
||||
{
|
||||
retval.a = 0;
|
||||
retval.b = 0;
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct a retval = make_me_big (a);
|
||||
retval = make_me_big (a);
|
||||
retval = make_me_big (a);
|
||||
retval = make_me_big (a);
|
||||
retval = make_me_big (a);
|
||||
retval = make_me_big (a);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
int val;
|
||||
test()
|
||||
{
|
||||
split_me (val);
|
||||
split_me (val);
|
||||
split_me (val);
|
||||
split_me (val);
|
||||
}
|
||||
/* { dg-final { scan-tree-dump-times "Splitting function" 1 "fnsplit"} } */
|
||||
/* { dg-final { cleanup-tree-dump "fnsplit" } } */
|
||||
/* { dg-final { scan-tree-dump "part" "optimized"} } */
|
||||
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
Loading…
Reference in New Issue
Block a user