OSDN Git Service

* simplify-rtx.c (simplify_binary_operation): Revert last change.
[pf3gnuchains/gcc-fork.git] / gcc / rtlanal.c
index b0fbcf3..5ac2c74 100644 (file)
@@ -2,36 +2,36 @@
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 
 #include "config.h"
 #include "system.h"
 #include "toplev.h"
 #include "rtl.h"
-
-static void reg_set_p_1                PARAMS ((rtx, rtx, void *));
-static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
-static void reg_set_last_1     PARAMS ((rtx, rtx, void *));
-
+#include "hard-reg-set.h"
 
 /* Forward declarations */
-static int jmp_uses_reg_or_mem         PARAMS ((rtx));
+static void set_of_1           PARAMS ((rtx, rtx, void *));
+static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
+static int computed_jump_p_1   PARAMS ((rtx));
+static int operand_preference  PARAMS ((rtx));
+static void parms_set          PARAMS ((rtx, rtx, void *));
 
 /* Bit flags that specify the machine subtype we are compiling for.
    Bits are tested using macros TARGET_... defined in the tm.h file
@@ -60,6 +60,7 @@ rtx_unstable_p (x)
     case QUEUED:
       return 1;
 
+    case ADDRESSOF:
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
@@ -70,7 +71,9 @@ rtx_unstable_p (x)
     case REG:
       /* As in rtx_varies_p, we have to use the actual rtx, not reg number.  */
       if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
-         || x == arg_pointer_rtx || RTX_UNCHANGING_P (x))
+         /* The arg pointer varies if it is not a fixed register.  */
+         || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])
+         || RTX_UNCHANGING_P (x))
        return 0;
 #ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
       /* ??? When call-clobbered, the value is stable modulo the restore
@@ -146,7 +149,8 @@ rtx_varies_p (x, for_alias)
         eliminated the frame and/or arg pointer and are using it
         for pseudos.  */
       if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
-         || x == arg_pointer_rtx)
+         /* The arg pointer varies if it is not a fixed register.  */
+         || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
        return 0;
       if (x == pic_offset_table_rtx
 #ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
@@ -162,8 +166,10 @@ rtx_varies_p (x, for_alias)
 
     case LO_SUM:
       /* The operand 0 of a LO_SUM is considered constant
-        (in fact is it related specifically to operand 1).  */
-      return rtx_varies_p (XEXP (x, 1), for_alias);
+        (in fact it is related specifically to operand 1)
+        during alias analysis.  */
+      return (! for_alias && rtx_varies_p (XEXP (x, 0), for_alias))
+            || rtx_varies_p (XEXP (x, 1), for_alias);
       
     case ASM_OPERANDS:
       if (MEM_VOLATILE_P (x))
@@ -204,17 +210,23 @@ rtx_addr_can_trap_p (x)
   switch (code)
     {
     case SYMBOL_REF:
+      return SYMBOL_REF_WEAK (x);
+
     case LABEL_REF:
-      /* SYMBOL_REF is problematic due to the possible presence of
-        a #pragma weak, but to say that loads from symbols can trap is
-        *very* costly.  It's not at all clear what's best here.  For
-        now, we ignore the impact of #pragma weak.  */
       return 0;
 
     case REG:
       /* As in rtx_varies_p, we have to use the actual rtx, not reg number.  */
-      return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
-               || x == stack_pointer_rtx || x == arg_pointer_rtx);
+      if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
+         || x == stack_pointer_rtx
+         /* The arg pointer varies if it is not a fixed register.  */
+         || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
+       return 0;
+      /* All of the virtual frame registers are stack references.  */
+      if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+         && REGNO (x) <= LAST_VIRTUAL_REGISTER)
+       return 0;
+      return 1;
 
     case CONST:
       return rtx_addr_can_trap_p (XEXP (x, 0));
@@ -229,8 +241,16 @@ rtx_addr_can_trap_p (x)
                    && CONSTANT_P (XEXP (x, 1))));
 
     case LO_SUM:
+    case PRE_MODIFY:
       return rtx_addr_can_trap_p (XEXP (x, 1));
-      
+
+    case PRE_DEC:
+    case PRE_INC:
+    case POST_DEC:
+    case POST_INC:
+    case POST_MODIFY:
+      return rtx_addr_can_trap_p (XEXP (x, 0));
+
     default:
       break;
     }
@@ -458,6 +478,8 @@ no_labels_between_p (beg, end)
      rtx beg, end;
 {
   register rtx p;
+  if (beg == end)
+    return 0;
   for (p = NEXT_INSN (beg); p != end; p = NEXT_INSN (p))
     if (GET_CODE (p) == CODE_LABEL)
       return 0;
@@ -617,24 +639,6 @@ reg_set_between_p (reg, from_insn, to_insn)
 }
 
 /* Internals of reg_set_between_p.  */
-
-static rtx reg_set_reg;
-static int reg_set_flag;
-
-static void
-reg_set_p_1 (x, pat, data)
-     rtx x;
-     rtx pat ATTRIBUTE_UNUSED;
-     void *data ATTRIBUTE_UNUSED;
-{
-  /* We don't want to return 1 if X is a MEM that contains a register
-     within REG_SET_REG.  */
-
-  if ((GET_CODE (x) != MEM)
-      && reg_overlap_mentioned_p (reg_set_reg, x))
-    reg_set_flag = 1;
-}
-
 int
 reg_set_p (reg, insn)
      rtx reg, insn;
@@ -662,10 +666,7 @@ reg_set_p (reg, insn)
       body = PATTERN (insn);
     }
 
-  reg_set_reg = reg;
-  reg_set_flag = 0;
-  note_stores (body, reg_set_p_1, NULL);
-  return reg_set_flag;
+  return set_of (reg, insn) != NULL_RTX;
 }
 
 /* Similar to reg_set_between_p, but check all registers in X.  Return 0
@@ -863,6 +864,38 @@ insn_dependent_p_1 (x, pat, data)
     *pinsn = NULL_RTX;
 }
 \f
+/* Helper function for set_of.  */
+struct set_of_data
+  {
+    rtx found;
+    rtx pat;
+  };
+
+static void
+set_of_1 (x, pat, data1)
+     rtx x;
+     rtx pat;
+     void *data1;
+{
+   struct set_of_data *data = (struct set_of_data *) (data1);
+   if (rtx_equal_p (x, data->pat)
+       || (GET_CODE (x) != MEM && reg_overlap_mentioned_p (data->pat, x)))
+     data->found = pat;
+}
+
+/* Give an INSN, return a SET or CLOBBER expression that does modify PAT
+   (eighter directly or via STRICT_LOW_PART and similar modifiers).  */
+rtx
+set_of (pat, insn)
+     rtx pat, insn;
+{
+  struct set_of_data data;
+  data.found = NULL_RTX;
+  data.pat = pat;
+  note_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
+  return data.found;
+}
+\f
 /* Given an INSN, return a SET expression if this insn has only a single SET.
    It may also have CLOBBERs, USEs, or SET whose output
    will not be used, which we ignore.  */
@@ -950,6 +983,87 @@ multiple_sets (insn)
   return 0;
 }
 \f
+/* Return nonzero if the destination of SET equals the source
+   and there are no side effects.  */
+
+int
+set_noop_p (set)
+     rtx set;
+{
+  rtx src = SET_SRC (set);
+  rtx dst = SET_DEST (set);
+
+  if (side_effects_p (src) || side_effects_p (dst))
+    return 0;
+
+  if (GET_CODE (dst) == MEM && GET_CODE (src) == MEM)
+    return rtx_equal_p (dst, src);
+
+  if (dst == pc_rtx && src == pc_rtx)
+    return 1;
+
+  if (GET_CODE (dst) == SIGN_EXTRACT
+      || GET_CODE (dst) == ZERO_EXTRACT)
+    return rtx_equal_p (XEXP (dst, 0), src)
+          && ! BYTES_BIG_ENDIAN && XEXP (dst, 2) == const0_rtx;
+
+  if (GET_CODE (dst) == STRICT_LOW_PART)
+    dst = XEXP (dst, 0);
+
+  if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
+    {
+      if (SUBREG_BYTE (src) != SUBREG_BYTE (dst))
+       return 0;
+      src = SUBREG_REG (src);
+      dst = SUBREG_REG (dst);
+    }
+
+  return (GET_CODE (src) == REG && GET_CODE (dst) == REG
+         && REGNO (src) == REGNO (dst));
+}
+\f
+/* Return nonzero if an insn consists only of SETs, each of which only sets a
+   value to itself.  */
+
+int
+noop_move_p (insn)
+     rtx insn;
+{
+  rtx pat = PATTERN (insn);
+
+  if (INSN_CODE (insn) == NOOP_MOVE_INSN_CODE)
+    return 1;
+
+  /* Insns carrying these notes are useful later on.  */
+  if (find_reg_note (insn, REG_EQUAL, NULL_RTX))
+    return 0;
+
+  if (GET_CODE (pat) == SET && set_noop_p (pat))
+    return 1;
+
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      int i;
+      /* If nothing but SETs of registers to themselves,
+        this insn can also be deleted.  */
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       {
+         rtx tem = XVECEXP (pat, 0, i);
+
+         if (GET_CODE (tem) == USE
+             || GET_CODE (tem) == CLOBBER)
+           continue;
+
+         if (GET_CODE (tem) != SET || ! set_noop_p (tem))
+           return 0;
+       }
+
+      return 1;
+    }
+  return 0;
+}
+\f
+
 /* Return the last thing that X was assigned from before *PINSN.  If VALID_TO
    is not NULL_RTX then verify that the object is not modified up to VALID_TO.
    If the object was modified, if we hit a partial assignment to X, or hit a
@@ -1053,7 +1167,7 @@ refers_to_regno_p (regno, endregno, x, loc)
       if (GET_CODE (SUBREG_REG (x)) == REG
          && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
        {
-         unsigned int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+         unsigned int inner_regno = subreg_regno (x);
          unsigned int inner_endregno
            = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
                             ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
@@ -1140,7 +1254,7 @@ reg_overlap_mentioned_p (x, in)
     case SUBREG:
       regno = REGNO (SUBREG_REG (x));
       if (regno < FIRST_PSEUDO_REGISTER)
-       regno += SUBREG_WORD (x);
+       regno = subreg_regno (x);
       goto do_reg;
 
     case REG:
@@ -1148,7 +1262,7 @@ reg_overlap_mentioned_p (x, in)
     do_reg:
       endregno = regno + (regno < FIRST_PSEUDO_REGISTER
                          ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
-      return refers_to_regno_p (regno, endregno, in, NULL_PTR);
+      return refers_to_regno_p (regno, endregno, in, (rtx*)0);
 
     case MEM:
       {
@@ -1173,19 +1287,13 @@ reg_overlap_mentioned_p (x, in)
 
     case PARALLEL:
       {
-       int i, n;
-
-       /* Check for a NULL entry, used to indicate that the parameter goes
-          both on the stack and in registers.  */
-       if (XEXP (XVECEXP (x, 0, 0), 0))
-         i = 0;
-       else
-         i = 1;
+       int i;
 
        /* If any register in here refers to it we return true.  */
-       for (n = XVECLEN (x, 0); i < n; ++i)
-         if (reg_overlap_mentioned_p (XEXP (XVECEXP (x, 0, i), 0), in))
-           return 1;
+       for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+         if (XEXP (XVECEXP (x, 0, i), 0) != 0
+             && reg_overlap_mentioned_p (XEXP (XVECEXP (x, 0, i), 0), in))
+             return 1;
        return 0;
       }
 
@@ -1196,45 +1304,6 @@ reg_overlap_mentioned_p (x, in)
   abort ();
 }
 \f
-/* Used for communications between the next few functions.  */
-
-static int reg_set_last_unknown;
-static rtx reg_set_last_value;
-static unsigned int reg_set_last_first_regno, reg_set_last_last_regno;
-
-/* Called via note_stores from reg_set_last.  */
-
-static void
-reg_set_last_1 (x, pat, data)
-     rtx x;
-     rtx pat;
-     void *data ATTRIBUTE_UNUSED;
-{
-  unsigned int first, last;
-
-  /* If X is not a register, or is not one in the range we care
-     about, ignore.  */
-  if (GET_CODE (x) != REG)
-    return;
-
-  first = REGNO (x);
-  last = first + (first < FIRST_PSEUDO_REGISTER
-                 ? HARD_REGNO_NREGS (first, GET_MODE (x)) : 1);
-
-  if (first >= reg_set_last_last_regno
-      || last <= reg_set_last_first_regno)
-    return;
-
-  /* If this is a CLOBBER or is some complex LHS, or doesn't modify
-     exactly the registers we care about, show we don't know the value.  */
-  if (GET_CODE (pat) == CLOBBER || SET_DEST (pat) != x
-      || first != reg_set_last_first_regno
-      || last != reg_set_last_last_regno)
-    reg_set_last_unknown = 1;
-  else
-    reg_set_last_value = SET_SRC (pat);
-}
-
 /* Return the last value to which REG was set prior to INSN.  If we can't
    find it easily, return 0.
 
@@ -1248,16 +1317,6 @@ reg_set_last (x, insn)
 {
   rtx orig_insn = insn;
 
-  reg_set_last_first_regno = REGNO (x);
-
-  reg_set_last_last_regno
-    = reg_set_last_first_regno
-      + (reg_set_last_first_regno < FIRST_PSEUDO_REGISTER
-        ? HARD_REGNO_NREGS (reg_set_last_first_regno, GET_MODE (x)) : 1);
-
-  reg_set_last_unknown = 0;
-  reg_set_last_value = 0;
-
   /* Scan backwards until reg_set_last_1 changed one of the above flags.
      Stop when we reach a label or X is a hard reg and we reach a
      CALL_INSN (if reg_set_last_last_regno is a hard reg).
@@ -1269,21 +1328,24 @@ reg_set_last (x, insn)
   for (;
        insn && GET_CODE (insn) != CODE_LABEL
        && ! (GET_CODE (insn) == CALL_INSN
-            && reg_set_last_last_regno <= FIRST_PSEUDO_REGISTER);
+            && REGNO (x) <= FIRST_PSEUDO_REGISTER);
        insn = PREV_INSN (insn))
     if (INSN_P (insn))
       {
-       note_stores (PATTERN (insn), reg_set_last_1, NULL);
-       if (reg_set_last_unknown)
-         return 0;
-       else if (reg_set_last_value)
+       rtx set = set_of (x, insn);
+       /* OK, this function modify our register.  See if we understand it.  */
+       if (set)
          {
-           if (CONSTANT_P (reg_set_last_value)
-               || ((GET_CODE (reg_set_last_value) == REG
-                    || GET_CODE (reg_set_last_value) == SUBREG)
-                   && ! reg_set_between_p (reg_set_last_value,
+           rtx last_value;
+           if (GET_CODE (set) != SET || SET_DEST (set) != x)
+             return 0;
+           last_value = SET_SRC (x);
+           if (CONSTANT_P (last_value)
+               || ((GET_CODE (last_value) == REG
+                    || GET_CODE (last_value) == SUBREG)
+                   && ! reg_set_between_p (last_value,
                                            insn, orig_insn)))
-             return reg_set_last_value;
+             return last_value;
            else
              return 0;
          }
@@ -1307,11 +1369,15 @@ note_stores (x, fun, data)
      void (*fun) PARAMS ((rtx, rtx, void *));
      void *data;
 {
+  int i;
+
   if (GET_CODE (x) == COND_EXEC)
     x = COND_EXEC_CODE (x);
+
   if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
     {
       register rtx dest = SET_DEST (x);
+
       while ((GET_CODE (dest) == SUBREG
              && (GET_CODE (SUBREG_REG (dest)) != REG
                  || REGNO (SUBREG_REG (dest)) >= FIRST_PSEUDO_REGISTER))
@@ -1320,47 +1386,108 @@ note_stores (x, fun, data)
             || GET_CODE (dest) == STRICT_LOW_PART)
        dest = XEXP (dest, 0);
 
-      if (GET_CODE (dest) == PARALLEL
-         && GET_MODE (dest) == BLKmode)
+      /* If we have a PARALLEL, SET_DEST is a list of EXPR_LIST expressions,
+        each of whose first operand is a register.  We can't know what
+        precisely is being set in these cases, so make up a CLOBBER to pass
+        to the function.  */
+      if (GET_CODE (dest) == PARALLEL)
        {
-         register int i;
          for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
-           (*fun) (SET_DEST (XVECEXP (dest, 0, i)), x, data);
+           if (XEXP (XVECEXP (dest, 0, i), 0) != 0)
+             (*fun) (XEXP (XVECEXP (dest, 0, i), 0),
+                     gen_rtx_CLOBBER (VOIDmode,
+                                      XEXP (XVECEXP (dest, 0, i), 0)),
+                     data);
        }
       else
        (*fun) (dest, x, data);
     }
+
   else if (GET_CODE (x) == PARALLEL)
+    for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+      note_stores (XVECEXP (x, 0, i), fun, data);
+}
+\f
+/* Like notes_stores, but call FUN for each expression that is being
+   referenced in PBODY, a pointer to the PATTERN of an insn.  We only call
+   FUN for each expression, not any interior subexpressions.  FUN receives a
+   pointer to the expression and the DATA passed to this function.
+
+   Note that this is not quite the same test as that done in reg_referenced_p
+   since that considers something as being referenced if it is being
+   partially set, while we do not.  */
+
+void
+note_uses (pbody, fun, data)
+     rtx *pbody;
+     void (*fun) PARAMS ((rtx *, void *));
+     void *data;
+{
+  rtx body = *pbody;
+  int i;
+
+  switch (GET_CODE (body))
     {
-      register int i;
-      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
-       {
-         register rtx y = XVECEXP (x, 0, i);
-         if (GET_CODE (y) == COND_EXEC)
-           y = COND_EXEC_CODE (y);
-         if (GET_CODE (y) == SET || GET_CODE (y) == CLOBBER)
-           {
-             register rtx dest = SET_DEST (y);
-             while ((GET_CODE (dest) == SUBREG
-                     && (GET_CODE (SUBREG_REG (dest)) != REG
-                         || (REGNO (SUBREG_REG (dest))
-                             >= FIRST_PSEUDO_REGISTER)))
-                    || GET_CODE (dest) == ZERO_EXTRACT
-                    || GET_CODE (dest) == SIGN_EXTRACT
-                    || GET_CODE (dest) == STRICT_LOW_PART)
-               dest = XEXP (dest, 0);
-             if (GET_CODE (dest) == PARALLEL
-                 && GET_MODE (dest) == BLKmode)
-               {
-                 register int i;
+    case COND_EXEC:
+      (*fun) (&COND_EXEC_TEST (body), data);
+      note_uses (&COND_EXEC_CODE (body), fun, data);
+      return;
 
-                 for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
-                   (*fun) (SET_DEST (XVECEXP (dest, 0, i)), y, data);
-               }
-             else
-               (*fun) (dest, y, data);
-           }
-       }
+    case PARALLEL:
+      for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
+       note_uses (&XVECEXP (body, 0, i), fun, data);
+      return;
+
+    case USE:
+      (*fun) (&XEXP (body, 0), data);
+      return;
+
+    case ASM_OPERANDS:
+      for (i = ASM_OPERANDS_INPUT_LENGTH (body) - 1; i >= 0; i--)
+       (*fun) (&ASM_OPERANDS_INPUT (body, i), data);
+      return;
+
+    case TRAP_IF:
+      (*fun) (&TRAP_CONDITION (body), data);
+      return;
+
+    case UNSPEC:
+    case UNSPEC_VOLATILE:
+      for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
+       (*fun) (&XVECEXP (body, 0, i), data);
+      return;
+
+    case CLOBBER:
+      if (GET_CODE (XEXP (body, 0)) == MEM)
+       (*fun) (&XEXP (XEXP (body, 0), 0), data);
+      return;
+
+    case SET:
+      {
+       rtx dest = SET_DEST (body);
+
+       /* For sets we replace everything in source plus registers in memory
+          expression in store and operands of a ZERO_EXTRACT.  */
+       (*fun) (&SET_SRC (body), data);
+
+       if (GET_CODE (dest) == ZERO_EXTRACT)
+         {
+           (*fun) (&XEXP (dest, 1), data);
+           (*fun) (&XEXP (dest, 2), data);
+         }
+
+       while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART)
+         dest = XEXP (dest, 0);
+
+       if (GET_CODE (dest) == MEM)
+         (*fun) (&XEXP (dest, 0), data);
+      }
+      return;
+
+    default:
+      /* All the other possibilities never store.  */
+      (*fun) (pbody, data);
+      return;
     }
 }
 \f
@@ -1546,6 +1673,23 @@ find_regno_note (insn, kind, regno)
   return 0;
 }
 
+/* Return a REG_EQUIV or REG_EQUAL note if insn has only a single set and
+   has such a note.  */
+
+rtx
+find_reg_equal_equiv_note (insn)
+     rtx insn;
+{
+  rtx note;
+
+  if (single_set (insn) == 0)
+    return 0;
+  else if ((note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
+    return note;
+  else
+    return find_reg_note (insn, REG_EQUAL, NULL_RTX);
+}
+
 /* Return true if DATUM, or any overlap of DATUM, of kind CODE is found
    in the CALL_INSN_FUNCTION_USAGE information of INSN.  */
 
@@ -1657,11 +1801,10 @@ remove_note (insn, note)
   abort ();
 }
 
-/* Search LISTP (an EXPR_LIST) for NODE and remove NODE from the list
-   if it is found.
+/* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and
+   remove that entry from the list if it is found.
 
-   A simple equality test is used to determine if NODE is on the
-   EXPR_LIST.  */
+   A simple equality test is used to determine if NODE matches.  */
 
 void
 remove_node_from_expr_list (node, listp)
@@ -1683,6 +1826,8 @@ remove_node_from_expr_list (node, listp)
 
          return;
        }
+
+      prev = temp;
       temp = XEXP (temp, 1);
     }
 }
@@ -1975,6 +2120,11 @@ may_trap_p (x)
        return 1;
       break;
 
+    case NEG:
+    case ABS:
+      /* These operations don't trap even with floating point.  */
+      break;
+
     default:
       /* Any floating arithmetic may trap.  */
       if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
@@ -2074,7 +2224,7 @@ replace_rtx (x, from, to)
   register const char *fmt;
 
   /* The following prevents loops occurrence when we change MEM in
-     CONST_DOUBLE onto the same CONST_DOUBLE. */
+     CONST_DOUBLE onto the same CONST_DOUBLE.  */
   if (x != 0 && GET_CODE (x) == CONST_DOUBLE)
     return x;
 
@@ -2157,26 +2307,9 @@ replace_regs (x, reg_map, nregs, replace_dest)
          && GET_CODE (reg_map[REGNO (SUBREG_REG (x))]) == SUBREG)
        {
          rtx map_val = reg_map[REGNO (SUBREG_REG (x))];
-         rtx map_inner = SUBREG_REG (map_val);
-
-         if (GET_MODE (x) == GET_MODE (map_inner))
-           return map_inner;
-         else
-           {
-             /* We cannot call gen_rtx here since we may be linked with
-                genattrtab.c.  */
-             /* Let's try clobbering the incoming SUBREG and see
-                if this is really safe.  */
-             SUBREG_REG (x) = map_inner;
-             SUBREG_WORD (x) += SUBREG_WORD (map_val);
-             return x;
-#if 0
-             rtx new = rtx_alloc (SUBREG);
-             PUT_MODE (new, GET_MODE (x));
-             SUBREG_REG (new) = map_inner;
-             SUBREG_WORD (new) = SUBREG_WORD (x) + SUBREG_WORD (map_val);
-#endif
-           }
+         return simplify_gen_subreg (GET_MODE (x), map_val,
+                                     GET_MODE (SUBREG_REG (x)), 
+                                     SUBREG_BYTE (x));
        }
       break;
 
@@ -2218,11 +2351,12 @@ replace_regs (x, reg_map, nregs, replace_dest)
   return x;
 }
 
-/* Return 1 if X, the SRC_SRC of  SET of (pc) contain a REG or MEM that is
-   not in the constant pool and not in the condition of an IF_THEN_ELSE.  */
+/* A subroutine of computed_jump_p, return 1 if X contains a REG or MEM or
+   constant that is not in the constant pool and not in the condition
+   of an IF_THEN_ELSE.  */
 
 static int
-jmp_uses_reg_or_mem (x)
+computed_jump_p_1 (x)
      rtx x;
 {
   enum rtx_code code = GET_CODE (x);
@@ -2231,11 +2365,14 @@ jmp_uses_reg_or_mem (x)
 
   switch (code)
     {
-    case CONST:
     case LABEL_REF:
     case PC:
       return 0;
 
+    case CONST:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
     case REG:
       return 1;
 
@@ -2244,12 +2381,8 @@ jmp_uses_reg_or_mem (x)
                && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)));
 
     case IF_THEN_ELSE:
-      return (jmp_uses_reg_or_mem (XEXP (x, 1))
-             || jmp_uses_reg_or_mem (XEXP (x, 2)));
-
-    case PLUS:  case MINUS:  case MULT:
-      return (jmp_uses_reg_or_mem (XEXP (x, 0))
-             || jmp_uses_reg_or_mem (XEXP (x, 1)));
+      return (computed_jump_p_1 (XEXP (x, 1))
+             || computed_jump_p_1 (XEXP (x, 2)));
 
     default:
       break;
@@ -2259,12 +2392,12 @@ jmp_uses_reg_or_mem (x)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e'
-         && jmp_uses_reg_or_mem (XEXP (x, i)))
+         && computed_jump_p_1 (XEXP (x, i)))
        return 1;
 
       else if (fmt[i] == 'E')
        for (j = 0; j < XVECLEN (x, i); j++)
-         if (jmp_uses_reg_or_mem (XVECEXP (x, i, j)))
+         if (computed_jump_p_1 (XVECEXP (x, i, j)))
            return 1;
     }
 
@@ -2302,12 +2435,12 @@ computed_jump_p (insn)
            for (i = len - 1; i >= 0; i--)
              if (GET_CODE (XVECEXP (pat, 0, i)) == SET
                  && SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx
-                 && jmp_uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
+                 && computed_jump_p_1 (SET_SRC (XVECEXP (pat, 0, i))))
                return 1;
        }
       else if (GET_CODE (pat) == SET
               && SET_DEST (pat) == pc_rtx
-              && jmp_uses_reg_or_mem (SET_SRC (pat)))
+              && computed_jump_p_1 (SET_SRC (pat)))
        return 1;
     }
   return 0;
@@ -2334,11 +2467,11 @@ for_each_rtx (x, f, data)
 {
   int result;
   int length;
-  const charformat;
+  const char *format;
   int i;
 
   /* Call F on X.  */
-  result = (*f)(x, data);
+  result = (*f) (x, data);
   if (result == -1)
     /* Do not traverse sub-expressions.  */
     return 0;
@@ -2419,6 +2552,53 @@ regno_use_in (regno, x)
   return NULL_RTX;
 }
 
+/* Return a value indicating whether OP, an operand of a commutative
+   operation, is preferred as the first or second operand.  The higher
+   the value, the stronger the preference for being the first operand.
+   We use negative values to indicate a preference for the first operand
+   and positive values for the second operand.  */
+
+static int
+operand_preference (op)
+     rtx op;
+{
+  /* Constants always come the second operand.  Prefer "nice" constants.  */
+  if (GET_CODE (op) == CONST_INT)
+    return -5;
+  if (GET_CODE (op) == CONST_DOUBLE)
+    return -4;
+  if (CONSTANT_P (op))
+    return -3;
+
+  /* SUBREGs of objects should come second.  */
+  if (GET_CODE (op) == SUBREG
+      && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op))) == 'o')
+    return -2;
+
+  /* If only one operand is a `neg', `not',
+    `mult', `plus', or `minus' expression, it will be the first
+    operand.  */
+  if (GET_CODE (op) == NEG || GET_CODE (op) == NOT
+      || GET_CODE (op) == MULT || GET_CODE (op) == PLUS
+      || GET_CODE (op) == MINUS)
+    return 2;
+
+  /* Complex expressions should be the first, so decrease priority
+     of objects.  */
+  if (GET_RTX_CLASS (GET_CODE (op)) == 'o')
+    return -1;
+  return 0;
+}
+
+/* Return 1 iff it is neccesary to swap operands of commutative operation
+   in order to canonicalize expression.  */
+
+int
+swap_commutative_operands_p (x, y)
+     rtx x, y;
+{
+  return operand_preference (x) < operand_preference (y);
+}
 
 /* Return 1 if X is an autoincrement side effect and the register is
    not the stack pointer.  */
@@ -2450,7 +2630,7 @@ auto_inc_p (x)
    end of the extended sequence.  
  
    For now, this function only checks that the region contains whole
-   exception regiongs, but it could be extended to check additional
+   exception regions, but it could be extended to check additional
    conditions as well.  */
 
 int
@@ -2547,3 +2727,143 @@ loc_mentioned_in_p (loc, in)
     }
   return 0;
 }
+
+/* This function returns the regno offset of a subreg expression.
+   xregno - A regno of an inner hard subreg_reg (or what will become one).
+   xmode  - The mode of xregno.
+   offset - The byte offset.
+   ymode  - The mode of a top level SUBREG (or what may become one).
+   RETURN - The regno offset which would be used.  
+   This function can be overridden by defining SUBREG_REGNO_OFFSET,
+   taking the same parameters.  */
+unsigned int
+subreg_regno_offset (xregno, xmode, offset, ymode)
+     unsigned int xregno;
+     enum machine_mode xmode;
+     unsigned int offset;
+     enum machine_mode ymode;
+{
+  unsigned ret;
+  int nregs_xmode, nregs_ymode;
+  int mode_multiple, nregs_multiple;
+  int y_offset;
+
+/* Check for an override, and use it instead.  */
+#ifdef SUBREG_REGNO_OFFSET
+  ret = SUBREG_REGNO_OFFSET (xregno, xmode, offset, ymode)
+#else
+  if (xregno >= FIRST_PSEUDO_REGISTER)
+    abort ();
+
+  nregs_xmode = HARD_REGNO_NREGS (xregno, xmode);
+  nregs_ymode = HARD_REGNO_NREGS (xregno, ymode);
+  if (offset == 0 || nregs_xmode == nregs_ymode)
+    return 0;
+  
+  /* size of ymode must not be greater than the size of xmode.  */
+  mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
+  if (mode_multiple == 0)
+    abort ();
+
+  y_offset = offset / GET_MODE_SIZE (ymode);
+  nregs_multiple =  nregs_xmode / nregs_ymode;
+  ret = (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode;
+#endif
+
+  return ret;
+}
+
+/* Return the final regno that a subreg expression refers to.  */
+unsigned int 
+subreg_regno (x)
+     rtx x;
+{
+  unsigned int ret;
+  rtx subreg = SUBREG_REG (x);
+  int regno = REGNO (subreg);
+
+  ret = regno + subreg_regno_offset (regno, 
+                                    GET_MODE (subreg), 
+                                    SUBREG_BYTE (x),
+                                    GET_MODE (x));
+  return ret;
+
+}
+struct parms_set_data
+{
+  int nregs;
+  HARD_REG_SET regs;
+};
+
+/* Helper function for noticing stores to parameter registers.  */
+static void
+parms_set (x, pat, data)
+       rtx x, pat ATTRIBUTE_UNUSED;
+       void *data;
+{
+  struct parms_set_data *d = data;
+  if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER
+      && TEST_HARD_REG_BIT (d->regs, REGNO (x)))
+    {
+      CLEAR_HARD_REG_BIT (d->regs, REGNO (x));
+      d->nregs--;
+    }
+}
+
+/* Look backward for first parameter to be loaded.  
+   Do not skip BOUNDARY.  */
+rtx
+find_first_parameter_load (call_insn, boundary)
+     rtx call_insn, boundary;
+{
+  struct parms_set_data parm;
+  rtx p, before;
+
+  /* Since different machines initialize their parameter registers
+     in different orders, assume nothing.  Collect the set of all
+     parameter registers.  */
+  CLEAR_HARD_REG_SET (parm.regs);
+  parm.nregs = 0;
+  for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
+    if (GET_CODE (XEXP (p, 0)) == USE
+       && GET_CODE (XEXP (XEXP (p, 0), 0)) == REG)
+      {
+       if (REGNO (XEXP (XEXP (p, 0), 0)) >= FIRST_PSEUDO_REGISTER)
+         abort ();
+
+       /* We only care about registers which can hold function
+          arguments.  */
+       if (!FUNCTION_ARG_REGNO_P (REGNO (XEXP (XEXP (p, 0), 0))))
+         continue;
+
+       SET_HARD_REG_BIT (parm.regs, REGNO (XEXP (XEXP (p, 0), 0)));
+       parm.nregs++;
+      }
+  before = call_insn;
+
+  /* Search backward for the first set of a register in this set.  */
+  while (parm.nregs && before != boundary)
+    {
+      before = PREV_INSN (before);
+
+      /* It is possible that some loads got CSEed from one call to
+         another.  Stop in that case.  */
+      if (GET_CODE (before) == CALL_INSN)
+       break;
+
+      /* Our caller needs either ensure that we will find all sets
+         (in case code has not been optimized yet), or take care
+         for possible labels in a way by setting boundary to preceeding
+         CODE_LABEL.  */
+      if (GET_CODE (before) == CODE_LABEL)
+       {
+         if (before != boundary)
+           abort ();
+         break;
+       }
+
+      if (INSN_P (before))
+        note_stores (PATTERN (before), parms_set, &parm);
+    }
+  return before;
+}