Commit 31ce8a53 by Bernd Schmidt Committed by Bernd Schmidt

re PR rtl-optimization/21803 ([ia64] gcc produces really odd predicated code)

gcc/
	PR target/21803
	* ifcvt.c (cond_exec_process_if_block): Look for identical sequences
	at the start and end of the then/else blocks, and omit them from the
	conversion.
	* cfgcleanup.c (flow_find_cross_jump): No longer static.  Remove MODE
	argument; all callers changed.  Pass zero to old_insns_match_p instead.
	(flow_find_head_matching_sequence): New function.
	(old_insns_match_p): Check REG_EH_REGION notes for calls.
	* basic-block.h (flow_find_cross_jump,
	flow_find_head_matching_sequence): Declare functions.

gcc/testsuite/
	PR target/21803
	* gcc.target/arm/pr42496.c: New test.

From-SVN: r158357
parent 943f82e7
2010-04-14 Bernd Schmidt <bernd.schmidt@codesourcery.com>
PR target/21803
* ifcvt.c (cond_exec_process_if_block): Look for identical sequences
at the start and end of the then/else blocks, and omit them from the
conversion.
* cfgcleanup.c (flow_find_cross_jump): No longer static. Remove MODE
argument; all callers changed. Pass zero to old_insns_match_p instead.
(flow_find_head_matching_sequence): New function.
(old_insns_match_p): Check REG_EH_REGION notes for calls.
* basic-block.h (flow_find_cross_jump,
flow_find_head_matching_sequence): Declare functions.
2010-04-14 Jason Merrill <jason@redhat.com> 2010-04-14 Jason Merrill <jason@redhat.com>
PR c++/36625 PR c++/36625
......
...@@ -894,6 +894,10 @@ extern void rtl_make_eh_edge (sbitmap, basic_block, rtx); ...@@ -894,6 +894,10 @@ extern void rtl_make_eh_edge (sbitmap, basic_block, rtx);
/* In cfgcleanup.c. */ /* In cfgcleanup.c. */
extern bool cleanup_cfg (int); extern bool cleanup_cfg (int);
extern int flow_find_cross_jump (basic_block, basic_block, rtx *, rtx *);
extern int flow_find_head_matching_sequence (basic_block, basic_block,
rtx *, rtx *, int);
extern bool delete_unreachable_blocks (void); extern bool delete_unreachable_blocks (void);
extern bool mark_dfs_back_edges (void); extern bool mark_dfs_back_edges (void);
......
...@@ -68,7 +68,6 @@ static bool crossjumps_occured; ...@@ -68,7 +68,6 @@ static bool crossjumps_occured;
static bool try_crossjump_to_edge (int, edge, edge); static bool try_crossjump_to_edge (int, edge, edge);
static bool try_crossjump_bb (int, basic_block); static bool try_crossjump_bb (int, basic_block);
static bool outgoing_edges_match (int, basic_block, basic_block); static bool outgoing_edges_match (int, basic_block, basic_block);
static int flow_find_cross_jump (int, basic_block, basic_block, rtx *, rtx *);
static bool old_insns_match_p (int, rtx, rtx); static bool old_insns_match_p (int, rtx, rtx);
static void merge_blocks_move_predecessor_nojumps (basic_block, basic_block); static void merge_blocks_move_predecessor_nojumps (basic_block, basic_block);
...@@ -972,13 +971,27 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2) ...@@ -972,13 +971,27 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
be filled that clobbers a parameter expected by the subroutine. be filled that clobbers a parameter expected by the subroutine.
??? We take the simple route for now and assume that if they're ??? We take the simple route for now and assume that if they're
equal, they were constructed identically. */ equal, they were constructed identically.
if (CALL_P (i1) Also check for identical exception regions. */
&& (!rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
if (CALL_P (i1))
{
/* Ensure the same EH region. */
rtx n1 = find_reg_note (i1, REG_EH_REGION, 0);
rtx n2 = find_reg_note (i2, REG_EH_REGION, 0);
if (!n1 && n2)
return false;
if (n1 && (!n2 || XEXP (n1, 0) != XEXP (n2, 0)))
return false;
if (!rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
CALL_INSN_FUNCTION_USAGE (i2)) CALL_INSN_FUNCTION_USAGE (i2))
|| SIBLING_CALL_P (i1) != SIBLING_CALL_P (i2))) || SIBLING_CALL_P (i1) != SIBLING_CALL_P (i2))
return false; return false;
}
#ifdef STACK_REGS #ifdef STACK_REGS
/* If cross_jump_death_matters is not 0, the insn's mode /* If cross_jump_death_matters is not 0, the insn's mode
...@@ -1017,6 +1030,29 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2) ...@@ -1017,6 +1030,29 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
return false; return false;
} }
/* When comparing insns I1 and I2 in flow_find_cross_jump or
flow_find_head_matching_sequence, ensure the notes match. */
static void
merge_notes (rtx i1, rtx i2)
{
/* If the merged insns have different REG_EQUAL notes, then
remove them. */
rtx equiv1 = find_reg_equal_equiv_note (i1);
rtx equiv2 = find_reg_equal_equiv_note (i2);
if (equiv1 && !equiv2)
remove_note (i1, equiv1);
else if (!equiv1 && equiv2)
remove_note (i2, equiv2);
else if (equiv1 && equiv2
&& !rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))
{
remove_note (i1, equiv1);
remove_note (i2, equiv2);
}
}
/* Look through the insns at the end of BB1 and BB2 and find the longest /* Look through the insns at the end of BB1 and BB2 and find the longest
sequence that are equivalent. Store the first insns for that sequence sequence that are equivalent. Store the first insns for that sequence
in *F1 and *F2 and return the sequence length. in *F1 and *F2 and return the sequence length.
...@@ -1024,9 +1060,8 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2) ...@@ -1024,9 +1060,8 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
To simplify callers of this function, if the blocks match exactly, To simplify callers of this function, if the blocks match exactly,
store the head of the blocks in *F1 and *F2. */ store the head of the blocks in *F1 and *F2. */
static int int
flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1, flow_find_cross_jump (basic_block bb1, basic_block bb2, rtx *f1, rtx *f2)
basic_block bb2, rtx *f1, rtx *f2)
{ {
rtx i1, i2, last1, last2, afterlast1, afterlast2; rtx i1, i2, last1, last2, afterlast1, afterlast2;
int ninsns = 0; int ninsns = 0;
...@@ -1066,7 +1101,7 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1, ...@@ -1066,7 +1101,7 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
if (i1 == BB_HEAD (bb1) || i2 == BB_HEAD (bb2)) if (i1 == BB_HEAD (bb1) || i2 == BB_HEAD (bb2))
break; break;
if (!old_insns_match_p (mode, i1, i2)) if (!old_insns_match_p (0, i1, i2))
break; break;
merge_memattrs (i1, i2); merge_memattrs (i1, i2);
...@@ -1074,21 +1109,7 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1, ...@@ -1074,21 +1109,7 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
/* Don't begin a cross-jump with a NOTE insn. */ /* Don't begin a cross-jump with a NOTE insn. */
if (INSN_P (i1)) if (INSN_P (i1))
{ {
/* If the merged insns have different REG_EQUAL notes, then merge_notes (i1, i2);
remove them. */
rtx equiv1 = find_reg_equal_equiv_note (i1);
rtx equiv2 = find_reg_equal_equiv_note (i2);
if (equiv1 && !equiv2)
remove_note (i1, equiv1);
else if (!equiv1 && equiv2)
remove_note (i2, equiv2);
else if (equiv1 && equiv2
&& !rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))
{
remove_note (i1, equiv1);
remove_note (i2, equiv2);
}
afterlast1 = last1, afterlast2 = last2; afterlast1 = last1, afterlast2 = last2;
last1 = i1, last2 = i2; last1 = i1, last2 = i2;
...@@ -1130,6 +1151,97 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1, ...@@ -1130,6 +1151,97 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
return ninsns; return ninsns;
} }
/* Like flow_find_cross_jump, except start looking for a matching sequence from
the head of the two blocks. Do not include jumps at the end.
If STOP_AFTER is nonzero, stop after finding that many matching
instructions. */
int
flow_find_head_matching_sequence (basic_block bb1, basic_block bb2, rtx *f1,
rtx *f2, int stop_after)
{
rtx i1, i2, last1, last2, beforelast1, beforelast2;
int ninsns = 0;
edge e;
edge_iterator ei;
int nehedges1 = 0, nehedges2 = 0;
FOR_EACH_EDGE (e, ei, bb1->succs)
if (e->flags & EDGE_EH)
nehedges1++;
FOR_EACH_EDGE (e, ei, bb2->succs)
if (e->flags & EDGE_EH)
nehedges2++;
i1 = BB_HEAD (bb1);
i2 = BB_HEAD (bb2);
last1 = beforelast1 = last2 = beforelast2 = NULL_RTX;
while (true)
{
/* Ignore notes. */
while (!NONDEBUG_INSN_P (i1) && i1 != BB_END (bb1))
i1 = NEXT_INSN (i1);
while (!NONDEBUG_INSN_P (i2) && i2 != BB_END (bb2))
i2 = NEXT_INSN (i2);
if (NOTE_P (i1) || NOTE_P (i2)
|| JUMP_P (i1) || JUMP_P (i2))
break;
/* A sanity check to make sure we're not merging insns with different
effects on EH. If only one of them ends a basic block, it shouldn't
have an EH edge; if both end a basic block, there should be the same
number of EH edges. */
if ((i1 == BB_END (bb1) && i2 != BB_END (bb2)
&& nehedges1 > 0)
|| (i2 == BB_END (bb2) && i1 != BB_END (bb1)
&& nehedges2 > 0)
|| (i1 == BB_END (bb1) && i2 == BB_END (bb2)
&& nehedges1 != nehedges2))
break;
if (!old_insns_match_p (0, i1, i2))
break;
merge_memattrs (i1, i2);
/* Don't begin a cross-jump with a NOTE insn. */
if (INSN_P (i1))
{
merge_notes (i1, i2);
beforelast1 = last1, beforelast2 = last2;
last1 = i1, last2 = i2;
ninsns++;
}
if (i1 == BB_END (bb1) || i2 == BB_END (bb2)
|| (stop_after > 0 && ninsns == stop_after))
break;
i1 = NEXT_INSN (i1);
i2 = NEXT_INSN (i2);
}
#ifdef HAVE_cc0
/* Don't allow a compare to be shared by cross-jumping unless the insn
after the compare is also shared. */
if (ninsns && reg_mentioned_p (cc0_rtx, last1) && sets_cc0_p (last1))
last1 = beforelast1, last2 = beforelast2, ninsns--;
#endif
if (ninsns)
{
*f1 = last1;
*f2 = last2;
}
return ninsns;
}
/* Return true iff outgoing edges of BB1 and BB2 match, together with /* Return true iff outgoing edges of BB1 and BB2 match, together with
the branch instruction. This means that if we commonize the control the branch instruction. This means that if we commonize the control
flow before end of the basic block, the semantic remains unchanged. flow before end of the basic block, the semantic remains unchanged.
...@@ -1498,7 +1610,7 @@ try_crossjump_to_edge (int mode, edge e1, edge e2) ...@@ -1498,7 +1610,7 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
return false; return false;
/* ... and part the second. */ /* ... and part the second. */
nmatch = flow_find_cross_jump (mode, src1, src2, &newpos1, &newpos2); nmatch = flow_find_cross_jump (src1, src2, &newpos1, &newpos2);
/* Don't proceed with the crossjump unless we found a sufficient number /* Don't proceed with the crossjump unless we found a sufficient number
of matching instructions or the 'from' block was totally matched of matching instructions or the 'from' block was totally matched
......
...@@ -385,7 +385,11 @@ cond_exec_process_if_block (ce_if_block_t * ce_info, ...@@ -385,7 +385,11 @@ cond_exec_process_if_block (ce_if_block_t * ce_info,
rtx false_expr; /* test for then block insns */ rtx false_expr; /* test for then block insns */
rtx true_prob_val; /* probability of else block */ rtx true_prob_val; /* probability of else block */
rtx false_prob_val; /* probability of then block */ rtx false_prob_val; /* probability of then block */
int n_insns; rtx then_last_head = NULL_RTX; /* Last match at the head of THEN */
rtx else_last_head = NULL_RTX; /* Last match at the head of ELSE */
rtx then_first_tail = NULL_RTX; /* First match at the tail of THEN */
rtx else_first_tail = NULL_RTX; /* First match at the tail of ELSE */
int then_n_insns, else_n_insns, n_insns;
enum rtx_code false_code; enum rtx_code false_code;
/* If test is comprised of && or || elements, and we've failed at handling /* If test is comprised of && or || elements, and we've failed at handling
...@@ -418,15 +422,78 @@ cond_exec_process_if_block (ce_if_block_t * ce_info, ...@@ -418,15 +422,78 @@ cond_exec_process_if_block (ce_if_block_t * ce_info,
number of insns and see if it is small enough to convert. */ number of insns and see if it is small enough to convert. */
then_start = first_active_insn (then_bb); then_start = first_active_insn (then_bb);
then_end = last_active_insn (then_bb, TRUE); then_end = last_active_insn (then_bb, TRUE);
n_insns = ce_info->num_then_insns = count_bb_insns (then_bb); then_n_insns = ce_info->num_then_insns = count_bb_insns (then_bb);
n_insns = then_n_insns;
max = MAX_CONDITIONAL_EXECUTE; max = MAX_CONDITIONAL_EXECUTE;
if (else_bb) if (else_bb)
{ {
int n_matching;
max *= 2; max *= 2;
else_start = first_active_insn (else_bb); else_start = first_active_insn (else_bb);
else_end = last_active_insn (else_bb, TRUE); else_end = last_active_insn (else_bb, TRUE);
n_insns += ce_info->num_else_insns = count_bb_insns (else_bb); else_n_insns = ce_info->num_else_insns = count_bb_insns (else_bb);
n_insns += else_n_insns;
/* Look for matching sequences at the head and tail of the two blocks,
and limit the range of insns to be converted if possible. */
n_matching = flow_find_cross_jump (then_bb, else_bb,
&then_first_tail, &else_first_tail);
if (then_first_tail == BB_HEAD (then_bb))
then_start = then_end = NULL_RTX;
if (else_first_tail == BB_HEAD (else_bb))
else_start = else_end = NULL_RTX;
if (n_matching > 0)
{
if (then_end)
then_end = prev_active_insn (then_first_tail);
if (else_end)
else_end = prev_active_insn (else_first_tail);
n_insns -= 2 * n_matching;
}
if (then_start && else_start)
{
int longest_match = MIN (then_n_insns - n_matching,
else_n_insns - n_matching);
n_matching
= flow_find_head_matching_sequence (then_bb, else_bb,
&then_last_head,
&else_last_head,
longest_match);
if (n_matching > 0)
{
rtx insn;
/* We won't pass the insns in the head sequence to
cond_exec_process_insns, so we need to test them here
to make sure that they don't clobber the condition. */
for (insn = BB_HEAD (then_bb);
insn != NEXT_INSN (then_last_head);
insn = NEXT_INSN (insn))
if (!LABEL_P (insn) && !NOTE_P (insn)
&& !DEBUG_INSN_P (insn)
&& modified_in_p (test_expr, insn))
return FALSE;
}
if (then_last_head == then_end)
then_start = then_end = NULL_RTX;
if (else_last_head == else_end)
else_start = else_end = NULL_RTX;
if (n_matching > 0)
{
if (then_start)
then_start = next_active_insn (then_last_head);
if (else_start)
else_start = next_active_insn (else_last_head);
n_insns -= 2 * n_matching;
}
}
} }
if (n_insns > max) if (n_insns > max)
...@@ -570,7 +637,21 @@ cond_exec_process_if_block (ce_if_block_t * ce_info, ...@@ -570,7 +637,21 @@ cond_exec_process_if_block (ce_if_block_t * ce_info,
fprintf (dump_file, "%d insn%s converted to conditional execution.\n", fprintf (dump_file, "%d insn%s converted to conditional execution.\n",
n_insns, (n_insns == 1) ? " was" : "s were"); n_insns, (n_insns == 1) ? " was" : "s were");
/* Merge the blocks! */ /* Merge the blocks! If we had matching sequences, make sure to delete one
copy at the appropriate location first: delete the copy in the THEN branch
for a tail sequence so that the remaining one is executed last for both
branches, and delete the copy in the ELSE branch for a head sequence so
that the remaining one is executed first for both branches. */
if (then_first_tail)
{
rtx from = then_first_tail;
if (!INSN_P (from))
from = next_active_insn (from);
delete_insn_chain (from, BB_END (then_bb), false);
}
if (else_last_head)
delete_insn_chain (first_active_insn (else_bb), else_last_head, false);
merge_if_block (ce_info); merge_if_block (ce_info);
cond_exec_changed_p = TRUE; cond_exec_changed_p = TRUE;
return TRUE; return TRUE;
......
2010-04-14 Bernd Schmidt <bernd.schmidt@codesourcery.com>
PR target/21803
* gcc.target/arm/pr42496.c: New test.
2010-04-14 Jason Merrill <jason@redhat.com> 2010-04-14 Jason Merrill <jason@redhat.com>
PR c++/36625 PR c++/36625
......
/* { dg-options "-O2" } */
void foo(int i)
{
extern int j;
if (i) {
j = 10;
}
else {
j = 20;
}
}
/* { dg-final { scan-assembler-not "strne" } } */
/* { dg-final { scan-assembler-not "streq" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment