OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index afdc8da..a061817 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,6 +1,6 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "config.h"
 /* stdio.h must precede rtl.h for FFS.  */
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
 #include "rtl.h"
 #include "tm_p.h"
@@ -38,6 +40,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "output.h"
 #include "ggc.h"
 #include "timevar.h"
+#include "except.h"
+#include "target.h"
+#include "params.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -247,8 +252,10 @@ struct qty_table_elem
   rtx comparison_const;
   int comparison_qty;
   unsigned int first_reg, last_reg;
-  enum machine_mode mode;
-  enum rtx_code comparison_code;
+  /* The sizes of these fields should match the sizes of the
+     code and mode fields of struct rtx_def (see rtl.h).  */
+  ENUM_BITFIELD(rtx_code) comparison_code : 16;
+  ENUM_BITFIELD(machine_mode) mode : 8;
 };
 
 /* The table of all qtys, indexed by qty number.  */
@@ -266,11 +273,11 @@ static struct qty_table_elem *qty_table;
 
 static rtx prev_insn_cc0;
 static enum machine_mode prev_insn_cc0_mode;
-#endif
 
 /* Previous actual insn.  0 if at first insn of basic block.  */
 
 static rtx prev_insn;
+#endif
 
 /* Insn being scanned.  */
 
@@ -316,6 +323,10 @@ struct cse_reg_info
      reg_tick value, such expressions existing in the hash table are
      invalid.  */
   int reg_in_table;
+
+  /* The SUBREG that was set when REG_TICK was last incremented.  Set
+     to -1 if the last store was to the whole register, not a subreg.  */
+  unsigned int subreg_ticked;
 };
 
 /* A free list of cse_reg_info entries.  */
@@ -454,7 +465,9 @@ struct table_elt
   struct table_elt *related_value;
   int cost;
   int regcost;
-  enum machine_mode mode;
+  /* The size of this field should match the size
+     of the mode field of struct rtx_def (see rtl.h).  */
+  ENUM_BITFIELD(machine_mode) mode : 8;
   char in_memory;
   char is_const;
   char flag;
@@ -514,6 +527,11 @@ struct table_elt
 
 #define REG_IN_TABLE(N) ((GET_CSE_REG_INFO (N))->reg_in_table)
 
+/* Get the SUBREG set at the last increment to REG_TICK (-1 if not a
+   SUBREG).  */
+
+#define SUBREG_TICKED(N) ((GET_CSE_REG_INFO (N))->subreg_ticked)
+
 /* Get the quantity number for REG.  */
 
 #define REG_QTY(N) ((GET_CSE_REG_INFO (N))->reg_qty)
@@ -552,10 +570,6 @@ static struct table_elt *last_jump_equiv_class;
 
 static int constant_pool_entries_cost;
 
-/* Define maximum length of a branch path.  */
-
-#define PATHLENGTH     10
-
 /* This data describes a block that will be processed by cse_basic_block.  */
 
 struct cse_basic_block_data
@@ -579,58 +593,10 @@ struct cse_basic_block_data
         except that it is used when the destination label is not preceded
        by a BARRIER.  */
       enum taken {TAKEN, NOT_TAKEN, AROUND} status;
-    } path[PATHLENGTH];
+    } *path;
 };
 
-/* Nonzero if X has the form (PLUS frame-pointer integer).  We check for
-   virtual regs here because the simplify_*_operation routines are called
-   by integrate.c, which is called before virtual register instantiation.
-
-   ?!? FIXED_BASE_PLUS_P and NONZERO_BASE_PLUS_P need to move into
-   a header file so that their definitions can be shared with the
-   simplification routines in simplify-rtx.c.  Until then, do not
-   change these macros without also changing the copy in simplify-rtx.c.  */
-
-#define FIXED_BASE_PLUS_P(X)                                   \
-  ((X) == frame_pointer_rtx || (X) == hard_frame_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             \
-          || ((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)
-
-/* Similar, but also allows reference to the stack pointer.
-
-   This used to include FIXED_BASE_PLUS_P, however, we can't assume that
-   arg_pointer_rtx by itself is nonzero, because on at least one machine,
-   the i960, the arg pointer is zero when it is unused.  */
-
-#define NONZERO_BASE_PLUS_P(X)                                 \
-  ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx   \
-   || (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             \
-          || ((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                                 \
-   || (X) == virtual_stack_dynamic_rtx                         \
-   || (X) == virtual_outgoing_args_rtx                         \
-   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
-       && (XEXP (X, 0) == stack_pointer_rtx                    \
-          || XEXP (X, 0) == virtual_stack_dynamic_rtx          \
-          || XEXP (X, 0) == virtual_outgoing_args_rtx))        \
-   || GET_CODE (X) == ADDRESSOF)
-
+static bool fixed_base_plus_p  PARAMS ((rtx x));
 static int notreg_cost         PARAMS ((rtx, enum rtx_code));
 static int approx_reg_cost_1   PARAMS ((rtx *, void *));
 static int approx_reg_cost     PARAMS ((rtx));
@@ -693,6 +659,39 @@ static bool insn_live_p            PARAMS ((rtx, int *));
 static bool set_live_p         PARAMS ((rtx, rtx, int *));
 static bool dead_libcall_p     PARAMS ((rtx, int *));
 \f
+/* Nonzero if X has the form (PLUS frame-pointer integer).  We check for
+   virtual regs here because the simplify_*_operation routines are called
+   by integrate.c, which is called before virtual register instantiation.  */
+
+static bool
+fixed_base_plus_p (x)
+     rtx x;
+{
+  switch (GET_CODE (x))
+    {
+    case REG:
+      if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx)
+       return true;
+      if (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])
+       return true;
+      if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+         && REGNO (x) <= LAST_VIRTUAL_REGISTER)
+       return true;
+      return false;
+
+    case PLUS:
+      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+       return false;
+      return fixed_base_plus_p (XEXP (x, 0));
+
+    case ADDRESSOF:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
 /* Dump the expressions in the equivalence class indicated by CLASSP.
    This function is used only for debugging.  */
 void
@@ -767,7 +766,7 @@ static int
 preferrable (cost_a, regcost_a, cost_b, regcost_b)
      int cost_a, regcost_a, cost_b, regcost_b;
 {
-  /* First, get rid of cases involving expressions that are entirely
+  /* First, get rid of cases involving expressions that are entirely
      unwanted.  */
   if (cost_a != cost_b)
     {
@@ -835,7 +834,7 @@ rtx_cost (x, outer_code)
     return 0;
 
   /* Compute the default costs of certain things.
-     Note that RTX_COSTS can override the defaults.  */
+     Note that targetm.rtx_costs can override the defaults.  */
 
   code = GET_CODE (x);
   switch (code)
@@ -870,17 +869,9 @@ rtx_cost (x, outer_code)
                              + GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD);
       break;
 
-#ifdef RTX_COSTS
-      RTX_COSTS (x, code, outer_code);
-#endif
-#ifdef CONST_COSTS
-      CONST_COSTS (x, code, outer_code);
-#endif
-
     default:
-#ifdef DEFAULT_RTX_COSTS
-      DEFAULT_RTX_COSTS (x, code, outer_code);
-#endif
+      if ((*targetm.rtx_costs) (x, code, outer_code, &total))
+       return total;
       break;
     }
 
@@ -906,7 +897,7 @@ address_cost (x, mode)
      rtx x;
      enum machine_mode mode;
 {
-  /* The ADDRESS_COST macro does not deal with ADDRESSOF nodes.  But,
+  /* The address_cost target hook does not deal with ADDRESSOF nodes.  But,
      during CSE, such nodes are present.  Using an ADDRESSOF node which
      refers to the address of a REG is a good thing because we can then
      turn (MEM (ADDRESSSOF (REG))) into just plain REG.  */
@@ -916,17 +907,22 @@ address_cost (x, mode)
 
   /* We may be asked for cost of various unusual addresses, such as operands
      of push instruction.  It is not worthwhile to complicate writing
-     of ADDRESS_COST macro by such cases.  */
+     of the target hook by such cases.  */
 
   if (!memory_address_p (mode, x))
     return 1000;
-#ifdef ADDRESS_COST
-  return ADDRESS_COST (x);
-#else
-  return rtx_cost (x, MEM);
-#endif
+
+  return (*targetm.address_cost) (x);
 }
 
+/* If the target doesn't override, compute the cost as with arithmetic.  */
+
+int
+default_address_cost (x)
+     rtx x;
+{
+  return rtx_cost (x, MEM);
+}
 \f
 static struct cse_reg_info *
 get_cse_reg_info (regno)
@@ -957,6 +953,7 @@ get_cse_reg_info (regno)
       /* Initialize it.  */
       p->reg_tick = 1;
       p->reg_in_table = -1;
+      p->subreg_ticked = -1;
       p->reg_qty = regno;
       p->regno = regno;
       p->next = cse_reg_info_used_list;
@@ -1022,9 +1019,8 @@ new_basic_block ()
        }
     }
 
-  prev_insn = 0;
-
 #ifdef HAVE_cc0
+  prev_insn = 0;
   prev_insn_cc0 = 0;
 #endif
 }
@@ -1191,6 +1187,7 @@ mention_regs (x)
            remove_invalid_refs (i);
 
          REG_IN_TABLE (i) = REG_TICK (i);
+         SUBREG_TICKED (i) = -1;
        }
 
       return 0;
@@ -1206,17 +1203,20 @@ mention_regs (x)
 
       if (REG_IN_TABLE (i) >= 0 && REG_IN_TABLE (i) != REG_TICK (i))
        {
-         /* If reg_tick has been incremented more than once since
-            reg_in_table was last set, that means that the entire
-            register has been set before, so discard anything memorized
-            for the entire register, including all SUBREG expressions.  */
-         if (REG_IN_TABLE (i) != REG_TICK (i) - 1)
+         /* If REG_IN_TABLE (i) differs from REG_TICK (i) by one, and
+            the last store to this register really stored into this
+            subreg, then remove the memory of this subreg.
+            Otherwise, remove any memory of the entire register and
+            all its subregs from the table.  */
+         if (REG_TICK (i) - REG_IN_TABLE (i) > 1
+             || SUBREG_TICKED (i) != REGNO (SUBREG_REG (x)))
            remove_invalid_refs (i);
          else
            remove_invalid_subreg_refs (i, SUBREG_BYTE (x), GET_MODE (x));
        }
 
       REG_IN_TABLE (i) = REG_TICK (i);
+      SUBREG_TICKED (i) = REGNO (SUBREG_REG (x));
       return 0;
     }
 
@@ -1597,7 +1597,7 @@ insert (x, classp, hash, mode)
                   || (GET_CODE (x) == REG
                       && RTX_UNCHANGING_P (x)
                       && REGNO (x) >= FIRST_PSEUDO_REGISTER)
-                  || FIXED_BASE_PLUS_P (x));
+                  || fixed_base_plus_p (x));
 
   if (table[hash])
     table[hash]->prev_same_hash = elt;
@@ -1861,6 +1861,7 @@ invalidate (x, full_mode)
 
        delete_reg_equiv (regno);
        REG_TICK (regno)++;
+       SUBREG_TICKED (regno) = -1;
 
        if (regno >= FIRST_PSEUDO_REGISTER)
          {
@@ -1888,6 +1889,7 @@ invalidate (x, full_mode)
                CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
                delete_reg_equiv (rn);
                REG_TICK (rn)++;
+               SUBREG_TICKED (rn) = -1;
              }
 
            if (in_table)
@@ -2093,7 +2095,10 @@ invalidate_for_call ()
       {
        delete_reg_equiv (regno);
        if (REG_TICK (regno) >= 0)
-         REG_TICK (regno)++;
+         {
+           REG_TICK (regno)++;
+           SUBREG_TICKED (regno) = -1;
+         }
 
        in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
       }
@@ -2320,11 +2325,7 @@ canon_hash (x, mode)
         the integers representing the constant.  */
       hash += (unsigned) code + (unsigned) GET_MODE (x);
       if (GET_MODE (x) != VOIDmode)
-       for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++)
-         {
-           unsigned HOST_WIDE_INT tem = XWINT (x, i);
-           hash += tem;
-         }
+       hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       else
        hash += ((unsigned) CONST_DOUBLE_LOW (x)
                 + (unsigned) CONST_DOUBLE_HIGH (x));
@@ -2363,10 +2364,9 @@ canon_hash (x, mode)
          do_not_record = 1;
          return 0;
        }
-      if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0)))
-       {
-         hash_arg_in_memory = 1;
-       }
+      if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
+       hash_arg_in_memory = 1;
+
       /* Now that we have already found this special case,
         might as well speed it up as much as possible.  */
       hash += (unsigned) MEM;
@@ -2384,7 +2384,7 @@ canon_hash (x, mode)
          hash += (unsigned) USE;
          x = XEXP (x, 0);
 
-         if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0)))
+         if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
            hash_arg_in_memory = 1;
 
          /* Now that we have already found this special case,
@@ -2772,9 +2772,9 @@ cse_rtx_varies_p (x, from_alias)
    replace each register reference inside it
    with the "oldest" equivalent register.
 
-   If INSN is non-zero and we are replacing a pseudo with a hard register
+   If INSN is nonzero and we are replacing a pseudo with a hard register
    or vice versa, validate_change is used to ensure that INSN remains valid
-   after we make our substitution.  The calls are made with IN_GROUP non-zero
+   after we make our substitution.  The calls are made with IN_GROUP nonzero
    so apply_change_group must be called upon the outermost return from this
    function (unless INSN is zero).  The result of apply_change_group can
    generally be discarded since the changes we are making are optional.  */
@@ -2871,13 +2871,12 @@ canon_reg (x, insn)
    is a good approximation for that cost.  However, most RISC machines have
    only a few (usually only one) memory reference formats.  If an address is
    valid at all, it is often just as cheap as any other address.  Hence, for
-   RISC machines, we use the configuration macro `ADDRESS_COST' to compare the
-   costs of various addresses.  For two addresses of equal cost, choose the one
-   with the highest `rtx_cost' value as that has the potential of eliminating
-   the most insns.  For equal costs, we choose the first in the equivalence
-   class.  Note that we ignore the fact that pseudo registers are cheaper
-   than hard registers here because we would also prefer the pseudo registers.
-  */
+   RISC machines, we use `address_cost' to compare the costs of various
+   addresses.  For two addresses of equal cost, choose the one with the
+   highest `rtx_cost' value as that has the potential of eliminating the
+   most insns.  For equal costs, we choose the first in the equivalence
+   class.  Note that we ignore the fact that pseudo registers are cheaper than
+   hard registers here because we would also prefer the pseudo registers.  */
 
 static void
 find_best_addr (insn, loc, mode)
@@ -2887,10 +2886,8 @@ find_best_addr (insn, loc, mode)
 {
   struct table_elt *elt;
   rtx addr = *loc;
-#ifdef ADDRESS_COST
   struct table_elt *p;
   int found_better = 1;
-#endif
   int save_do_not_record = do_not_record;
   int save_hash_arg_in_memory = hash_arg_in_memory;
   int addr_volatile;
@@ -2954,22 +2951,6 @@ find_best_addr (insn, loc, mode)
 
   elt = lookup (addr, hash, Pmode);
 
-#ifndef ADDRESS_COST
-  if (elt)
-    {
-      int our_cost = elt->cost;
-
-      /* Find the lowest cost below ours that works.  */
-      for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
-       if (elt->cost < our_cost
-           && (GET_CODE (elt->exp) == REG
-               || exp_equiv_p (elt->exp, elt->exp, 1, 0))
-           && validate_change (insn, loc,
-                               canon_reg (copy_rtx (elt->exp), NULL_RTX), 0))
-         return;
-    }
-#else
-
   if (elt)
     {
       /* We need to find the best (under the criteria documented above) entry
@@ -3028,10 +3009,9 @@ find_best_addr (insn, loc, mode)
   if (flag_expensive_optimizations
       && (GET_RTX_CLASS (GET_CODE (*loc)) == '2'
          || GET_RTX_CLASS (GET_CODE (*loc)) == 'c')
-      && GET_CODE (XEXP (*loc, 0)) == REG
-      && GET_CODE (XEXP (*loc, 1)) == CONST_INT)
+      && GET_CODE (XEXP (*loc, 0)) == REG)
     {
-      rtx c = XEXP (*loc, 1);
+      rtx op1 = XEXP (*loc, 1);
 
       do_not_record = 0;
       hash = HASH (XEXP (*loc, 0), Pmode);
@@ -3073,7 +3053,7 @@ find_best_addr (insn, loc, mode)
                    || exp_equiv_p (p->exp, p->exp, 1, 0)))
              {
                rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
-                                              p->exp, c);
+                                              p->exp, op1);
                int new_cost;
                new_cost = address_cost (new, mode);
 
@@ -3100,7 +3080,6 @@ find_best_addr (insn, loc, mode)
            }
        }
     }
-#endif
 }
 \f
 /* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison
@@ -3129,7 +3108,7 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 
   while (arg2 == CONST0_RTX (GET_MODE (arg1)))
     {
-      /* Set non-zero when we find something of interest.  */
+      /* Set nonzero when we find something of interest.  */
       rtx x = 0;
       int reverse_code = 0;
       struct table_elt *p = 0;
@@ -3147,13 +3126,17 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 
       else if (GET_RTX_CLASS (GET_CODE (arg1)) == '<')
        {
+#ifdef FLOAT_STORE_FLAG_VALUE
+         REAL_VALUE_TYPE fsfv;
+#endif
+
          if (code == NE
              || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
                  && code == LT && STORE_FLAG_VALUE == -1)
 #ifdef FLOAT_STORE_FLAG_VALUE
              || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
-                 && (REAL_VALUE_NEGATIVE
-                     (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
+                 && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+                     REAL_VALUE_NEGATIVE (fsfv)))
 #endif
              )
            x = arg1;
@@ -3162,8 +3145,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
                       && code == GE && STORE_FLAG_VALUE == -1)
 #ifdef FLOAT_STORE_FLAG_VALUE
                   || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
-                      && (REAL_VALUE_NEGATIVE
-                          (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
+                      && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+                          REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                   )
            x = arg1, reverse_code = 1;
@@ -3199,6 +3182,9 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
       for (; p; p = p->next_same_value)
        {
          enum machine_mode inner_mode = GET_MODE (p->exp);
+#ifdef FLOAT_STORE_FLAG_VALUE
+         REAL_VALUE_TYPE fsfv;
+#endif
 
          /* If the entry isn't valid, skip it.  */
          if (! exp_equiv_p (p->exp, p->exp, 1, 0))
@@ -3223,8 +3209,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 #ifdef FLOAT_STORE_FLAG_VALUE
                   || (code == LT
                       && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                      && (REAL_VALUE_NEGATIVE
-                          (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
+                      && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+                          REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                   )
                  && GET_RTX_CLASS (GET_CODE (p->exp)) == '<'))
@@ -3243,8 +3229,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 #ifdef FLOAT_STORE_FLAG_VALUE
                    || (code == GE
                        && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                       && (REAL_VALUE_NEGATIVE
-                           (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
+                       && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+                           REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                    )
                   && GET_RTX_CLASS (GET_CODE (p->exp)) == '<')
@@ -3254,9 +3240,10 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
              break;
            }
 
-         /* If this is fp + constant, the equivalent is a better operand since
-            it may let us predict the value of the comparison.  */
-         else if (NONZERO_BASE_PLUS_P (p->exp))
+         /* If this non-trapping address, e.g. fp + constant, the
+            equivalent is a better operand since it may let us predict
+            the value of the comparison.  */
+         else if (!rtx_addr_can_trap_p (p->exp))
            {
              arg1 = p->exp;
              continue;
@@ -3365,17 +3352,11 @@ fold_rtx (x, insn)
       /* If the next insn is a CODE_LABEL followed by a jump table,
         PC's value is a LABEL_REF pointing to that label.  That
         lets us fold switch statements on the VAX.  */
-      if (insn && GET_CODE (insn) == JUMP_INSN)
-       {
-         rtx next = next_nonnote_insn (insn);
-
-         if (next && GET_CODE (next) == CODE_LABEL
-             && NEXT_INSN (next) != 0
-             && GET_CODE (NEXT_INSN (next)) == JUMP_INSN
-             && (GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_VEC
-                 || GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_DIFF_VEC))
-           return gen_rtx_LABEL_REF (Pmode, next);
-       }
+      {
+       rtx next;
+       if (insn && tablejump_p (insn, &next, NULL))
+         return gen_rtx_LABEL_REF (Pmode, next);
+      }
       break;
 
     case SUBREG:
@@ -3729,6 +3710,7 @@ fold_rtx (x, insn)
        rtx cheap_arg, expensive_arg;
        rtx replacements[2];
        int j;
+       int old_cost = COST_IN (XEXP (x, i), code);
 
        /* Most arguments are cheap, so handle them specially.  */
        switch (GET_CODE (arg))
@@ -3819,7 +3801,6 @@ fold_rtx (x, insn)
 
        for (j = 0; j < 2 && replacements[j]; j++)
          {
-           int old_cost = COST_IN (XEXP (x, i), code);
            int new_cost = COST_IN (replacements[j], code);
 
            /* Stop if what existed before was cheaper.  Prefer constants
@@ -3957,17 +3938,10 @@ fold_rtx (x, insn)
             comparison.  */
          if (const_arg0 == 0 || const_arg1 == 0)
            {
-             /* Is FOLDED_ARG0 frame-pointer plus a constant?  Or
-                non-explicit constant?  These aren't zero, but we
-                don't know their sign.  */
+             /* Some addresses are known to be nonzero.  We don't know
+                their sign, but equality comparisons are known.  */
              if (const_arg1 == const0_rtx
-                 && (NONZERO_BASE_PLUS_P (folded_arg0)
-#if 0  /* Sad to say, on sysvr4, #pragma weak can make a symbol address
-         come out as 0.  */
-                     || GET_CODE (folded_arg0) == SYMBOL_REF
-#endif
-                     || GET_CODE (folded_arg0) == LABEL_REF
-                     || GET_CODE (folded_arg0) == CONST))
+                 && nonzero_address_p (folded_arg0))
                {
                  if (code == EQ)
                    return false_rtx;
@@ -4209,7 +4183,7 @@ fold_rtx (x, insn)
        from_plus:
        case SMIN:    case SMAX:      case UMIN:    case UMAX:
        case IOR:     case AND:       case XOR:
-       case MULT:    case DIV:       case UDIV:
+       case MULT:
        case ASHIFT:  case LSHIFTRT:  case ASHIFTRT:
          /* If we have (<op> <reg> <const_int>) for an associative OP and REG
             is known to be of similar form, we may be able to replace the
@@ -4257,11 +4231,9 @@ fold_rtx (x, insn)
                break;
 
              /* Compute the code used to compose the constants.  For example,
-                A/C1/C2 is A/(C1 * C2), so if CODE == DIV, we want MULT.  */
+                A-C1-C2 is A-(C1 + C2), so if CODE == MINUS, we want PLUS.  */
 
-             associate_code
-               = (code == MULT || code == DIV || code == UDIV ? MULT
-                  : is_shift || code == PLUS || code == MINUS ? PLUS : code);
+             associate_code = (is_shift || code == MINUS ? PLUS : code);
 
              new_const = simplify_binary_operation (associate_code, mode,
                                                     const_arg1, inner_const);
@@ -4299,6 +4271,14 @@ fold_rtx (x, insn)
            }
          break;
 
+       case DIV:       case UDIV:
+         /* ??? The associative optimization performed immediately above is
+            also possible for DIV and UDIV using associate_code of MULT.
+            However, we would need extra code to verify that the
+            multiplication does not overflow, that is, there is no overflow
+            in the calculation of new_const.  */
+         break;
+
        default:
          break;
        }
@@ -4325,9 +4305,14 @@ fold_rtx (x, insn)
       break;
 
     case 'x':
-      /* Always eliminate CONSTANT_P_RTX at this stage.  */
+      /* Eliminate CONSTANT_P_RTX if its constant.  */
       if (code == CONSTANT_P_RTX)
-       return (const_arg0 ? const1_rtx : const0_rtx);
+       {
+         if (const_arg0)
+           return const1_rtx;
+         if (optimize == 0 || !flag_gcse)
+           return const0_rtx;
+       }
       break;
     }
 
@@ -4727,8 +4712,10 @@ struct set
   /* Nonzero if the SET_SRC contains something
      whose value cannot be predicted and understood.  */
   char src_volatile;
-  /* Original machine mode, in case it becomes a CONST_INT.  */
-  enum machine_mode mode;
+  /* Original machine mode, in case it becomes a CONST_INT.
+     The size of this field should match the size of the mode
+     field of struct rtx_def (see rtl.h).  */
+  ENUM_BITFIELD(machine_mode) mode : 8;
   /* A constant equivalent for SET_SRC, if any.  */
   rtx src_const;
   /* Original SET_SRC value used for libcall notes.  */
@@ -5001,7 +4988,7 @@ cse_insn (insn, libcall_insn)
       int src_folded_regcost = MAX_COST;
       int src_related_regcost = MAX_COST;
       int src_elt_regcost = MAX_COST;
-      /* Set non-zero if we need to call force_const_mem on with the
+      /* Set nonzero if we need to call force_const_mem on with the
         contents of src_folded before using it.  */
       int src_folded_force_flag = 0;
 
@@ -5341,9 +5328,9 @@ cse_insn (insn, libcall_insn)
       if (src == src_folded)
        src_folded = 0;
 
-      /* At this point, ELT, if non-zero, points to a class of expressions
+      /* At this point, ELT, if nonzero, points to a class of expressions
          equivalent to the source of this SET and SRC, SRC_EQV, SRC_FOLDED,
-        and SRC_RELATED, if non-zero, each contain additional equivalent
+        and SRC_RELATED, if nonzero, each contain additional equivalent
         expressions.  Prune these latter expressions by deleting expressions
         already in the equivalence class.
 
@@ -5550,6 +5537,8 @@ cse_insn (insn, libcall_insn)
          /* Look for a substitution that makes a valid insn.  */
          else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
            {
+             rtx new = canon_reg (SET_SRC (sets[i].rtl), insn);
+
              /* If we just made a substitution inside a libcall, then we
                 need to make the same substitution in any notes attached
                 to the RETVAL insn.  */
@@ -5557,15 +5546,13 @@ cse_insn (insn, libcall_insn)
                  && (GET_CODE (sets[i].orig_src) == REG
                      || GET_CODE (sets[i].orig_src) == SUBREG
                      || GET_CODE (sets[i].orig_src) == MEM))
-               replace_rtx (REG_NOTES (libcall_insn), sets[i].orig_src,
-                            canon_reg (SET_SRC (sets[i].rtl), insn));
+               simplify_replace_rtx (REG_NOTES (libcall_insn),
+                                     sets[i].orig_src, copy_rtx (new));
 
              /* The result of apply_change_group can be ignored; see
                 canon_reg.  */
 
-             validate_change (insn, &SET_SRC (sets[i].rtl),
-                              canon_reg (SET_SRC (sets[i].rtl), insn),
-                              1);
+             validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
              apply_change_group ();
              break;
            }
@@ -5678,12 +5665,16 @@ cse_insn (insn, libcall_insn)
                && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
                && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
        {
-         /* Make sure that the rtx is not shared with any other insn.  */
-         src_const = copy_rtx (src_const);
+         /* We only want a REG_EQUAL note if src_const != src.  */
+         if (! rtx_equal_p (src, src_const))
+           {
+             /* Make sure that the rtx is not shared.  */
+             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.  */
-         set_unique_reg_note (insn, REG_EQUAL, src_const);
+             /* Record the actual constant value in a REG_EQUAL note,
+                making a new one if one does not already exist.  */
+             set_unique_reg_note (insn, REG_EQUAL, src_const);
+           }
 
          /* If storing a constant value in a register that
             previously held the constant value 0,
@@ -6161,7 +6152,7 @@ cse_insn (insn, libcall_insn)
 
        elt->in_memory = (GET_CODE (sets[i].inner_dest) == MEM
                          && (! RTX_UNCHANGING_P (sets[i].inner_dest)
-                             || FIXED_BASE_PLUS_P (XEXP (sets[i].inner_dest,
+                             || fixed_base_plus_p (XEXP (sets[i].inner_dest,
                                                          0))));
 
        /* If we have (set (subreg:m1 (reg:m2 foo) 0) (bar:m1)), M1 is no
@@ -6203,14 +6194,23 @@ cse_insn (insn, libcall_insn)
                    && ! exp_equiv_p (elt->exp, elt->exp, 1, 0))
                  continue;
 
-               /* Calculate big endian correction for the SUBREG_BYTE
-                  (or equivalent).  We have already checked that M1
-                  ( GET_MODE (dest) ) is not narrower than M2 (new_mode).  */
-               if (BYTES_BIG_ENDIAN)
-                 byte = (GET_MODE_SIZE (GET_MODE (dest))
-                         - GET_MODE_SIZE (new_mode));
-               new_src = simplify_gen_subreg (new_mode, elt->exp,
-                                              GET_MODE (dest), byte);
+               /* We may have already been playing subreg games.  If the
+                  mode is already correct for the destination, use it.  */
+               if (GET_MODE (elt->exp) == new_mode)
+                 new_src = elt->exp;
+               else
+                 {
+                   /* Calculate big endian correction for the SUBREG_BYTE.
+                      We have already checked that M1 (GET_MODE (dest))
+                      is not narrower than M2 (new_mode).  */
+                   if (BYTES_BIG_ENDIAN)
+                     byte = (GET_MODE_SIZE (GET_MODE (dest))
+                             - GET_MODE_SIZE (new_mode));
+
+                   new_src = simplify_gen_subreg (new_mode, elt->exp,
+                                                  GET_MODE (dest), byte);
+                 }
+
                /* The call to simplify_gen_subreg fails if the value
                   is VOIDmode, yet we can't do any simplification, e.g.
                   for EXPR_LISTs denoting function call results.
@@ -6279,8 +6279,16 @@ cse_insn (insn, libcall_insn)
       if ((src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
          && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
        {
-         rtx prev = prev_nonnote_insn (insn);
-
+         rtx prev = insn;
+         /* Scan for the previous nonnote insn, but stop at a basic
+            block boundary.  */
+         do
+           {
+             prev = PREV_INSN (prev);
+           }
+         while (prev && GET_CODE (prev) == NOTE
+                && NOTE_LINE_NUMBER (prev) != NOTE_INSN_BASIC_BLOCK);
+           
          /* Do not swap the registers around if the previous instruction
             attaches a REG_EQUIV note to REG1.
 
@@ -6291,7 +6299,7 @@ cse_insn (insn, libcall_insn)
 
             This section previously turned the REG_EQUIV into a REG_EQUAL
             note.  We cannot do that because REG_EQUIV may provide an
-            uninitialised stack slot when REG_PARM_STACK_SPACE is used.  */
+            uninitialized stack slot when REG_PARM_STACK_SPACE is used.  */
 
          if (prev != 0 && GET_CODE (prev) == INSN
              && GET_CODE (PATTERN (prev)) == SET
@@ -6355,9 +6363,8 @@ cse_insn (insn, libcall_insn)
 
   prev_insn_cc0 = this_insn_cc0;
   prev_insn_cc0_mode = this_insn_cc0_mode;
-#endif
-
   prev_insn = insn;
+#endif
 }
 \f
 /* Remove from the hash table all expressions that reference memory.  */
@@ -6389,7 +6396,11 @@ addr_affects_sp_p (addr)
       && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
     {
       if (REG_TICK (STACK_POINTER_REGNUM) >= 0)
-       REG_TICK (STACK_POINTER_REGNUM)++;
+       {
+         REG_TICK (STACK_POINTER_REGNUM)++;
+         /* Is it possible to use a subreg of SP?  */
+         SUBREG_TICKED (STACK_POINTER_REGNUM) = -1;
+       }
 
       /* This should be *very* rare.  */
       if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
@@ -6643,9 +6654,7 @@ invalidate_skipped_set (dest, set, data)
     }
 
   if (GET_CODE (set) == CLOBBER
-#ifdef HAVE_cc0
-      || dest == cc0_rtx
-#endif
+      || CC0_P (dest)
       || dest == pc_rtx)
     return;
 
@@ -6777,6 +6786,8 @@ cse_set_around_loop (x, insn, loop_start)
                       SET_SRC, add an insn after P to copy its destination
                       to what we will be replacing SET_SRC with.  */
                    if (cse_check_loop_start_value
+                       && single_set (p)
+                       && !can_throw_internal (insn)
                        && validate_change (insn, &SET_SRC (x),
                                            src_elt->exp, 0))
                      {
@@ -6819,10 +6830,10 @@ cse_set_around_loop (x, insn, loop_start)
    the total number of SETs in all the insns of the block, the last insn of the
    block, and the branch path.
 
-   The branch path indicates which branches should be followed.  If a non-zero
+   The branch path indicates which branches should be followed.  If a nonzero
    path size is specified, the block should be rescanned and a different set
    of branches will be taken.  The branch path is only used if
-   FLAG_CSE_FOLLOW_JUMPS or FLAG_CSE_SKIP_BLOCKS is non-zero.
+   FLAG_CSE_FOLLOW_JUMPS or FLAG_CSE_SKIP_BLOCKS is nonzero.
 
    DATA is a pointer to a struct cse_basic_block_data, defined below, that is
    used to describe the block.  It is filled in with the information about
@@ -6848,7 +6859,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
   /* Update the previous branch path, if any.  If the last branch was
      previously TAKEN, mark it NOT_TAKEN.  If it was previously NOT_TAKEN,
      shorten the path by one and look at the previous branch.  We know that
-     at least one branch must have been taken if PATH_SIZE is non-zero.  */
+     at least one branch must have been taken if PATH_SIZE is nonzero.  */
   while (path_size > 0)
     {
       if (data->path[path_size - 1].status != NOT_TAKEN)
@@ -6932,7 +6943,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
         In this case invalidate_skipped_block will be called to invalidate any
         registers set in the block when following the jump.  */
 
-      else if ((follow_jumps || skip_blocks) && path_size < PATHLENGTH - 1
+      else if ((follow_jumps || skip_blocks) && path_size < PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH) - 1
               && GET_CODE (p) == JUMP_INSN
               && GET_CODE (PATTERN (p)) == SET
               && GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE
@@ -7062,6 +7073,9 @@ cse_main (f, nregs, after_loop, file)
   rtx insn = f;
   int i;
 
+  val.path = xmalloc (sizeof (struct branch_path)
+                     * PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
+
   cse_jumps_altered = 0;
   recorded_label_ref = 0;
   constant_pool_entries_cost = 0;
@@ -7185,6 +7199,7 @@ cse_main (f, nregs, after_loop, file)
   end_alias_analysis ();
   free (uid_cuid);
   free (reg_eqv_table);
+  free (val.path);
 
   return cse_jumps_altered || recorded_label_ref;
 }
@@ -7193,7 +7208,7 @@ cse_main (f, nregs, after_loop, file)
    block.  NEXT_BRANCH points to the branch path when following jumps or
    a null path when not following jumps.
 
-   AROUND_LOOP is non-zero if we are to try to cse around to the start of a
+   AROUND_LOOP is nonzero if we are to try to cse around to the start of a
    loop.  This is true when we are being called for the last time on a
    block and this CSE pass is before loop.c.  */
 
@@ -7257,8 +7272,8 @@ cse_basic_block (from, to, next_branch, around_loop)
                 Then follow this branch.  */
 #ifdef HAVE_cc0
              prev_insn_cc0 = 0;
-#endif
              prev_insn = insn;
+#endif
              insn = JUMP_LABEL (insn);
              continue;
            }
@@ -7362,7 +7377,10 @@ cse_basic_block (from, to, next_branch, around_loop)
             following branches in this case.  */
          to_usage = 0;
          val.path_size = 0;
+         val.path = xmalloc (sizeof (struct branch_path)
+                             * PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
          cse_end_of_basic_block (insn, &val, 0, 0, 0);
+         free (val.path);
 
          /* If the tables we allocated have enough space left
             to handle all the SETs in the next basic block,
@@ -7444,6 +7462,7 @@ count_reg_usage (x, counts, dest, incr)
      int incr;
 {
   enum rtx_code code;
+  rtx note;
   const char *fmt;
   int i, j;
 
@@ -7478,15 +7497,8 @@ count_reg_usage (x, counts, dest, incr)
       /* Unless we are setting a REG, count everything in SET_DEST.  */
       if (GET_CODE (SET_DEST (x)) != REG)
        count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
-
-      /* If SRC has side-effects, then we can't delete this insn, so the
-        usage of SET_DEST inside SRC counts.
-
-        ??? Strictly-speaking, we might be preserving this insn
-        because some other SET has side-effects, but that's hard
-        to do and can't happen now.  */
       count_reg_usage (SET_SRC (x), counts,
-                      side_effects_p (SET_SRC (x)) ? NULL_RTX : SET_DEST (x),
+                      SET_DEST (x),
                       incr);
       return;
 
@@ -7501,17 +7513,39 @@ count_reg_usage (x, counts, dest, incr)
       /* Things used in a REG_EQUAL note aren't dead since loop may try to
         use them.  */
 
-      count_reg_usage (REG_NOTES (x), counts, NULL_RTX, incr);
+      note = find_reg_equal_equiv_note (x);
+      if (note)
+       {
+         rtx eqv = XEXP (note, 0);
+
+         if (GET_CODE (eqv) == EXPR_LIST)
+         /* This REG_EQUAL note describes the result of a function call.
+            Process all the arguments.  */
+           do
+             {
+               count_reg_usage (XEXP (eqv, 0), counts, NULL_RTX, incr);
+               eqv = XEXP (eqv, 1);
+             }
+           while (eqv && GET_CODE (eqv) == EXPR_LIST);
+         else
+           count_reg_usage (eqv, counts, NULL_RTX, incr);
+       }
       return;
 
     case EXPR_LIST:
-    case INSN_LIST:
       if (REG_NOTE_KIND (x) == REG_EQUAL
-         || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE))
+         || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)
+         /* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)),
+            involving registers in the address.  */
+         || GET_CODE (XEXP (x, 0)) == CLOBBER)
        count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
+
       count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
       return;
 
+    case INSN_LIST:
+      abort ();
+
     default:
       break;
     }
@@ -7570,7 +7604,9 @@ insn_live_p (insn, counts)
      int *counts;
 {
   int i;
-  if (GET_CODE (PATTERN (insn)) == SET)
+  if (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+    return true;
+  else if (GET_CODE (PATTERN (insn)) == SET)
     return set_live_p (PATTERN (insn), insn, counts);
   else if (GET_CODE (PATTERN (insn)) == PARALLEL)
     {
@@ -7599,33 +7635,49 @@ dead_libcall_p (insn, counts)
      rtx insn;
      int *counts;
 {
-  rtx note;
+  rtx note, set, new;
+
   /* See if there's a REG_EQUAL note on this insn and try to
      replace the source with the REG_EQUAL expression.
 
      We assume that insns with REG_RETVALs can only be reg->reg
      copies at this point.  */
   note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-  if (note)
-    {
-      rtx set = single_set (insn);
-      rtx new = simplify_rtx (XEXP (note, 0));
+  if (!note)
+    return false;
+
+  set = single_set (insn);
+  if (!set)
+    return false;
 
-      if (!new)
-       new = XEXP (note, 0);
+  new = simplify_rtx (XEXP (note, 0));
+  if (!new)
+    new = XEXP (note, 0);
 
-      /* While changing insn, we must update the counts accordingly.  */
-      count_reg_usage (insn, counts, NULL_RTX, -1);
+  /* While changing insn, we must update the counts accordingly.  */
+  count_reg_usage (insn, counts, NULL_RTX, -1);
 
-      if (set && validate_change (insn, &SET_SRC (set), new, 0))
+  if (validate_change (insn, &SET_SRC (set), new, 0))
+    {
+      count_reg_usage (insn, counts, NULL_RTX, 1);
+      remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
+      remove_note (insn, note);
+      return true;
+    }
+
+  if (CONSTANT_P (new))
+    {
+      new = force_const_mem (GET_MODE (SET_DEST (set)), new);
+      if (new && validate_change (insn, &SET_SRC (set), new, 0))
        {
-          count_reg_usage (insn, counts, NULL_RTX, 1);
+         count_reg_usage (insn, counts, NULL_RTX, 1);
          remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
          remove_note (insn, note);
          return true;
        }
-       count_reg_usage (insn, counts, NULL_RTX, 1);
     }
+      
+  count_reg_usage (insn, counts, NULL_RTX, 1);
   return false;
 }