Commit 93de5c31 by Mark Mitchell Committed by Mark Mitchell

jump.c (duplicate_loop_exit_test): Don't refuse to copy a section of code just…

jump.c (duplicate_loop_exit_test): Don't refuse to copy a section of code just because it contains...

	* jump.c (duplicate_loop_exit_test): Don't refuse to copy a
	section of code just because it contains
	NOTE_INSN_BLOCK_{BEG,END}.
	* stmt.c (expand_end_loop): Likewise.  Also, don't refuse to
	move CALL_INSNs or CODE_LABELs.  When moving code, don't move
	NOTE_INSN_BLOCK_{BEG,END}.

From-SVN: r20952
parent 561252fd
Mon Jul 6 10:42:05 1998 Mark Mitchell <mark@markmitchell.com>
* jump.c (duplicate_loop_exit_test): Don't refuse to copy a
section of code just because it contains
NOTE_INSN_BLOCK_{BEG,END}.
* stmt.c (expand_end_loop): Likewise. Also, don't refuse to
move CALL_INSNs or CODE_LABELs. When moving code, don't move
NOTE_INSN_BLOCK_{BEG,END}.
Mon Jul 6 09:38:15 1998 Mark Mitchell <mark@markmitchell.com> Mon Jul 6 09:38:15 1998 Mark Mitchell <mark@markmitchell.com>
* cse.c (CSE_ADDRESS_COST): New macro, based on ADDRESS_COST, but * cse.c (CSE_ADDRESS_COST): New macro, based on ADDRESS_COST, but
......
...@@ -2403,10 +2403,18 @@ duplicate_loop_exit_test (loop_start) ...@@ -2403,10 +2403,18 @@ duplicate_loop_exit_test (loop_start)
This can be avoided by checking here for NOTE_INSN_LOOP_CONT. */ This can be avoided by checking here for NOTE_INSN_LOOP_CONT. */
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT) || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
return 0; return 0;
if (optimize < 2
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
/* If we were to duplicate this code, we would not move
the BLOCK notes, and so debugging the moved code would
be difficult. Thus, we only move the code with -O2 or
higher. */
return 0;
break; break;
case JUMP_INSN: case JUMP_INSN:
case INSN: case INSN:
......
...@@ -1923,17 +1923,33 @@ expand_end_loop () ...@@ -1923,17 +1923,33 @@ expand_end_loop ()
do_pending_stack_adjust (); do_pending_stack_adjust ();
/* If optimizing, perhaps reorder the loop. If the loop /* If optimizing, perhaps reorder the loop. If the loop starts with
starts with a conditional exit, roll that to the end a loop exit, roll that to the end where it will optimize together
where it will optimize together with the jump back. with the jump back.
We look for the last conditional branch to the exit that we encounter We look for the conditional branch to the exit, except that once
before hitting 30 insns or a CALL_INSN. If we see an unconditional we find such a branch, we don't look past 30 instructions.
branch to the exit first, use it.
In more detail, if the loop presently looks like this (in pseudo-C):
We must also stop at NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes
because moving them is not valid. */ start_label:
if (test) goto end_label;
body;
goto start_label;
end_label;
transform it to look like:
goto start_label;
newstart_label:
body;
start_label:
if (test) goto end_label;
goto newstart_label;
end_label;
Here, the `test' may actually consist of some reasonably complex
code, terminating in a test. */
if (optimize if (optimize
&& &&
! (GET_CODE (insn) == JUMP_INSN ! (GET_CODE (insn) == JUMP_INSN
...@@ -1941,18 +1957,46 @@ expand_end_loop () ...@@ -1941,18 +1957,46 @@ expand_end_loop ()
&& SET_DEST (PATTERN (insn)) == pc_rtx && SET_DEST (PATTERN (insn)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)) && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE))
{ {
int eh_regions = 0;
/* Scan insns from the top of the loop looking for a qualified /* Scan insns from the top of the loop looking for a qualified
conditional exit. */ conditional exit. */
for (insn = NEXT_INSN (loop_stack->data.loop.start_label); insn; for (insn = NEXT_INSN (loop_stack->data.loop.start_label); insn;
insn = NEXT_INSN (insn)) insn = NEXT_INSN (insn))
{ {
if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == CODE_LABEL) if (GET_CODE (insn) == NOTE)
break; {
if (optimize < 2
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
/* The code that actually moves the exit test will
carefully leave BLOCK notes in their original
location. That means, however, that we can't debug
the exit test itself. So, we refuse to move code
containing BLOCK notes at low optimization levels. */
break;
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
++eh_regions;
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
{
--eh_regions;
if (eh_regions < 0)
/* We've come to the end of an EH region, but
never saw the beginning of that region. That
means that an EH region begins before the top
of the loop, and ends in the middle of it. The
existence of such a situation violates a basic
assumption in this code, since that would imply
that even when EH_REGIONS is zero, we might
move code out of an exception region. */
abort ();
}
if (GET_CODE (insn) == NOTE /* We already know this INSN is a NOTE, so there's no
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG point in looking at it to see if it's a JUMP. */
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)) continue;
break; }
if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN) if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN)
num_insns++; num_insns++;
...@@ -1960,6 +2004,36 @@ expand_end_loop () ...@@ -1960,6 +2004,36 @@ expand_end_loop ()
if (last_test_insn && num_insns > 30) if (last_test_insn && num_insns > 30)
break; break;
if (eh_regions > 0)
/* We don't want to move a partial EH region. Consider:
while ( ( { try {
if (cond ()) 0;
else {
bar();
1;
}
} catch (...) {
1;
} )) {
body;
}
This isn't legal C++, but here's what it's supposed to
mean: if cond() is true, stop looping. Otherwise,
call bar, and keep looping. In addition, if cond
throws an exception, catch it and keep looping. Such
constructs are certainy legal in LISP.
We should not move the `if (cond()) 0' test since then
the EH-region for the try-block would be broken up.
(In this case we would the EH_BEG note for the `try'
and `if cond()' but not the call to bar() or the
EH_END note.)
So we don't look for tests within an EH region. */
continue;
if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == SET if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == pc_rtx && SET_DEST (PATTERN (insn)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE
...@@ -1994,6 +2068,7 @@ expand_end_loop () ...@@ -1994,6 +2068,7 @@ expand_end_loop ()
to jump to there. */ to jump to there. */
register rtx newstart_label = gen_label_rtx (); register rtx newstart_label = gen_label_rtx ();
register rtx start_move = start_label; register rtx start_move = start_label;
rtx next_insn;
/* If the start label is preceded by a NOTE_INSN_LOOP_CONT note, /* If the start label is preceded by a NOTE_INSN_LOOP_CONT note,
then we want to move this note also. */ then we want to move this note also. */
...@@ -2003,7 +2078,38 @@ expand_end_loop () ...@@ -2003,7 +2078,38 @@ expand_end_loop ()
start_move = PREV_INSN (start_move); start_move = PREV_INSN (start_move);
emit_label_after (newstart_label, PREV_INSN (start_move)); emit_label_after (newstart_label, PREV_INSN (start_move));
reorder_insns (start_move, last_test_insn, get_last_insn ());
/* Actually move the insns. Start at the beginning, and
keep copying insns until we've copied the
last_test_insn. */
for (insn = start_move; insn; insn = next_insn)
{
/* Figure out which insn comes after this one. We have
to do this before we move INSN. */
if (insn == last_test_insn)
/* We've moved all the insns. */
next_insn = NULL_RTX;
else
next_insn = NEXT_INSN (insn);
if (GET_CODE (insn) == NOTE
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
/* We don't want to move NOTE_INSN_BLOCK_BEGs or
NOTE_INSN_BLOCK_ENDs because the correct generation
of debugging information depends on these appearing
in the same order in the RTL and in the tree
structure, where they are represented as BLOCKs.
So, we don't move block notes. Of course, moving
the code inside the block is likely to make it
impossible to debug the instructions in the exit
test, but such is the price of optimization. */
continue;
/* Move the INSN. */
reorder_insns (insn, insn, get_last_insn ());
}
emit_jump_insn_after (gen_jump (start_label), emit_jump_insn_after (gen_jump (start_label),
PREV_INSN (newstart_label)); PREV_INSN (newstart_label));
emit_barrier_after (PREV_INSN (newstart_label)); emit_barrier_after (PREV_INSN (newstart_label));
......
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