OSDN Git Service

2010-04-28 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index f26b9e5..2e81efc 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -92,7 +92,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "expr.h"
 #include "insn-attr.h"
 #include "recog.h"
-#include "real.h"
 #include "toplev.h"
 #include "target.h"
 #include "optabs.h"
@@ -391,7 +390,7 @@ static int contains_muldiv (rtx);
 static rtx try_combine (rtx, rtx, rtx, int *);
 static void undo_all (void);
 static void undo_commit (void);
-static rtx *find_split_point (rtx *, rtx);
+static rtx *find_split_point (rtx *, rtx, bool);
 static rtx subst (rtx, rtx, rtx, int, int);
 static rtx combine_simplify_rtx (rtx, enum machine_mode, int);
 static rtx simplify_if_then_else (rtx);
@@ -1343,7 +1342,7 @@ setup_incoming_promotions (rtx first)
   for (arg = DECL_ARGUMENTS (current_function_decl); arg;
        arg = TREE_CHAIN (arg))
     {
-      rtx reg = DECL_INCOMING_RTL (arg);
+      rtx x, reg = DECL_INCOMING_RTL (arg);
       int uns1, uns3;
       enum machine_mode mode1, mode2, mode3, mode4;
 
@@ -1375,34 +1374,38 @@ setup_incoming_promotions (rtx first)
       /* The mode of the register in which the argument is being passed.  */
       mode4 = GET_MODE (reg);
 
-      /* Eliminate sign extensions in the callee when possible.  Only
-         do this when:
-        (a) A mode promotion has occurred;
-        (b) The mode of the register is the same as the mode of
-            the argument as it is passed; and
-        (c) Either there's no language level extension, or the extension
-            from source to end result is valid.  The later case is true
-            when the signedness of the extensions match, or when the 
-            language level extension is unsigned.  In the later case,
-            a zero extension followed by a sign extension is the same
-            as one big zero extension.
-        (d) When no language-level promotions (which we cannot guarantee
-            will have been done by an external caller) are necessary,
-            unless we know that this function is only ever called from
-            the current compilation unit -- all of whose call sites will
-            do the mode1 --> mode2 promotion.  */
-      if (mode1 != mode3
-          && mode3 == mode4
-         && (mode1 == mode2 || ((uns1 || !uns3) && strictly_local)))
-        {
-         /* Record that the value was promoted from mode1 to mode3,
-            so that any sign extension at the head of the current
-            function may be eliminated.  */
-         rtx x;
-         x = gen_rtx_CLOBBER (mode1, const0_rtx);
-         x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
-         record_value_for_reg (reg, first, x);
-       }
+      /* Eliminate sign extensions in the callee when:
+        (a) A mode promotion has occurred;  */
+      if (mode1 == mode3)
+       continue;
+      /* (b) The mode of the register is the same as the mode of
+            the argument as it is passed; */
+      if (mode3 != mode4)
+       continue;
+      /* (c) There's no language level extension;  */
+      if (mode1 == mode2)
+       ;
+      /* (c.1) All callers are from the current compilation unit.  If that's
+        the case we don't have to rely on an ABI, we only have to know
+        what we're generating right now, and we know that we will do the
+        mode1 to mode2 promotion with the given sign.  */
+      else if (!strictly_local)
+       continue;
+      /* (c.2) The combination of the two promotions is useful.  This is
+        true when the signs match, or if the first promotion is unsigned.
+        In the later case, (sign_extend (zero_extend x)) is the same as
+        (zero_extend (zero_extend x)), so make sure to force UNS3 true.  */
+      else if (uns1)
+       uns3 = true;
+      else if (uns3)
+       continue;
+
+      /* Record that the value was promoted from mode1 to mode3,
+        so that any sign extension at the head of the current
+        function may be eliminated.  */
+      x = gen_rtx_CLOBBER (mode1, const0_rtx);
+      x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
+      record_value_for_reg (reg, first, x);
     }
 }
 
@@ -2072,14 +2075,14 @@ likely_spilled_retval_p (rtx insn)
   unsigned regno, nregs;
   /* We assume here that no machine mode needs more than
      32 hard registers when the value overlaps with a register
-     for which FUNCTION_VALUE_REGNO_P is true.  */
+     for which TARGET_FUNCTION_VALUE_REGNO_P is true.  */
   unsigned mask;
   struct likely_spilled_retval_info info;
 
   if (!NONJUMP_INSN_P (use) || GET_CODE (PATTERN (use)) != USE || insn == use)
     return 0;
   reg = XEXP (PATTERN (use), 0);
-  if (!REG_P (reg) || !FUNCTION_VALUE_REGNO_P (REGNO (reg)))
+  if (!REG_P (reg) || !targetm.calls.function_value_regno_p (REGNO (reg)))
     return 0;
   regno = REGNO (reg);
   nregs = hard_regno_nregs[regno][GET_MODE (reg)];
@@ -2282,10 +2285,12 @@ struct rtx_subst_pair
    substituted.  */
 
 static rtx
-propagate_for_debug_subst (rtx from ATTRIBUTE_UNUSED, void *data)
+propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
 {
   struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data;
 
+  if (!rtx_equal_p (from, old_rtx))
+    return NULL_RTX;
   if (!pair->adjusted)
     {
       pair->adjusted = true;
@@ -2304,6 +2309,7 @@ static void
 propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move)
 {
   rtx next, move_pos = move ? last : NULL_RTX, loc;
+  bool first_p;
 
 #ifdef AUTO_INC_DEC
   struct rtx_subst_pair p;
@@ -2312,6 +2318,7 @@ propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move)
   p.after = move;
 #endif
 
+  first_p = true;
   next = NEXT_INSN (insn);
   while (next != last)
     {
@@ -2319,6 +2326,11 @@ propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move)
       next = NEXT_INSN (insn);
       if (DEBUG_INSN_P (insn))
        {
+         if (first_p)
+           {
+             src = make_compound_operation (src, SET);
+             first_p = false;
+           }
 #ifdef AUTO_INC_DEC
          loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
                                         dest, propagate_for_debug_subst, &p);
@@ -2659,10 +2671,16 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          i2dest = SET_DEST (temp);
          i2dest_killed = dead_or_set_p (i2, i2dest);
 
+         /* Replace the source in I2 with the new constant and make the
+            resulting insn the new pattern for I3.  Then skip to where we
+            validate the pattern.  Everything was set up above.  */
          SUBST (SET_SRC (temp),
                 immed_double_const (olo, ohi, GET_MODE (SET_DEST (temp))));
 
          newpat = PATTERN (i2);
+
+          /* The dest of I3 has been replaced with the dest of I2.  */
+          changed_i3_dest = 1;
          goto validate_replacement;
        }
     }
@@ -3034,8 +3052,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        }
     }
 
-  /* We come here when we are replacing a destination in I2 with the
-     destination of I3.  */
  validate_replacement:
 
   /* Note which hard regs this insn has as inputs.  */
@@ -3257,7 +3273,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       /* If we can split it and use I2DEST, go ahead and see if that
         helps things be recognized.  Verify that none of the registers
         are set between I2 and I3.  */
-      if (insn_code_number < 0 && (split = find_split_point (&newpat, i3)) != 0
+      if (insn_code_number < 0
+          && (split = find_split_point (&newpat, i3, false)) != 0
 #ifdef HAVE_cc0
          && REG_P (i2dest)
 #endif
@@ -3283,6 +3300,14 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
          i2scratch = true;
 
+         /* *SPLIT may be part of I2SRC, so make sure we have the
+            original expression around for later debug processing.
+            We should not need I2SRC any more in other cases.  */
+         if (MAY_HAVE_DEBUG_INSNS)
+           i2src = copy_rtx (i2src);
+         else
+           i2src = NULL;
+
          /* Get NEWDEST as a register in the proper mode.  We have already
             validated that we can do this.  */
          if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
@@ -3779,7 +3804,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        call_usage = copy_rtx (call_usage);
 
        if (substed_i2)
-         replace_rtx (call_usage, i2dest, i2src);
+         {
+           /* I2SRC must still be meaningful at this point.  Some splitting
+              operations can invalidate I2SRC, but those operations do not
+              apply to calls.  */
+           gcc_assert (i2src);
+           replace_rtx (call_usage, i2dest, i2src);
+         }
 
        if (substed_i1)
          replace_rtx (call_usage, i1dest, i1src);
@@ -4134,7 +4165,7 @@ undo_commit (void)
    two insns.  */
 
 static rtx *
-find_split_point (rtx *loc, rtx insn)
+find_split_point (rtx *loc, rtx insn, bool set_src)
 {
   rtx x = *loc;
   enum rtx_code code = GET_CODE (x);
@@ -4154,7 +4185,7 @@ find_split_point (rtx *loc, rtx insn)
       if (MEM_P (SUBREG_REG (x)))
        return loc;
 #endif
-      return find_split_point (&SUBREG_REG (x), insn);
+      return find_split_point (&SUBREG_REG (x), insn, false);
 
     case MEM:
 #ifdef HAVE_lo_sum
@@ -4271,12 +4302,12 @@ find_split_point (rtx *loc, rtx insn)
 #endif
 
       /* See if we can split SET_SRC as it stands.  */
-      split = find_split_point (&SET_SRC (x), insn);
+      split = find_split_point (&SET_SRC (x), insn, true);
       if (split && split != &SET_SRC (x))
        return split;
 
       /* See if we can split SET_DEST as it stands.  */
-      split = find_split_point (&SET_DEST (x), insn);
+      split = find_split_point (&SET_DEST (x), insn, false);
       if (split && split != &SET_DEST (x))
        return split;
 
@@ -4320,7 +4351,7 @@ find_split_point (rtx *loc, rtx insn)
 
          SUBST (SET_DEST (x), dest);
 
-         split = find_split_point (&SET_SRC (x), insn);
+         split = find_split_point (&SET_SRC (x), insn, true);
          if (split && split != &SET_SRC (x))
            return split;
        }
@@ -4356,7 +4387,7 @@ find_split_point (rtx *loc, rtx insn)
              if (extraction != 0)
                {
                  SUBST (SET_SRC (x), extraction);
-                 return find_split_point (loc, insn);
+                 return find_split_point (loc, insn, false);
                }
            }
          break;
@@ -4378,7 +4409,7 @@ find_split_point (rtx *loc, rtx insn)
                                                    XEXP (SET_SRC (x), 0),
                                                    GEN_INT (pos))));
 
-             split = find_split_point (&SET_SRC (x), insn);
+             split = find_split_point (&SET_SRC (x), insn, true);
              if (split && split != &SET_SRC (x))
                return split;
            }
@@ -4437,7 +4468,7 @@ find_split_point (rtx *loc, rtx insn)
                                   GEN_INT (pos)),
                                  GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
 
-             split = find_split_point (&SET_SRC (x), insn);
+             split = find_split_point (&SET_SRC (x), insn, true);
              if (split && split != &SET_SRC (x))
                return split;
            }
@@ -4452,7 +4483,7 @@ find_split_point (rtx *loc, rtx insn)
                                               - len - pos)),
                      GEN_INT (GET_MODE_BITSIZE (mode) - len)));
 
-             split = find_split_point (&SET_SRC (x), insn);
+             split = find_split_point (&SET_SRC (x), insn, true);
              if (split && split != &SET_SRC (x))
                return split;
            }
@@ -4492,7 +4523,7 @@ find_split_point (rtx *loc, rtx insn)
                                              GET_MODE (x),
                                              XEXP (XEXP (x, 0), 0),
                                              XEXP (XEXP (x, 1), 0))));
-         return find_split_point (loc, insn);
+         return find_split_point (loc, insn, set_src);
        }
 
       /* Many RISC machines have a large set of logical insns.  If the
@@ -4506,6 +4537,14 @@ find_split_point (rtx *loc, rtx insn)
        }
       break;
 
+    case PLUS:
+    case MINUS:
+      /* Split at a multiply-accumulate instruction.  However if this is
+         the SET_SRC, we likely do not have such an instruction and it's
+         worthless to try this split.  */
+      if (!set_src && GET_CODE (XEXP (x, 0)) == MULT)
+        return loc;
+
     default:
       break;
     }
@@ -4515,7 +4554,7 @@ find_split_point (rtx *loc, rtx insn)
     {
     case RTX_BITFIELD_OPS:             /* This is ZERO_EXTRACT and SIGN_EXTRACT.  */
     case RTX_TERNARY:
-      split = find_split_point (&XEXP (x, 2), insn);
+      split = find_split_point (&XEXP (x, 2), insn, false);
       if (split)
        return split;
       /* ... fall through ...  */
@@ -4523,7 +4562,7 @@ find_split_point (rtx *loc, rtx insn)
     case RTX_COMM_ARITH:
     case RTX_COMPARE:
     case RTX_COMM_COMPARE:
-      split = find_split_point (&XEXP (x, 1), insn);
+      split = find_split_point (&XEXP (x, 1), insn, false);
       if (split)
        return split;
       /* ... fall through ...  */
@@ -4533,7 +4572,7 @@ find_split_point (rtx *loc, rtx insn)
       if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND)
        return &XEXP (x, 0);
 
-      split = find_split_point (&XEXP (x, 0), insn);
+      split = find_split_point (&XEXP (x, 0), insn, false);
       if (split)
        return split;
       return loc;
@@ -6783,8 +6822,10 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       if (mode == tmode)
        return new_rtx;
 
-      if (CONST_INT_P (new_rtx))
-       return gen_int_mode (INTVAL (new_rtx), mode);
+      if (CONST_INT_P (new_rtx)
+         || GET_CODE (new_rtx) == CONST_DOUBLE)
+       return simplify_unary_operation (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
+                                        mode, new_rtx, tmode);
 
       /* If we know that no extraneous bits are set, and that the high
         bit is not set, convert the extraction to the cheaper of
@@ -7302,15 +7343,14 @@ make_compound_operation (rtx x, enum rtx_code in_code)
       tem = make_compound_operation (SUBREG_REG (x), in_code);
 
       {
-       rtx simplified;
-       simplified = simplify_subreg (GET_MODE (x), tem, GET_MODE (tem),
-                                     SUBREG_BYTE (x));
+       rtx simplified = simplify_subreg (mode, tem, GET_MODE (SUBREG_REG (x)),
+                                         SUBREG_BYTE (x));
 
        if (simplified)
          tem = simplified;
 
        if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
-           && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
+           && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
            && subreg_lowpart_p (x))
          {
            rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,