OSDN Git Service

* gcse.c (dump_hash_table): Fix whitespace in declaration.
authorlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 21 Mar 1999 20:49:10 +0000 (20:49 +0000)
committerlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 21 Mar 1999 20:49:10 +0000 (20:49 +0000)
(compute_transpout): Renamed from pre_compute_transpout.
(compute_pre_*): Deleted
(pre_expr_reaches_here_p): New argument, CHECK_PRE_COMP.  All
callers changed.
(insert_insn_end_bb): Renamed from pre_insert_insn.
(pre_*): Delete unused variables.  Only leave local properties and
global redundant/optimal computation points.
(alloc_pre_mem, free_pre_mem): Corresponding changes.
(compute_pre_data): Simplify and call pre_lcm to run the lazy
code motion dataflow analysis.
(pre_insert, pre_insert_copies, pre_delete): Revamp to use LCM
based redundant and optimal computation points.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@25886 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/gcse.c

index 97cdf17..b93a97e 100644 (file)
@@ -1,5 +1,19 @@
 Sun Mar 21 17:33:48 1999  Jeffrey A Law  (law@cygnus.com)
 
+       * gcse.c (dump_hash_table): Fix whitespace in declaration.
+       (compute_transpout): Renamed from pre_compute_transpout.
+       (compute_pre_*): Deleted
+       (pre_expr_reaches_here_p): New argument, CHECK_PRE_COMP.  All
+       callers changed.
+       (insert_insn_end_bb): Renamed from pre_insert_insn.
+       (pre_*): Delete unused variables.  Only leave local properties and
+       global redundant/optimal computation points.
+       (alloc_pre_mem, free_pre_mem): Corresponding changes.
+       (compute_pre_data): Simplify and call pre_lcm to run the lazy
+       code motion dataflow analysis.
+       (pre_insert, pre_insert_copies, pre_delete): Revamp to use LCM
+       based redundant and optimal computation points.
+
        * basic-block.h (pre_lcm, pre_rev_lcm): Declare.
 
        * toplev.c (main): A debug option without a level defaults to
index a522755..dc970cd 100644 (file)
@@ -550,7 +550,8 @@ static void compute_set_hash_table    PROTO ((void));
 static void alloc_expr_hash_table     PROTO ((int));
 static void free_expr_hash_table      PROTO ((void));
 static void compute_expr_hash_table   PROTO ((void));
-static void dump_hash_table       PROTO ((FILE *, const char *, struct expr **, int, int));
+static void dump_hash_table       PROTO ((FILE *, const char *, struct expr **,
+                                          int, int));
 static struct expr *lookup_expr       PROTO ((rtx));
 static struct expr *lookup_set PROTO ((int, rtx));
 static struct expr *next_set     PROTO ((int, struct expr *));
@@ -564,6 +565,7 @@ static void mark_oprs_set        PROTO ((rtx));
 static void alloc_cprop_mem       PROTO ((int, int));
 static void free_cprop_mem         PROTO ((void));
 static void compute_transp         PROTO ((rtx, int, sbitmap *, int));
+static void compute_transpout      PROTO ((void));
 static void compute_local_properties  PROTO ((sbitmap *, sbitmap *,
                                              sbitmap *, int));
 static void compute_cprop_avinout     PROTO ((void));
@@ -577,14 +579,10 @@ static int one_cprop_pass      PROTO ((int, int));
 
 static void alloc_pre_mem           PROTO ((int, int));
 static void free_pre_mem             PROTO ((void));
-static void compute_pre_avinout       PROTO ((void));
-static void compute_pre_antinout      PROTO ((void));
-static void compute_pre_pavinout      PROTO ((void));
-static void compute_pre_ppinout       PROTO ((void));
 static void compute_pre_data     PROTO ((void));
-static int pre_expr_reaches_here_p    PROTO ((struct occr *, struct expr *,
-                                             int, char *));
-static void pre_insert_insn       PROTO ((struct expr *, int));
+static int pre_expr_reaches_here_p    PROTO ((int, struct expr *,
+                                             int, int, char *));
+static void insert_insn_end_bb PROTO ((struct expr *, int, int));
 static void pre_insert         PROTO ((struct expr **));
 static void pre_insert_copy_insn      PROTO ((struct expr *, rtx));
 static void pre_insert_copies   PROTO ((void));
@@ -3924,339 +3922,63 @@ one_cprop_pass (pass, alter_jumps)
   return changed;
 }
 \f
-/* Compute PRE working variables.  */
+/* Compute PRE+LCM working variables.  */
 
 /* Local properties of expressions.  */
 /* Nonzero for expressions that are transparent in the block.  */
-static sbitmap *pre_transp;
-/* Nonzero for expressions that are computed (available) in the block.  */
-static sbitmap *pre_comp;
-/* Nonzero for expressions that are locally anticipatable in the block.  */
-static sbitmap *pre_antloc;
-
-/* Global properties (computed from the expression local properties).  */
-/* Nonzero for expressions that are available on block entry/exit.  */
-static sbitmap *pre_avin;
-static sbitmap *pre_avout;
-/* Nonzero for expressions that are anticipatable on block entry/exit.  */
-static sbitmap *pre_antin;
-static sbitmap *pre_antout;
-/* Nonzero for expressions that are partially available on block entry/exit.  */
-static sbitmap *pre_pavin;
-static sbitmap *pre_pavout;
-/* Nonzero for expressions that are "placement possible" on block entry/exit.  */
-static sbitmap *pre_ppin;
-static sbitmap *pre_ppout;
+static sbitmap *transp;
 
 /* Nonzero for expressions that are transparent at the end of the block.
    This is only zero for expressions killed by abnormal critical edge
    created by a calls.  */
-static sbitmap *pre_transpout;
+static sbitmap *transpout;
 
-/* Used while performing PRE to denote which insns are redundant.  */
-static sbitmap pre_redundant;
-
-/* Allocate vars used for PRE analysis.  */
-
-static void
-alloc_pre_mem (n_blocks, n_exprs)
-     int n_blocks, n_exprs;
-{
-  pre_transp = sbitmap_vector_alloc (n_blocks, n_exprs);
-  pre_comp = sbitmap_vector_alloc (n_blocks, n_exprs);
-  pre_antloc = sbitmap_vector_alloc (n_blocks, n_exprs);
+/* Nonzero for expressions that are computed (available) in the block.  */
+static sbitmap *comp;
 
-  pre_avin = sbitmap_vector_alloc (n_blocks, n_exprs);
-  pre_avout = sbitmap_vector_alloc (n_blocks, n_exprs);
-  pre_antin = sbitmap_vector_alloc (n_blocks, n_exprs);
-  pre_antout = sbitmap_vector_alloc (n_blocks, n_exprs);
+/* Nonzero for expressions that are locally anticipatable in the block.  */
+static sbitmap *antloc;
 
-  pre_pavin = sbitmap_vector_alloc (n_blocks, n_exprs);
-  pre_pavout = sbitmap_vector_alloc (n_blocks, n_exprs);
-  pre_ppin = sbitmap_vector_alloc (n_blocks, n_exprs);
-  pre_ppout = sbitmap_vector_alloc (n_blocks, n_exprs);
+/* Nonzero for expressions where this block is an optimal computation
+   point.  */
+static sbitmap *pre_optimal;
 
-  pre_transpout = sbitmap_vector_alloc (n_blocks, n_exprs);
-}
+/* Nonzero for expressions which are redundant in a particular block.  */
+static sbitmap *pre_redundant;
 
-/* Free vars used for PRE analysis.  */
+static sbitmap *temp_bitmap;
 
-static void
-free_pre_mem ()
-{
-  free (pre_transp);
-  free (pre_comp);
-  free (pre_antloc);
-  free (pre_avin);
-  free (pre_avout);
-  free (pre_antin);
-  free (pre_antout);
-
-  free (pre_pavin);
-  free (pre_pavout);
-  free (pre_ppin);
-  free (pre_ppout);
-  free (pre_transpout);
-}
+/* Redundant insns.  */
+static sbitmap pre_redundant_insns;
 
-/* Compute expression availability at entrance and exit of each block.  */
-
-static void
-compute_pre_avinout ()
-{
-  int bb, changed, passes;
-
-  sbitmap_zero (pre_avin[0]);
-  sbitmap_vector_ones (pre_avout, n_basic_blocks);
-
-  passes = 0;
-  changed = 1;
-  while (changed)
-    {
-      changed = 0;
-      for (bb = 0; bb < n_basic_blocks; bb++)
-       {
-         if (bb != 0)
-           sbitmap_intersect_of_predecessors (pre_avin[bb], pre_avout,
-                                              bb, s_preds);
-         changed |= sbitmap_a_or_b_and_c (pre_avout[bb], pre_comp[bb],
-                                          pre_transp[bb], pre_avin[bb]);
-       }
-      passes++;
-    }
-
-  if (gcse_file)
-    fprintf (gcse_file, "avail expr computation: %d passes\n", passes);
-}
-
-/* Compute expression anticipatability at entrance and exit of each block.  */
+/* Allocate vars used for PRE analysis.  */
 
 static void
-compute_pre_antinout ()
+alloc_pre_mem (n_blocks, n_exprs)
+     int n_blocks, n_exprs;
 {
-  int bb, changed, passes;
-
-  sbitmap_zero (pre_antout[n_basic_blocks - 1]);
-  sbitmap_vector_ones (pre_antin, n_basic_blocks);
-
-  passes = 0;
-  changed = 1;
-  while (changed)
-    {
-      changed = 0;
-      /* We scan the blocks in the reverse order to speed up
-        the convergence.  */
-      for (bb = n_basic_blocks - 1; bb >= 0; bb--)
-       {
-         if (bb != n_basic_blocks - 1)
-           sbitmap_intersect_of_successors (pre_antout[bb], pre_antin,
-                                            bb, s_succs);
-         changed |= sbitmap_a_or_b_and_c (pre_antin[bb], pre_antloc[bb],
-                                          pre_transp[bb], pre_antout[bb]);
-       }
-      passes++;
-    }
-
-  if (gcse_file)
-    fprintf (gcse_file, "antic expr computation: %d passes\n", passes);
+  transp = sbitmap_vector_alloc (n_blocks, n_exprs);
+  comp = sbitmap_vector_alloc (n_blocks, n_exprs);
+  antloc = sbitmap_vector_alloc (n_blocks, n_exprs);
+
+  temp_bitmap = sbitmap_vector_alloc (n_blocks, n_exprs);
+  pre_optimal = sbitmap_vector_alloc (n_blocks, n_exprs);
+  pre_redundant = sbitmap_vector_alloc (n_blocks, n_exprs);
+  transpout = sbitmap_vector_alloc (n_blocks, n_exprs);
 }
 
-/* Compute expression partial availability at entrance and exit of
-   each block.  */
-
-static void
-compute_pre_pavinout ()
-{
-  int bb, changed, passes;
-
-  sbitmap_zero (pre_pavin[0]);
-  sbitmap_vector_zero (pre_pavout, n_basic_blocks);
-
-  passes = 0;
-  changed = 1;
-  while (changed)
-    {
-      changed = 0;
-      for (bb = 0; bb < n_basic_blocks; bb++)
-       {
-         if (bb != 0)
-           sbitmap_union_of_predecessors (pre_pavin[bb], pre_pavout,
-                                          bb, s_preds);
-         changed |= sbitmap_a_or_b_and_c (pre_pavout[bb], pre_comp[bb],
-                                          pre_transp[bb], pre_pavin[bb]);
-       }
-      passes++;
-    }
-
-  if (gcse_file)
-    fprintf (gcse_file, "partially avail expr computation: %d passes\n", passes);
-}
-
-/* Compute transparent outgoing information for each block.
-
-   An expression is transparent to an edge unless it is killed by
-   the edge itself.  This can only happen with abnormal control flow,
-   when the edge is traversed through a call.  This happens with
-   non-local labels and exceptions.
-
-   This would not be necessary if we split the edge.  While this is
-   normally impossible for abnormal critical edges, with some effort
-   it should be possible with exception handling, since we still have
-   control over which handler should be invoked.  But due to increased
-   EH table sizes, this may not be worthwhile.  */
-
-static void
-compute_pre_transpout ()
-{
-  int bb;
-
-  sbitmap_vector_ones (pre_transpout, n_basic_blocks);
-
-  for (bb = 0; bb < n_basic_blocks; ++bb)
-    {
-      int i;
-
-      /* Note that flow inserted a nop a the end of basic blocks that
-        end in call instructions for reasons other than abnormal
-        control flow.  */
-      if (GET_CODE (BLOCK_END (bb)) != CALL_INSN)
-       continue;
-
-      for (i = 0; i < expr_hash_table_size; i++)
-       {
-         struct expr *expr;
-         for (expr = expr_hash_table[i]; expr ; expr = expr->next_same_hash)
-           if (GET_CODE (expr->expr) == MEM)
-             {
-               rtx addr = XEXP (expr->expr, 0);
-
-               if (GET_CODE (addr) == SYMBOL_REF
-                   && CONSTANT_POOL_ADDRESS_P (addr))
-                 continue;
-               
-               /* ??? Optimally, we would use interprocedural alias
-                  analysis to determine if this mem is actually killed
-                  by this call.  */
-               RESET_BIT (pre_transpout[bb], expr->bitmap_index);
-             }
-       }
-    }
-}   
-
-/* Compute "placement possible" information on entrance and exit of
-   each block.
-
-   From Fred Chow's Thesis:
-   A computation `e' is PP at a point `p' if it is anticipated at `p' and
-   all the anticipated e's can be rendered redundant by zero or more
-   insertions at that point and some other points in the procedure, and
-   these insertions satisfy the conditions that the insertions are always
-   at points that `e' is anticipated and the first anticipated e's after the
-   insertions are rendered redundant.  */
+/* Free vars used for PRE analysis.  */
 
 static void
-compute_pre_ppinout ()
+free_pre_mem ()
 {
-  int bb, i, changed, size, passes;
-
-  sbitmap_vector_ones (pre_ppin, n_basic_blocks);
-  /* ??? Inefficient as we set pre_ppin[0] twice, but simple.  */
-  sbitmap_zero (pre_ppin[0]);
-
-  sbitmap_vector_ones (pre_ppout, n_basic_blocks);
-  /* ??? Inefficient as we set pre_ppout[n_basic_blocks-1] twice, but simple.  */
-  sbitmap_zero (pre_ppout[n_basic_blocks - 1]);
-
-  size = pre_ppin[0]->size;
-  passes = 0;
-  changed = 1;
-  while (changed)
-    {
-      changed = 0;
-      for (bb = 1; bb < n_basic_blocks; bb++)
-       {
-         sbitmap_ptr antin = pre_antin[bb]->elms;
-         sbitmap_ptr pavin = pre_pavin[bb]->elms;
-         sbitmap_ptr antloc = pre_antloc[bb]->elms;
-         sbitmap_ptr transp = pre_transp[bb]->elms;
-         sbitmap_ptr ppout = pre_ppout[bb]->elms;
-         sbitmap_ptr ppin = pre_ppin[bb]->elms;
-
-         for (i = 0; i < size; i++)
-           {
-             int_list_ptr pred;
-             SBITMAP_ELT_TYPE tmp = *antin & *pavin & (*antloc | (*transp & *ppout));
-             SBITMAP_ELT_TYPE pred_val = (SBITMAP_ELT_TYPE) -1;
-
-             for (pred = s_preds[bb]; pred != NULL; pred = pred->next)
-               {
-                 int pred_bb = INT_LIST_VAL (pred);
-                 sbitmap_ptr ppout_j,avout_j;
-
-                 if (pred_bb == ENTRY_BLOCK)
-                   continue;
-
-                 /* If this is a back edge, propagate info along the back
-                    edge to allow for loop invariant code motion.
-
-                    See FOLLOW_BACK_EDGES at the top of this file for a longer
-                    discussion about loop invariant code motion in pre.  */
-                 if (! FOLLOW_BACK_EDGES
-                     && (INSN_CUID (BLOCK_HEAD (bb))
-                         < INSN_CUID (BLOCK_END (pred_bb))))
-                   {
-                     pred_val = 0;
-                   }
-                 else
-                   {
-                     ppout_j = pre_ppout[pred_bb]->elms + i;
-                     avout_j = pre_avout[pred_bb]->elms + i;
-                     pred_val &= *ppout_j | *avout_j;
-                   }
-               }
-             tmp &= pred_val;
-             *ppin = tmp;
-             antin++; pavin++; antloc++; transp++; ppout++; ppin++;
-           }
-       }
-
-      for (bb = 0; bb < n_basic_blocks - 1; bb++)
-       {
-         sbitmap_ptr ppout = pre_ppout[bb]->elms;
-         sbitmap_ptr transpout = pre_transpout[bb]->elms;
-
-         for (i = 0; i < size; i++)
-           {
-             int_list_ptr succ;
-             SBITMAP_ELT_TYPE tmp = *transpout;
-
-             for (succ = s_succs[bb]; succ != NULL; succ = succ->next)
-               {
-                 int succ_bb = INT_LIST_VAL (succ);
-                 sbitmap_ptr ppin;
-
-                 if (succ_bb == EXIT_BLOCK)
-                   continue;
-
-                 ppin = pre_ppin[succ_bb]->elms + i;
-                 tmp &= *ppin;
-               }
-
-             if (*ppout != tmp)
-               {
-                 changed = 1;
-                 *ppout = tmp;
-               }
-
-             ppout++; transpout++;
-           }
-       }
-
-      passes++;
-    }
+  free (transp);
+  free (comp);
+  free (antloc);
 
-  if (gcse_file)
-    fprintf (gcse_file, "placement possible computation: %d passes\n", passes);
+  free (pre_optimal);
+  free (pre_redundant);
+  free (transpout);
 }
 
 /* Top level routine to do the dataflow analysis needed by PRE.  */
@@ -4264,23 +3986,24 @@ compute_pre_ppinout ()
 static void
 compute_pre_data ()
 {
-  compute_local_properties (pre_transp, pre_comp, pre_antloc, 0);
-  compute_pre_avinout ();
-  compute_pre_antinout ();
-  compute_pre_pavinout ();
-  compute_pre_transpout ();
-  compute_pre_ppinout ();
-  if (gcse_file)
-    fprintf (gcse_file, "\n");
+  compute_local_properties (transp, comp, antloc, 0);
+  compute_transpout ();
+  pre_lcm (n_basic_blocks, n_exprs, s_preds, s_succs, transp,
+          antloc, pre_redundant, pre_optimal);
 }
+
 \f
 /* PRE utilities */
 
-/* Return non-zero if occurrence OCCR of expression EXPR reaches block BB.
+/* Return non-zero if an occurrence of expression EXPR in OCCR_BB would reach
+   block BB.
 
    VISITED is a pointer to a working buffer for tracking which BB's have
    been visited.  It is NULL for the top-level call.
 
+   CHECK_PRE_COMP controls whether or not we check for a computation of
+   EXPR in OCCR_BB.
+
    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
@@ -4289,10 +4012,11 @@ compute_pre_data ()
    the closest such expression.  */
 
 static int
-pre_expr_reaches_here_p (occr, expr, bb, visited)
-     struct occr *occr;
+pre_expr_reaches_here_p (occr_bb, expr, bb, check_pre_comp, visited)
+     int occr_bb;
      struct expr *expr;
      int bb;
+     int check_pre_comp;
      char *visited;
 {
   int_list_ptr pred;
@@ -4314,23 +4038,25 @@ pre_expr_reaches_here_p (occr, expr, bb, visited)
          /* Nothing to do.  */
        }
       /* Does this predecessor generate this expression?  */
-      else if (TEST_BIT (pre_comp[pred_bb], expr->bitmap_index))
+      else if ((!check_pre_comp && occr_bb == pred_bb)
+              || TEST_BIT (comp[pred_bb], 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)
+         if (occr_bb == pred_bb)
            return 1;
          visited[pred_bb] = 1;
        }
       /* Ignore this predecessor if it kills the expression.  */
-      else if (! TEST_BIT (pre_transp[pred_bb], expr->bitmap_index))
+      else if (! TEST_BIT (transp[pred_bb], expr->bitmap_index))
        visited[pred_bb] = 1;
       /* Neither gen nor kill.  */
       else
        {
          visited[pred_bb] = 1;
-         if (pre_expr_reaches_here_p (occr, expr, pred_bb, visited))
+         if (pre_expr_reaches_here_p (occr_bb, expr, pred_bb,
+                                      check_pre_comp, visited))
            return 1;
        }
     }
@@ -4339,20 +4065,33 @@ pre_expr_reaches_here_p (occr, expr, bb, visited)
   return 0;
 }
 \f
-/* Add EXPR to the end of basic block BB.  */
+/* Add EXPR to the end of basic block BB.
+
+   This is used by both the PRE and code hoisting.
+
+   For PRE, we want to verify that the expr is either transparent
+   or locally anticipatable in the target block.  This check makes
+   no sense for code hoisting.  */
 
 static void
-pre_insert_insn (expr, bb)
+insert_insn_end_bb (expr, bb, pre)
      struct expr *expr;
      int bb;
+     int pre;
 {
   rtx insn = BLOCK_END (bb);
   rtx new_insn;
   rtx reg = expr->reaching_reg;
   int regno = REGNO (reg);
-  rtx pat;
+  rtx pat, copied_expr;
+  rtx first_new_insn;
 
-  pat = gen_rtx_SET (VOIDmode, reg, copy_rtx (expr->expr));
+  start_sequence ();
+  copied_expr = copy_rtx (expr->expr);
+  emit_move_insn (reg, copied_expr);
+  first_new_insn = get_insns ();
+  pat = gen_sequence ();
+  end_sequence ();
 
   /* If the last insn is a jump, insert EXPR in front [taking care to
      handle cc0, etc. properly].  */
@@ -4387,7 +4126,6 @@ pre_insert_insn (expr, bb)
 #endif
       /* FIXME: What if something in cc0/jump uses value set in new insn?  */
       new_insn = emit_insn_before (pat, insn);
-      add_label_notes (SET_SRC (pat), new_insn);
       if (BLOCK_HEAD (bb) == insn)
        BLOCK_HEAD (bb) = new_insn;
     }
@@ -4405,11 +4143,11 @@ pre_insert_insn (expr, bb)
         presumtion that we'll get better code elsewhere as well.  */
 
       /* It should always be the case that we can put these instructions
-        anywhere in the basic block.  Check this.  */
-      /* ??? Well, it would be the case if we'd split all critical edges.
-        Since we didn't, we may very well abort.  */
-      if (!TEST_BIT (pre_antloc[bb], expr->bitmap_index)
-         && !TEST_BIT (pre_transp[bb], expr->bitmap_index))
+        anywhere in the basic block with performing PRE optimizations.
+        Check this.  */
+      if (pre
+         && !TEST_BIT (antloc[bb], expr->bitmap_index)
+          && !TEST_BIT (transp[bb], expr->bitmap_index))
        abort ();
 
       /* Since different machines initialize their parameter registers
@@ -4449,62 +4187,101 @@ pre_insert_insn (expr, bb)
   else
     {
       new_insn = emit_insn_after (pat, insn);
-      add_label_notes (SET_SRC (pat), new_insn);
       BLOCK_END (bb) = new_insn;
     }
 
-  /* Keep block number table up to date.  */
-  set_block_num (new_insn, bb);
-  /* Keep register set table up to date.  */
-  record_one_set (regno, new_insn);
+  /* Keep block number table up to date.
+     Note, PAT could be a multiple insn sequence, we have to make
+     sure that each insn in the sequence is handled.  */
+  if (GET_CODE (pat) == SEQUENCE)
+    {
+      int i;
+
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       {
+         rtx insn = XVECEXP (pat, 0, i);
+         set_block_num (insn, bb);
+         if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+           add_label_notes (PATTERN (insn), new_insn);
+         record_set_insn = insn;
+         note_stores (PATTERN (insn), record_set_info);
+       }
+    }
+  else
+    {
+      add_label_notes (SET_SRC (pat), new_insn);
+      set_block_num (new_insn, bb);
+      /* Keep register set table up to date.  */
+      record_one_set (regno, new_insn);
+    }
 
   gcse_create_count++;
 
   if (gcse_file)
     {
-      fprintf (gcse_file, "PRE: end of bb %d, insn %d, copying expression %d to reg %d\n",
+      fprintf (gcse_file, "PRE/HOIST: end of bb %d, insn %d, copying expression %d to reg %d\n",
               bb, INSN_UID (new_insn), expr->bitmap_index, regno);
     }
 }
 
 /* Insert partially redundant expressions at the ends of appropriate basic
-   blocks making them now redundant.  */
+   blocks making them fully redundant.  */
 
 static void
 pre_insert (index_map)
      struct expr **index_map;
 {
-  int bb, i, size;
+  int bb, i, set_size;
+  sbitmap *inserted;
+
+  /* Compute INSERT = PRE_OPTIMAL & ~PRE_REDUNDANT. 
+     Where INSERT is nonzero, we add the expression at the end of the basic
+     block if it reaches any of the deleted expressions.  */
 
-  /* Compute INSERT = PPOUT & (~AVOUT) & (~PPIN | ~TRANSP) for each
-     expression.  Where INSERT == TRUE, add the expression at the end of
-     the basic block.  */
+  set_size = pre_optimal[0]->size;
+  inserted = sbitmap_vector_alloc (n_basic_blocks, n_exprs);
+  sbitmap_vector_zero (inserted, n_basic_blocks);
 
-  size = pre_ppout[0]->size;
   for (bb = 0; bb < n_basic_blocks; bb++)
     {
       int indx;
-      sbitmap_ptr ppout = pre_ppout[bb]->elms;
-      sbitmap_ptr avout = pre_avout[bb]->elms;
-      sbitmap_ptr ppin = pre_ppin[bb]->elms;
-      sbitmap_ptr transp = pre_transp[bb]->elms;
-
-      for (i = indx = 0;
-          i < size;
-          i++, indx += SBITMAP_ELT_BITS, ppout++, avout++, ppin++, transp++)
+
+      /* This computes the number of potential insertions we need.  */
+      sbitmap_not (temp_bitmap[bb], pre_redundant[bb]);
+      sbitmap_a_and_b (temp_bitmap[bb], temp_bitmap[bb], pre_optimal[bb]);
+
+      /* TEMP_BITMAP[bb] now contains a bitmap of the expressions that we need
+        to insert at the end of this basic block.  */
+      for (i = indx = 0; i < set_size; i++, indx += SBITMAP_ELT_BITS)
        {
+         SBITMAP_ELT_TYPE insert = temp_bitmap[bb]->elms[i];
          int j;
-         SBITMAP_ELT_TYPE insert = *ppout & (~*avout) & (~*ppin | ~*transp);
 
-         for (j = indx; insert != 0 && j < n_exprs; j++, insert >>= 1)
+         for (j = indx; insert && j < n_exprs; j++, insert >>= 1)
            {
-             if ((insert & 1) != 0
-                 /* If the basic block isn't reachable, PPOUT will be TRUE.
-                    However, we don't want to insert a copy here because the
-                    expression may not really be redundant.  So only insert
-                    an insn if the expression was deleted.  */
-                 && index_map[j]->reaching_reg != NULL)
-               pre_insert_insn (index_map[j], bb);
+             if ((insert & 1) != 0 && index_map[j]->reaching_reg != NULL_RTX)
+               {
+                 struct expr *expr = index_map[j];
+                 struct occr *occr;
+
+                 /* Now look at each deleted occurence of this expression.  */
+                 for (occr = expr->antic_occr; occr != NULL; occr = occr->next)
+                   {
+                     if (! occr->deleted_p)
+                       continue;
+
+                     /* Insert this expression at the end of BB if it would
+                        reach the deleted occurence.  */
+                     if (!TEST_BIT (inserted[bb], j)
+                         && pre_expr_reaches_here_p (bb, expr,
+                                                  BLOCK_NUM (occr->insn), 0,
+                                                  NULL))
+                       {
+                         SET_BIT (inserted[bb], j);
+                         insert_insn_end_bb (index_map[j], bb, 1);
+                       }
+                   }
+               }
            }
        }
     }
@@ -4548,7 +4325,12 @@ pre_insert_copy_insn (expr, insn)
 static void
 pre_insert_copies ()
 {
-  int i;
+  int i, bb;
+
+  for (bb = 0; bb < n_basic_blocks; bb++)
+    {
+      sbitmap_a_and_b (temp_bitmap[bb], pre_optimal[bb], pre_redundant[bb]);
+    }
 
   /* For each available expression in the table, copy the result to
      `reaching_reg' if the expression reaches a deleted one.
@@ -4583,17 +4365,21 @@ pre_insert_copies ()
              for (avail = expr->avail_occr; avail != NULL; avail = avail->next)
                {
                  rtx insn = avail->insn;
+                 int bb = BLOCK_NUM (insn);
+
+                 if (!TEST_BIT (temp_bitmap[bb], expr->bitmap_index))
+                   continue;
 
                  /* No need to handle this one if handled already.  */
                  if (avail->copied_p)
                    continue;
                  /* Don't handle this one if it's a redundant one.  */
-                 if (TEST_BIT (pre_redundant, INSN_CUID (insn)))
+                 if (TEST_BIT (pre_redundant_insns, INSN_CUID (insn)))
                    continue;
                  /* Or if the expression doesn't reach the deleted one.  */
-                 if (! pre_expr_reaches_here_p (avail, expr,
+                 if (! pre_expr_reaches_here_p (BLOCK_NUM (avail->insn), expr,
                                                 BLOCK_NUM (occr->insn),
-                                                NULL))
+                                                1, NULL))
                    continue;
 
                  /* Copy the result of avail to reaching_reg.  */
@@ -4606,7 +4392,6 @@ pre_insert_copies ()
 }
 
 /* Delete redundant computations.
-   These are ones that satisy ANTLOC & PPIN.
    Deletion is done by changing the insn to copy the `reaching_reg' of
    the expression into the result of the SET.  It is left to later passes
    (cprop, cse2, flow, combine, regmove) to propagate the copy or eliminate it.
@@ -4616,7 +4401,15 @@ pre_insert_copies ()
 static int
 pre_delete ()
 {
-  int i, changed;
+  int i, bb, changed;
+
+  /* Compute the expressions which are redundant and need to be replaced by
+     copies from the reaching reg to the target reg.  */
+  for (bb = 0; bb < n_basic_blocks; bb++)
+    {
+      sbitmap_not (temp_bitmap[bb], pre_optimal[bb]);
+      sbitmap_a_and_b (temp_bitmap[bb], temp_bitmap[bb], pre_redundant[bb]);
+    }
 
   changed = 0;
   for (i = 0; i < expr_hash_table_size; i++)
@@ -4636,9 +4429,8 @@ pre_delete ()
              rtx insn = occr->insn;
              rtx set;
              int bb = BLOCK_NUM (insn);
-             sbitmap ppin = pre_ppin[bb];
 
-             if (TEST_BIT (ppin, indx))
+             if (TEST_BIT (temp_bitmap[bb], indx))
                {
                  set = single_set (insn);
                  if (! set)
@@ -4662,14 +4454,15 @@ pre_delete ()
                                       expr->reaching_reg, 0))
                    {
                      occr->deleted_p = 1;
-                     SET_BIT (pre_redundant, INSN_CUID (insn));
+                     SET_BIT (pre_redundant_insns, INSN_CUID (insn));
                      changed = 1;
                      gcse_subst_count++;
                    }
 
                  if (gcse_file)
                    {
-                     fprintf (gcse_file, "PRE: redundant insn %d (expression %d) in bb %d, reaching reg is %d\n",
+                     fprintf (gcse_file,
+                              "PRE: redundant insn %d (expression %d) in bb %d, reaching reg is %d\n",
                               INSN_UID (insn), indx, bb, REGNO (expr->reaching_reg));
                    }
                }
@@ -4684,10 +4477,9 @@ pre_delete ()
    This is called by one_pre_gcse_pass after all the dataflow analysis
    has been done.
 
-   This is based on the original Morel-Renvoise paper and Fred Chow's thesis.
-
-   The M-R paper uses "TRANSP" to describe an expression as being transparent
-   in a block where as Chow's thesis uses "ALTERED".  We use TRANSP.
+   This is based on the original Morel-Renvoise paper Fred Chow's thesis,
+   and lazy code motion from Knoop, Ruthing and Steffen as described in
+   Advanced Compiler Design and Implementation.
 
    ??? A new pseudo reg is created to hold the reaching expression.
    The nice thing about the classical approach is that it would try to
@@ -4722,8 +4514,8 @@ pre_gcse ()
     }
 
   /* Reset bitmap used to track which insns are redundant.  */
-  pre_redundant = sbitmap_alloc (max_cuid);
-  sbitmap_zero (pre_redundant);
+  pre_redundant_insns = sbitmap_alloc (max_cuid);
+  sbitmap_zero (pre_redundant_insns);
 
   /* Delete the redundant insns first so that
      - we know what register to use for the new insns and for the other
@@ -4739,7 +4531,7 @@ pre_gcse ()
      specially allocated pseudo-reg that reaches the redundant expression.  */
   pre_insert_copies ();
 
-  free (pre_redundant);
+  free (pre_redundant_insns);
 
   return changed;
 }
@@ -4824,3 +4616,54 @@ add_label_notes (x, insn)
          add_label_notes (XVECEXP (x, i, j), insn);
     }
 }
+
+/* Compute transparent outgoing information for each block.
+
+   An expression is transparent to an edge unless it is killed by
+   the edge itself.  This can only happen with abnormal control flow,
+   when the edge is traversed through a call.  This happens with
+   non-local labels and exceptions.
+
+   This would not be necessary if we split the edge.  While this is
+   normally impossible for abnormal critical edges, with some effort
+   it should be possible with exception handling, since we still have
+   control over which handler should be invoked.  But due to increased
+   EH table sizes, this may not be worthwhile.  */
+
+static void
+compute_transpout ()
+{
+  int bb;
+
+  sbitmap_vector_ones (transpout, n_basic_blocks);
+
+  for (bb = 0; bb < n_basic_blocks; ++bb)
+    {
+      int i;
+
+      /* Note that flow inserted a nop a the end of basic blocks that
+        end in call instructions for reasons other than abnormal
+        control flow.  */
+      if (GET_CODE (BLOCK_END (bb)) != CALL_INSN)
+       continue;
+
+      for (i = 0; i < expr_hash_table_size; i++)
+       {
+         struct expr *expr;
+         for (expr = expr_hash_table[i]; expr ; expr = expr->next_same_hash)
+           if (GET_CODE (expr->expr) == MEM)
+             {
+               rtx addr = XEXP (expr->expr, 0);
+
+               if (GET_CODE (addr) == SYMBOL_REF
+                   && CONSTANT_POOL_ADDRESS_P (addr))
+                 continue;
+               
+               /* ??? Optimally, we would use interprocedural alias
+                  analysis to determine if this mem is actually killed
+                  by this call.  */
+               RESET_BIT (transpout[bb], expr->bitmap_index);
+             }
+       }
+    }
+}