OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 787b0db..67bd776 100644 (file)
@@ -1,7 +1,7 @@
 /* Optimize by combining instructions for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   2011, 2012 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -367,14 +367,14 @@ static int nonzero_sign_valid;
 /* Record one modification to rtl structure
    to be undone by storing old_contents into *where.  */
 
-enum undo_kind { UNDO_RTX, UNDO_INT, UNDO_MODE };
+enum undo_kind { UNDO_RTX, UNDO_INT, UNDO_MODE, UNDO_LINKS };
 
 struct undo
 {
   struct undo *next;
   enum undo_kind kind;
-  union { rtx r; int i; enum machine_mode m; } old_contents;
-  union { rtx *r; int *i; } where;
+  union { rtx r; int i; enum machine_mode m; struct insn_link *l; } old_contents;
+  union { rtx *r; int *i; struct insn_link **l; } where;
 };
 
 /* Record a bunch of changes to be undone, up to MAX_UNDO of them.
@@ -789,6 +789,34 @@ do_SUBST_MODE (rtx *into, enum machine_mode newval)
 }
 
 #define SUBST_MODE(INTO, NEWVAL)  do_SUBST_MODE(&(INTO), (NEWVAL))
+
+#ifndef HAVE_cc0
+/* Similar to SUBST, but NEWVAL is a LOG_LINKS expression.  */
+
+static void
+do_SUBST_LINK (struct insn_link **into, struct insn_link *newval)
+{
+  struct undo *buf;
+  struct insn_link * oldval = *into;
+
+  if (oldval == newval)
+    return;
+
+  if (undobuf.frees)
+    buf = undobuf.frees, undobuf.frees = buf->next;
+  else
+    buf = XNEW (struct undo);
+
+  buf->kind = UNDO_LINKS;
+  buf->where.l = into;
+  buf->old_contents.l = oldval;
+  *into = newval;
+
+  buf->next = undobuf.undos, undobuf.undos = buf;
+}
+
+#define SUBST_LINK(oldval, newval) do_SUBST_LINK (&oldval, newval)
+#endif
 \f
 /* Subroutine of try_combine.  Determine whether the replacement patterns
    NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_rtx_cost
@@ -1672,6 +1700,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED,
   rtx link;
 #endif
   bool all_adjacent = true;
+  int (*is_volatile_p) (const_rtx);
 
   if (succ)
     {
@@ -1793,6 +1822,10 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED,
   if (set == 0)
     return 0;
 
+  /* The simplification in expand_field_assignment may call back to
+     get_last_value, so set safe guard here.  */
+  subst_low_luid = DF_INSN_LUID (insn);
+
   set = expand_field_assignment (set);
   src = SET_SRC (set), dest = SET_DEST (set);
 
@@ -1920,11 +1953,17 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED,
       && REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER)
     return 0;
 
-  /* If there are any volatile insns between INSN and I3, reject, because
-     they might affect machine state.  */
+  /* If INSN contains volatile references (specifically volatile MEMs),
+     we cannot combine across any other volatile references.
+     Even if INSN doesn't contain volatile references, any intervening
+     volatile insn might affect machine state.  */
 
+  is_volatile_p = volatile_refs_p (PATTERN (insn))
+    ? volatile_refs_p
+    : volatile_insn_p;
+    
   for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
-    if (INSN_P (p) && p != succ && p != succ2 && volatile_insn_p (PATTERN (p)))
+    if (INSN_P (p) && p != succ && p != succ2 && is_volatile_p (PATTERN (p)))
       return 0;
 
   /* If INSN contains an autoincrement or autodecrement, make sure that
@@ -2556,8 +2595,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
   rtx i3dest_killed = 0;
   /* SET_DEST and SET_SRC of I2, I1 and I0.  */
   rtx i2dest = 0, i2src = 0, i1dest = 0, i1src = 0, i0dest = 0, i0src = 0;
-  /* Copy of SET_SRC of I1, if needed.  */
-  rtx i1src_copy = 0;
+  /* Copy of SET_SRC of I1 and I0, if needed.  */
+  rtx i1src_copy = 0, i0src_copy = 0, i0src_copy2 = 0;
   /* Set if I2DEST was reused as a scratch register.  */
   bool i2scratch = false;
   /* The PATTERNs of I0, I1, and I2, or a copy of them in certain cases.  */
@@ -2865,6 +2904,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
          SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
          SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
                 SET_DEST (PATTERN (i1)));
+         SUBST_LINK (LOG_LINKS (i2), alloc_insn_link (i1, LOG_LINKS (i2)));
        }
     }
 #endif
@@ -3210,6 +3250,11 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
       n_occurrences = 0;
       subst_low_luid = DF_INSN_LUID (i1);
 
+      /* If the following substitution will modify I1SRC, make a copy of it
+        for the case where it is substituted for I1DEST in I2PAT later.  */
+      if (added_sets_2 && i1_feeds_i2_n)
+       i1src_copy = copy_rtx (i1src);
+
       /* If I0 feeds into I1 and I0DEST is in I0SRC, we need to make a unique
         copy of I1SRC each time we substitute it, in order to avoid creating
         self-referential RTL when we will be substituting I0SRC for I0DEST
@@ -3237,10 +3282,14 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
          return 0;
        }
 
-      /* If the following substitution will modify I1SRC, make a copy of it
-        for the case where it is substituted for I1DEST in I2PAT later.  */
-      if (i0_feeds_i1_n && added_sets_2 && i1_feeds_i2_n)
-       i1src_copy = copy_rtx (i1src);
+      /* If the following substitution will modify I0SRC, make a copy of it
+        for the case where it is substituted for I0DEST in I1PAT later.  */
+      if (added_sets_1 && i0_feeds_i1_n)
+       i0src_copy = copy_rtx (i0src);
+      /* And a copy for I0DEST in I2PAT substitution.  */
+      if (added_sets_2 && ((i0_feeds_i1_n && i1_feeds_i2_n)
+                          || (i0_feeds_i2_n)))
+       i0src_copy2 = copy_rtx (i0src);
 
       n_occurrences = 0;
       subst_low_luid = DF_INSN_LUID (i0);
@@ -3306,7 +3355,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
        {
          rtx t = i1pat;
          if (i0_feeds_i1_n)
-           t = subst (t, i0dest, i0src, 0, 0, 0);
+           t = subst (t, i0dest, i0src_copy ? i0src_copy : i0src, 0, 0, 0);
 
          XVECEXP (newpat, 0, --total_sets) = t;
        }
@@ -3317,7 +3366,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
            t = subst (t, i1dest, i1src_copy ? i1src_copy : i1src, 0, 0,
                       i0_feeds_i1_n && i0dest_in_i0src);
          if ((i0_feeds_i1_n && i1_feeds_i2_n) || i0_feeds_i2_n)
-           t = subst (t, i0dest, i0src, 0, 0, 0);
+           t = subst (t, i0dest, i0src_copy2 ? i0src_copy2 : i0src, 0, 0, 0);
 
          XVECEXP (newpat, 0, --total_sets) = t;
        }
@@ -4494,6 +4543,9 @@ undo_all (void)
        case UNDO_MODE:
          adjust_reg_mode (*undo->where.r, undo->old_contents.m);
          break;
+       case UNDO_LINKS:
+         *undo->where.l = undo->old_contents.l;
+         break;
        default:
          gcc_unreachable ();
        }
@@ -5939,7 +5991,9 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest,
       else if (SHIFT_COUNT_TRUNCATED && !REG_P (XEXP (x, 1)))
        SUBST (XEXP (x, 1),
               force_to_mode (XEXP (x, 1), GET_MODE (XEXP (x, 1)),
-                             targetm.shift_truncation_mask (GET_MODE (x)),
+                             ((unsigned HOST_WIDE_INT) 1
+                              << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
+                             - 1,
                              0));
       break;
 
@@ -6008,7 +6062,7 @@ simplify_if_then_else (rtx x)
          && exact_log2 (nzb = nonzero_bits (from, GET_MODE (from))) >= 0)
        {
          false_code = EQ;
-         false_val = GEN_INT (trunc_int_for_mode (nzb, GET_MODE (from)));
+         false_val = gen_int_mode (nzb, GET_MODE (from));
        }
       else if (true_code == EQ && true_val == const0_rtx
               && (num_sign_bit_copies (from, GET_MODE (from))
@@ -6301,7 +6355,7 @@ simplify_set (rtx x)
   rtx *cc_use;
 
   /* (set (pc) (return)) gets written as (return).  */
-  if (GET_CODE (dest) == PC && GET_CODE (src) == RETURN)
+  if (GET_CODE (dest) == PC && ANY_RETURN_P (src))
     return src;
 
   /* Now that we know for sure which bits of SRC we are using, see if we can
@@ -6825,11 +6879,11 @@ expand_compound_operation (rtx x)
       rtx temp2 = expand_compound_operation (temp);
 
       /* Make sure this is a profitable operation.  */
-      if (rtx_cost (x, SET, optimize_this_for_speed_p)
-          > rtx_cost (temp2, SET, optimize_this_for_speed_p))
+      if (set_src_cost (x, optimize_this_for_speed_p)
+          > set_src_cost (temp2, optimize_this_for_speed_p))
        return temp2;
-      else if (rtx_cost (x, SET, optimize_this_for_speed_p)
-               > rtx_cost (temp, SET, optimize_this_for_speed_p))
+      else if (set_src_cost (x, optimize_this_for_speed_p)
+               > set_src_cost (temp, optimize_this_for_speed_p))
        return temp;
       else
        return x;
@@ -7251,8 +7305,8 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
 
          /* Prefer ZERO_EXTENSION, since it gives more information to
             backends.  */
-         if (rtx_cost (temp, SET, optimize_this_for_speed_p)
-             <= rtx_cost (temp1, SET, optimize_this_for_speed_p))
+         if (set_src_cost (temp, optimize_this_for_speed_p)
+             <= set_src_cost (temp1, optimize_this_for_speed_p))
            return temp;
          return temp1;
        }
@@ -7453,8 +7507,8 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
 
          /* Prefer ZERO_EXTENSION, since it gives more information to
             backends.  */
-         if (rtx_cost (temp1, SET, optimize_this_for_speed_p)
-             < rtx_cost (temp, SET, optimize_this_for_speed_p))
+         if (set_src_cost (temp1, optimize_this_for_speed_p)
+             < set_src_cost (temp, optimize_this_for_speed_p))
            temp = temp1;
        }
       pos_rtx = temp;
@@ -7785,6 +7839,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
          && GET_CODE (lhs) == ASHIFT
          && CONST_INT_P (XEXP (lhs, 1))
          && INTVAL (rhs) >= INTVAL (XEXP (lhs, 1))
+         && INTVAL (XEXP (lhs, 1)) >= 0
          && INTVAL (rhs) < mode_width)
        {
          new_rtx = make_compound_operation (XEXP (lhs, 0), next_code);
@@ -8220,8 +8275,8 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
 
              y = simplify_gen_binary (AND, GET_MODE (x),
                                       XEXP (x, 0), GEN_INT (cval));
-             if (rtx_cost (y, SET, optimize_this_for_speed_p)
-                 < rtx_cost (x, SET, optimize_this_for_speed_p))
+             if (set_src_cost (y, optimize_this_for_speed_p)
+                 < set_src_cost (x, optimize_this_for_speed_p))
                x = y;
            }
 
@@ -8381,6 +8436,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
         in OP_MODE.  */
 
       if (CONST_INT_P (XEXP (x, 1))
+         && INTVAL (XEXP (x, 1)) >= 0
          && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
          && HWI_COMPUTABLE_MODE_P (op_mode))
        {
@@ -9374,8 +9430,8 @@ distribute_and_simplify_rtx (rtx x, int n)
   tmp = apply_distributive_law (simplify_gen_binary (inner_code, mode,
                                                     new_op0, new_op1));
   if (GET_CODE (tmp) != outer_code
-      && rtx_cost (tmp, SET, optimize_this_for_speed_p)
-         < rtx_cost (x, SET, optimize_this_for_speed_p))
+      && (set_src_cost (tmp, optimize_this_for_speed_p)
+         < set_src_cost (x, optimize_this_for_speed_p)))
     return tmp;
 
   return NULL_RTX;
@@ -9875,7 +9931,7 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
      want to do this inside the loop as it makes it more difficult to
      combine shifts.  */
   if (SHIFT_COUNT_TRUNCATED)
-    orig_count &= targetm.shift_truncation_mask (mode);
+    orig_count &= GET_MODE_BITSIZE (mode) - 1;
 
   /* If we were given an invalid count, don't do anything except exactly
      what was requested.  */
@@ -10244,8 +10300,7 @@ simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
            break;
 
          /* Make this fit the case below.  */
-         varop = gen_rtx_XOR (mode, XEXP (varop, 0),
-                              GEN_INT (GET_MODE_MASK (mode)));
+         varop = gen_rtx_XOR (mode, XEXP (varop, 0), constm1_rtx);
          continue;
 
        case IOR:
@@ -10747,13 +10802,6 @@ gen_lowpart_for_combine (enum machine_mode omode, rtx x)
   if (omode == imode)
     return x;
 
-  /* Return identity if this is a CONST or symbolic reference.  */
-  if (omode == Pmode
-      && (GET_CODE (x) == CONST
-         || GET_CODE (x) == SYMBOL_REF
-         || GET_CODE (x) == LABEL_REF))
-    return x;
-
   /* We can only support MODE being wider than a word if X is a
      constant integer or has a mode the same size.  */
   if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
@@ -11394,9 +11442,10 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
             later on, and then we wouldn't know whether to sign- or
             zero-extend.  */
          mode = GET_MODE (XEXP (op0, 0));
-         if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
+         if (GET_MODE_CLASS (mode) == MODE_INT
              && ! unsigned_comparison_p
-             && val_signbit_known_clear_p (mode, const_op)
+             && HWI_COMPUTABLE_MODE_P (mode)
+             && trunc_int_for_mode (const_op, mode) == const_op
              && have_insn_for (COMPARE, mode))
            {
              op0 = XEXP (op0, 0);
@@ -11474,10 +11523,11 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
 
        case ZERO_EXTEND:
          mode = GET_MODE (XEXP (op0, 0));
-         if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
+         if (GET_MODE_CLASS (mode) == MODE_INT
              && (unsigned_comparison_p || equality_comparison_p)
              && HWI_COMPUTABLE_MODE_P (mode)
-             && ((unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode))
+             && (unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (mode)
+             && const_op >= 0
              && have_insn_for (COMPARE, mode))
            {
              op0 = XEXP (op0, 0);
@@ -13270,8 +13320,40 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
            }
          break;
 
+       case REG_ARGS_SIZE:
+         /* ??? How to distribute between i3-i1.  Assume i3 contains the
+            entire adjustment.  Assert i3 contains at least some adjust.  */
+         if (!noop_move_p (i3))
+           {
+             int old_size, args_size = INTVAL (XEXP (note, 0));
+             /* fixup_args_size_notes looks at REG_NORETURN note,
+                so ensure the note is placed there first.  */
+             if (CALL_P (i3))
+               {
+                 rtx *np;
+                 for (np = &next_note; *np; np = &XEXP (*np, 1))
+                   if (REG_NOTE_KIND (*np) == REG_NORETURN)
+                     {
+                       rtx n = *np;
+                       *np = XEXP (n, 1);
+                       XEXP (n, 1) = REG_NOTES (i3);
+                       REG_NOTES (i3) = n;
+                       break;
+                     }
+               }
+             old_size = fixup_args_size_notes (PREV_INSN (i3), i3, args_size);
+             /* emit_call_1 adds for !ACCUMULATE_OUTGOING_ARGS
+                REG_ARGS_SIZE note to all noreturn calls, allow that here.  */
+             gcc_assert (old_size != args_size
+                         || (CALL_P (i3)
+                             && !ACCUMULATE_OUTGOING_ARGS
+                             && find_reg_note (i3, REG_NORETURN, NULL_RTX)));
+           }
+         break;
+
        case REG_NORETURN:
        case REG_SETJMP:
+       case REG_TM:
          /* These notes must remain with the call.  It should not be
             possible for both I2 and I3 to be a call.  */
          if (CALL_P (i3))