OSDN Git Service

(fold_rtx, case PLUS): When seeing if negative of constant is around,
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index ba816d7..260da29 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,5 +1,5 @@
 /* Common subexpression elimination for GNU compiler.
-   Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -478,12 +478,24 @@ struct table_elt
   ((REG_USERVAR_P (N) && REGNO (N) < FIRST_PSEUDO_REGISTER)    \
    || CHEAP_REGNO (REGNO (N)))
 
-#define COST(X)                                                \
-  (GET_CODE (X) == REG                                 \
-   ? (CHEAP_REG (X) ? 0                                        \
-      : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1         \
-      : 2)                                             \
-   : rtx_cost (X, SET) * 2)
+#define COST(X)                                                                \
+  (GET_CODE (X) == REG                                                 \
+   ? (CHEAP_REG (X) ? 0                                                        \
+      : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1                         \
+      : 2)                                                             \
+   : ((GET_CODE (X) == SUBREG                                          \
+       && GET_CODE (SUBREG_REG (X)) == REG                             \
+       && GET_MODE_CLASS (GET_MODE (X)) == MODE_INT                    \
+       && GET_MODE_CLASS (GET_MODE (SUBREG_REG (X))) == MODE_INT       \
+       && (GET_MODE_SIZE (GET_MODE (X))                                        \
+          < GET_MODE_SIZE (GET_MODE (SUBREG_REG (X))))                 \
+       && subreg_lowpart_p (X)                                         \
+       && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (X)),      \
+                                GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (X))))) \
+      ? (CHEAP_REG (SUBREG_REG (X)) ? 0                                        \
+        : REGNO (SUBREG_REG (X)) >= FIRST_PSEUDO_REGISTER ? 1          \
+        : 2)                                                           \
+      : rtx_cost (X, SET) * 2))
 
 /* Determine if the quantity number for register X represents a valid index
    into the `qty_...' variables.  */
@@ -1891,7 +1903,8 @@ canon_hash (x, mode)
        if (regno < FIRST_PSEUDO_REGISTER
            && (global_regs[regno]
 #ifdef SMALL_REGISTER_CLASSES
-               || (! fixed_regs[regno]
+               || (SMALL_REGISTER_CLASSES
+                   && ! fixed_regs[regno]
                    && regno != FRAME_POINTER_REGNUM
                    && regno != HARD_FRAME_POINTER_REGNUM
                    && regno != ARG_POINTER_REGNUM
@@ -1945,7 +1958,7 @@ canon_hash (x, mode)
          do_not_record = 1;
          return 0;
        }
-      if (! RTX_UNCHANGING_P (x))
+      if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0)))
        {
          hash_arg_in_memory = 1;
          if (MEM_IN_STRUCT_P (x)) hash_arg_in_struct = 1;
@@ -2582,6 +2595,7 @@ canon_reg (x, insn)
       if (fmt[i] == 'e')
        {
          rtx new = canon_reg (XEXP (x, i), insn);
+         int insn_code;
 
          /* If replacing pseudo with hard reg or vice versa, ensure the
             insn remains valid.  Likewise if the insn has MATCH_DUPs.  */
@@ -2589,7 +2603,8 @@ canon_reg (x, insn)
              && GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG
              && (((REGNO (new) < FIRST_PSEUDO_REGISTER)
                   != (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER))
-                 || insn_n_dups[recog_memoized (insn)] > 0))
+                 || (insn_code = recog_memoized (insn)) < 0
+                 || insn_n_dups[insn_code] > 0))
            validate_change (insn, &XEXP (x, i), new, 1);
          else
            XEXP (x, i) = new;
@@ -2602,7 +2617,7 @@ canon_reg (x, insn)
   return x;
 }
 \f
-/* LOC is a location with INSN that is an operand address (the contents of
+/* LOC is a location within INSN that is an operand address (the contents of
    a MEM).  Find the best equivalent address to use that is valid for this
    insn.
 
@@ -5160,6 +5175,12 @@ fold_rtx (x, insn)
 
        return x;
       }
+
+    case ASM_OPERANDS:
+      for (i = XVECLEN (x, 3) - 1; i >= 0; i--)
+       validate_change (insn, &XVECEXP (x, 3, i),
+                        fold_rtx (XVECEXP (x, 3, i), insn), 0);
+      break;
     }
 
   const_arg0 = 0;
@@ -5560,11 +5581,17 @@ fold_rtx (x, insn)
          /* If second operand is a register equivalent to a negative
             CONST_INT, see if we can find a register equivalent to the
             positive constant.  Make a MINUS if so.  Don't do this for
-            a negative constant since we might then alternate between
+            a non-negative constant since we might then alternate between
             chosing positive and negative constants.  Having the positive
-            constant previously-used is the more common case.  */
-         if (const_arg1 && GET_CODE (const_arg1) == CONST_INT
-             && INTVAL (const_arg1) < 0 && GET_CODE (folded_arg1) == REG)
+            constant previously-used is the more common case.  Be sure
+            the resulting constant is non-negative; if const_arg1 were
+            the smallest negative number this would overflow: depending
+            on the mode, this would either just be the same value (and
+            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
+             && GET_CODE (folded_arg1) == REG)
            {
              rtx new_const = GEN_INT (- INTVAL (const_arg1));
              struct table_elt *p
@@ -6309,11 +6336,13 @@ cse_insn (insn, in_libcall_block)
       rtx dest = SET_DEST (sets[i].rtl);
       rtx src = SET_SRC (sets[i].rtl);
       rtx new = canon_reg (src, insn);
+      int insn_code;
 
       if ((GET_CODE (new) == REG && GET_CODE (src) == REG
           && ((REGNO (new) < FIRST_PSEUDO_REGISTER)
               != (REGNO (src) < FIRST_PSEUDO_REGISTER)))
-         || insn_n_dups[recog_memoized (insn)] > 0)
+         || (insn_code = recog_memoized (insn)) < 0
+         || insn_n_dups[insn_code] > 0)
        validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
       else
        SET_SRC (sets[i].rtl) = new;
@@ -7377,7 +7406,9 @@ cse_insn (insn, in_libcall_block)
        elt = insert (dest, sets[i].src_elt,
                      sets[i].dest_hash, GET_MODE (dest));
        elt->in_memory = (GET_CODE (sets[i].inner_dest) == MEM
-                         && ! RTX_UNCHANGING_P (sets[i].inner_dest));
+                         && (! RTX_UNCHANGING_P (sets[i].inner_dest)
+                             || FIXED_BASE_PLUS_P (XEXP (sets[i].inner_dest,
+                                                         0))));
 
        if (elt->in_memory)
          {
@@ -7632,15 +7663,13 @@ invalidate_from_clobbers (w, x)
   if (GET_CODE (x) == CLOBBER)
     {
       rtx ref = XEXP (x, 0);
-      if (ref)
-       {
-         if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
-             || (GET_CODE (ref) == MEM && ! w->all))
-           invalidate (ref, VOIDmode);
-         else if (GET_CODE (ref) == STRICT_LOW_PART
-                  || GET_CODE (ref) == ZERO_EXTRACT)
-           invalidate (XEXP (ref, 0), GET_MODE (ref));
-       }
+
+      if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
+         || (GET_CODE (ref) == MEM && ! w->all))
+       invalidate (ref, VOIDmode);
+      else if (GET_CODE (ref) == STRICT_LOW_PART
+              || GET_CODE (ref) == ZERO_EXTRACT)
+       invalidate (XEXP (ref, 0), GET_MODE (ref));
     }
   else if (GET_CODE (x) == PARALLEL)
     {