OSDN Git Service

(fold_rtx, case PLUS): When seeing if negative of constant is around,
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index e1c6bca..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.  */
@@ -534,7 +546,7 @@ static int constant_pool_entries_cost;
 
 struct write_data
 {
-  int sp : 1;                  /* Invalidate stack pointer. */
+  int sp : 1;                  /* Invalidate stack pointer.  */
   int var : 1;                 /* Invalidate variable addresses.  */
   int nonscalar : 1;           /* Invalidate all but scalar variables.  */
   int all : 1;                 /* Invalidate all memory refs.  */
@@ -559,7 +571,7 @@ struct cse_basic_block_data {
   int path_size;
   /* Current branch path, indicating which branches will be taken.  */
   struct branch_path {
-    /* The branch insn. */
+    /* The branch insn.  */
     rtx branch;
     /* Whether it should be taken or not.  AROUND is the same as taken
        except that it is used when the destination label is not preceded
@@ -1466,7 +1478,7 @@ merge_equiv_classes (class1, class2)
 
       /* Remove old entry, make a new one in CLASS1's class.
         Don't do this for invalid entries as we cannot find their
-        hash code (it also isn't necessary). */
+        hash code (it also isn't necessary).  */
       if (GET_CODE (exp) == REG || exp_equiv_p (exp, exp, 1, 0))
        {
          hash_arg_in_memory = 0;
@@ -1886,12 +1898,13 @@ canon_hash (x, mode)
        /* On some machines, we can't record any non-fixed hard register,
           because extending its life will cause reload problems.  We
           consider ap, fp, and sp to be fixed for this purpose.
-          On all machines, we can't record any global registers. */
+          On all machines, we can't record any global registers.  */
 
        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.
 
@@ -3179,7 +3194,7 @@ simplify_unary_operation (code, mode, op, op_mode)
     }
 
   /* We can do some operations on integer CONST_DOUBLEs.  Also allow
-     for a DImode operation on a CONST_INT. */
+     for a DImode operation on a CONST_INT.  */
   else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2
           && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
     {
@@ -3525,7 +3540,7 @@ simplify_binary_operation (code, mode, op0, op1)
          neg_double (l2, h2, &lv, &hv);
          l2 = lv, h2 = hv;
 
-         /* .. fall through ... */
+         /* .. fall through ...  */
 
        case PLUS:
          add_double (l1, h1, l2, h2, &lv, &hv);
@@ -3878,6 +3893,11 @@ simplify_binary_operation (code, mode, op0, op1)
             we are still generating RTL.  This test is a kludge.  */
          if (GET_CODE (op1) == CONST_INT
              && (val = exact_log2 (INTVAL (op1))) >= 0
+             /* If the mode is larger than the host word size, and the
+                uppermost bit is set, then this isn't a power of two due
+                to implicit sign extension.  */
+             && (width <= HOST_BITS_PER_WIDE_INT
+                 || val != HOST_BITS_PER_WIDE_INT - 1)
              && ! rtx_equal_function_value_matters)
            return gen_rtx (ASHIFT, mode, op0, GEN_INT (val));
 
@@ -3957,7 +3977,7 @@ simplify_binary_operation (code, mode, op0, op1)
              && (arg1 = exact_log2 (INTVAL (op1))) > 0)
            return gen_rtx (LSHIFTRT, mode, op0, GEN_INT (arg1));
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case DIV:
          if (op1 == CONST1_RTX (mode))
@@ -4003,7 +4023,7 @@ simplify_binary_operation (code, mode, op0, op1)
              && exact_log2 (INTVAL (op1)) > 0)
            return gen_rtx (AND, mode, op0, GEN_INT (INTVAL (op1) - 1));
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case MOD:
          if ((op0 == const0_rtx || op1 == const1_rtx)
@@ -4019,7 +4039,7 @@ simplify_binary_operation (code, mode, op0, op1)
              && ! side_effects_p (op1))
            return op0;
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case ASHIFT:
        case ASHIFTRT:
@@ -5155,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;
@@ -5376,12 +5402,14 @@ fold_rtx (x, insn)
          if (mode_arg0 == VOIDmode || GET_MODE_CLASS (mode_arg0) == MODE_CC)
            break;
 
-         /* If we do not now have two constants being compared, see if we
-            can nevertheless deduce some things about the comparison.  */
+         /* If we do not now have two constants being compared, see
+            if we can nevertheless deduce some things about the
+            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. */
+             /* Is FOLDED_ARG0 frame-pointer plus a constant?  Or
+                non-explicit constant?  These aren't zero, but we
+                don't know their sign.  */
              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
@@ -5553,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
@@ -5584,7 +5618,7 @@ fold_rtx (x, insn)
                                 NULL_RTX);
            }
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        from_plus:
        case SMIN:    case SMAX:      case UMIN:    case UMAX:
@@ -6164,7 +6198,7 @@ cse_insn (insn, in_libcall_block)
         someplace else, so it isn't worth cse'ing (and on 80386 is unsafe)!
         Ensure we invalidate the destination register.  On the 80386 no
         other code would invalidate it since it is a fixed_reg.
-        We need not check the return of apply_change_group; see canon_reg. */
+        We need not check the return of apply_change_group; see canon_reg.  */
 
       else if (GET_CODE (SET_SRC (x)) == CALL)
        {
@@ -6302,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;
@@ -6736,7 +6772,7 @@ cse_insn (insn, in_libcall_block)
          that are when they are equal cost.  Note that we can never
          worsen an insn as the current contents will also succeed.
         If we find an equivalent identical to the destination, use it as best,
-        since this insn will probably be eliminated in that case. */
+        since this insn will probably be eliminated in that case.  */
       if (src)
        {
          if (rtx_equal_p (src, dest))
@@ -7370,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)
          {
@@ -7558,7 +7596,7 @@ note_mem_written (written, writes_ptr)
     *writes_ptr = everything;
   else if (GET_CODE (written) == MEM)
     {
-      /* Pushing or popping the stack invalidates just the stack pointer. */
+      /* Pushing or popping the stack invalidates just the stack pointer.  */
       rtx addr = XEXP (written, 0);
       if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
           || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
@@ -7576,10 +7614,15 @@ note_mem_written (written, writes_ptr)
             and that's just as good as a structure element
             in implying that we need not invalidate scalar variables.
             However, we must allow QImode aliasing of scalars, because the
-            ANSI C standard allows character pointers to alias anything.  */
+            ANSI C standard allows character pointers to alias anything.
+            We must also allow AND addresses, because they may generate
+            accesses outside the object being referenced.  This is used to
+            generate aligned addresses from unaligned addresses, for instance,
+            the alpha storeqi_unaligned pattern.  */
          if (! ((MEM_IN_STRUCT_P (written)
                  || GET_CODE (XEXP (written, 0)) == PLUS)
-                && GET_MODE (written) != QImode))
+                && GET_MODE (written) != QImode
+                && GET_CODE (XEXP (written, 0)) != AND))
            writes_ptr->all = 1;
          writes_ptr->nonscalar = 1;
        }
@@ -7620,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)
     {
@@ -7697,6 +7738,7 @@ cse_process_notes (x, object)
 
     case SIGN_EXTEND:
     case ZERO_EXTEND:
+    case SUBREG:
       {
        rtx new = cse_process_notes (XEXP (x, 0), object);
        /* We don't substitute VOIDmode constants into these rtx,
@@ -7820,13 +7862,6 @@ invalidate_skipped_set (dest, set)
      rtx set;
      rtx dest;
 {
-  if (GET_CODE (set) == CLOBBER
-#ifdef HAVE_cc0
-      || dest == cc0_rtx
-#endif
-      || dest == pc_rtx)
-    return;
-
   if (GET_CODE (dest) == MEM)
     note_mem_written (dest, &skipped_writes_memory);
 
@@ -7836,6 +7871,13 @@ invalidate_skipped_set (dest, set)
   if (skipped_writes_memory.nonscalar)
     skipped_writes_memory.all = 1;
 
+  if (GET_CODE (set) == CLOBBER
+#ifdef HAVE_cc0
+      || dest == cc0_rtx
+#endif
+      || dest == pc_rtx)
+    return;
+
   if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
       || (! skipped_writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
     invalidate (dest, VOIDmode);
@@ -7989,7 +8031,8 @@ cse_set_around_loop (x, insn, loop_start)
   if (writes_memory.var)
     invalidate_memory (&writes_memory);
 
-  /* See comment on similar code in cse_insn for explanation of these tests. */
+  /* See comment on similar code in cse_insn for explanation of these
+     tests.  */
   if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
       || (GET_CODE (SET_DEST (x)) == MEM && ! writes_memory.all
          && ! cse_rtx_addr_varies_p (SET_DEST (x))))