This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Improvement to loop optimization in presence of inlining
- To: egcs-patches at cygnus dot com
- Subject: Improvement to loop optimization in presence of inlining
- From: Mark Mitchell <mark at markmitchell dot com>
- Date: Sun, 28 Jun 1998 20:47:55 -0700
- Cc: Jeff Law <law at cygnus dot com>
- Reply-to: mark at markmitchell dot com
I got curious as to why:
double u_m;
double v_m;
typedef struct s_t {
int n_m;
double* x_m;
double* a_m;
double* b_m;
} s_t;
__inline s_t*
identity (s_t* s)
{
return s;
}
void f(s_t* s)
{
int i;
for (i=0; i < identity(s)->n_m; ++i)
s->x_m[i] = (u_m * s->a_m[i]) + (v_m * s->b_m[i]);
}
didn't result in the same code as the version in which `identity' was
a macro (with -O2 -fstrict-aliasing). The reason, it turns out, was
that the NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END generated by the
inlining of `identity' caused expand_loop_end not to move the loop
test to the bottom of the loop. This, in turn prevented
duplicate_loop_exit_test from doing its job, which caused maybe_never
to be set in scan_loop, which prevented moving the invariants (like
s->a_m) out of the loop, since they might cause traps.
I've appended a fix. The compiler bootstraps fine, and the test
reuslts don't change, but I'm curious if anyone knows why
expand_end_loop was refusing to move CALL_INSNs and CODE_LABELs. The
patch here won't work if it's modified not to move CODE_LABELs, since
returns from inline functions generate labels, at least if a function
epilogue is used. It would still work if it didn't move CALL_INSNs,
but I don't see why they shouldn't be moved.
Jeff, OK?
--
Mark Mitchell mark@markmitchell.com
Mark Mitchell Consulting http://www.markmitchell.com
Sun Jun 28 18:25:20 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}. Do refuse to move partial blocks,
though.
* stmt.c (expand_end_loop): Likewise. Also, don't refuse to
move CALL_INSNs or CODE_LABELs.
Index: jump.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/jump.c,v
retrieving revision 1.27
diff -c -p -r1.27 jump.c
*** jump.c 1998/06/27 23:30:35 1.27
--- jump.c 1998/06/29 03:34:46
*************** duplicate_loop_exit_test (loop_start)
*** 2378,2383 ****
--- 2378,2385 ----
Also, don't do this if the exit code is more than 20 insns. */
+ int blocks = 0;
+
for (insn = exitcode;
insn
&& ! (GET_CODE (insn) == NOTE
*************** duplicate_loop_exit_test (loop_start)
*** 2400,2409 ****
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;
break;
case JUMP_INSN:
case INSN:
--- 2402,2421 ----
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_LOOP_CONT)
return 0;
+
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
+ blocks++;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
+ {
+ blocks--;
+ if (blocks < 0)
+ /* We've seen an unmatched BLOCK_END. There's no way
+ the section can contain all of that block, and we
+ don't want to move partial blocks. */
+ return 0;
+ }
break;
case JUMP_INSN:
case INSN:
*************** duplicate_loop_exit_test (loop_start)
*** 2417,2424 ****
}
}
! /* Unless INSN is zero, we can do the optimization. */
! if (insn == 0)
return 0;
lastexit = insn;
--- 2429,2438 ----
}
}
! /* If INSN is zero, we cannot do the optimization. If BLOCKS is
! non-zero, then we'd be duplicating a piece of a block, but not
! the whole block. */
! if (insn == 0 || blocks != 0)
return 0;
lastexit = insn;
Index: stmt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/stmt.c,v
retrieving revision 1.43
diff -c -p -r1.43 stmt.c
*** stmt.c 1998/06/25 15:14:28 1.43
--- stmt.c 1998/06/29 03:35:03
*************** expand_end_loop ()
*** 1923,1939 ****
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.
!
! 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 must also stop at NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes
! because moving them is not valid. */
if (optimize
&&
! (GET_CODE (insn) == JUMP_INSN
--- 1923,1958 ----
do_pending_stack_adjust ();
! /* 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 conditional branch to the exit, except that once
! we find such a branch, we don't look past 30 instructions.
+ 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;
+ 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.
+
+ We can only move NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END
+ notes if we move them in matched pairs. */
+
if (optimize
&&
! (GET_CODE (insn) == JUMP_INSN
*************** expand_end_loop ()
*** 1941,1961 ****
&& SET_DEST (PATTERN (insn)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE))
{
/* 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
- && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
- break;
-
if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN)
num_insns++;
if (last_test_insn && num_insns > 30)
break;
--- 1960,1998 ----
&& SET_DEST (PATTERN (insn)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE))
{
+ int blocks = 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) == NOTE)
! {
! if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
! blocks++;
! else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
! {
! blocks--;
! if (blocks < 0)
! {
! /* We've seen an unmatched BLOCK_END. There's no way
! the section can contain all of that block, and we
! don't want to move partial blocks. */
! last_test_insn = NULL_RTX;
! break;
! }
! }
! continue;
! }
if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN)
num_insns++;
+
+ if (blocks != 0)
+ /* We're current in the middle of some block. We don't
+ want to move part of a block. */
+ continue;
if (last_test_insn && num_insns > 30)
break;