This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Fix null pointer deletion optimization


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]