OSDN Git Service

* gcc.texi: Fixes for makeinfo 4.0 --html.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index aa26539..fe5e4a6 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -537,16 +537,6 @@ struct table_elt
 
 #define REGNO_QTY_VALID_P(N) (REG_QTY (N) != (int) (N))
 
-#ifdef ADDRESS_COST
-/* The ADDRESS_COST macro 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.  */
-#define CSE_ADDRESS_COST(RTX)                                  \
-  ((GET_CODE (RTX) == ADDRESSOF && REG_P (XEXP ((RTX), 0)))    \
-   ? -1 : ADDRESS_COST(RTX))
-#endif 
-
 static struct table_elt *table[HASH_SIZE];
 
 /* Chain of `struct table_elt's made so far for this function
@@ -683,7 +673,7 @@ static unsigned canon_hash  PARAMS ((rtx, enum machine_mode));
 static unsigned safe_hash      PARAMS ((rtx, enum machine_mode));
 static int exp_equiv_p         PARAMS ((rtx, rtx, int, int));
 static rtx canon_reg           PARAMS ((rtx, rtx));
-static void find_best_addr     PARAMS ((rtx, rtx *));
+static void find_best_addr     PARAMS ((rtx, rtx *, enum machine_mode));
 static enum rtx_code find_comparison_args PARAMS ((enum rtx_code, rtx *, rtx *,
                                                   enum machine_mode *,
                                                   enum machine_mode *));
@@ -705,6 +695,7 @@ static rtx cse_basic_block  PARAMS ((rtx, rtx, struct branch_path *, int));
 static void count_reg_usage    PARAMS ((rtx, int *, rtx, int));
 extern void dump_class          PARAMS ((struct table_elt*));
 static struct cse_reg_info * get_cse_reg_info PARAMS ((unsigned int));
+static int check_dependence    PARAMS ((rtx *, void *));
 
 static void flush_hash_table   PARAMS ((void));
 \f
@@ -848,6 +839,34 @@ rtx_cost (x, outer_code)
   return total;
 }
 \f
+/* Return cost of address expression X.  Expect that X is propertly formed address
+   reference.  */
+int
+address_cost (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  /* The ADDRESS_COST macro 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.  */
+
+  if (GET_CODE (x) == ADDRESSOF && REG_P (XEXP ((x), 0)))
+    return -1;
+
+  /* We may be asked for cost of various unusual addresses, such as operands
+     of push instruction.  It is not worthwhile to complicate writting
+     of ADDRESS_COST macro 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
+}
+\f
 static struct cse_reg_info *
 get_cse_reg_info (regno)
      unsigned int regno;
@@ -1721,6 +1740,24 @@ flush_hash_table ()
       }
 }
 \f
+/* Function called for each rtx to check whether true dependence exist.  */
+struct check_dependence_data
+{
+  enum machine_mode mode;
+  rtx exp;
+};
+static int
+check_dependence (x, data)
+     rtx *x;
+     void *data;
+{
+  struct check_dependence_data *d = (struct check_dependence_data *) data;
+  if (*x && GET_CODE (*x) == MEM)
+    return true_dependence (d->exp, d->mode, *x, cse_rtx_varies_p);
+  else
+    return 0;
+}
+\f
 /* Remove from the hash table, or mark as invalid, all expressions whose
    values could be altered by storing in X.  X is a register, a subreg, or
    a memory reference with nonvarying address (because, when a memory
@@ -1846,20 +1883,18 @@ invalidate (x, full_mode)
              next = p->next_same_hash;
              if (p->in_memory)
                {
-                 if (GET_CODE (p->exp) != MEM)
+                 struct check_dependence_data d;
+
+                 /* Just canonicalize the expression once;
+                    otherwise each time we call invalidate
+                    true_dependence will canonicalize the
+                    expression again.  */
+                 if (!p->canon_exp)
+                   p->canon_exp = canon_rtx (p->exp);
+                 d.exp = x;
+                 d.mode = full_mode;
+                 if (for_each_rtx (&p->canon_exp, check_dependence, &d))
                    remove_from_table (p, i);
-                 else 
-                   {
-                     /* Just canonicalize the expression once;
-                        otherwise each time we call invalidate
-                        true_dependence will canonicalize the
-                        expression again.  */
-                     if (!p->canon_exp)
-                       p->canon_exp = canon_rtx (p->exp);
-                     if (true_dependence (x, full_mode, p->canon_exp,
-                                          cse_rtx_varies_p))
-                       remove_from_table (p, i);
-                   }
                }
            }
        }
@@ -2664,9 +2699,10 @@ canon_reg (x, insn)
   */
 
 static void
-find_best_addr (insn, loc)
+find_best_addr (insn, loc, mode)
      rtx insn;
      rtx *loc;
+     enum machine_mode mode;
 {
   struct table_elt *elt;
   rtx addr = *loc;
@@ -2678,6 +2714,7 @@ find_best_addr (insn, loc)
   int save_hash_arg_in_memory = hash_arg_in_memory;
   int addr_volatile;
   int regno;
+  int folded_cost, addr_cost;
   unsigned hash;
 
   /* Do not try to replace constant addresses or addresses of local and
@@ -2711,14 +2748,13 @@ find_best_addr (insn, loc)
     {
       rtx folded = fold_rtx (copy_rtx (addr), NULL_RTX);
 
-      if (1
-#ifdef ADDRESS_COST
-         && (CSE_ADDRESS_COST (folded) < CSE_ADDRESS_COST (addr)
-             || (CSE_ADDRESS_COST (folded) == CSE_ADDRESS_COST (addr)
-                 && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
-#else
+      folded_cost = address_cost (folded, mode);
+      addr_cost = address_cost (addr, mode);
+
+      if ((folded_cost < addr_cost
+          || (folded_cost == addr_cost
+              && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
          && rtx_cost (folded, MEM) < rtx_cost (addr, MEM)
-#endif
          && validate_change (insn, loc, folded, 0))
        addr = folded;
     }
@@ -2765,8 +2801,9 @@ find_best_addr (insn, loc)
 
       while (found_better)
        {
-         int best_addr_cost = CSE_ADDRESS_COST (*loc);
+         int best_addr_cost = address_cost (*loc, mode);
          int best_rtx_cost = (elt->cost + 1) >> 1;
+         int exp_cost;
          struct table_elt *best_elt = elt; 
 
          found_better = 0;
@@ -2775,12 +2812,12 @@ find_best_addr (insn, loc)
              {
                if ((GET_CODE (p->exp) == REG
                     || exp_equiv_p (p->exp, p->exp, 1, 0))
-                   && (CSE_ADDRESS_COST (p->exp) < best_addr_cost
-                       || (CSE_ADDRESS_COST (p->exp) == best_addr_cost
-                           && (p->cost + 1) >> 1 > best_rtx_cost)))
+                   && ((exp_cost = address_cost (p->exp, mode)) < best_addr_cost
+                       || (exp_cost == best_addr_cost
+                           && (p->cost + 1) >> 1 < best_rtx_cost)))
                  {
                    found_better = 1;
-                   best_addr_cost = CSE_ADDRESS_COST (p->exp);
+                   best_addr_cost = exp_cost;
                    best_rtx_cost = (p->cost + 1) >> 1;
                    best_elt = p;
                  }
@@ -2834,7 +2871,7 @@ find_best_addr (insn, loc)
 
       while (found_better)
        {
-         int best_addr_cost = CSE_ADDRESS_COST (*loc);
+         int best_addr_cost = address_cost (*loc, mode);
          int best_rtx_cost = (COST (*loc) + 1) >> 1;
          struct table_elt *best_elt = elt; 
          rtx best_rtx = *loc;
@@ -2856,13 +2893,15 @@ find_best_addr (insn, loc)
              {
                rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
                                               p->exp, c);
+               int new_cost;
+               new_cost = address_cost (new, mode);
 
-               if ((CSE_ADDRESS_COST (new) < best_addr_cost
-                   || (CSE_ADDRESS_COST (new) == best_addr_cost
-                       && (COST (new) + 1) >> 1 > best_rtx_cost)))
+               if (new_cost < best_addr_cost
+                   || (new_cost == best_addr_cost
+                       && (COST (new) + 1) >> 1 > best_rtx_cost))
                  {
                    found_better = 1;
-                   best_addr_cost = CSE_ADDRESS_COST (new);
+                   best_addr_cost = new_cost;
                    best_rtx_cost = (COST (new) + 1) >> 1;
                    best_elt = p;
                    best_rtx = new;
@@ -3333,7 +3372,7 @@ fold_rtx (x, insn)
         best address.  Not only don't we care, but we could modify the
         MEM in an invalid way since we have no insn to validate against.  */
       if (insn != 0)
-       find_best_addr (insn, &XEXP (x, 0));
+       find_best_addr (insn, &XEXP (x, 0), GET_MODE (x));
 
       {
        /* Even if we don't fold in the insn itself,
@@ -5233,6 +5272,11 @@ cse_insn (insn, libcall_insn)
 
              PATTERN (insn) = gen_jump (XEXP (trial, 0));
              INSN_CODE (insn) = -1;
+
+             if (NEXT_INSN (insn) != 0
+                 && GET_CODE (NEXT_INSN (insn)) != BARRIER)
+               emit_barrier_after (insn);
+
              cse_jumps_altered = 1;
              break;
            }
@@ -5911,13 +5955,12 @@ cse_insn (insn, libcall_insn)
          }
       }
 
-  /* Special handling for (set REG0 REG1)
-     where REG0 is the "cheapest", cheaper than REG1.
-     After cse, REG1 will probably not be used in the sequel, 
-     so (if easily done) change this insn to (set REG1 REG0) and
-     replace REG1 with REG0 in the previous insn that computed their value.
-     Then REG1 will become a dead store and won't cloud the situation
-     for later optimizations.
+  /* Special handling for (set REG0 REG1) where REG0 is the
+     "cheapest", cheaper than REG1.  After cse, REG1 will probably not
+     be used in the sequel, so (if easily done) change this insn to
+     (set REG1 REG0) and replace REG1 with REG0 in the previous insn
+     that computed their value.  Then REG1 will become a dead store
+     and won't cloud the situation for later optimizations.
 
      Do not make this change if REG1 is a hard register, because it will
      then be used in the sequel and we may be changing a two-operand insn
@@ -5941,19 +5984,18 @@ 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_INSN (insn);
-         while (prev && GET_CODE (prev) == NOTE)
-           prev = PREV_INSN (prev);
+         rtx prev = prev_nonnote_insn (insn);
 
-         if (prev && GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SET
+         if (prev != 0 && GET_CODE (prev) == INSN
+             && GET_CODE (PATTERN (prev)) == SET
              && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl))
            {
              rtx dest = SET_DEST (sets[0].rtl);
+             rtx src = SET_SRC (sets[0].rtl);
              rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX);
 
              validate_change (prev, & SET_DEST (PATTERN (prev)), dest, 1);
-             validate_change (insn, & SET_DEST (sets[0].rtl),
-                              SET_SRC (sets[0].rtl), 1);
+             validate_change (insn, & SET_DEST (sets[0].rtl), src, 1);
              validate_change (insn, & SET_SRC (sets[0].rtl), dest, 1);
              apply_change_group ();
 
@@ -5975,10 +6017,14 @@ cse_insn (insn, libcall_insn)
                  REG_NOTES (prev) = note;
                }
 
-             /* If INSN has a REG_EQUAL note, and this note mentions REG0,
-                then we must delete it, because the value in REG0 has changed.  */
+             /* If INSN has a REG_EQUAL note, and this note mentions
+                REG0, then we must delete it, because the value in
+                REG0 has changed.  If the note's value is REG1, we must
+                also delete it because that is now this insn's dest.  */
              note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-             if (note && reg_mentioned_p (dest, XEXP (note, 0)))
+             if (note != 0
+                 && (reg_mentioned_p (dest, XEXP (note, 0))
+                     || rtx_equal_p (src, XEXP (note, 0))))
                remove_note (insn, note);
            }
        }
@@ -7269,6 +7315,10 @@ delete_trivially_dead_insns (insns, nreg)
              && rtx_equal_p (SET_DEST (PATTERN (insn)),
                              SET_SRC (PATTERN (insn))))
            ;
+         else if (GET_CODE (SET_DEST (PATTERN (insn))) == STRICT_LOW_PART
+                  && rtx_equal_p (XEXP (SET_DEST (PATTERN (insn)), 0),
+                                  SET_SRC (PATTERN (insn))))
+           ;
 
 #ifdef HAVE_cc0
          else if (GET_CODE (SET_DEST (PATTERN (insn))) == CC0