Where is rd_gen computed in gcse.c

Steven Bosscher stevenb@suse.de
Fri May 14 15:17:00 GMT 2004


On Monday 10 May 2004 18:39, Steven Bosscher wrote:
> On Monday 10 May 2004 18:21, law@redhat.com wrote:
> > I wouldn't lose a huge amount of sleep if the old classic GCSE algorithm
> > went away and we just didn't bother with GCSE at all when optimizing for
> > size.
>
> I wouldn't want you to lose any sleep at all, but I'll prepare
> a patch to remove classic gcse anyway.  Whee, gcse is getting
> smaller and smaller :)

Like so.  I also took the liberty of removing delete_null_pointer_checks
as discussed.  Bootstrapped&tested on amd64, OK?

Gr.
Steven

-------------- next part --------------
	* common.opt (fdelete-null-pointer-checks): Remove.
	* opts.c (decode_options): Don't set delete_null_pointer_checks.
	(common_handle_option): Likewise.
	* passes.c (rest_of_handle_null_pointer): Remove.
	(rest_of_handle_cse): Don't call rest_of_handle_null_pointer.
	(rest_of_compilation): Likewise.
	* toplev.c (flag_delete_null_pointer_checks): Remove flag.
	* toplev.h (flag_delete_null_pointer_checks): Likewise.
	* rtl.h (delete_null_pointer_checks): Remove prototype.
	* gcse.c (rd_kill, rd_gen, reaching_defs, rd_out, ae_in, ae_out):
	Remove declarations.
	(get_bitmap_width, alloc_rd_mem, free_rd_mem, handle_rd_kill_set,
	compute_kill_rd, compute_rd, alloc_avail_expr_mem,
	free_avail_expr_mem, compute_ae_gen, expr_killed_p, compute_ae_kill,
	expr_reaches_here_p, computing_insn, def_reaches_here_p,
	can_disregard_other_sets, handle_avail_expr, classic_gcse,
	one_classic_gcse_pass, invalidate_nonnull_info,
	delete_null_pointer_checks_1, delete_null_pointer_checks,
	expr_reached_here_p_work): Remove.
	(gcse_main): Do not perform classic GCSE when optimizing for size.
	(alloc_pre_mem, free_pre_mem): Don't touch ae_in and ae_out, they
	are never used.

	* doc/invoke.texi: Remove all references to null pointer check
	elimination.

Index: common.opt
===================================================================
RCS file: /cvs/gcc/gcc/gcc/common.opt,v
retrieving revision 1.33
diff -c -3 -p -r1.33 common.opt
*** common.opt	13 May 2004 06:39:33 -0000	1.33
--- common.opt	14 May 2004 14:49:57 -0000
*************** fdelayed-branch
*** 302,311 ****
  Common
  Attempt to fill delay slots of branch instructions
  
- fdelete-null-pointer-checks
- Common
- Delete useless null pointer checks
- 
  fdiagnostics-show-location=
  Common Joined RejectNegative
  -fdiagnostics-show-location=[once|every-line]	How often to emit source location at the beginning of line-wrapped diagnostics
--- 302,307 ----
Index: gcse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcse.c,v
retrieving revision 1.302
diff -c -3 -p -r1.302 gcse.c
*** gcse.c	13 May 2004 06:39:40 -0000	1.302
--- gcse.c	14 May 2004 14:50:01 -0000
*************** Software Foundation, 59 Temple Place - S
*** 192,198 ****
  
     3) Perform copy/constant propagation.
  
!    4) Perform global cse.
  
     5) Perform another pass of copy/constant propagation.
  
--- 192,199 ----
  
     3) Perform copy/constant propagation.
  
!    4) Perform global cse using lazy code motion if not optimizing
!       for size, or code hoisting if we are.
  
     5) Perform another pass of copy/constant propagation.
  
*************** static struct ls_expr * pre_ldst_mems = 
*** 485,491 ****
  static regset reg_set_bitmap;
  
  /* For each block, a bitmap of registers set in the block.
!    This is used by expr_killed_p and compute_transp.
     It is computed during hash table computation and not by compute_sets
     as it includes registers added since the last pass (or between cprop and
     gcse) and it's currently not easy to realloc sbitmap vectors.  */
--- 486,492 ----
  static regset reg_set_bitmap;
  
  /* For each block, a bitmap of registers set in the block.
!    This is used by compute_transp.
     It is computed during hash table computation and not by compute_sets
     as it includes registers added since the last pass (or between cprop and
     gcse) and it's currently not easy to realloc sbitmap vectors.  */
*************** static int const_prop_count;
*** 515,539 ****
  /* Number of copys propagated.  */
  static int copy_prop_count;
  
! /* These variables are used by classic GCSE.
!    Normally they'd be defined a bit later, but `rd_gen' needs to
!    be declared sooner.  */
! 
! /* Each block has a bitmap of each type.
!    The length of each blocks bitmap is:
! 
!        max_cuid  - for reaching definitions
!        n_exprs - for available expressions
! 
!    Thus we view the bitmaps as 2 dimensional arrays.  i.e.
!    rd_kill[block_num][cuid_num]
!    ae_kill[block_num][expr_num]			 */
! 
! /* For reaching defs */
! static sbitmap *rd_kill, *rd_gen, *reaching_defs, *rd_out;
! 
! /* for available exprs */
! static sbitmap *ae_kill, *ae_gen, *ae_in, *ae_out;
  
  /* Objects of this type are passed around by the null-pointer check
     removal routines.  */
--- 516,523 ----
  /* Number of copys propagated.  */
  static int copy_prop_count;
  
! /* For available exprs */
! static sbitmap *ae_kill, *ae_gen;
  
  /* Objects of this type are passed around by the null-pointer check
     removal routines.  */
*************** static void alloc_gcse_mem (rtx);
*** 558,564 ****
  static void free_gcse_mem (void);
  static void alloc_reg_set_mem (int);
  static void free_reg_set_mem (void);
- static int get_bitmap_width (int, int, int);
  static void record_one_set (int, rtx);
  static void replace_one_set (int, rtx, rtx);
  static void record_set_info (rtx, rtx, void *);
--- 542,547 ----
*************** static void compute_code_hoist_data (voi
*** 640,670 ****
  static int hoist_expr_reaches_here_p (basic_block, int, basic_block, char *);
  static void hoist_code (void);
  static int one_code_hoisting_pass (void);
- static void alloc_rd_mem (int, int);
- static void free_rd_mem (void);
- static void handle_rd_kill_set (rtx, int, basic_block);
- static void compute_kill_rd (void);
- static void compute_rd (void);
- static void alloc_avail_expr_mem (int, int);
- static void free_avail_expr_mem (void);
- static void compute_ae_gen (struct hash_table *);
- static int expr_killed_p (rtx, basic_block);
- static void compute_ae_kill (sbitmap *, sbitmap *, struct hash_table *);
- static int expr_reaches_here_p (struct occr *, struct expr *, basic_block,
- 				int);
- static rtx computing_insn (struct expr *, rtx);
- static int def_reaches_here_p (rtx, rtx);
- static int can_disregard_other_sets (struct reg_set **, rtx, int);
- static int handle_avail_expr (rtx, struct expr *);
- static int classic_gcse (void);
- static int one_classic_gcse_pass (int);
- static void invalidate_nonnull_info (rtx, rtx, void *);
- static int delete_null_pointer_checks_1 (unsigned int *, sbitmap *, sbitmap *,
- 					 struct null_pointer_info *);
  static rtx process_insert_insn (struct expr *);
  static int pre_edge_insert (struct edge_list *, struct expr **);
- static int expr_reaches_here_p_work (struct occr *, struct expr *,
- 				     basic_block, int, char *);
  static int pre_expr_reaches_here_p_work (basic_block, struct expr *,
  					 basic_block, char *);
  static struct ls_expr * ldst_entry (rtx);
--- 623,630 ----
*************** gcse_main (rtx f, FILE *file)
*** 790,796 ****
        changed = one_cprop_pass (pass + 1, 0, 0);
  
        if (optimize_size)
! 	changed |= one_classic_gcse_pass (pass + 1);
        else
  	{
  	  changed |= one_pre_gcse_pass (pass + 1);
--- 750,756 ----
        changed = one_cprop_pass (pass + 1, 0, 0);
  
        if (optimize_size)
! 	/* Do nothing.  */ ;
        else
  	{
  	  changed |= one_pre_gcse_pass (pass + 1);
*************** gcse_main (rtx f, FILE *file)
*** 821,828 ****
        /* It does not make sense to run code hoisting unless we are optimizing
  	 for code size -- it rarely makes programs faster, and can make
  	 them bigger if we did partial redundancy elimination (when optimizing
! 	 for space, we use a classic gcse algorithm instead of partial
! 	 redundancy algorithms).  */
        if (optimize_size)
  	{
  	  max_gcse_regno = max_reg_num ();
--- 781,787 ----
        /* It does not make sense to run code hoisting unless we are optimizing
  	 for code size -- it rarely makes programs faster, and can make
  	 them bigger if we did partial redundancy elimination (when optimizing
! 	 for space, we don't run the partial redundancy algorithms).  */
        if (optimize_size)
  	{
  	  max_gcse_regno = max_reg_num ();
*************** free_gcse_mem (void)
*** 1025,1070 ****
    BITMAP_XFREE (modify_mem_list_set);
    BITMAP_XFREE (canon_modify_mem_list_set);
  }
- 
- /* Many of the global optimization algorithms work by solving dataflow
-    equations for various expressions.  Initially, some local value is
-    computed for each expression in each block.  Then, the values across the
-    various blocks are combined (by following flow graph edges) to arrive at
-    global values.  Conceptually, each set of equations is independent.  We
-    may therefore solve all the equations in parallel, solve them one at a
-    time, or pick any intermediate approach.
- 
-    When you're going to need N two-dimensional bitmaps, each X (say, the
-    number of blocks) by Y (say, the number of expressions), call this
-    function.  It's not important what X and Y represent; only that Y
-    correspond to the things that can be done in parallel.  This function will
-    return an appropriate chunking factor C; you should solve C sets of
-    equations in parallel.  By going through this function, we can easily
-    trade space against time; by solving fewer equations in parallel we use
-    less space.  */
- 
- static int
- get_bitmap_width (int n, int x, int y)
- {
-   /* It's not really worth figuring out *exactly* how much memory will
-      be used by a particular choice.  The important thing is to get
-      something approximately right.  */
-   size_t max_bitmap_memory = 10 * 1024 * 1024;
- 
-   /* The number of bytes we'd use for a single column of minimum
-      width.  */
-   size_t column_size = n * x * sizeof (SBITMAP_ELT_TYPE);
- 
-   /* Often, it's reasonable just to solve all the equations in
-      parallel.  */
-   if (column_size * SBITMAP_SET_SIZE (y) <= max_bitmap_memory)
-     return y;
- 
-   /* Otherwise, pick the largest width we can, without going over the
-      limit.  */
-   return SBITMAP_ELT_BITS * ((max_bitmap_memory + column_size - 1)
- 			     / column_size);
- }
  
  /* Compute the local properties of each recorded expression.
  
--- 984,989 ----
*************** mark_oprs_set (rtx insn)
*** 2878,3638 ****
  }
  
  
- /* Classic GCSE reaching definition support.  */
- 
- /* Allocate reaching def variables.  */
- 
- static void
- alloc_rd_mem (int n_blocks, int n_insns)
- {
-   rd_kill = sbitmap_vector_alloc (n_blocks, n_insns);
-   sbitmap_vector_zero (rd_kill, n_blocks);
- 
-   rd_gen = sbitmap_vector_alloc (n_blocks, n_insns);
-   sbitmap_vector_zero (rd_gen, n_blocks);
- 
-   reaching_defs = sbitmap_vector_alloc (n_blocks, n_insns);
-   sbitmap_vector_zero (reaching_defs, n_blocks);
- 
-   rd_out = sbitmap_vector_alloc (n_blocks, n_insns);
-   sbitmap_vector_zero (rd_out, n_blocks);
- }
- 
- /* Free reaching def variables.  */
- 
- static void
- free_rd_mem (void)
- {
-   sbitmap_vector_free (rd_kill);
-   sbitmap_vector_free (rd_gen);
-   sbitmap_vector_free (reaching_defs);
-   sbitmap_vector_free (rd_out);
- }
- 
- /* Add INSN to the kills of BB.  REGNO, set in BB, is killed by INSN.  */
- 
- static void
- handle_rd_kill_set (rtx insn, int regno, basic_block bb)
- {
-   struct reg_set *this_reg;
- 
-   for (this_reg = reg_set_table[regno]; this_reg; this_reg = this_reg ->next)
-     if (BLOCK_NUM (this_reg->insn) != BLOCK_NUM (insn))
-       SET_BIT (rd_kill[bb->index], INSN_CUID (this_reg->insn));
- }
- 
- /* Compute the set of kill's for reaching definitions.  */
- 
- static void
- compute_kill_rd (void)
- {
-   int cuid;
-   unsigned int regno;
-   int i;
-   basic_block bb;
- 
-   /* For each block
-        For each set bit in `gen' of the block (i.e each insn which
- 	   generates a definition in the block)
- 	 Call the reg set by the insn corresponding to that bit regx
- 	 Look at the linked list starting at reg_set_table[regx]
- 	 For each setting of regx in the linked list, which is not in
- 	     this block
- 	   Set the bit in `kill' corresponding to that insn.  */
-   FOR_EACH_BB (bb)
-     for (cuid = 0; cuid < max_cuid; cuid++)
-       if (TEST_BIT (rd_gen[bb->index], cuid))
- 	{
- 	  rtx insn = CUID_INSN (cuid);
- 	  rtx pat = PATTERN (insn);
- 
- 	  if (GET_CODE (insn) == CALL_INSN)
- 	    {
- 	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- 		if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
- 		  handle_rd_kill_set (insn, regno, bb);
- 	    }
- 
- 	  if (GET_CODE (pat) == PARALLEL)
- 	    {
- 	      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
- 		{
- 		  enum rtx_code code = GET_CODE (XVECEXP (pat, 0, i));
- 
- 		  if ((code == SET || code == CLOBBER)
- 		      && GET_CODE (XEXP (XVECEXP (pat, 0, i), 0)) == REG)
- 		    handle_rd_kill_set (insn,
- 					REGNO (XEXP (XVECEXP (pat, 0, i), 0)),
- 					bb);
- 		}
- 	    }
- 	  else if (GET_CODE (pat) == SET && GET_CODE (SET_DEST (pat)) == REG)
- 	    /* Each setting of this register outside of this block
- 	       must be marked in the set of kills in this block.  */
- 	    handle_rd_kill_set (insn, REGNO (SET_DEST (pat)), bb);
- 	}
- }
- 
- /* Compute the reaching definitions as in
-    Compilers Principles, Techniques, and Tools. Aho, Sethi, Ullman,
-    Chapter 10.  It is the same algorithm as used for computing available
-    expressions but applied to the gens and kills of reaching definitions.  */
- 
- static void
- compute_rd (void)
- {
-   int changed, passes;
-   basic_block bb;
- 
-   FOR_EACH_BB (bb)
-     sbitmap_copy (rd_out[bb->index] /*dst*/, rd_gen[bb->index] /*src*/);
- 
-   passes = 0;
-   changed = 1;
-   while (changed)
-     {
-       changed = 0;
-       FOR_EACH_BB (bb)
- 	{
- 	  sbitmap_union_of_preds (reaching_defs[bb->index], rd_out, bb->index);
- 	  changed |= sbitmap_union_of_diff_cg (rd_out[bb->index], rd_gen[bb->index],
- 					       reaching_defs[bb->index], rd_kill[bb->index]);
- 	}
-       passes++;
-     }
- 
-   if (gcse_file)
-     fprintf (gcse_file, "reaching def computation: %d passes\n", passes);
- }
- 
- /* Classic GCSE available expression support.  */
- 
- /* Allocate memory for available expression computation.  */
- 
- static void
- alloc_avail_expr_mem (int n_blocks, int n_exprs)
- {
-   ae_kill = sbitmap_vector_alloc (n_blocks, n_exprs);
-   sbitmap_vector_zero (ae_kill, n_blocks);
- 
-   ae_gen = sbitmap_vector_alloc (n_blocks, n_exprs);
-   sbitmap_vector_zero (ae_gen, n_blocks);
- 
-   ae_in = sbitmap_vector_alloc (n_blocks, n_exprs);
-   sbitmap_vector_zero (ae_in, n_blocks);
- 
-   ae_out = sbitmap_vector_alloc (n_blocks, n_exprs);
-   sbitmap_vector_zero (ae_out, n_blocks);
- }
- 
- static void
- free_avail_expr_mem (void)
- {
-   sbitmap_vector_free (ae_kill);
-   sbitmap_vector_free (ae_gen);
-   sbitmap_vector_free (ae_in);
-   sbitmap_vector_free (ae_out);
- }
- 
- /* Compute the set of available expressions generated in each basic block.  */
- 
- static void
- compute_ae_gen (struct hash_table *expr_hash_table)
- {
-   unsigned int i;
-   struct expr *expr;
-   struct occr *occr;
- 
-   /* For each recorded occurrence of each expression, set ae_gen[bb][expr].
-      This is all we have to do because an expression is not recorded if it
-      is not available, and the only expressions we want to work with are the
-      ones that are recorded.  */
-   for (i = 0; i < expr_hash_table->size; i++)
-     for (expr = expr_hash_table->table[i]; expr != 0; expr = expr->next_same_hash)
-       for (occr = expr->avail_occr; occr != 0; occr = occr->next)
- 	SET_BIT (ae_gen[BLOCK_NUM (occr->insn)], expr->bitmap_index);
- }
- 
- /* Return nonzero if expression X is killed in BB.  */
- 
- static int
- expr_killed_p (rtx x, basic_block bb)
- {
-   int i, j;
-   enum rtx_code code;
-   const char *fmt;
- 
-   if (x == 0)
-     return 1;
- 
-   code = GET_CODE (x);
-   switch (code)
-     {
-     case REG:
-       return TEST_BIT (reg_set_in_block[bb->index], REGNO (x));
- 
-     case MEM:
-       if (load_killed_in_block_p (bb, get_max_uid () + 1, x, 0))
- 	return 1;
-       else
- 	return expr_killed_p (XEXP (x, 0), bb);
- 
-     case PC:
-     case CC0: /*FIXME*/
-     case CONST:
-     case CONST_INT:
-     case CONST_DOUBLE:
-     case CONST_VECTOR:
-     case SYMBOL_REF:
-     case LABEL_REF:
-     case ADDR_VEC:
-     case ADDR_DIFF_VEC:
-       return 0;
- 
-     default:
-       break;
-     }
- 
-   for (i = GET_RTX_LENGTH (code) - 1, fmt = GET_RTX_FORMAT (code); i >= 0; i--)
-     {
-       if (fmt[i] == 'e')
- 	{
- 	  /* If we are about to do the last recursive call
- 	     needed at this level, change it into iteration.
- 	     This function is called enough to be worth it.  */
- 	  if (i == 0)
- 	    return expr_killed_p (XEXP (x, i), bb);
- 	  else if (expr_killed_p (XEXP (x, i), bb))
- 	    return 1;
- 	}
-       else if (fmt[i] == 'E')
- 	for (j = 0; j < XVECLEN (x, i); j++)
- 	  if (expr_killed_p (XVECEXP (x, i, j), bb))
- 	    return 1;
-     }
- 
-   return 0;
- }
- 
- /* Compute the set of available expressions killed in each basic block.  */
- 
- static void
- compute_ae_kill (sbitmap *ae_gen, sbitmap *ae_kill,
- 		 struct hash_table *expr_hash_table)
- {
-   basic_block bb;
-   unsigned int i;
-   struct expr *expr;
- 
-   FOR_EACH_BB (bb)
-     for (i = 0; i < expr_hash_table->size; i++)
-       for (expr = expr_hash_table->table[i]; expr; expr = expr->next_same_hash)
- 	{
- 	  /* Skip EXPR if generated in this block.  */
- 	  if (TEST_BIT (ae_gen[bb->index], expr->bitmap_index))
- 	    continue;
- 
- 	  if (expr_killed_p (expr->expr, bb))
- 	    SET_BIT (ae_kill[bb->index], expr->bitmap_index);
- 	}
- }
- 
- /* Actually perform the Classic GCSE optimizations.  */
- 
- /* Return nonzero if occurrence OCCR of expression EXPR reaches block BB.
- 
-    CHECK_SELF_LOOP is nonzero if we should consider a block reaching itself
-    as a positive reach.  We want to do this when there are two computations
-    of the expression in the block.
- 
-    VISITED is a pointer to a working buffer for tracking which BB's have
-    been visited.  It is NULL for the top-level call.
- 
-    We treat reaching expressions that go through blocks containing the same
-    reaching expression as "not reaching".  E.g. if EXPR is generated in blocks
-    2 and 3, INSN is in block 4, and 2->3->4, we treat the expression in block
-    2 as not reaching.  The intent is to improve the probability of finding
-    only one reaching expression and to reduce register lifetimes by picking
-    the closest such expression.  */
- 
- static int
- expr_reaches_here_p_work (struct occr *occr, struct expr *expr,
- 			  basic_block bb, int check_self_loop, char *visited)
- {
-   edge pred;
- 
-   for (pred = bb->pred; pred != NULL; pred = pred->pred_next)
-     {
-       basic_block pred_bb = pred->src;
- 
-       if (visited[pred_bb->index])
- 	/* This predecessor has already been visited. Nothing to do.  */
- 	  ;
-       else if (pred_bb == bb)
- 	{
- 	  /* BB loops on itself.  */
- 	  if (check_self_loop
- 	      && TEST_BIT (ae_gen[pred_bb->index], expr->bitmap_index)
- 	      && BLOCK_NUM (occr->insn) == pred_bb->index)
- 	    return 1;
- 
- 	  visited[pred_bb->index] = 1;
- 	}
- 
-       /* Ignore this predecessor if it kills the expression.  */
-       else if (TEST_BIT (ae_kill[pred_bb->index], expr->bitmap_index))
- 	visited[pred_bb->index] = 1;
- 
-       /* Does this predecessor generate this expression?  */
-       else if (TEST_BIT (ae_gen[pred_bb->index], expr->bitmap_index))
- 	{
- 	  /* Is this the occurrence we're looking for?
- 	     Note that there's only one generating occurrence per block
- 	     so we just need to check the block number.  */
- 	  if (BLOCK_NUM (occr->insn) == pred_bb->index)
- 	    return 1;
- 
- 	  visited[pred_bb->index] = 1;
- 	}
- 
-       /* Neither gen nor kill.  */
-       else
- 	{
- 	  visited[pred_bb->index] = 1;
- 	  if (expr_reaches_here_p_work (occr, expr, pred_bb, check_self_loop,
- 	      visited))
- 
- 	    return 1;
- 	}
-     }
- 
-   /* All paths have been checked.  */
-   return 0;
- }
- 
- /* This wrapper for expr_reaches_here_p_work() is to ensure that any
-    memory allocated for that function is returned.  */
- 
- static int
- expr_reaches_here_p (struct occr *occr, struct expr *expr, basic_block bb,
- 		     int check_self_loop)
- {
-   int rval;
-   char *visited = xcalloc (last_basic_block, 1);
- 
-   rval = expr_reaches_here_p_work (occr, expr, bb, check_self_loop, visited);
- 
-   free (visited);
-   return rval;
- }
- 
- /* Return the instruction that computes EXPR that reaches INSN's basic block.
-    If there is more than one such instruction, return NULL.
- 
-    Called only by handle_avail_expr.  */
- 
- static rtx
- computing_insn (struct expr *expr, rtx insn)
- {
-   basic_block bb = BLOCK_FOR_INSN (insn);
- 
-   if (expr->avail_occr->next == NULL)
-     {
-       if (BLOCK_FOR_INSN (expr->avail_occr->insn) == bb)
- 	/* The available expression is actually itself
- 	   (i.e. a loop in the flow graph) so do nothing.  */
- 	return NULL;
- 
-       /* (FIXME) Case that we found a pattern that was created by
- 	 a substitution that took place.  */
-       return expr->avail_occr->insn;
-     }
-   else
-     {
-       /* Pattern is computed more than once.
- 	 Search backwards from this insn to see how many of these
- 	 computations actually reach this insn.  */
-       struct occr *occr;
-       rtx insn_computes_expr = NULL;
-       int can_reach = 0;
- 
-       for (occr = expr->avail_occr; occr != NULL; occr = occr->next)
- 	{
- 	  if (BLOCK_FOR_INSN (occr->insn) == bb)
- 	    {
- 	      /* The expression is generated in this block.
- 		 The only time we care about this is when the expression
- 		 is generated later in the block [and thus there's a loop].
- 		 We let the normal cse pass handle the other cases.  */
- 	      if (INSN_CUID (insn) < INSN_CUID (occr->insn)
- 		  && expr_reaches_here_p (occr, expr, bb, 1))
- 		{
- 		  can_reach++;
- 		  if (can_reach > 1)
- 		    return NULL;
- 
- 		  insn_computes_expr = occr->insn;
- 		}
- 	    }
- 	  else if (expr_reaches_here_p (occr, expr, bb, 0))
- 	    {
- 	      can_reach++;
- 	      if (can_reach > 1)
- 		return NULL;
- 
- 	      insn_computes_expr = occr->insn;
- 	    }
- 	}
- 
-       if (insn_computes_expr == NULL)
- 	abort ();
- 
-       return insn_computes_expr;
-     }
- }
- 
- /* Return nonzero if the definition in DEF_INSN can reach INSN.
-    Only called by can_disregard_other_sets.  */
- 
- static int
- def_reaches_here_p (rtx insn, rtx def_insn)
- {
-   rtx reg;
- 
-   if (TEST_BIT (reaching_defs[BLOCK_NUM (insn)], INSN_CUID (def_insn)))
-     return 1;
- 
-   if (BLOCK_NUM (insn) == BLOCK_NUM (def_insn))
-     {
-       if (INSN_CUID (def_insn) < INSN_CUID (insn))
- 	{
- 	  if (GET_CODE (PATTERN (def_insn)) == PARALLEL)
- 	    return 1;
- 	  else if (GET_CODE (PATTERN (def_insn)) == CLOBBER)
- 	    reg = XEXP (PATTERN (def_insn), 0);
- 	  else if (GET_CODE (PATTERN (def_insn)) == SET)
- 	    reg = SET_DEST (PATTERN (def_insn));
- 	  else
- 	    abort ();
- 
- 	  return ! reg_set_between_p (reg, NEXT_INSN (def_insn), insn);
- 	}
-       else
- 	return 0;
-     }
- 
-   return 0;
- }
- 
- /* Return nonzero if *ADDR_THIS_REG can only have one value at INSN.  The
-    value returned is the number of definitions that reach INSN.  Returning a
-    value of zero means that [maybe] more than one definition reaches INSN and
-    the caller can't perform whatever optimization it is trying.  i.e. it is
-    always safe to return zero.  */
- 
- static int
- can_disregard_other_sets (struct reg_set **addr_this_reg, rtx insn, int for_combine)
- {
-   int number_of_reaching_defs = 0;
-   struct reg_set *this_reg;
- 
-   for (this_reg = *addr_this_reg; this_reg != 0; this_reg = this_reg->next)
-     if (def_reaches_here_p (insn, this_reg->insn))
-       {
- 	number_of_reaching_defs++;
- 	/* Ignore parallels for now.  */
- 	if (GET_CODE (PATTERN (this_reg->insn)) == PARALLEL)
- 	  return 0;
- 
- 	if (!for_combine
- 	    && (GET_CODE (PATTERN (this_reg->insn)) == CLOBBER
- 		|| ! rtx_equal_p (SET_SRC (PATTERN (this_reg->insn)),
- 				  SET_SRC (PATTERN (insn)))))
- 	  /* A setting of the reg to a different value reaches INSN.  */
- 	  return 0;
- 
- 	if (number_of_reaching_defs > 1)
- 	  {
- 	    /* If in this setting the value the register is being set to is
- 	       equal to the previous value the register was set to and this
- 	       setting reaches the insn we are trying to do the substitution
- 	       on then we are ok.  */
- 	    if (GET_CODE (PATTERN (this_reg->insn)) == CLOBBER)
- 	      return 0;
- 	    else if (! rtx_equal_p (SET_SRC (PATTERN (this_reg->insn)),
- 				    SET_SRC (PATTERN (insn))))
- 	      return 0;
- 	  }
- 
- 	*addr_this_reg = this_reg;
-       }
- 
-   return number_of_reaching_defs;
- }
- 
- /* Expression computed by insn is available and the substitution is legal,
-    so try to perform the substitution.
- 
-    The result is nonzero if any changes were made.  */
- 
- static int
- handle_avail_expr (rtx insn, struct expr *expr)
- {
-   rtx pat, insn_computes_expr, expr_set;
-   rtx to;
-   struct reg_set *this_reg;
-   int found_setting, use_src;
-   int changed = 0;
- 
-   /* We only handle the case where one computation of the expression
-      reaches this instruction.  */
-   insn_computes_expr = computing_insn (expr, insn);
-   if (insn_computes_expr == NULL)
-     return 0;
-   expr_set = single_set (insn_computes_expr);
-   /* The set might be in a parallel with multiple sets; we could
-      probably handle that, but there's currently no easy way to find
-      the relevant sub-expression.  */
-   if (!expr_set)
-     return 0;
- 
-   found_setting = 0;
-   use_src = 0;
- 
-   /* At this point we know only one computation of EXPR outside of this
-      block reaches this insn.  Now try to find a register that the
-      expression is computed into.  */
-   if (GET_CODE (SET_SRC (expr_set)) == REG)
-     {
-       /* This is the case when the available expression that reaches
- 	 here has already been handled as an available expression.  */
-       unsigned int regnum_for_replacing
- 	= REGNO (SET_SRC (expr_set));
- 
-       /* If the register was created by GCSE we can't use `reg_set_table',
- 	 however we know it's set only once.  */
-       if (regnum_for_replacing >= max_gcse_regno
- 	  /* If the register the expression is computed into is set only once,
- 	     or only one set reaches this insn, we can use it.  */
- 	  || (((this_reg = reg_set_table[regnum_for_replacing]),
- 	       this_reg->next == NULL)
- 	      || can_disregard_other_sets (&this_reg, insn, 0)))
- 	{
- 	  use_src = 1;
- 	  found_setting = 1;
- 	}
-     }
- 
-   if (!found_setting)
-     {
-       unsigned int regnum_for_replacing
- 	= REGNO (SET_DEST (expr_set));
- 
-       /* This shouldn't happen.  */
-       if (regnum_for_replacing >= max_gcse_regno)
- 	abort ();
- 
-       this_reg = reg_set_table[regnum_for_replacing];
- 
-       /* If the register the expression is computed into is set only once,
- 	 or only one set reaches this insn, use it.  */
-       if (this_reg->next == NULL
- 	  || can_disregard_other_sets (&this_reg, insn, 0))
- 	found_setting = 1;
-     }
- 
-   if (found_setting)
-     {
-       pat = PATTERN (insn);
-       if (use_src)
- 	to = SET_SRC (expr_set);
-       else
- 	to = SET_DEST (expr_set);
-       changed = validate_change (insn, &SET_SRC (pat), to, 0);
- 
-       /* We should be able to ignore the return code from validate_change but
- 	 to play it safe we check.  */
-       if (changed)
- 	{
- 	  gcse_subst_count++;
- 	  if (gcse_file != NULL)
- 	    {
- 	      fprintf (gcse_file, "GCSE: Replacing the source in insn %d with",
- 		       INSN_UID (insn));
- 	      fprintf (gcse_file, " reg %d %s insn %d\n",
- 		       REGNO (to), use_src ? "from" : "set in",
- 		       INSN_UID (insn_computes_expr));
- 	    }
- 	}
-     }
- 
-   /* The register that the expr is computed into is set more than once.  */
-   else if (1 /*expensive_op(this_pattrn->op) && do_expensive_gcse)*/)
-     {
-       /* Insert an insn after insnx that copies the reg set in insnx
- 	 into a new pseudo register call this new register REGN.
- 	 From insnb until end of basic block or until REGB is set
- 	 replace all uses of REGB with REGN.  */
-       rtx new_insn;
- 
-       to = gen_reg_rtx (GET_MODE (SET_DEST (expr_set)));
- 
-       /* Generate the new insn.  */
-       /* ??? If the change fails, we return 0, even though we created
- 	 an insn.  I think this is ok.  */
-       new_insn
- 	= emit_insn_after (gen_rtx_SET (VOIDmode, to,
- 					SET_DEST (expr_set)),
- 			   insn_computes_expr);
- 
-       /* Keep register set table up to date.  */
-       record_one_set (REGNO (to), new_insn);
- 
-       gcse_create_count++;
-       if (gcse_file != NULL)
- 	{
- 	  fprintf (gcse_file, "GCSE: Creating insn %d to copy value of reg %d",
- 		   INSN_UID (NEXT_INSN (insn_computes_expr)),
- 		   REGNO (SET_SRC (PATTERN (NEXT_INSN (insn_computes_expr)))));
- 	  fprintf (gcse_file, ", computed in insn %d,\n",
- 		   INSN_UID (insn_computes_expr));
- 	  fprintf (gcse_file, "      into newly allocated reg %d\n",
- 		   REGNO (to));
- 	}
- 
-       pat = PATTERN (insn);
- 
-       /* Do register replacement for INSN.  */
-       changed = validate_change (insn, &SET_SRC (pat),
- 				 SET_DEST (PATTERN
- 					   (NEXT_INSN (insn_computes_expr))),
- 				 0);
- 
-       /* We should be able to ignore the return code from validate_change but
- 	 to play it safe we check.  */
-       if (changed)
- 	{
- 	  gcse_subst_count++;
- 	  if (gcse_file != NULL)
- 	    {
- 	      fprintf (gcse_file,
- 		       "GCSE: Replacing the source in insn %d with reg %d ",
- 		       INSN_UID (insn),
- 		       REGNO (SET_DEST (PATTERN (NEXT_INSN
- 						 (insn_computes_expr)))));
- 	      fprintf (gcse_file, "set in insn %d\n",
- 		       INSN_UID (insn_computes_expr));
- 	    }
- 	}
-     }
- 
-   return changed;
- }
- 
- /* Perform classic GCSE.  This is called by one_classic_gcse_pass after all
-    the dataflow analysis has been done.
- 
-    The result is nonzero if a change was made.  */
- 
- static int
- classic_gcse (void)
- {
-   int changed;
-   rtx insn;
-   basic_block bb;
- 
-   /* Note we start at block 1.  */
- 
-   if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR)
-     return 0;
- 
-   changed = 0;
-   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb->next_bb, EXIT_BLOCK_PTR, next_bb)
-     {
-       /* Reset tables used to keep track of what's still valid [since the
- 	 start of the block].  */
-       reset_opr_set_tables ();
- 
-       for (insn = BB_HEAD (bb);
- 	   insn != NULL && insn != NEXT_INSN (BB_END (bb));
- 	   insn = NEXT_INSN (insn))
- 	{
- 	  /* Is insn of form (set (pseudo-reg) ...)?  */
- 	  if (GET_CODE (insn) == INSN
- 	      && GET_CODE (PATTERN (insn)) == SET
- 	      && GET_CODE (SET_DEST (PATTERN (insn))) == REG
- 	      && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_PSEUDO_REGISTER)
- 	    {
- 	      rtx pat = PATTERN (insn);
- 	      rtx src = SET_SRC (pat);
- 	      struct expr *expr;
- 
- 	      if (want_to_gcse_p (src)
- 		  /* Is the expression recorded?  */
- 		  && ((expr = lookup_expr (src, &expr_hash_table)) != NULL)
- 		  /* Is the expression available [at the start of the
- 		     block]?  */
- 		  && TEST_BIT (ae_in[bb->index], expr->bitmap_index)
- 		  /* Are the operands unchanged since the start of the
- 		     block?  */
- 		  && oprs_not_set_p (src, insn))
- 		changed |= handle_avail_expr (insn, expr);
- 	    }
- 
- 	  /* Keep track of everything modified by this insn.  */
- 	  /* ??? Need to be careful w.r.t. mods done to INSN.  */
- 	  if (INSN_P (insn))
- 	    mark_oprs_set (insn);
- 	}
-     }
- 
-   return changed;
- }
- 
- /* Top level routine to perform one classic GCSE pass.
- 
-    Return nonzero if a change was made.  */
- 
- static int
- one_classic_gcse_pass (int pass)
- {
-   int changed = 0;
- 
-   gcse_subst_count = 0;
-   gcse_create_count = 0;
- 
-   alloc_hash_table (max_cuid, &expr_hash_table, 0);
-   alloc_rd_mem (last_basic_block, max_cuid);
-   compute_hash_table (&expr_hash_table);
-   if (gcse_file)
-     dump_hash_table (gcse_file, "Expression", &expr_hash_table);
- 
-   if (expr_hash_table.n_elems > 0)
-     {
-       compute_kill_rd ();
-       compute_rd ();
-       alloc_avail_expr_mem (last_basic_block, expr_hash_table.n_elems);
-       compute_ae_gen (&expr_hash_table);
-       compute_ae_kill (ae_gen, ae_kill, &expr_hash_table);
-       compute_available (ae_gen, ae_kill, ae_out, ae_in);
-       changed = classic_gcse ();
-       free_avail_expr_mem ();
-     }
- 
-   free_rd_mem ();
-   free_hash_table (&expr_hash_table);
- 
-   if (gcse_file)
-     {
-       fprintf (gcse_file, "\n");
-       fprintf (gcse_file, "GCSE of %s, pass %d: %d bytes needed, %d substs,",
- 	       current_function_name (), pass, bytes_used, gcse_subst_count);
-       fprintf (gcse_file, "%d insns created\n", gcse_create_count);
-     }
- 
-   return changed;
- }
- 
  /* Compute copy/constant propagation working variables.  */
  
  /* Local properties of assignments.  */
--- 2797,2802 ----
*************** alloc_pre_mem (int n_blocks, int n_exprs
*** 5046,5053 ****
    pre_redundant = NULL;
    pre_insert_map = NULL;
    pre_delete_map = NULL;
-   ae_in = NULL;
-   ae_out = NULL;
    ae_kill = sbitmap_vector_alloc (n_blocks, n_exprs);
  
    /* pre_insert and pre_delete are allocated later.  */
--- 4210,4215 ----
*************** free_pre_mem (void)
*** 5071,5084 ****
      sbitmap_vector_free (pre_insert_map);
    if (pre_delete_map)
      sbitmap_vector_free (pre_delete_map);
-   if (ae_in)
-     sbitmap_vector_free (ae_in);
-   if (ae_out)
-     sbitmap_vector_free (ae_out);
  
    transp = comp = NULL;
    pre_optimal = pre_redundant = pre_insert_map = pre_delete_map = NULL;
-   ae_in = ae_out = NULL;
  }
  
  /* Top level routine to do the dataflow analysis needed by PRE.  */
--- 4233,4241 ----
*************** compute_pre_data (void)
*** 5107,5114 ****
    /* Compute ae_kill for each basic block using:
  
       ~(TRANSP | COMP)
! 
!      This is significantly faster than compute_ae_kill.  */
  
    FOR_EACH_BB (bb)
      {
--- 4264,4270 ----
    /* Compute ae_kill for each basic block using:
  
       ~(TRANSP | COMP)
!   */
  
    FOR_EACH_BB (bb)
      {
*************** compute_transpout (void)
*** 5911,6205 ****
  	      RESET_BIT (transpout[bb->index], expr->bitmap_index);
  	    }
      }
- }
- 
- /* Removal of useless null pointer checks */
- 
- /* Called via note_stores.  X is set by SETTER.  If X is a register we must
-    invalidate nonnull_local and set nonnull_killed.  DATA is really a
-    `null_pointer_info *'.
- 
-    We ignore hard registers.  */
- 
- static void
- invalidate_nonnull_info (rtx x, rtx setter ATTRIBUTE_UNUSED, void *data)
- {
-   unsigned int regno;
-   struct null_pointer_info *npi = (struct null_pointer_info *) data;
- 
-   while (GET_CODE (x) == SUBREG)
-     x = SUBREG_REG (x);
- 
-   /* Ignore anything that is not a register or is a hard register.  */
-   if (GET_CODE (x) != REG
-       || REGNO (x) < npi->min_reg
-       || REGNO (x) >= npi->max_reg)
-     return;
- 
-   regno = REGNO (x) - npi->min_reg;
- 
-   RESET_BIT (npi->nonnull_local[npi->current_block->index], regno);
-   SET_BIT (npi->nonnull_killed[npi->current_block->index], regno);
- }
- 
- /* Do null-pointer check elimination for the registers indicated in
-    NPI.  NONNULL_AVIN and NONNULL_AVOUT are pre-allocated sbitmaps;
-    they are not our responsibility to free.  */
- 
- static int
- delete_null_pointer_checks_1 (unsigned int *block_reg, sbitmap *nonnull_avin,
- 			      sbitmap *nonnull_avout,
- 			      struct null_pointer_info *npi)
- {
-   basic_block bb, current_block;
-   sbitmap *nonnull_local = npi->nonnull_local;
-   sbitmap *nonnull_killed = npi->nonnull_killed;
-   int something_changed = 0;
- 
-   /* Compute local properties, nonnull and killed.  A register will have
-      the nonnull property if at the end of the current block its value is
-      known to be nonnull.  The killed property indicates that somewhere in
-      the block any information we had about the register is killed.
- 
-      Note that a register can have both properties in a single block.  That
-      indicates that it's killed, then later in the block a new value is
-      computed.  */
-   sbitmap_vector_zero (nonnull_local, last_basic_block);
-   sbitmap_vector_zero (nonnull_killed, last_basic_block);
- 
-   FOR_EACH_BB (current_block)
-     {
-       rtx insn, stop_insn;
- 
-       /* Set the current block for invalidate_nonnull_info.  */
-       npi->current_block = current_block;
- 
-       /* Scan each insn in the basic block looking for memory references and
- 	 register sets.  */
-       stop_insn = NEXT_INSN (BB_END (current_block));
-       for (insn = BB_HEAD (current_block);
- 	   insn != stop_insn;
- 	   insn = NEXT_INSN (insn))
- 	{
- 	  rtx set;
- 	  rtx reg;
- 
- 	  /* Ignore anything that is not a normal insn.  */
- 	  if (! INSN_P (insn))
- 	    continue;
- 
- 	  /* Basically ignore anything that is not a simple SET.  We do have
- 	     to make sure to invalidate nonnull_local and set nonnull_killed
- 	     for such insns though.  */
- 	  set = single_set (insn);
- 	  if (!set)
- 	    {
- 	      note_stores (PATTERN (insn), invalidate_nonnull_info, npi);
- 	      continue;
- 	    }
- 
- 	  /* See if we've got a usable 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 ((reg = XEXP (SET_SRC (set), 0))) == REG
- 	      && REGNO (reg) >= npi->min_reg
- 	      && REGNO (reg) < npi->max_reg)
- 	    SET_BIT (nonnull_local[current_block->index],
- 		     REGNO (reg) - npi->min_reg);
- 
- 	  /* Now invalidate stuff clobbered by this insn.  */
- 	  note_stores (PATTERN (insn), invalidate_nonnull_info, npi);
- 
- 	  /* 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 ((reg = XEXP (SET_DEST (set), 0))) == REG
- 	      && REGNO (reg) >= npi->min_reg
- 	      && REGNO (reg) < npi->max_reg)
- 	    SET_BIT (nonnull_local[current_block->index],
- 		     REGNO (reg) - npi->min_reg);
- 	}
-     }
- 
-   /* Now compute global properties based on the local properties.   This
-      is a classic global availability algorithm.  */
-   compute_available (nonnull_local, nonnull_killed,
- 		     nonnull_avout, nonnull_avin);
- 
-   /* Now look at each bb and see if it ends with a compare of a value
-      against zero.  */
-   FOR_EACH_BB (bb)
-     {
-       rtx last_insn = BB_END (bb);
-       rtx condition, earliest;
-       int compare_and_branch;
- 
-       /* Since MIN_REG is always at least FIRST_PSEUDO_REGISTER, and
- 	 since BLOCK_REG[BB] is zero if this block did not end with a
- 	 comparison against zero, this condition works.  */
-       if (block_reg[bb->index] < npi->min_reg
- 	  || block_reg[bb->index] >= npi->max_reg)
- 	continue;
- 
-       /* LAST_INSN is a conditional jump.  Get its condition.  */
-       condition = get_condition (last_insn, &earliest, false);
- 
-       /* If we can't determine the condition then skip.  */
-       if (! condition)
- 	continue;
- 
-       /* Is the register known to have a nonzero value?  */
-       if (!TEST_BIT (nonnull_avout[bb->index], block_reg[bb->index] - npi->min_reg))
- 	continue;
- 
-       /* Try to compute whether the compare/branch at the loop end is one or
- 	 two instructions.  */
-       if (earliest == last_insn)
- 	compare_and_branch = 1;
-       else if (earliest == prev_nonnote_insn (last_insn))
- 	compare_and_branch = 2;
-       else
- 	continue;
- 
-       /* We know the register in this comparison is nonnull at exit from
- 	 this block.  We can optimize this comparison.  */
-       if (GET_CODE (condition) == NE)
- 	{
- 	  rtx new_jump;
- 
- 	  new_jump = emit_jump_insn_after (gen_jump (JUMP_LABEL (last_insn)),
- 					   last_insn);
- 	  JUMP_LABEL (new_jump) = JUMP_LABEL (last_insn);
- 	  LABEL_NUSES (JUMP_LABEL (new_jump))++;
- 	  emit_barrier_after (new_jump);
- 	}
- 
-       something_changed = 1;
-       delete_insn (last_insn);
- #ifdef HAVE_cc0
-       if (compare_and_branch == 2)
- 	delete_insn (earliest);
- #endif
-       purge_dead_edges (bb);
- 
-       /* Don't check this block again.  (Note that BB_END is
- 	 invalid here; we deleted the last instruction in the
- 	 block.)  */
-       block_reg[bb->index] = 0;
-     }
- 
-   return something_changed;
- }
- 
- /* Find EQ/NE comparisons against zero which can be (indirectly) evaluated
-    at compile time.
- 
-    This is conceptually similar to global constant/copy propagation and
-    classic global CSE (it even uses the same dataflow equations as cprop).
- 
-    If a register is used as memory address with the form (mem (reg)), then we
-    know that REG can not be zero at that point in the program.  Any instruction
-    which sets REG "kills" this property.
- 
-    So, if every path leading to a conditional branch has an available memory
-    reference of that form, then we know the register can not have the value
-    zero at the conditional branch.
- 
-    So we merely need to compute the local properties and propagate that data
-    around the cfg, then optimize where possible.
- 
-    We run this pass two times.  Once before CSE, then again after CSE.  This
-    has proven to be the most profitable approach.  It is rare for new
-    optimization opportunities of this nature to appear after the first CSE
-    pass.
- 
-    This could probably be integrated with global cprop with a little work.  */
- 
- int
- delete_null_pointer_checks (rtx f ATTRIBUTE_UNUSED)
- {
-   sbitmap *nonnull_avin, *nonnull_avout;
-   unsigned int *block_reg;
-   basic_block bb;
-   int reg;
-   int regs_per_pass;
-   int max_reg = max_reg_num ();
-   struct null_pointer_info npi;
-   int something_changed = 0;
- 
-   /* If we have only a single block, or it is too expensive, give up.  */
-   if (n_basic_blocks <= 1
-       || is_too_expensive (_ ("NULL pointer checks disabled")))
-     return 0;
- 
-   /* We need four bitmaps, each with a bit for each register in each
-      basic block.  */
-   regs_per_pass = get_bitmap_width (4, last_basic_block, max_reg);
- 
-   /* Allocate bitmaps to hold local and global properties.  */
-   npi.nonnull_local = sbitmap_vector_alloc (last_basic_block, regs_per_pass);
-   npi.nonnull_killed = sbitmap_vector_alloc (last_basic_block, regs_per_pass);
-   nonnull_avin = sbitmap_vector_alloc (last_basic_block, regs_per_pass);
-   nonnull_avout = sbitmap_vector_alloc (last_basic_block, regs_per_pass);
- 
-   /* Go through the basic blocks, seeing whether or not each block
-      ends with a conditional branch whose condition is a comparison
-      against zero.  Record the register compared in BLOCK_REG.  */
-   block_reg = xcalloc (last_basic_block, sizeof (int));
-   FOR_EACH_BB (bb)
-     {
-       rtx last_insn = BB_END (bb);
-       rtx condition, earliest, reg;
- 
-       /* We only want conditional branches.  */
-       if (GET_CODE (last_insn) != JUMP_INSN
- 	  || !any_condjump_p (last_insn)
- 	  || !onlyjump_p (last_insn))
- 	continue;
- 
-       /* LAST_INSN is a conditional jump.  Get its condition.  */
-       condition = get_condition (last_insn, &earliest, false);
- 
-       /* If we were unable to get the condition, or it is not an equality
- 	 comparison against zero then there's nothing we can do.  */
-       if (!condition
- 	  || (GET_CODE (condition) != NE && GET_CODE (condition) != EQ)
- 	  || GET_CODE (XEXP (condition, 1)) != CONST_INT
- 	  || (XEXP (condition, 1)
- 	      != CONST0_RTX (GET_MODE (XEXP (condition, 0)))))
- 	continue;
- 
-       /* We must be checking a register against zero.  */
-       reg = XEXP (condition, 0);
-       if (GET_CODE (reg) != REG)
- 	continue;
- 
-       block_reg[bb->index] = REGNO (reg);
-     }
- 
-   /* 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);
-       something_changed |= delete_null_pointer_checks_1 (block_reg,
- 							 nonnull_avin,
- 							 nonnull_avout,
- 							 &npi);
-     }
- 
-   /* Free the table of registers compared at the end of every block.  */
-   free (block_reg);
- 
-   /* Free bitmaps.  */
-   sbitmap_vector_free (npi.nonnull_local);
-   sbitmap_vector_free (npi.nonnull_killed);
-   sbitmap_vector_free (nonnull_avin);
-   sbitmap_vector_free (nonnull_avout);
- 
-   return something_changed;
  }
  
  /* Code Hoisting variables and subroutines.  */
--- 5067,5072 ----
Index: opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/opts.c,v
retrieving revision 1.68
diff -c -3 -p -r1.68 opts.c
*** opts.c	13 May 2004 06:39:44 -0000	1.68
--- opts.c	14 May 2004 14:50:02 -0000
*************** decode_options (unsigned int argc, const
*** 580,586 ****
  #endif
        flag_regmove = 1;
        flag_strict_aliasing = 1;
-       flag_delete_null_pointer_checks = 1;
        flag_reorder_blocks = 1;
        flag_reorder_functions = 1;
        flag_unit_at_a_time = 1;
--- 580,585 ----
*************** common_handle_option (size_t scode, cons
*** 997,1006 ****
  
      case OPT_fdelayed_branch:
        flag_delayed_branch = value;
-       break;
- 
-     case OPT_fdelete_null_pointer_checks:
-       flag_delete_null_pointer_checks = value;
        break;
  
      case OPT_fdiagnostics_show_location_:
--- 996,1001 ----
Index: passes.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/passes.c,v
retrieving revision 2.12
diff -c -3 -p -r2.12 passes.c
*** passes.c	13 May 2004 06:39:44 -0000	2.12
--- passes.c	14 May 2004 14:50:02 -0000
*************** rest_of_handle_jump_bypass (tree decl, r
*** 1004,1023 ****
  #endif
  }
  
- /* Try to identify useless null pointer tests and delete them.  */
- static void
- rest_of_handle_null_pointer (tree decl, rtx insns)
- {
-   open_dump_file (DFI_null, decl);
-   if (dump_file)
-     dump_flow_info (dump_file);
- 
-   if (delete_null_pointer_checks (insns))
-     cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
- 
-   close_dump_file (DFI_null, print_rtl_with_bb, insns);
- }
- 
  /* Try combining insns through substitution.  */
  static void
  rest_of_handle_combine (tree decl, rtx insns)
--- 1004,1009 ----
*************** rest_of_handle_cse (tree decl, rtx insns
*** 1120,1138 ****
  
    if (tem || optimize > 1)
      cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
-   /* Try to identify useless null pointer tests and delete them.  */
-   if (flag_delete_null_pointer_checks)
-     {
-       timevar_push (TV_JUMP);
- 
-       if (delete_null_pointer_checks (insns))
- 	cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
-       timevar_pop (TV_JUMP);
-     }
- 
-   /* The second pass of jump optimization is likely to have
-      removed a bunch more instructions.  */
-   renumber_insns (dump_file);
  
    timevar_pop (TV_CSE);
    close_dump_file (DFI_cse, print_rtl_with_bb, insns);
--- 1106,1111 ----
*************** rest_of_compilation (tree decl)
*** 1546,1554 ****
  
    if (optimize)
      cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
- 
-   if (flag_delete_null_pointer_checks)
-     rest_of_handle_null_pointer (decl, insns);
  
    /* Jump optimization, and the removal of NULL pointer checks, may
       have reduced the number of instructions substantially.  CSE, and
--- 1519,1524 ----
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.471
diff -c -3 -p -r1.471 rtl.h
*** rtl.h	13 May 2004 06:39:45 -0000	1.471
--- rtl.h	14 May 2004 14:50:03 -0000
*************** extern void cannot_change_mode_set_regs 
*** 2320,2327 ****
  extern bool invalid_mode_change_p (unsigned int, enum reg_class,
  				   enum machine_mode);
  
- extern int delete_null_pointer_checks (rtx);
- 
  /* In regmove.c */
  #ifdef BUFSIZ
  extern void regmove_optimize (rtx, int, FILE *);
--- 2320,2325 ----
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.897
diff -c -3 -p -r1.897 toplev.c
*** toplev.c	13 May 2004 06:39:45 -0000	1.897
--- toplev.c	14 May 2004 14:50:03 -0000
*************** int flag_if_conversion;
*** 524,534 ****
  
  int flag_if_conversion2;
  
- /* Nonzero means to use global dataflow analysis to eliminate
-    useless null pointer tests.  */
- 
- int flag_delete_null_pointer_checks;
- 
  /* Nonzero means perform global CSE.  */
  
  int flag_gcse = 0;
--- 524,529 ----
*************** static const lang_independent_options f_
*** 996,1002 ****
    {"if-conversion2", &flag_if_conversion2, 1 },
    {"rerun-cse-after-loop", &flag_rerun_cse_after_loop, 1 },
    {"rerun-loop-opt", &flag_rerun_loop_opt, 1 },
-   {"delete-null-pointer-checks", &flag_delete_null_pointer_checks, 1 },
    {"schedule-insns", &flag_schedule_insns, 1 },
    {"schedule-insns2", &flag_schedule_insns_after_reload, 1 },
    {"sched-interblock",&flag_schedule_interblock, 1 },
--- 991,996 ----
Index: toplev.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.h,v
retrieving revision 1.120
diff -c -3 -p -r1.120 toplev.h
*** toplev.h	13 May 2004 06:39:45 -0000	1.120
--- toplev.h	14 May 2004 14:50:03 -0000
*************** extern int flag_loop_optimize;
*** 113,119 ****
  extern int flag_crossjumping;
  extern int flag_if_conversion;
  extern int flag_if_conversion2;
- extern int flag_delete_null_pointer_checks;
  extern int flag_keep_static_consts;
  extern int flag_peel_loops;
  extern int flag_rerun_cse_after_loop;
--- 113,118 ----
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.460
diff -c -3 -p -r1.460 invoke.texi
*** doc/invoke.texi	13 May 2004 06:40:25 -0000	1.460
--- doc/invoke.texi	14 May 2004 14:50:13 -0000
*************** in the following sections.
*** 281,287 ****
  -fbranch-target-load-optimize2 -fbtr-bb-exclusive @gol
  -fcaller-saves  -fcprop-registers @gol
  -fcse-follow-jumps  -fcse-skip-blocks  -fdata-sections @gol
! -fdelayed-branch  -fdelete-null-pointer-checks @gol
  -fexpensive-optimizations  -ffast-math  -ffloat-store @gol
  -fforce-addr  -fforce-mem  -ffunction-sections @gol
  -fgcse  -fgcse-lm  -fgcse-sm  -fgcse-las  -fgcse-after-reload @gol
--- 281,287 ----
  -fbranch-target-load-optimize2 -fbtr-bb-exclusive @gol
  -fcaller-saves  -fcprop-registers @gol
  -fcse-follow-jumps  -fcse-skip-blocks  -fdata-sections @gol
! -fdelayed-branch @gol
  -fexpensive-optimizations  -ffast-math  -ffloat-store @gol
  -fforce-addr  -fforce-mem  -ffunction-sections @gol
  -fgcse  -fgcse-lm  -fgcse-sm  -fgcse-las  -fgcse-after-reload @gol
*************** also turns on the following optimization
*** 3802,3808 ****
  -fcse-follow-jumps  -fcse-skip-blocks @gol
  -frerun-cse-after-loop  -frerun-loop-opt @gol
  -fgcse  -fgcse-lm  -fgcse-sm  -fgcse-las @gol
- -fdelete-null-pointer-checks @gol
  -fexpensive-optimizations @gol
  -fregmove @gol
  -fschedule-insns  -fschedule-insns2 @gol
--- 3802,3807 ----
*************** Use conditional execution (where availab
*** 4204,4223 ****
  branch-less equivalents.
  
  Enabled at levels @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}.
- 
- @item -fdelete-null-pointer-checks
- @opindex fdelete-null-pointer-checks
- Use global dataflow analysis to identify and eliminate useless checks
- for null pointers.  The compiler assumes that dereferencing a null
- pointer would have halted the program.  If a pointer is checked after
- it has already been dereferenced, it cannot be null.
- 
- In some environments, this assumption is not true, and programs can
- safely dereference null pointers.  Use
- @option{-fno-delete-null-pointer-checks} to disable this optimization
- for programs which depend on that behavior.
- 
- Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
  
  @item -fexpensive-optimizations
  @opindex fexpensive-optimizations
--- 4203,4208 ----


More information about the Gcc-patches mailing list