[PATCH] Fix null pointer deletion optimization

Jakub Jelinek jakub@redhat.com
Wed Apr 4 13:03:00 GMT 2001


On Wed, Apr 04, 2001 at 05:11:56PM +0100, Bernd Schmidt wrote:
> On Wed, 4 Apr 2001, Jakub Jelinek wrote:
> > 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.
> 
> Don't you risk deleting an insn twice with this patch?

I don't think the chance of deleting something twice is any higher than it
used to be. Anyway, unless it is a user defined label being deleted twice,
delete_insn is protected against multiple deletion (by checking
INSN_DELETED_P and not doing anything if it is set). But delete_null_... is
never deleting CODE_LABELs directly and in order to delete it twice
indirectly, the only JUMP_INSN pointing to it would have to be not flagged
with INSN_DELETED_P (but it will be always).

BTW: I mailed the patch too early, bootstrap failed, because I need to pass
address of varray_type variable, not varray_type variable.
Here is what I'm commiting:

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	Wed Apr  4 18:44:09 2001
+++ gcc/gcse.c	Wed Apr  4 19:04:29 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 **));
@@ -4875,7 +4875,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;
@@ -5005,9 +5007,12 @@ delete_null_pointer_checks_1 (block_reg,
 	  LABEL_NUSES (JUMP_LABEL (new_jump))++;
 	  emit_barrier_after (new_jump);
 	}
-      delete_insn (last_insn);
+      if (!*delete_list)
+	VARRAY_RTX_INIT (*delete_list, 10, "delete_list");
+
+      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 
@@ -5046,10 +5051,12 @@ delete_null_pointer_checks (f)
 {
   sbitmap *nonnull_avin, *nonnull_avout;
   unsigned int *block_reg;
+  varray_type delete_list = NULL;
   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.  */
@@ -5118,8 +5125,16 @@ delete_null_pointer_checks (f)
     {
       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.  */
+  if (delete_list)
+    {
+      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.  */


	Jakub



More information about the Gcc-patches mailing list