passes.c (rest_of_handle_null_pointer): Remove.
authorSteven Bosscher <stevenb@suse.de>
Fri, 14 May 2004 15:35:11 +0000 (15:35 +0000)
committerSteven Bosscher <steven@gcc.gnu.org>
Fri, 14 May 2004 15:35:11 +0000 (15:35 +0000)
* passes.c (rest_of_handle_null_pointer): Remove.
(rest_of_handle_cse): Don't call rest_of_handle_null_pointer.
(rest_of_compilation): 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.

From-SVN: r81849

gcc/ChangeLog
gcc/gcse.c
gcc/passes.c
gcc/rtl.h

index 97cb0440a855eaf3261318dcbc46c4a450d3cb68..67de34125e3584e606a7ee00c47961f369185869 100644 (file)
@@ -1,3 +1,23 @@
+2004-05-14  Steven Bosscher  <stevenb@suse.de>
+
+       * passes.c (rest_of_handle_null_pointer): Remove.
+       (rest_of_handle_cse): Don't call rest_of_handle_null_pointer.
+       (rest_of_compilation): 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.
+
 2004-05-14  Andrew Pinski  <pinskia@physics.uc.edu>
 
        PR optimization/14466
index 9e6ced54dd1f2ad1d8ba955ba12a50e91a2b2a6f..b6d0a6b4d4a3d018303860f51153df1c0a791a3d 100644 (file)
@@ -192,7 +192,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
    3) Perform copy/constant propagation.
 
-   4) Perform global cse.
+   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.
 
@@ -485,7 +486,7 @@ static struct ls_expr * pre_ldst_mems = NULL;
 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.
+   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.  */
@@ -515,25 +516,8 @@ static int const_prop_count;
 /* Number of copys propagated.  */
 static int copy_prop_count;
 \f
-/* 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;
+/* For available exprs */
+static sbitmap *ae_kill, *ae_gen;
 
 /* Objects of this type are passed around by the null-pointer check
    removal routines.  */
@@ -558,7 +542,6 @@ static void alloc_gcse_mem (rtx);
 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 *);
@@ -640,31 +623,8 @@ static void compute_code_hoist_data (void);
 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);
@@ -790,7 +750,7 @@ gcse_main (rtx f, FILE *file)
       changed = one_cprop_pass (pass + 1, 0, 0);
 
       if (optimize_size)
-       changed |= one_classic_gcse_pass (pass + 1);
+       /* Do nothing.  */ ;
       else
        {
          changed |= one_pre_gcse_pass (pass + 1);
@@ -821,8 +781,7 @@ gcse_main (rtx f, FILE *file)
       /* 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).  */
+        for space, we don't run the partial redundancy algorithms).  */
       if (optimize_size)
        {
          max_gcse_regno = max_reg_num ();
@@ -1025,46 +984,6 @@ free_gcse_mem (void)
   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);
-}
 \f
 /* Compute the local properties of each recorded expression.
 
@@ -2878,204 +2797,136 @@ mark_oprs_set (rtx insn)
 }
 
 \f
-/* 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);
+/* Compute copy/constant propagation working variables.  */
 
-  reaching_defs = sbitmap_vector_alloc (n_blocks, n_insns);
-  sbitmap_vector_zero (reaching_defs, n_blocks);
+/* Local properties of assignments.  */
+static sbitmap *cprop_pavloc;
+static sbitmap *cprop_absaltered;
 
-  rd_out = sbitmap_vector_alloc (n_blocks, n_insns);
-  sbitmap_vector_zero (rd_out, n_blocks);
-}
+/* Global properties of assignments (computed from the local properties).  */
+static sbitmap *cprop_avin;
+static sbitmap *cprop_avout;
 
-/* Free reaching def variables.  */
+/* Allocate vars used for copy/const propagation.  N_BLOCKS is the number of
+   basic blocks.  N_SETS is the number of sets.  */
 
 static void
-free_rd_mem (void)
+alloc_cprop_mem (int n_blocks, int n_sets)
 {
-  sbitmap_vector_free (rd_kill);
-  sbitmap_vector_free (rd_gen);
-  sbitmap_vector_free (reaching_defs);
-  sbitmap_vector_free (rd_out);
+  cprop_pavloc = sbitmap_vector_alloc (n_blocks, n_sets);
+  cprop_absaltered = sbitmap_vector_alloc (n_blocks, n_sets);
+
+  cprop_avin = sbitmap_vector_alloc (n_blocks, n_sets);
+  cprop_avout = sbitmap_vector_alloc (n_blocks, n_sets);
 }
 
-/* Add INSN to the kills of BB.  REGNO, set in BB, is killed by INSN.  */
+/* Free vars used by copy/const propagation.  */
 
 static void
-handle_rd_kill_set (rtx insn, int regno, basic_block bb)
+free_cprop_mem (void)
 {
-  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));
+  sbitmap_vector_free (cprop_pavloc);
+  sbitmap_vector_free (cprop_absaltered);
+  sbitmap_vector_free (cprop_avin);
+  sbitmap_vector_free (cprop_avout);
 }
 
-/* Compute the set of kill's for reaching definitions.  */
+/* For each block, compute whether X is transparent.  X is either an
+   expression or an assignment [though we don't care which, for this context
+   an assignment is treated as an expression].  For each block where an
+   element of X is modified, set (SET_P == 1) or reset (SET_P == 0) the INDX
+   bit in BMAP.  */
 
 static void
-compute_kill_rd (void)
+compute_transp (rtx x, int indx, sbitmap *bmap, int set_p)
 {
-  int cuid;
-  unsigned int regno;
-  int i;
+  int i, j;
   basic_block bb;
+  enum rtx_code code;
+  reg_set *r;
+  const char *fmt;
 
-  /* 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);
+  /* repeat is used to turn tail-recursion into iteration since GCC
+     can't do it when there's no return value.  */
+ repeat:
 
-         if (GET_CODE (insn) == CALL_INSN)
+  if (x == 0)
+    return;
+
+  code = GET_CODE (x);
+  switch (code)
+    {
+    case REG:
+      if (set_p)
+       {
+         if (REGNO (x) < FIRST_PSEUDO_REGISTER)
            {
-             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);
+             FOR_EACH_BB (bb)
+               if (TEST_BIT (reg_set_in_block[bb->index], REGNO (x)))
+                 SET_BIT (bmap[bb->index], indx);
            }
-
-         if (GET_CODE (pat) == PARALLEL)
+         else
            {
-             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);
-               }
+             for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
+               SET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
            }
-         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)
+      else
        {
-         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]);
+         if (REGNO (x) < FIRST_PSEUDO_REGISTER)
+           {
+             FOR_EACH_BB (bb)
+               if (TEST_BIT (reg_set_in_block[bb->index], REGNO (x)))
+                 RESET_BIT (bmap[bb->index], indx);
+           }
+         else
+           {
+             for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
+               RESET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
+           }
        }
-      passes++;
-    }
-
-  if (gcse_file)
-    fprintf (gcse_file, "reaching def computation: %d passes\n", passes);
-}
-\f
-/* 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;
+      return;
 
-  /* 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);
-}
+    case MEM:
+      FOR_EACH_BB (bb)
+       {
+         rtx list_entry = canon_modify_mem_list[bb->index];
 
-/* Return nonzero if expression X is killed in BB.  */
+         while (list_entry)
+           {
+             rtx dest, dest_addr;
 
-static int
-expr_killed_p (rtx x, basic_block bb)
-{
-  int i, j;
-  enum rtx_code code;
-  const char *fmt;
+             if (GET_CODE (XEXP (list_entry, 0)) == CALL_INSN)
+               {
+                 if (set_p)
+                   SET_BIT (bmap[bb->index], indx);
+                 else
+                   RESET_BIT (bmap[bb->index], indx);
+                 break;
+               }
+             /* LIST_ENTRY must be an INSN of some kind that sets memory.
+                Examine each hunk of memory that is modified.  */
 
-  if (x == 0)
-    return 1;
+             dest = XEXP (list_entry, 0);
+             list_entry = XEXP (list_entry, 1);
+             dest_addr = XEXP (list_entry, 0);
 
-  code = GET_CODE (x);
-  switch (code)
-    {
-    case REG:
-      return TEST_BIT (reg_set_in_block[bb->index], REGNO (x));
+             if (canon_true_dependence (dest, GET_MODE (dest), dest_addr,
+                                        x, rtx_addr_varies_p))
+               {
+                 if (set_p)
+                   SET_BIT (bmap[bb->index], indx);
+                 else
+                   RESET_BIT (bmap[bb->index], indx);
+                 break;
+               }
+             list_entry = XEXP (list_entry, 1);
+           }
+       }
 
-    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);
+      x = XEXP (x, 0);
+      goto repeat;
 
     case PC:
     case CC0: /*FIXME*/
@@ -3087,7 +2938,7 @@ expr_killed_p (rtx x, basic_block bb)
     case LABEL_REF:
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
-      return 0;
+      return;
 
     default:
       break;
@@ -3101,755 +2952,68 @@ expr_killed_p (rtx x, basic_block bb)
             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;
+           {
+             x = XEXP (x, i);
+             goto repeat;
+           }
+
+         compute_transp (XEXP (x, i), indx, bmap, set_p);
        }
       else if (fmt[i] == 'E')
        for (j = 0; j < XVECLEN (x, i); j++)
-         if (expr_killed_p (XVECEXP (x, i, j), bb))
-           return 1;
+         compute_transp (XVECEXP (x, i, j), indx, bmap, set_p);
     }
-
-  return 0;
 }
 
-/* Compute the set of available expressions killed in each basic block.  */
+/* Top level routine to do the dataflow analysis needed by copy/const
+   propagation.  */
 
 static void
-compute_ae_kill (sbitmap *ae_gen, sbitmap *ae_kill,
-                struct hash_table *expr_hash_table)
+compute_cprop_data (void)
 {
-  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);
-       }
+  compute_local_properties (cprop_absaltered, cprop_pavloc, NULL, &set_hash_table);
+  compute_available (cprop_pavloc, cprop_absaltered,
+                    cprop_avout, cprop_avin);
 }
 \f
-/* Actually perform the Classic GCSE optimizations.  */
+/* Copy/constant propagation.  */
 
-/* Return nonzero if occurrence OCCR of expression EXPR reaches block BB.
+/* Maximum number of register uses in an insn that we handle.  */
+#define MAX_USES 8
 
-   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.
+/* Table of uses found in an insn.
+   Allocated statically to avoid alloc/free complexity and overhead.  */
+static struct reg_use reg_use_table[MAX_USES];
 
-   VISITED is a pointer to a working buffer for tracking which BB's have
-   been visited.  It is NULL for the top-level call.
+/* Index into `reg_use_table' while building it.  */
+static int reg_use_count;
 
-   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.  */
+/* Set up a list of register numbers used in INSN.  The found uses are stored
+   in `reg_use_table'.  `reg_use_count' is initialized to zero before entry,
+   and contains the number of uses in the table upon exit.
 
-static int
-expr_reaches_here_p_work (struct occr *occr, struct expr *expr,
-                         basic_block bb, int check_self_loop, char *visited)
+   ??? If a register appears multiple times we will record it multiple times.
+   This doesn't hurt anything but it will slow things down.  */
+
+static void
+find_used_regs (rtx *xptr, void *data ATTRIBUTE_UNUSED)
 {
-  edge pred;
+  int i, j;
+  enum rtx_code code;
+  const char *fmt;
+  rtx x = *xptr;
 
-  for (pred = bb->pred; pred != NULL; pred = pred->pred_next)
+  /* repeat is used to turn tail-recursion into iteration since GCC
+     can't do it when there's no return value.  */
+ repeat:
+  if (x == 0)
+    return;
+
+  code = GET_CODE (x);
+  if (REG_P (x))
     {
-      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;
-}
-\f
-/* Compute copy/constant propagation working variables.  */
-
-/* Local properties of assignments.  */
-static sbitmap *cprop_pavloc;
-static sbitmap *cprop_absaltered;
-
-/* Global properties of assignments (computed from the local properties).  */
-static sbitmap *cprop_avin;
-static sbitmap *cprop_avout;
-
-/* Allocate vars used for copy/const propagation.  N_BLOCKS is the number of
-   basic blocks.  N_SETS is the number of sets.  */
-
-static void
-alloc_cprop_mem (int n_blocks, int n_sets)
-{
-  cprop_pavloc = sbitmap_vector_alloc (n_blocks, n_sets);
-  cprop_absaltered = sbitmap_vector_alloc (n_blocks, n_sets);
-
-  cprop_avin = sbitmap_vector_alloc (n_blocks, n_sets);
-  cprop_avout = sbitmap_vector_alloc (n_blocks, n_sets);
-}
-
-/* Free vars used by copy/const propagation.  */
-
-static void
-free_cprop_mem (void)
-{
-  sbitmap_vector_free (cprop_pavloc);
-  sbitmap_vector_free (cprop_absaltered);
-  sbitmap_vector_free (cprop_avin);
-  sbitmap_vector_free (cprop_avout);
-}
-
-/* For each block, compute whether X is transparent.  X is either an
-   expression or an assignment [though we don't care which, for this context
-   an assignment is treated as an expression].  For each block where an
-   element of X is modified, set (SET_P == 1) or reset (SET_P == 0) the INDX
-   bit in BMAP.  */
-
-static void
-compute_transp (rtx x, int indx, sbitmap *bmap, int set_p)
-{
-  int i, j;
-  basic_block bb;
-  enum rtx_code code;
-  reg_set *r;
-  const char *fmt;
-
-  /* repeat is used to turn tail-recursion into iteration since GCC
-     can't do it when there's no return value.  */
- repeat:
-
-  if (x == 0)
-    return;
-
-  code = GET_CODE (x);
-  switch (code)
-    {
-    case REG:
-      if (set_p)
-       {
-         if (REGNO (x) < FIRST_PSEUDO_REGISTER)
-           {
-             FOR_EACH_BB (bb)
-               if (TEST_BIT (reg_set_in_block[bb->index], REGNO (x)))
-                 SET_BIT (bmap[bb->index], indx);
-           }
-         else
-           {
-             for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
-               SET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
-           }
-       }
-      else
-       {
-         if (REGNO (x) < FIRST_PSEUDO_REGISTER)
-           {
-             FOR_EACH_BB (bb)
-               if (TEST_BIT (reg_set_in_block[bb->index], REGNO (x)))
-                 RESET_BIT (bmap[bb->index], indx);
-           }
-         else
-           {
-             for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
-               RESET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
-           }
-       }
-
-      return;
-
-    case MEM:
-      FOR_EACH_BB (bb)
-       {
-         rtx list_entry = canon_modify_mem_list[bb->index];
-
-         while (list_entry)
-           {
-             rtx dest, dest_addr;
-
-             if (GET_CODE (XEXP (list_entry, 0)) == CALL_INSN)
-               {
-                 if (set_p)
-                   SET_BIT (bmap[bb->index], indx);
-                 else
-                   RESET_BIT (bmap[bb->index], indx);
-                 break;
-               }
-             /* LIST_ENTRY must be an INSN of some kind that sets memory.
-                Examine each hunk of memory that is modified.  */
-
-             dest = XEXP (list_entry, 0);
-             list_entry = XEXP (list_entry, 1);
-             dest_addr = XEXP (list_entry, 0);
-
-             if (canon_true_dependence (dest, GET_MODE (dest), dest_addr,
-                                        x, rtx_addr_varies_p))
-               {
-                 if (set_p)
-                   SET_BIT (bmap[bb->index], indx);
-                 else
-                   RESET_BIT (bmap[bb->index], indx);
-                 break;
-               }
-             list_entry = XEXP (list_entry, 1);
-           }
-       }
-
-      x = XEXP (x, 0);
-      goto repeat;
-
-    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;
-
-    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)
-           {
-             x = XEXP (x, i);
-             goto repeat;
-           }
-
-         compute_transp (XEXP (x, i), indx, bmap, set_p);
-       }
-      else if (fmt[i] == 'E')
-       for (j = 0; j < XVECLEN (x, i); j++)
-         compute_transp (XVECEXP (x, i, j), indx, bmap, set_p);
-    }
-}
-
-/* Top level routine to do the dataflow analysis needed by copy/const
-   propagation.  */
-
-static void
-compute_cprop_data (void)
-{
-  compute_local_properties (cprop_absaltered, cprop_pavloc, NULL, &set_hash_table);
-  compute_available (cprop_pavloc, cprop_absaltered,
-                    cprop_avout, cprop_avin);
-}
-\f
-/* Copy/constant propagation.  */
-
-/* Maximum number of register uses in an insn that we handle.  */
-#define MAX_USES 8
-
-/* Table of uses found in an insn.
-   Allocated statically to avoid alloc/free complexity and overhead.  */
-static struct reg_use reg_use_table[MAX_USES];
-
-/* Index into `reg_use_table' while building it.  */
-static int reg_use_count;
-
-/* Set up a list of register numbers used in INSN.  The found uses are stored
-   in `reg_use_table'.  `reg_use_count' is initialized to zero before entry,
-   and contains the number of uses in the table upon exit.
-
-   ??? If a register appears multiple times we will record it multiple times.
-   This doesn't hurt anything but it will slow things down.  */
-
-static void
-find_used_regs (rtx *xptr, void *data ATTRIBUTE_UNUSED)
-{
-  int i, j;
-  enum rtx_code code;
-  const char *fmt;
-  rtx x = *xptr;
-
-  /* repeat is used to turn tail-recursion into iteration since GCC
-     can't do it when there's no return value.  */
- repeat:
-  if (x == 0)
-    return;
-
-  code = GET_CODE (x);
-  if (REG_P (x))
-    {
-      if (reg_use_count == MAX_USES)
-       return;
+      if (reg_use_count == MAX_USES)
+       return;
 
       reg_use_table[reg_use_count].reg_rtx = x;
       reg_use_count++;
@@ -5046,8 +4210,6 @@ alloc_pre_mem (int n_blocks, int n_exprs)
   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.  */
@@ -5071,14 +4233,9 @@ free_pre_mem (void)
     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.  */
@@ -5107,8 +4264,7 @@ compute_pre_data (void)
   /* Compute ae_kill for each basic block using:
 
      ~(TRANSP | COMP)
-
-     This is significantly faster than compute_ae_kill.  */
+  */
 
   FOR_EACH_BB (bb)
     {
@@ -5913,295 +5069,6 @@ compute_transpout (void)
     }
 }
 
-/* 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.  */
 
 /* Very busy expressions.  */
index 43b46e2cae7f2dd657d9354b499bd775f7b94f86..5c8e5a6fd0f13e773fdd9de70bc4e520a2519799 100644 (file)
@@ -1004,20 +1004,6 @@ rest_of_handle_jump_bypass (tree decl, rtx insns)
 #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)
@@ -1120,19 +1106,6 @@ rest_of_handle_cse (tree decl, rtx insns)
 
   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);
@@ -1547,9 +1520,6 @@ rest_of_compilation (tree decl)
   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
      future passes, allocate arrays whose dimensions involve the
index d5f7a1ec644b288f0fdfaa432d81b48bc10265c1..1041d020e1ab1d589a832546d3866ea231095d40 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2320,8 +2320,6 @@ extern void cannot_change_mode_set_regs (HARD_REG_SET *,
 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 *);