This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to improve delete_computation.
- To: gcc-patches at gcc dot gnu dot org
- Subject: Patch to improve delete_computation.
- From: John Wehle <john at feith dot com>
- Date: Sun, 1 Aug 1999 23:58:26 -0400 (EDT)
This patch improves delete_computation in a few areas.
1) FIND_REG_INC_NOTE is used to determine if it is safe to delete
an insn. I don't believe that it's desirable to delete insns
which contain a reference to volatile memory so it seems to me
that side_effects_p is a better choice.
2) The REG_DEAD note may be omitted for a register which is both
set and used by the same insn. When it's omitted delete_computation
fails to delete all the insns.
3) Multi-word hard registers are only deleted if the prior instruction
sets the exact same multi-word hard register. Situations where
instructions are deleted which use different portitions of a
multi-word register are not recognized by delete_computation.
For example using -O2 -fno-schedule-insns2 on a x86 platform to compile:
long long
subr(long long b)
{
long long c;
c = b;
c -= c;
if (b)
return c >> 3;
return c;
}
without the patch produces:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%edx
movl 12(%ebp),%ecx
movl %edx,%eax
movl $0,%eax
movl $0,%edx
leave
ret
with the patch:
pushl %ebp
movl %esp,%ebp
movl $0,%eax
movl $0,%edx
leave
ret
This patch passes make bootstrap and make check on FreeBSD-3.2 x86.
Note:
1) This patch is a bit more useful if the earlier patch
"Patch to fix sched2 REG_DEAD note handling" is
installed (though it's not required).
ChangeLog:
Sun Aug 1 00:25:42 EDT 1999 John Wehle (john@feith.com)
* jump.c (delete_prior_computation): New function, broken
out of delete_computation. Check for side effects with
side_effects_p instead of FIND_REG_INC_NOTE. Handle
multi-word hard registers.
(delete_computation): Use it. Check for side effects with
side_effects_p instead of FIND_REG_INC_NOTE. Synthesize a
missing REG_DEAD note for a register which is both set and
used by an insn.
Enjoy!
-- John Wehle
------------------8<------------------------8<------------------------
*** gcc/jump.c.ORIGINAL Sat Jul 24 00:27:45 1999
--- gcc/jump.c Sun Aug 1 01:33:09 1999
*************** delete_jump (insn)
*** 3811,3816 ****
--- 3811,3922 ----
delete_computation (insn);
}
+ /* Recursively delete prior insns that compute the value (used only by INSN
+ which the caller is deleting) stored in the register mentioned by NOTE
+ which is a REG_DEAD note associated with INSN. */
+
+ static void
+ delete_prior_computation (note, insn)
+ rtx note;
+ rtx insn;
+ {
+ rtx our_prev;
+ rtx reg = XEXP (note, 0);
+
+ for (our_prev = prev_nonnote_insn (insn);
+ our_prev && GET_CODE (our_prev) == INSN;
+ our_prev = prev_nonnote_insn (our_prev))
+ {
+ rtx pat = PATTERN (our_prev);
+
+ /* If we reach a SEQUENCE, it is too complex to try to
+ do anything with it, so give up. */
+ if (GET_CODE (pat) == SEQUENCE)
+ break;
+
+ if (GET_CODE (pat) == USE
+ && GET_CODE (XEXP (pat, 0)) == INSN)
+ /* reorg creates USEs that look like this. We leave them
+ alone because reorg needs them for its own purposes. */
+ break;
+
+ if (reg_set_p (reg, pat))
+ {
+ if (side_effects_p (pat))
+ break;
+
+ if (GET_CODE (pat) == PARALLEL)
+ {
+ /* If we find a SET of something else, we can't
+ delete the insn. */
+
+ int i;
+
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ {
+ rtx part = XVECEXP (pat, 0, i);
+
+ if (GET_CODE (part) == SET
+ && SET_DEST (part) != reg)
+ break;
+ }
+
+ if (i == XVECLEN (pat, 0))
+ delete_computation (our_prev);
+ }
+ else if (GET_CODE (pat) == SET
+ && GET_CODE (SET_DEST (pat)) == REG)
+ {
+ int dest_regno = REGNO (SET_DEST (pat));
+ int dest_endregno
+ = dest_regno + (dest_regno < FIRST_PSEUDO_REGISTER
+ ? HARD_REGNO_NREGS (dest_regno,
+ GET_MODE (SET_DEST (pat))) : 1);
+ int regno = REGNO (reg);
+ int endregno = regno + (regno < FIRST_PSEUDO_REGISTER
+ ? HARD_REGNO_NREGS (regno, GET_MODE (reg)) : 1);
+
+ if (dest_regno >= regno
+ && dest_endregno <= endregno)
+ delete_computation (our_prev);
+
+ /* We may have a multi-word hard register and some, but not
+ all, of the words of the register are needed in subsequent
+ insns. Write REG_UNUSED notes for those parts that were not
+ needed. */
+ else if (dest_regno <= regno
+ && dest_endregno >= endregno
+ && ! find_regno_note (our_prev, REG_UNUSED, REGNO(reg)))
+ {
+ int i;
+
+ REG_NOTES (our_prev)
+ = gen_rtx_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (our_prev));
+
+ for (i = dest_regno; i < dest_endregno; i++)
+ if (! find_regno_note (our_prev, REG_UNUSED, i))
+ break;
+
+ if (i == dest_endregno)
+ delete_computation (our_prev);
+ }
+ }
+
+ break;
+ }
+
+ /* If PAT references the register that dies here, it is an
+ additional use. Hence any prior SET isn't dead. However, this
+ insn becomes the new place for the REG_DEAD note. */
+ if (reg_overlap_mentioned_p (reg, pat))
+ {
+ XEXP (note, 1) = REG_NOTES (our_prev);
+ REG_NOTES (our_prev) = note;
+ break;
+ }
+ }
+ }
+
/* Delete INSN and recursively delete insns that compute values used only
by INSN. This uses the REG_DEAD notes computed during flow analysis.
If we are running before flow.c, we need do nothing since flow.c will
*************** delete_computation (insn)
*** 3829,3834 ****
--- 3935,3941 ----
rtx insn;
{
rtx note, next;
+ rtx set;
#ifdef HAVE_cc0
if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
*************** delete_computation (insn)
*** 3844,3850 ****
&& sets_cc0_p (PATTERN (prev)))
{
if (sets_cc0_p (PATTERN (prev)) > 0
! && !FIND_REG_INC_NOTE (prev, NULL_RTX))
delete_computation (prev);
else
/* Otherwise, show that cc0 won't be used. */
--- 3951,3957 ----
&& sets_cc0_p (PATTERN (prev)))
{
if (sets_cc0_p (PATTERN (prev)) > 0
! && ! side_effects_p (PATTERN (prev)))
delete_computation (prev);
else
/* Otherwise, show that cc0 won't be used. */
*************** delete_computation (insn)
*** 3865,3874 ****
}
#endif
for (note = REG_NOTES (insn); note; note = next)
{
- rtx our_prev;
-
next = XEXP (note, 1);
if (REG_NOTE_KIND (note) != REG_DEAD
--- 3972,3981 ----
}
#endif
+ set = single_set (insn);
+
for (note = REG_NOTES (insn); note; note = next)
{
next = XEXP (note, 1);
if (REG_NOTE_KIND (note) != REG_DEAD
*************** delete_computation (insn)
*** 3876,3938 ****
|| GET_CODE (XEXP (note, 0)) != REG)
continue;
! for (our_prev = prev_nonnote_insn (insn);
! our_prev && GET_CODE (our_prev) == INSN;
! our_prev = prev_nonnote_insn (our_prev))
! {
! /* If we reach a SEQUENCE, it is too complex to try to
! do anything with it, so give up. */
! if (GET_CODE (PATTERN (our_prev)) == SEQUENCE)
! break;
!
! if (GET_CODE (PATTERN (our_prev)) == USE
! && GET_CODE (XEXP (PATTERN (our_prev), 0)) == INSN)
! /* reorg creates USEs that look like this. We leave them
! alone because reorg needs them for its own purposes. */
! break;
!
! if (reg_set_p (XEXP (note, 0), PATTERN (our_prev)))
! {
! if (FIND_REG_INC_NOTE (our_prev, NULL_RTX))
! break;
! if (GET_CODE (PATTERN (our_prev)) == PARALLEL)
! {
! /* If we find a SET of something else, we can't
! delete the insn. */
!
! int i;
!
! for (i = 0; i < XVECLEN (PATTERN (our_prev), 0); i++)
! {
! rtx part = XVECEXP (PATTERN (our_prev), 0, i);
!
! if (GET_CODE (part) == SET
! && SET_DEST (part) != XEXP (note, 0))
! break;
! }
!
! if (i == XVECLEN (PATTERN (our_prev), 0))
! delete_computation (our_prev);
! }
! else if (GET_CODE (PATTERN (our_prev)) == SET
! && SET_DEST (PATTERN (our_prev)) == XEXP (note, 0))
! delete_computation (our_prev);
!
! break;
! }
! /* If OUR_PREV references the register that dies here, it is an
! additional use. Hence any prior SET isn't dead. However, this
! insn becomes the new place for the REG_DEAD note. */
! if (reg_overlap_mentioned_p (XEXP (note, 0),
! PATTERN (our_prev)))
! {
! XEXP (note, 1) = REG_NOTES (our_prev);
! REG_NOTES (our_prev) = note;
! break;
! }
! }
}
delete_insn (insn);
--- 3983,4002 ----
|| GET_CODE (XEXP (note, 0)) != REG)
continue;
! if (set && reg_overlap_mentioned_p (SET_DEST (set), XEXP (note, 0)))
! set = NULL_RTX;
! delete_prior_computation (note, insn);
! }
! /* The REG_DEAD note may have been omitted for a register
! which is both set and used by the insn. */
! if (set
! && GET_CODE (SET_DEST (set)) == REG
! && reg_mentioned_p (SET_DEST (set), SET_SRC (set)))
! {
! note = gen_rtx_EXPR_LIST (REG_DEAD, SET_DEST (set), NULL_RTX);
! delete_prior_computation (note, insn);
}
delete_insn (insn);
-------------------------------------------------------------------------
| Feith Systems | Voice: 1-215-646-8000 | Email: john@feith.com |
| John Wehle | Fax: 1-215-540-5495 | |
-------------------------------------------------------------------------