OSDN Git Service

* flow.c (find_unreachable_blocks): New function.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 3d0f1a7..43cbf9c 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 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -382,11 +382,14 @@ static int cse_altered;
 
 static int cse_jumps_altered;
 
-/* Nonzero if we put a LABEL_REF into the hash table.  Since we may have put
-   it into an INSN without a REG_LABEL, we have to rerun jump after CSE
-   to put in the note.  */
+/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a
+   REG_LABEL, we have to rerun jump after CSE to put in the note.  */
 static int recorded_label_ref;
 
+/* Says which LABEL_REF was put in the hash table.  Used to see if we need
+   to set the above flag.  */
+static rtx new_label_ref;
+
 /* canon_hash stores 1 in do_not_record
    if it notices a reference to CC0, PC, or some other volatile
    subexpression.  */
@@ -1217,11 +1220,11 @@ mention_regs (x)
          /* 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 entrire register, including all SUBREG expressions.  */
+            for the entire register, including all SUBREG expressions.  */
          if (REG_IN_TABLE (i) != REG_TICK (i) - 1)
            remove_invalid_refs (i);
          else
-           remove_invalid_subreg_refs (i, SUBREG_WORD (x), GET_MODE (x));
+           remove_invalid_subreg_refs (i, SUBREG_BYTE (x), GET_MODE (x));
        }
 
       REG_IN_TABLE (i) = REG_TICK (i);
@@ -1242,7 +1245,7 @@ mention_regs (x)
     {
       if (GET_CODE (XEXP (x, 0)) == REG
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
-       if (insert_regs (XEXP (x, 0), NULL_PTR, 0))
+       if (insert_regs (XEXP (x, 0), NULL, 0))
          {
            rehash_using_reg (XEXP (x, 0));
            changed = 1;
@@ -1250,7 +1253,7 @@ mention_regs (x)
 
       if (GET_CODE (XEXP (x, 1)) == REG
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
-       if (insert_regs (XEXP (x, 1), NULL_PTR, 0))
+       if (insert_regs (XEXP (x, 1), NULL, 0))
          {
            rehash_using_reg (XEXP (x, 1));
            changed = 1;
@@ -1343,7 +1346,7 @@ insert_regs (x, classp, modified)
   else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
           && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
     {
-      insert_regs (SUBREG_REG (x), NULL_PTR, 0);
+      insert_regs (SUBREG_REG (x), NULL, 0);
       mention_regs (x);
       return 1;
     }
@@ -1581,7 +1584,7 @@ insert (x, classp, hash, mode)
   if (GET_CODE (x) == LABEL_REF
       || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
          && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF))
-    recorded_label_ref = 1;
+    new_label_ref = x;
 
   /* Put an element for X into the right hash bucket.  */
 
@@ -1721,7 +1724,7 @@ insert (x, classp, hash, mode)
          subhash = safe_hash (subexp, mode) & HASH_MASK;
          subelt = lookup (subexp, subhash, mode);
          if (subelt == 0)
-           subelt = insert (subexp, NULL_PTR, subhash, mode);
+           subelt = insert (subexp, NULL, subhash, mode);
          /* Initialize SUBELT's circular chain if it has none.  */
          if (subelt->related_value == 0)
            subelt->related_value = subelt;
@@ -1996,38 +1999,37 @@ remove_invalid_refs (regno)
       {
        next = p->next_same_hash;
        if (GET_CODE (p->exp) != REG
-           && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
+           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx*)0))
          remove_from_table (p, i);
       }
 }
 
-/* Likewise for a subreg with subreg_reg WORD and mode MODE.  */
+/* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
+   and mode MODE.  */
 static void
-remove_invalid_subreg_refs (regno, word, mode)
+remove_invalid_subreg_refs (regno, offset, mode)
      unsigned int regno;
-     unsigned int word;
+     unsigned int offset;
      enum machine_mode mode;
 {
   unsigned int i;
   struct table_elt *p, *next;
-  unsigned int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
+  unsigned int end = offset + (GET_MODE_SIZE (mode) - 1);
 
   for (i = 0; i < HASH_SIZE; i++)
     for (p = table[i]; p; p = next)
       {
-       rtx exp;
+       rtx exp = p->exp;
        next = p->next_same_hash;
 
-       exp = p->exp;
-       if (GET_CODE (p->exp) != REG
+       if (GET_CODE (exp) != REG
            && (GET_CODE (exp) != SUBREG
                || GET_CODE (SUBREG_REG (exp)) != REG
                || REGNO (SUBREG_REG (exp)) != regno
-               || (((SUBREG_WORD (exp)
-                     + (GET_MODE_SIZE (GET_MODE (exp)) - 1) / UNITS_PER_WORD)
-                    >= word)
-                   && SUBREG_WORD (exp) <= end))
-           && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
+               || (((SUBREG_BYTE (exp)
+                     + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
+                   && SUBREG_BYTE (exp) <= end))
+           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx*)0))
          remove_from_table (p, i);
       }
 }
@@ -2299,7 +2301,8 @@ canon_hash (x, mode)
        if (GET_CODE (SUBREG_REG (x)) == REG)
          {
            hash += (((unsigned) SUBREG << 7)
-                    + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
+                    + REGNO (SUBREG_REG (x))
+                    + (SUBREG_BYTE (x) / UNITS_PER_WORD));
            return hash;
          }
        break;
@@ -2975,7 +2978,7 @@ find_best_addr (insn, loc, mode)
                     || exp_equiv_p (p->exp, p->exp, 1, 0))
                    && ((exp_cost = address_cost (p->exp, mode)) < best_addr_cost
                        || (exp_cost == best_addr_cost
-                           && (p->cost + 1) >> 1 < best_rtx_cost)))
+                           && ((p->cost + 1) >> 1) > best_rtx_cost)))
                  {
                    found_better = 1;
                    best_addr_cost = exp_cost;
@@ -3405,15 +3408,8 @@ fold_rtx (x, insn)
 
       if (folded_arg0 != SUBREG_REG (x))
        {
-         new = 0;
-
-         if (GET_MODE_CLASS (mode) == MODE_INT
-             && GET_MODE_SIZE (mode) == UNITS_PER_WORD
-             && GET_MODE (SUBREG_REG (x)) != VOIDmode)
-           new = operand_subword (folded_arg0, SUBREG_WORD (x), 0,
-                                  GET_MODE (SUBREG_REG (x)));
-         if (new == 0 && subreg_lowpart_p (x))
-           new = gen_lowpart_if_possible (mode, folded_arg0);
+         new = simplify_subreg (mode, folded_arg0,
+                                GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
          if (new)
            return new;
        }
@@ -3910,15 +3906,15 @@ fold_rtx (x, insn)
       if (const_arg0 == 0 || const_arg1 == 0)
        {
          struct table_elt *p0, *p1;
-         rtx true = const_true_rtx, false = const0_rtx;
+         rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
          enum machine_mode mode_arg1;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
          if (GET_MODE_CLASS (mode) == MODE_FLOAT)
            {
-             true = (CONST_DOUBLE_FROM_REAL_VALUE
+             true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
                      (FLOAT_STORE_FLAG_VALUE (mode), mode));
-             false = CONST0_RTX (mode);
+             false_rtx = CONST0_RTX (mode);
            }
 #endif
 
@@ -3952,9 +3948,9 @@ fold_rtx (x, insn)
                      || GET_CODE (folded_arg0) == CONST))
                {
                  if (code == EQ)
-                   return false;
+                   return false_rtx;
                  else if (code == NE)
-                   return true;
+                   return true_rtx;
                }
 
              /* See if the two operands are the same.  */
@@ -3974,16 +3970,17 @@ fold_rtx (x, insn)
                {
                   /* Sadly two equal NaNs are not equivalent.  */
                   if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-                      || ! FLOAT_MODE_P (mode_arg0) || flag_fast_math)
+                      || ! FLOAT_MODE_P (mode_arg0) 
+                      || flag_unsafe_math_optimizations)
                      return ((code == EQ || code == LE || code == GE
                               || code == LEU || code == GEU || code == UNEQ
                               || code == UNLE || code == UNGE || code == ORDERED)
-                             ? true : false);
+                             ? true_rtx : false_rtx);
                   /* Take care for the FP compares we can resolve.  */
                   if (code == UNEQ || code == UNLE || code == UNGE)
-                    return true;
+                    return true_rtx;
                   if (code == LTGT || code == LT || code == GT)
-                    return false;
+                    return false_rtx;
                }
 
              /* If FOLDED_ARG0 is a register, see if the comparison we are
@@ -4008,7 +4005,7 @@ fold_rtx (x, insn)
                              || (GET_CODE (folded_arg1) == REG
                                  && (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
                        return (comparison_dominates_p (ent->comparison_code, code)
-                               ? true : false);
+                               ? true_rtx : false_rtx);
                    }
                }
            }
@@ -4032,30 +4029,30 @@ fold_rtx (x, insn)
              int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
                              && (INTVAL (inner_const)
                                  & ((HOST_WIDE_INT) 1 << sign_bitnum)));
-             rtx true = const_true_rtx, false = const0_rtx;
+             rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
              if (GET_MODE_CLASS (mode) == MODE_FLOAT)
                {
-                 true = (CONST_DOUBLE_FROM_REAL_VALUE
+                 true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
                          (FLOAT_STORE_FLAG_VALUE (mode), mode));
-                 false = CONST0_RTX (mode);
+                 false_rtx = CONST0_RTX (mode);
                }
 #endif
 
              switch (code)
                {
                case EQ:
-                 return false;
+                 return false_rtx;
                case NE:
-                 return true;
+                 return true_rtx;
                case LT:  case LE:
                  if (has_sign)
-                   return true;
+                   return true_rtx;
                  break;
                case GT:  case GE:
                  if (has_sign)
-                   return false;
+                   return false_rtx;
                  break;
                default:
                  break;
@@ -4389,10 +4386,12 @@ gen_lowpart_if_possible (mode, x)
        offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
                  - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
       if (BYTES_BIG_ENDIAN)
-       /* Adjust the address so that the address-after-the-data is
-          unchanged.  */
-       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
-                  - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
+       {
+         /* Adjust the address so that the address-after-the-data is
+            unchanged.  */
+         offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
+                    - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
+       }
       new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
       if (! memory_address_p (mode, XEXP (new, 0)))
        return 0;
@@ -4596,7 +4595,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
         new quantity number.  */
       if (op0_elt == 0)
        {
-         if (insert_regs (op0, NULL_PTR, 0))
+         if (insert_regs (op0, NULL, 0))
            {
              rehash_using_reg (op0);
              op0_hash = HASH (op0, mode);
@@ -4608,7 +4607,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
                op1_hash = HASH (op1,mode);
            }
 
-         op0_elt = insert (op0, NULL_PTR, op0_hash, mode);
+         op0_elt = insert (op0, NULL, op0_hash, mode);
          op0_elt->in_memory = op0_in_memory;
        }
 
@@ -4624,13 +4623,13 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
          /* Put OP1 in the hash table so it gets a new quantity number.  */
          if (op1_elt == 0)
            {
-             if (insert_regs (op1, NULL_PTR, 0))
+             if (insert_regs (op1, NULL, 0))
                {
                  rehash_using_reg (op1);
                  op1_hash = HASH (op1, mode);
                }
 
-             op1_elt = insert (op1, NULL_PTR, op1_hash, mode);
+             op1_elt = insert (op1, NULL, op1_hash, mode);
              op1_elt->in_memory = op1_in_memory;
            }
 
@@ -4651,25 +4650,25 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
 
   if (op0_elt == 0)
     {
-      if (insert_regs (op0, NULL_PTR, 0))
+      if (insert_regs (op0, NULL, 0))
        {
          rehash_using_reg (op0);
          op0_hash = HASH (op0, mode);
        }
 
-      op0_elt = insert (op0, NULL_PTR, op0_hash, mode);
+      op0_elt = insert (op0, NULL, op0_hash, mode);
       op0_elt->in_memory = op0_in_memory;
     }
 
   if (op1_elt == 0)
     {
-      if (insert_regs (op1, NULL_PTR, 0))
+      if (insert_regs (op1, NULL, 0))
        {
          rehash_using_reg (op1);
          op1_hash = HASH (op1, mode);
        }
 
-      op1_elt = insert (op1, NULL_PTR, op1_hash, mode);
+      op1_elt = insert (op1, NULL, op1_hash, mode);
       op1_elt->in_memory = op1_in_memory;
     }
 
@@ -4742,7 +4741,7 @@ cse_insn (insn, libcall_insn)
   int src_eqv_in_memory = 0;
   unsigned src_eqv_hash = 0;
 
-  struct set *sets = (struct set *) NULL_PTR;
+  struct set *sets = (struct set *) 0;
 
   this_insn = insn;
 
@@ -4754,8 +4753,11 @@ cse_insn (insn, libcall_insn)
   if (GET_CODE (insn) == CALL_INSN)
     {
       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-       if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
-         invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+       {
+         if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
+           invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+         XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
+       }
     }
 
   if (GET_CODE (x) == SET)
@@ -5057,18 +5059,16 @@ cse_insn (insn, libcall_insn)
       sets[i].src_in_memory = hash_arg_in_memory;
 
       /* If SRC is a MEM, there is a REG_EQUIV note for SRC, and DEST is
-        a pseudo that is set more than once, do not record SRC.  Using
-        SRC as a replacement for anything else will be incorrect in that
-        situation.  Note that this usually occurs only for stack slots,
-        in which case all the RTL would be referring to SRC, so we don't
-        lose any optimization opportunities by not having SRC in the
-        hash table.  */
+        a pseudo, do not record SRC.  Using SRC as a replacement for
+        anything else will be incorrect in that situation.  Note that
+        this usually occurs only for stack slots, in which case all the
+        RTL would be referring to SRC, so we don't lose any optimization
+        opportunities by not having SRC in the hash table.  */
 
       if (GET_CODE (src) == MEM
-         && find_reg_note (insn, REG_EQUIV, src) != 0
+         && find_reg_note (insn, REG_EQUIV, NULL_RTX) != 0
          && GET_CODE (dest) == REG
-         && REGNO (dest) >= FIRST_PSEUDO_REGISTER
-         && REG_N_SETS (REGNO (dest)) != 1)
+         && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
        sets[i].src_volatile = 1;
 
 #if 0
@@ -5510,31 +5510,17 @@ cse_insn (insn, libcall_insn)
             check for this separately here.  We will delete such an
             insn below.
 
-            Tablejump insns contain a USE of the table, so simply replacing
-            the operand with the constant won't match.  This is simply an
-            unconditional branch, however, and is therefore valid.  Just
-            insert the substitution here and we will delete and re-emit
-            the insn later.  */
-
+            For other cases such as a table jump or conditional jump
+            where we know the ultimate target, go ahead and replace the
+            operand.  While that may not make a valid insn, we will
+            reemit the jump below (and also insert any necessary
+            barriers).  */
          if (n_sets == 1 && dest == pc_rtx
              && (trial == pc_rtx
                  || (GET_CODE (trial) == LABEL_REF
                      && ! condjump_p (insn))))
            {
-             if (trial == pc_rtx)
-               {
-                 SET_SRC (sets[i].rtl) = trial;
-                 cse_jumps_altered = 1;
-                 break;
-               }
-
-             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);
-
+             SET_SRC (sets[i].rtl) = trial;
              cse_jumps_altered = 1;
              break;
            }
@@ -5796,13 +5782,17 @@ cse_insn (insn, libcall_insn)
        }
 
       /* If this SET is now setting PC to a label, we know it used to
-        be a conditional or computed branch.  So we see if we can follow
-        it.  If it was a computed branch, delete it and re-emit.  */
+        be a conditional or computed branch.  */
       else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
        {
-         /* If this is not in the format for a simple branch and
-            we are the only SET in it, re-emit it.  */
-         if (! simplejump_p (insn) && n_sets == 1)
+         /* We reemit the jump in as many cases as possible just in
+            case the form of an unconditional jump is significantly
+            different than a computed jump or conditional jump.
+
+            If this insn has multiple sets, then reemitting the
+            jump is nontrivial.  So instead we just force rerecognition
+            and hope for the best.  */
+         if (n_sets == 1)
            {
              rtx new = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
              JUMP_LABEL (new) = XEXP (src, 0);
@@ -5810,11 +5800,6 @@ cse_insn (insn, libcall_insn)
              insn = new;
            }
          else
-           /* Otherwise, force rerecognition, since it probably had
-              a different pattern before.
-              This shouldn't really be necessary, since whatever
-              changed the source value above should have done this.
-              Until the right place is found, might as well do this here.  */
            INSN_CODE (insn) = -1;
 
          never_reached_warning (insn);
@@ -7116,7 +7101,7 @@ cse_main (f, nregs, after_loop, file)
 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
         && ! (i == ARG_POINTER_REGNUM && fixed_regs[i])
 #endif
-#if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
+#if !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
         && ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
 #endif
         )
@@ -7305,7 +7290,17 @@ cse_basic_block (from, to, next_branch, around_loop)
                libcall_insn = 0;
            }
 
+         new_label_ref = 0;
          cse_insn (insn, libcall_insn);
+
+         /* If this insn uses a LABEL_REF and there isn't a REG_LABEL
+            note for it, we must rerun jump since it needs to place the
+            note.  If this is a LABEL_REF for a CODE_LABEL that isn't in
+            the insn chain, don't do this since no REG_LABEL will be added. */
+         if (new_label_ref != 0 && INSN_UID (XEXP (new_label_ref, 0)) != 0
+             && reg_mentioned_p (new_label_ref, PATTERN (insn))
+             && ! find_reg_note (insn, REG_LABEL, XEXP (new_label_ref, 0)))
+           recorded_label_ref = 1;
        }
 
       /* If INSN is now an unconditional jump, skip to the end of our
@@ -7592,14 +7587,7 @@ delete_trivially_dead_insns (insns, nreg)
        live_insn = ! dead_libcall;
       else if (GET_CODE (PATTERN (insn)) == SET)
        {
-         if ((GET_CODE (SET_DEST (PATTERN (insn))) == REG
-              || GET_CODE (SET_DEST (PATTERN (insn))) == SUBREG)
-             && 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))))
+         if (set_noop_p (PATTERN (insn)))
            ;
 
 #ifdef HAVE_cc0
@@ -7629,9 +7617,7 @@ delete_trivially_dead_insns (insns, nreg)
 
            if (GET_CODE (elt) == SET)
              {
-               if ((GET_CODE (SET_DEST (elt)) == REG
-                    || GET_CODE (SET_DEST (elt)) == SUBREG)
-                   && rtx_equal_p (SET_DEST (elt), SET_SRC (elt)))
+               if (set_noop_p (elt))
                  ;
 
 #ifdef HAVE_cc0