This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
proposed patch for gcse.c (delete_null_pointer_checks)
- To: gcc-patches at gcc dot gnu dot org
- Subject: proposed patch for gcse.c (delete_null_pointer_checks)
- From: Tom Truscott <trt at unx dot sas dot com>
- Date: Wed, 27 Oct 1999 13:31:26 -0400 (EDT)
Here is a patch I would like applied to gcse.c.
In delete_null_pointer_checks() a pointer is deduced to be non-zero
when it is dereferenced with "p[0]".
This patch also deduces this for small offsets such as "p[1]".
A bootstrapped 19991025 gcc deletes 59 tests
thanks to the current delete_null_pointer_checks() code.
With the patch it deletes 116 more, such as these in gcse.c:
while (BLOCK_NUM (occr->insn) != dominated && occr)
occr = occr->next;
/* Should never happen. */
if (!occr)
abort ();
The "&& occr", and the "if...abort();", are deleted.
The current delete_null_pointer_checks() misses these only
because "occr->insn" is the second (not the first) member of occr.
The patch has an arbitrary limit of 8192 bytes for the offset.
I am not sure any limit is actually needed,
but am worried that an absolute integer address
such as "((int *)0xf0000)[i]" might somehow cause
gcc to erroneously deduce that "i" is non-zero.
On a large collection of source code, the vanilla gcc deleted
509 tests, a version with a limit of 1024 deleted 3536 tests,
and the patch (8192) version deleted 3828. Diminishing returns.
There is an oddity in the current code (and retained in the patch).
The first (memory load) case limits itself to "pseudo registers".
The second (memory store) case does not. Huh?
*** gcse.c.orig Mon Oct 25 22:22:31 1999
--- gcse.c Wed Oct 27 12:33:35 1999
***************
*** 5037,5047 ****
/* See if we've got a useable memory load. We handle it first
in case it uses its address register as a dest (which kills
the nonnull property). */
! if (GET_CODE (SET_SRC (set)) == MEM
! && GET_CODE (XEXP (SET_SRC (set), 0)) == REG
! && REGNO (XEXP (SET_SRC (set), 0)) >= FIRST_PSEUDO_REGISTER)
! SET_BIT (nonnull_local[current_block],
! REGNO (XEXP (SET_SRC (set), 0)));
/* Now invalidate stuff clobbered by this insn. */
note_stores (PATTERN (insn), invalidate_nonnull_info);
--- 5037,5053 ----
/* See if we've got a useable memory load. We handle it first
in case it uses its address register as a dest (which kills
the nonnull property). */
! if (GET_CODE (SET_SRC (set)) == MEM)
! {
! rtx addr = XEXP (SET_SRC (set), 0);
! if (GET_CODE (addr) == PLUS
! && GET_CODE (XEXP (addr, 1)) == CONST_INT
! && (unsigned HOST_WIDE_INT) INTVAL (XEXP (addr, 1)) < 8192)
! addr = XEXP (addr, 0);
! if (GET_CODE (addr) == REG
! && REGNO (addr) >= FIRST_PSEUDO_REGISTER)
! SET_BIT (nonnull_local[current_block], REGNO (addr));
! }
/* Now invalidate stuff clobbered by this insn. */
note_stores (PATTERN (insn), invalidate_nonnull_info);
***************
*** 5049,5058 ****
/* And handle stores, we do these last since any sets in INSN can
not kill the nonnull property if it is derived from a MEM
appearing in a SET_DEST. */
! if (GET_CODE (SET_DEST (set)) == MEM
! && GET_CODE (XEXP (SET_DEST (set), 0)) == REG)
! SET_BIT (nonnull_local[current_block],
! REGNO (XEXP (SET_DEST (set), 0)));
}
}
--- 5055,5070 ----
/* And handle stores, we do these last since any sets in INSN can
not kill the nonnull property if it is derived from a MEM
appearing in a SET_DEST. */
! if (GET_CODE (SET_DEST (set)) == MEM)
! {
! rtx addr = XEXP (SET_DEST (set), 0);
! if (GET_CODE (addr) == PLUS
! && GET_CODE (XEXP (addr, 1)) == CONST_INT
! && (unsigned HOST_WIDE_INT) INTVAL (XEXP (addr, 1)) < 8192)
! addr = XEXP (addr, 0);
! if (GET_CODE (addr) == REG)
! SET_BIT (nonnull_local[current_block], REGNO (addr));
! }
}
}