This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix null pointer deletion optimization
- To: rth at redhat dot com
- Subject: [PATCH] Fix null pointer deletion optimization
- From: Jakub Jelinek <jakub at redhat dot com>
- Date: Wed, 4 Apr 2001 16:53:52 +0200
- Cc: gcc-patches at gcc dot gnu dot org
- Reply-To: Jakub Jelinek <jakub at redhat dot com>
Hi!
I got a segfault in delete_null_pointer_checkks_1, unfortunately the
testcase is huge, cannot be simplified much (because the bug goes away
quickly) and cannot even be reproduced in current CVS (but can from time to
time on various recent CVS snapshots).
The issue is that delete_null_pointer_checks_1 uses CFG for its work, but at
the same time it breaks it using delete_insn(). The particular segfault was
when delete_null_pointer_checks_1 was called for the second time
(delete_null_pointer_checks decided not to do all pseudos at once because it
would eat too much memory) and in the first pass delete_insn deleted one
conditional jump which deleted the label it pointed to (because it was used
just once) and that deleted the whole basic block. The loop in
delete_null_pointer_checks_1 then obviously has not found end of the basic
block and searched until end of function where it crashed.
IMHO the only safe way is to delay all delete_insns until this optimization
no longer needs an up-to-date CFG. This fixes the testcase.
Ok to commit?
2001-04-04 Jakub Jelinek <jakub@redhat.com>
* gcse.c (delete_null_pointer_checks_1): Add delete_list argument,
push insns to delete to it instead of deleting them.
(delete_null_pointer_checks): Delete insns from delete_list after
all delete_null_pointer_checks_1 passes are done.
--- gcc/gcse.c.jj Mon Jul 31 20:02:11 2000
+++ gcc/gcse.c Wed Apr 4 17:19:53 2001
@@ -626,8 +626,8 @@ static int handle_avail_expr PARAMS ((rt
static int classic_gcse PARAMS ((void));
static int one_classic_gcse_pass PARAMS ((int));
static void invalidate_nonnull_info PARAMS ((rtx, rtx, void *));
-static void delete_null_pointer_checks_1 PARAMS ((unsigned int *, sbitmap *,
- sbitmap *,
+static void delete_null_pointer_checks_1 PARAMS ((varray_type, unsigned int *,
+ sbitmap *, sbitmap *,
struct null_pointer_info *));
static rtx process_insert_insn PARAMS ((struct expr *));
static int pre_edge_insert PARAMS ((struct edge_list *, struct expr **));
@@ -4868,7 +4868,9 @@ invalidate_nonnull_info (x, setter, data
they are not our responsibility to free. */
static void
-delete_null_pointer_checks_1 (block_reg, nonnull_avin, nonnull_avout, npi)
+delete_null_pointer_checks_1 (delete_list, block_reg, nonnull_avin,
+ nonnull_avout, npi)
+ varray_type delete_list;
unsigned int *block_reg;
sbitmap *nonnull_avin;
sbitmap *nonnull_avout;
@@ -4998,9 +5000,9 @@ delete_null_pointer_checks_1 (block_reg,
LABEL_NUSES (JUMP_LABEL (new_jump))++;
emit_barrier_after (new_jump);
}
- delete_insn (last_insn);
+ VARRAY_PUSH_RTX (delete_list, last_insn);
if (compare_and_branch == 2)
- delete_insn (earliest);
+ VARRAY_PUSH_RTX (delete_list, earliest);
/* Don't check this block again. (Note that BLOCK_END is
invalid here; we deleted the last instruction in the
@@ -5039,10 +5041,12 @@ delete_null_pointer_checks (f)
{
sbitmap *nonnull_avin, *nonnull_avout;
unsigned int *block_reg;
+ varray_type delete_list;
int bb;
int reg;
int regs_per_pass;
int max_reg;
+ unsigned int i;
struct null_pointer_info npi;
/* If we have only a single block, then there's nothing to do. */
@@ -5106,14 +5110,21 @@ delete_null_pointer_checks (f)
block_reg[bb] = REGNO (reg);
}
+ VARRAY_RTX_INIT (delete_list, 10, "delete_list");
+
/* Go through the algorithm for each block of registers. */
for (reg = FIRST_PSEUDO_REGISTER; reg < max_reg; reg += regs_per_pass)
{
npi.min_reg = reg;
npi.max_reg = MIN (reg + regs_per_pass, max_reg);
- delete_null_pointer_checks_1 (block_reg, nonnull_avin,
+ delete_null_pointer_checks_1 (delete_list, block_reg, nonnull_avin,
nonnull_avout, &npi);
}
+
+ /* Now delete the instructions all at once. This breaks the CFG. */
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (delete_list); i++)
+ delete_insn (VARRAY_RTX (delete_list, i));
+ VARRAY_FREE (delete_list);
/* Free the table of registers compared at the end of every block. */
free (block_reg);
Jakub