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
This commit is contained in:
Mark Mitchell 1998-07-06 10:42:43 +00:00 committed by Mark Mitchell
parent 561252fd0b
commit 93de5c3105
3 changed files with 140 additions and 17 deletions

View File

@ -1,3 +1,12 @@
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>
* cse.c (CSE_ADDRESS_COST): New macro, based on ADDRESS_COST, but

View File

@ -2403,10 +2403,18 @@ duplicate_loop_exit_test (loop_start)
This can be avoided by checking here for NOTE_INSN_LOOP_CONT. */
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)
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;
case JUMP_INSN:
case INSN:

View File

@ -1923,17 +1923,33 @@ expand_end_loop ()
do_pending_stack_adjust ();
/* If optimizing, perhaps reorder the loop. If the loop
starts with a conditional exit, roll that to the end
where it will optimize together with the jump back.
/* If optimizing, perhaps reorder the loop. If the loop starts with
a loop exit, roll that to the end where it will optimize together
with the jump back.
We look for the last conditional branch to the exit that we encounter
before hitting 30 insns or a CALL_INSN. If we see an unconditional
branch to the exit first, use it.
We look for the conditional branch to the exit, except that once
we find such a branch, we don't look past 30 instructions.
We must also stop at NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes
because moving them is not valid. */
In more detail, if the loop presently looks like this (in pseudo-C):
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
&&
! (GET_CODE (insn) == JUMP_INSN
@ -1941,18 +1957,46 @@ expand_end_loop ()
&& SET_DEST (PATTERN (insn)) == pc_rtx
&& 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
conditional exit. */
for (insn = NEXT_INSN (loop_stack->data.loop.start_label); insn;
insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == CODE_LABEL)
break;
if (GET_CODE (insn) == NOTE)
{
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 (GET_CODE (insn) == NOTE
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
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 ();
}
/* We already know this INSN is a NOTE, so there's no
point in looking at it to see if it's a JUMP. */
continue;
}
if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN)
num_insns++;
@ -1960,6 +2004,36 @@ expand_end_loop ()
if (last_test_insn && num_insns > 30)
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
&& SET_DEST (PATTERN (insn)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE
@ -1994,6 +2068,7 @@ expand_end_loop ()
to jump to there. */
register rtx newstart_label = gen_label_rtx ();
register rtx start_move = start_label;
rtx next_insn;
/* If the start label is preceded by a NOTE_INSN_LOOP_CONT note,
then we want to move this note also. */
@ -2003,7 +2078,38 @@ expand_end_loop ()
start_move = 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),
PREV_INSN (newstart_label));
emit_barrier_after (PREV_INSN (newstart_label));