OSDN Git Service

* c-parse.in (cast_expr): Constify.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 72a1ff6..d729cb2 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -25,16 +25,19 @@ Boston, MA 02111-1307, USA.  */
 #include <setjmp.h>
 
 #include "rtl.h"
+#include "tm_p.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "flags.h"
 #include "real.h"
 #include "insn-config.h"
 #include "recog.h"
+#include "function.h"
 #include "expr.h"
 #include "toplev.h"
 #include "output.h"
-#include "splay-tree.h"
+#include "hashtab.h"
+#include "ggc.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -42,12 +45,14 @@ Boston, MA 02111-1307, USA.  */
    expressions encountered with the cheapest equivalent expression.
 
    It is too complicated to keep track of the different possibilities
-   when control paths merge; so, at each label, we forget all that is
-   known and start fresh.  This can be described as processing each
-   basic block separately.  Note, however, that these are not quite
-   the same as the basic blocks found by a later pass and used for
-   data flow analysis and register packing.  We do not need to start fresh
-   after a conditional jump instruction if there is no label there.
+   when control paths merge in this code; so, at each label, we forget all
+   that is known and start fresh.  This can be described as processing each
+   extended basic block separately.  We have a separate pass to perform
+   global CSE.
+
+   Note CSE can turn a conditional or computed jump into a nop or
+   an unconditional jump.  When this occurs we arrange to run the jump
+   optimizer after CSE to delete the unreachable code.
 
    We use two data structures to record the equivalent expressions:
    a hash table for most expressions, and several vectors together
@@ -287,14 +292,12 @@ static int *reg_next_eqv;
 static int *reg_prev_eqv;
 
 struct cse_reg_info {
-  union {
-    /* The number of times the register has been altered in the current
-       basic block.  */
-    int reg_tick;
-    
-    /* The next cse_reg_info structure in the free list.  */
-    struct cse_reg_info* next;
-  } variant;
+  /* The number of times the register has been altered in the current
+     basic block.  */
+  int reg_tick;
+
+  /* The next cse_reg_info structure in the free or used list.  */
+  struct cse_reg_info* next;
 
   /* The REG_TICK value at which rtx's containing this register are
      valid in the hash table.  If this does not equal the current
@@ -304,13 +307,20 @@ struct cse_reg_info {
 
   /* The quantity number of the register's current contents.  */
   int reg_qty;
+
+  /* Search key */
+  int regno;
 };
 
 /* A free list of cse_reg_info entries.  */
 static struct cse_reg_info *cse_reg_info_free_list;
 
+/* A used list of cse_reg_info entries.  */
+static struct cse_reg_info *cse_reg_info_used_list;
+static struct cse_reg_info *cse_reg_info_used_list_end;
+
 /* A mapping from registers to cse_reg_info data structures.  */
-static splay_tree cse_reg_info_tree;
+static hash_table_t cse_reg_info_tree;
 
 /* The last lookup we did into the cse_reg_info_tree.  This allows us
    to cache repeated lookups.  */
@@ -506,7 +516,7 @@ struct table_elt
 /* Get the number of times this register has been updated in this
    basic block.  */
 
-#define REG_TICK(N) ((GET_CSE_REG_INFO (N))->variant.reg_tick)
+#define REG_TICK(N) ((GET_CSE_REG_INFO (N))->reg_tick)
 
 /* Get the point at which REG was recorded in the table.  */
 
@@ -594,13 +604,14 @@ struct cse_basic_block_data {
 
 #define FIXED_BASE_PLUS_P(X)                                   \
   ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx   \
-   || (X) == arg_pointer_rtx                                   \
+   || ((X) == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])\
    || (X) == virtual_stack_vars_rtx                            \
    || (X) == virtual_incoming_args_rtx                         \
    || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
        && (XEXP (X, 0) == frame_pointer_rtx                    \
           || XEXP (X, 0) == hard_frame_pointer_rtx             \
-          || XEXP (X, 0) == arg_pointer_rtx                    \
+          || ((X) == arg_pointer_rtx                           \
+              && fixed_regs[ARG_POINTER_REGNUM])               \
           || XEXP (X, 0) == virtual_stack_vars_rtx             \
           || XEXP (X, 0) == virtual_incoming_args_rtx))        \
    || GET_CODE (X) == ADDRESSOF)
@@ -618,7 +629,8 @@ struct cse_basic_block_data {
    || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
        && (XEXP (X, 0) == frame_pointer_rtx                    \
           || XEXP (X, 0) == hard_frame_pointer_rtx             \
-          || XEXP (X, 0) == arg_pointer_rtx                    \
+          || ((X) == arg_pointer_rtx                           \
+              && fixed_regs[ARG_POINTER_REGNUM])               \
           || XEXP (X, 0) == virtual_stack_vars_rtx             \
           || XEXP (X, 0) == virtual_incoming_args_rtx))        \
    || (X) == stack_pointer_rtx                                 \
@@ -690,10 +702,11 @@ static void count_reg_usage       PROTO((rtx, int *, rtx, int));
 extern void dump_class          PROTO((struct table_elt*));
 static void check_fold_consts  PROTO((PTR));
 static struct cse_reg_info* get_cse_reg_info PROTO((int));
-static void free_cse_reg_info   PROTO((splay_tree_value));
-static void flush_hash_table   PROTO((void));
+static unsigned int hash_cse_reg_info PROTO((hash_table_entry_t));
+static int cse_reg_info_equal_p        PROTO((hash_table_entry_t,
+                                      hash_table_entry_t));
 
-extern int rtx_equal_function_value_matters;
+static void flush_hash_table   PROTO((void));
 \f
 /* Dump the expressions in the equivalence class indicated by CLASSP.
    This function is used only for debugging.  */
@@ -754,7 +767,7 @@ rtx_cost (x, outer_code)
 {
   register int i, j;
   register enum rtx_code code;
-  register char *fmt;
+  register const char *fmt;
   register int total;
 
   if (x == 0)
@@ -840,32 +853,38 @@ get_cse_reg_info (regno)
      int regno;
 {
   struct cse_reg_info *cri;
-  splay_tree_node n;
+  struct cse_reg_info **entry;
+  struct cse_reg_info temp;
 
   /* See if we already have this entry.  */
-  n = splay_tree_lookup (cse_reg_info_tree, 
-                       (splay_tree_key) regno);
-  if (n)
-    cri = (struct cse_reg_info *) (n->value);
+  temp.regno = regno;
+  entry = (struct cse_reg_info **) find_hash_table_entry (cse_reg_info_tree,
+                                                         &temp, TRUE);
+
+  if (*entry)
+    cri = *entry;
   else 
     {
       /* Get a new cse_reg_info structure.  */
       if (cse_reg_info_free_list) 
        {
          cri = cse_reg_info_free_list;
-         cse_reg_info_free_list = cri->variant.next;
+         cse_reg_info_free_list = cri->next;
        }
       else
        cri = (struct cse_reg_info *) xmalloc (sizeof (struct cse_reg_info));
 
       /* Initialize it.  */
-      cri->variant.reg_tick = 0;
+      cri->reg_tick = 0;
       cri->reg_in_table = -1;
       cri->reg_qty = regno;
-
-      splay_tree_insert (cse_reg_info_tree, 
-                        (splay_tree_key) regno, 
-                        (splay_tree_value) cri);
+      cri->regno = regno;
+      cri->next = cse_reg_info_used_list;
+      cse_reg_info_used_list = cri;
+      if (!cse_reg_info_used_list_end)
+       cse_reg_info_used_list_end = cri;
+      
+      *entry = cri;
     }
 
   /* Cache this lookup; we tend to be looking up information about the
@@ -876,14 +895,20 @@ get_cse_reg_info (regno)
   return cri;
 }
 
-static void
-free_cse_reg_info (v)
-     splay_tree_value v;
+static unsigned int
+hash_cse_reg_info (el_ptr)
+     hash_table_entry_t el_ptr;
 {
-  struct cse_reg_info *cri = (struct cse_reg_info *) v;
-  
-  cri->variant.next = cse_reg_info_free_list;
-  cse_reg_info_free_list = cri;
+  return ((const struct cse_reg_info *) el_ptr)->regno;
+}
+
+static int
+cse_reg_info_equal_p (el_ptr1, el_ptr2)
+     hash_table_entry_t el_ptr1;
+     hash_table_entry_t el_ptr2;
+{
+  return (((const struct cse_reg_info *) el_ptr1)->regno
+         == ((const struct cse_reg_info *) el_ptr2)->regno);
 }
 
 /* Clear the hash table and initialize each register with its own quantity,
@@ -898,12 +923,18 @@ new_basic_block ()
 
   if (cse_reg_info_tree) 
     {
-      splay_tree_delete (cse_reg_info_tree);
+      delete_hash_table (cse_reg_info_tree);
+      if (cse_reg_info_used_list)
+       {
+         cse_reg_info_used_list_end->next = cse_reg_info_free_list;
+         cse_reg_info_free_list = cse_reg_info_used_list;
+         cse_reg_info_used_list = cse_reg_info_used_list_end = 0;
+       }
       cached_cse_reg_info = 0;
     }
 
-  cse_reg_info_tree = splay_tree_new (splay_tree_compare_ints, 0, 
-                                     free_cse_reg_info);
+  cse_reg_info_tree = create_hash_table (0, hash_cse_reg_info,
+                                        cse_reg_info_equal_p);
 
   CLEAR_HARD_REG_SET (hard_regs_in_table);
 
@@ -1058,7 +1089,7 @@ mention_regs (x)
 {
   register enum rtx_code code;
   register int i, j;
-  register char *fmt;
+  register const char *fmt;
   register int changed = 0;
 
   if (x == 0)
@@ -1978,12 +2009,6 @@ invalidate_for_call ()
        {
          next = p->next_same_hash;
 
-         if (p->in_memory)
-           {
-             remove_from_table (p, hash);
-             continue;
-           }
-
          if (GET_CODE (p->exp) != REG
              || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
            continue;
@@ -2098,7 +2123,7 @@ canon_hash (x, mode)
   register int i, j;
   register unsigned hash = 0;
   register enum rtx_code code;
-  register char *fmt;
+  register const char *fmt;
 
   /* repeat is used to turn tail-recursion into iteration.  */
  repeat:
@@ -2167,7 +2192,7 @@ canon_hash (x, mode)
       if (GET_MODE (x) != VOIDmode)
        for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++)
          {
-           unsigned tem = XINT (x, i);
+           unsigned HOST_WIDE_INT tem = XWINT (x, i);
            hash += tem;
          }
       else
@@ -2260,7 +2285,7 @@ canon_hash (x, mode)
          register unsigned tem = XINT (x, i);
          hash += tem;
        }
-      else if (fmt[i] == '0')
+      else if (fmt[i] == '0' || fmt[i] == 't')
        /* unused */;
       else
        abort ();
@@ -2308,7 +2333,7 @@ exp_equiv_p (x, y, validate, equal_values)
 {
   register int i, j;
   register enum rtx_code code;
-  register char *fmt;
+  register const char *fmt;
 
   /* Note: it is incorrect to assume an expression is equivalent to itself
      if VALIDATE is nonzero.  */
@@ -2443,6 +2468,7 @@ exp_equiv_p (x, y, validate, equal_values)
        break;
 
        case '0':
+       case 't':
          break;
 
        default:
@@ -2463,7 +2489,7 @@ refers_to_p (x, y)
 {
   register int i;
   register enum rtx_code code;
-  register char *fmt;
+  register const char *fmt;
 
  repeat:
   if (x == y)
@@ -2723,7 +2749,7 @@ canon_reg (x, insn)
 {
   register int i;
   register enum rtx_code code;
-  register char *fmt;
+  register const char *fmt;
 
   if (x == 0)
     return x;
@@ -2782,7 +2808,7 @@ canon_reg (x, insn)
              && (((REGNO (new) < FIRST_PSEUDO_REGISTER)
                   != (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER))
                  || (insn_code = recog_memoized (insn)) < 0
-                 || insn_n_dups[insn_code] > 0))
+                 || insn_data[insn_code].n_dups > 0))
            validate_change (insn, &XEXP (x, i), new, 1);
          else
            XEXP (x, i) = new;
@@ -3364,27 +3390,7 @@ simplify_unary_operation (code, mode, op, op_mode)
          abort ();
        }
 
-      /* Clear the bits that don't belong in our mode,
-        unless they and our sign bit are all one.
-        So we get either a reasonable negative value or a reasonable
-        unsigned value for this mode.  */
-      if (width < HOST_BITS_PER_WIDE_INT
-         && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-             != ((HOST_WIDE_INT) (-1) << (width - 1))))
-       val &= ((HOST_WIDE_INT) 1 << width) - 1;
-
-      /* If this would be an entire word for the target, but is not for
-        the host, then sign-extend on the host so that the number will look
-        the same way on the host that it would on the target.
-
-        For example, when building a 64 bit alpha hosted 32 bit sparc
-        targeted compiler, then we want the 32 bit unsigned value -1 to be
-        represented as a 64 bit value -1, and not as 0x00000000ffffffff.
-        The later confuses the sparc backend.  */
-
-      if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
-         && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
-       val |= ((HOST_WIDE_INT) (-1) << width);
+      val = trunc_int_for_mode (val, mode);
 
       return GEN_INT (val);
     }
@@ -3556,27 +3562,7 @@ simplify_unary_operation (code, mode, op, op_mode)
 
       set_float_handler (NULL_PTR);
 
-      /* Clear the bits that don't belong in our mode,
-        unless they and our sign bit are all one.
-        So we get either a reasonable negative value or a reasonable
-        unsigned value for this mode.  */
-      if (width < HOST_BITS_PER_WIDE_INT
-         && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-             != ((HOST_WIDE_INT) (-1) << (width - 1))))
-       val &= ((HOST_WIDE_INT) 1 << width) - 1;
-
-      /* If this would be an entire word for the target, but is not for
-        the host, then sign-extend on the host so that the number will look
-        the same way on the host that it would on the target.
-
-        For example, when building a 64 bit alpha hosted 32 bit sparc
-        targeted compiler, then we want the 32 bit unsigned value -1 to be
-        represented as a 64 bit value -1, and not as 0x00000000ffffffff.
-        The later confuses the sparc backend.  */
-
-      if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
-         && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
-       val |= ((HOST_WIDE_INT) (-1) << width);
+      val = trunc_int_for_mode (val, mode);
 
       return GEN_INT (val);
     }
@@ -4065,9 +4051,11 @@ simplify_binary_operation (code, mode, op0, op1)
          if (GET_CODE (op1) == AND)
            {
             if (rtx_equal_p (op0, XEXP (op1, 0)))
-              return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 1)));
+              return cse_gen_binary (AND, mode, op0,
+                                     gen_rtx_NOT (mode, XEXP (op1, 1)));
             if (rtx_equal_p (op0, XEXP (op1, 1)))
-              return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 0)));
+              return cse_gen_binary (AND, mode, op0,
+                                     gen_rtx_NOT (mode, XEXP (op1, 0)));
           }
          break;
 
@@ -4212,8 +4200,9 @@ simplify_binary_operation (code, mode, op0, op1)
                  return gen_rtx_MULT (mode, op0, 
                                       CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
 #else
-                 return gen_rtx_MULT (mode, op0, 
-                                      CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
+                 return
+                   gen_rtx_MULT (mode, op0, 
+                                 CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
 #endif
                }
            }
@@ -4238,7 +4227,7 @@ simplify_binary_operation (code, mode, op0, op1)
        case ROTATE:
          /* Rotating ~0 always results in ~0.  */
          if (GET_CODE (op0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
-             && INTVAL (op0) == GET_MODE_MASK (mode)
+             && (unsigned HOST_WIDE_INT) INTVAL (op0) == GET_MODE_MASK (mode)
              && ! side_effects_p (op1))
            return op0;
 
@@ -4264,7 +4253,7 @@ simplify_binary_operation (code, mode, op0, op1)
           
        case SMAX:
          if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
-             && (INTVAL (op1)
+             && ((unsigned HOST_WIDE_INT) INTVAL (op1)
                  == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
              && ! side_effects_p (op0))
            return op1;
@@ -4458,26 +4447,7 @@ simplify_binary_operation (code, mode, op0, op1)
       abort ();
     }
 
-  /* Clear the bits that don't belong in our mode, unless they and our sign
-     bit are all one.  So we get either a reasonable negative value or a
-     reasonable unsigned value for this mode.  */
-  if (width < HOST_BITS_PER_WIDE_INT
-      && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-         != ((HOST_WIDE_INT) (-1) << (width - 1))))
-    val &= ((HOST_WIDE_INT) 1 << width) - 1;
-
-  /* If this would be an entire word for the target, but is not for
-     the host, then sign-extend on the host so that the number will look
-     the same way on the host that it would on the target.
-
-     For example, when building a 64 bit alpha hosted 32 bit sparc
-     targeted compiler, then we want the 32 bit unsigned value -1 to be
-     represented as a 64 bit value -1, and not as 0x00000000ffffffff.
-     The later confuses the sparc backend.  */
-
-  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
-      && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
-    val |= ((HOST_WIDE_INT) (-1) << width);
+  val = trunc_int_for_mode (val, mode);
 
   return GEN_INT (val);
 }
@@ -4898,14 +4868,14 @@ simplify_relational_operation (code, mode, op0, op1)
          /* Unsigned values are never greater than the largest
             unsigned value.  */
          if (GET_CODE (op1) == CONST_INT
-             && INTVAL (op1) == GET_MODE_MASK (mode)
+             && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
            && INTEGRAL_MODE_P (mode))
          return const_true_rtx;
          break;
 
        case GTU:
          if (GET_CODE (op1) == CONST_INT
-             && INTVAL (op1) == GET_MODE_MASK (mode)
+             && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
              && INTEGRAL_MODE_P (mode))
            return const0_rtx;
          break;
@@ -5057,7 +5027,7 @@ fold_rtx (x, insn)
 {
   register enum rtx_code code;
   register enum machine_mode mode;
-  register char *fmt;
+  register const char *fmt;
   register int i;
   rtx new = 0;
   int copied = 0;
@@ -5861,7 +5831,15 @@ fold_rtx (x, insn)
             hence not save anything) or be incorrect.  */
          if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT
              && INTVAL (const_arg1) < 0
-             && - INTVAL (const_arg1) >= 0
+             /* This used to test
+
+                - INTVAL (const_arg1) >= 0
+
+                But The Sun V5.0 compilers mis-compiled that test.  So
+                instead we test for the problematic value in a more direct
+                manner and hope the Sun compilers get it correct.  */
+             && INTVAL (const_arg1) !=
+               ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1))
              && GET_CODE (folded_arg1) == REG)
            {
              rtx new_const = GEN_INT (- INTVAL (const_arg1));
@@ -6399,8 +6377,6 @@ struct set
   unsigned dest_hash;
   /* The SET_DEST, with SUBREG, etc., stripped.  */
   rtx inner_dest;
-  /* Place where the pointer to the INNER_DEST was found.  */
-  rtx *inner_dest_loc;
   /* Nonzero if the SET_SRC is in memory.  */ 
   char src_in_memory;
   /* Nonzero if the SET_SRC is in a structure.  */ 
@@ -6436,12 +6412,12 @@ cse_insn (insn, libcall_insn)
 
   rtx src_eqv = 0;
   struct table_elt *src_eqv_elt = 0;
-  int src_eqv_volatile;
-  int src_eqv_in_memory;
-  int src_eqv_in_struct;
-  unsigned src_eqv_hash;
+  int src_eqv_volatile = 0;
+  int src_eqv_in_memory = 0;
+  int src_eqv_in_struct = 0;
+  unsigned src_eqv_hash = 0;
 
-  struct set *sets;
+  struct set *sets = NULL_PTR;
 
   this_insn = insn;
 
@@ -6615,7 +6591,7 @@ cse_insn (insn, libcall_insn)
           && ((REGNO (new) < FIRST_PSEUDO_REGISTER)
               != (REGNO (src) < FIRST_PSEUDO_REGISTER)))
          || (insn_code = recog_memoized (insn)) < 0
-         || insn_n_dups[insn_code] > 0)
+         || insn_data[insn_code].n_dups > 0)
        validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
       else
        SET_SRC (sets[i].rtl) = new;
@@ -7263,9 +7239,10 @@ cse_insn (insn, libcall_insn)
          && qty_first_reg[REG_QTY (REGNO (dest))] != REGNO (dest)
          && GET_CODE (src) == REG && REGNO (src) == REGNO (dest)
          /* Don't do this if the original insn had a hard reg as
-            SET_SRC.  */
+            SET_SRC or SET_DEST.  */
          && (GET_CODE (sets[i].src) != REG
-             || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER))
+             || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER)
+         && (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER))
        /* We can't call canon_reg here because it won't do anything if
           SRC is a hard register.  */
        {
@@ -7323,6 +7300,9 @@ cse_insn (insn, libcall_insn)
        {
          tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
          
+         /* Make sure that the rtx is not shared with any other insn.  */
+         src_const = copy_rtx (src_const);
+
          /* Record the actual constant value in a REG_EQUAL note, making
             a new one if one does not already exist.  */
          if (tem)
@@ -7355,16 +7335,15 @@ cse_insn (insn, libcall_insn)
                  if (note)
                    XEXP (note, 0) = const_insn;
                  else
-                   REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_WAS_0,
-                                                         const_insn,
-                                                         REG_NOTES (insn));
+                   REG_NOTES (insn)
+                     = gen_rtx_INSN_LIST (REG_WAS_0, const_insn,
+                                          REG_NOTES (insn));
                }
            }
        }
 
       /* Now deal with the destination.  */
       do_not_record = 0;
-      sets[i].inner_dest_loc = &SET_DEST (sets[0].rtl);
 
       /* Look within any SIGN_EXTRACT or ZERO_EXTRACT
         to the MEM or REG within it.  */
@@ -7372,10 +7351,7 @@ cse_insn (insn, libcall_insn)
             || GET_CODE (dest) == ZERO_EXTRACT
             || GET_CODE (dest) == SUBREG
             || GET_CODE (dest) == STRICT_LOW_PART)
-       {
-         sets[i].inner_dest_loc = &XEXP (dest, 0);
-         dest = XEXP (dest, 0);
-       }
+       dest = XEXP (dest, 0);
 
       sets[i].inner_dest = dest;
 
@@ -7432,13 +7408,13 @@ cse_insn (insn, libcall_insn)
         the insn.  */
       else if (n_sets == 1 && dest == pc_rtx && src == pc_rtx)
        {
+         /* One less use of the label this insn used to jump to.  */
+         if (JUMP_LABEL (insn) != 0)
+           --LABEL_NUSES (JUMP_LABEL (insn));
          PUT_CODE (insn, NOTE);
          NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
          NOTE_SOURCE_FILE (insn) = 0;
          cse_jumps_altered = 1;
-         /* One less use of the label this insn used to jump to.  */
-         if (JUMP_LABEL (insn) != 0)
-           --LABEL_NUSES (JUMP_LABEL (insn));
          /* No more processing for this set.  */
          sets[i].rtl = 0;
        }
@@ -7448,8 +7424,6 @@ cse_insn (insn, libcall_insn)
         it.  If it was a computed branch, delete it and re-emit.  */
       else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
        {
-         rtx p;
-
          /* If this is not in the format for a simple branch and
             we are the only SET in it, re-emit it.  */
          if (! simplejump_p (insn) && n_sets == 1)
@@ -7457,7 +7431,6 @@ cse_insn (insn, libcall_insn)
              rtx new = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
              JUMP_LABEL (new) = XEXP (src, 0);
              LABEL_NUSES (XEXP (src, 0))++;
-             delete_insn (insn);
              insn = new;
            }
          else
@@ -7468,39 +7441,13 @@ cse_insn (insn, libcall_insn)
               Until the right place is found, might as well do this here.  */
            INSN_CODE (insn) = -1;
 
-         /* Now that we've converted this jump to an unconditional jump,
-            there is dead code after it.  Delete the dead code until we
-            reach a BARRIER, the end of the function, or a label.  Do
-            not delete NOTEs except for NOTE_INSN_DELETED since later
-            phases assume these notes are retained.  */
+         never_reached_warning (insn);
 
-         p = insn;
-
-         while (NEXT_INSN (p) != 0
-                && GET_CODE (NEXT_INSN (p)) != BARRIER
-                && GET_CODE (NEXT_INSN (p)) != CODE_LABEL)
-           {
-             if (GET_CODE (NEXT_INSN (p)) != NOTE
-                 || NOTE_LINE_NUMBER (NEXT_INSN (p)) == NOTE_INSN_DELETED)
-               delete_insn (NEXT_INSN (p));
-             else
-               p = NEXT_INSN (p);
-           }
-
-         /* If we don't have a BARRIER immediately after INSN, put one there.
-            Much code assumes that there are no NOTEs between a JUMP_INSN and
-            BARRIER.  */
-
-         if (NEXT_INSN (insn) == 0
-             || GET_CODE (NEXT_INSN (insn)) != BARRIER)
-           emit_barrier_before (NEXT_INSN (insn));
-
-         /* We might have two BARRIERs separated by notes.  Delete the second
-            one if so.  */
-
-         if (p != insn && NEXT_INSN (p) != 0
-             && GET_CODE (NEXT_INSN (p)) == BARRIER)
-           delete_insn (NEXT_INSN (p));
+         /* Now emit a BARRIER after the unconditional jump.  Do not bother
+            deleting any unreachable code, let jump/flow do that.  */
+         if (NEXT_INSN (insn) != 0
+             && GET_CODE (NEXT_INSN (insn)) != BARRIER)
+           emit_barrier_after (insn);
 
          cse_jumps_altered = 1;
          sets[i].rtl = 0;
@@ -7604,7 +7551,12 @@ cse_insn (insn, libcall_insn)
            enum machine_mode mode
              = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
 
-           if (sets[i].src_elt == 0)
+           /* Don't put a hard register source into the table if this is
+              the last insn of a libcall.  */
+           if (sets[i].src_elt == 0
+               && (GET_CODE (src) != REG
+                   || REGNO (src) >= FIRST_PSEUDO_REGISTER
+                   || ! find_reg_note (insn, REG_RETVAL, NULL_RTX)))
              {
                register struct table_elt *elt;
 
@@ -8097,7 +8049,7 @@ cse_process_notes (x, object)
      rtx object;
 {
   enum rtx_code code = GET_CODE (x);
-  char *fmt = GET_RTX_FORMAT (code);
+  const char *fmt = GET_RTX_FORMAT (code);
   int i;
 
   switch (code)
@@ -8490,6 +8442,15 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
        path_size--;
     }
 
+  /* If the first instruction is marked with QImode, that means we've
+     already processed this block.  Our caller will look at DATA->LAST
+     to figure out where to go next.  We want to return the next block
+     in the instruction stream, not some branched-to block somewhere
+     else.  We accomplish this by pretending our called forbid us to
+     follow jumps, or skip blocks.  */
+  if (GET_MODE (insn) == QImode)
+    follow_jumps = skip_blocks = 0;
+
   /* Scan to end of this basic block.  */
   while (p && GET_CODE (p) != CODE_LABEL)
     {
@@ -8764,6 +8725,9 @@ cse_main (f, nregs, after_loop, file)
        || global_regs[i])
       SET_HARD_REG_BIT (regs_invalidated_by_call, i);
 
+  if (ggc_p)
+    ggc_push_context ();
+
   /* Loop over basic blocks.
      Compute the maximum number of qty's needed for each basic block
      (which is 2 for each SET).  */
@@ -8820,11 +8784,17 @@ cse_main (f, nregs, after_loop, file)
          cse_jumps_altered |= old_cse_jumps_altered;
        }
 
+      if (ggc_p)
+       ggc_collect ();
+
 #ifdef USE_C_ALLOCA
       alloca (0);
 #endif
     }
 
+  if (ggc_p)
+    ggc_pop_context ();
+
   /* Tell refers_to_mem_p that qty_const info is not available.  */
   qty_const = 0;
 
@@ -8858,7 +8828,8 @@ cse_basic_block (from, to, next_branch, around_loop)
 
   qty_first_reg = (int *) alloca ((max_qty - max_reg) * sizeof (int));
   qty_last_reg = (int *) alloca ((max_qty - max_reg) * sizeof (int));
-  qty_mode= (enum machine_mode *) alloca ((max_qty - max_reg) * sizeof (enum machine_mode));
+  qty_mode = (enum machine_mode *) alloca ((max_qty - max_reg)
+                                          * sizeof (enum machine_mode));
   qty_const = (rtx *) alloca ((max_qty - max_reg) * sizeof (rtx));
   qty_const_insn = (rtx *) alloca ((max_qty - max_reg) * sizeof (rtx));
   qty_comparison_code
@@ -8988,9 +8959,6 @@ cse_basic_block (from, to, next_branch, around_loop)
 
          insn = NEXT_INSN (to);
 
-         if (LABEL_NUSES (to) == 0)
-           insn = delete_insn (to);
-
          /* If TO was the last insn in the function, we are done.  */
          if (insn == 0)
            return 0;
@@ -9063,7 +9031,7 @@ count_reg_usage (x, counts, dest, incr)
      int incr;
 {
   enum rtx_code code;
-  char *fmt;
+  const char *fmt;
   int i, j;
 
   if (x == 0)
@@ -9173,8 +9141,16 @@ delete_trivially_dead_insns (insns, nreg)
 
   /* Go from the last insn to the first and delete insns that only set unused
      registers or copy a register to itself.  As we delete an insn, remove
-     usage counts for registers it uses.  */
-  for (insn = prev_real_insn (get_last_insn ()); insn; insn = prev)
+     usage counts for registers it uses. 
+
+     The first jump optimization pass may leave a real insn as the last
+     insn in the function.   We must not skip that insn or we may end
+     up deleting code that is not really dead.   */
+  insn = get_last_insn ();
+  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+    insn = prev_real_insn (insn);
+
+  for ( ; insn; insn = prev)
     {
       int live_insn = 0;
       rtx note;
@@ -9229,7 +9205,13 @@ delete_trivially_dead_insns (insns, nreg)
          else if (GET_CODE (SET_DEST (PATTERN (insn))) != REG
                   || REGNO (SET_DEST (PATTERN (insn))) < FIRST_PSEUDO_REGISTER
                   || counts[REGNO (SET_DEST (PATTERN (insn)))] != 0
-                  || side_effects_p (SET_SRC (PATTERN (insn))))
+                  || side_effects_p (SET_SRC (PATTERN (insn)))
+                  /* An ADDRESSOF expression can turn into a use of the
+                     internal arg pointer, so always consider the
+                     internal arg pointer live.  If it is truly dead,
+                     flow will delete the initializing insn.  */
+                  || (SET_DEST (PATTERN (insn))
+                      == current_function_internal_arg_pointer))
            live_insn = 1;
        }
       else if (GET_CODE (PATTERN (insn)) == PARALLEL)
@@ -9254,7 +9236,13 @@ delete_trivially_dead_insns (insns, nreg)
                else if (GET_CODE (SET_DEST (elt)) != REG
                         || REGNO (SET_DEST (elt)) < FIRST_PSEUDO_REGISTER
                         || counts[REGNO (SET_DEST (elt))] != 0
-                        || side_effects_p (SET_SRC (elt)))
+                        || side_effects_p (SET_SRC (elt))
+                        /* An ADDRESSOF expression can turn into a use of the
+                           internal arg pointer, so always consider the
+                           internal arg pointer live.  If it is truly dead,
+                           flow will delete the initializing insn.  */
+                        || (SET_DEST (elt)
+                            == current_function_internal_arg_pointer))
                  live_insn = 1;
              }
            else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)