OSDN Git Service

PR target/33135
[pf3gnuchains/gcc-fork.git] / gcc / rtlanal.c
index c3cdd31..7c4a49b 100644 (file)
@@ -1,7 +1,7 @@
 /* Analyze RTL for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
 /* Analyze RTL 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
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 
 This file is part of GCC.
 
@@ -25,8 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "diagnostic-core.h"
 #include "coretypes.h"
 #include "tm.h"
 #include "diagnostic-core.h"
-#include "rtl.h"
 #include "hard-reg-set.h"
 #include "hard-reg-set.h"
+#include "rtl.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "target.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "target.h"
@@ -999,6 +999,56 @@ set_of (const_rtx pat, const_rtx insn)
   note_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
   return data.found;
 }
   note_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
   return data.found;
 }
+
+/* This function, called through note_stores, collects sets and
+   clobbers of hard registers in a HARD_REG_SET, which is pointed to
+   by DATA.  */
+void
+record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
+{
+  HARD_REG_SET *pset = (HARD_REG_SET *)data;
+  if (REG_P (x) && HARD_REGISTER_P (x))
+    add_to_hard_reg_set (pset, GET_MODE (x), REGNO (x));
+}
+
+/* Examine INSN, and compute the set of hard registers written by it.
+   Store it in *PSET.  Should only be called after reload.  */
+void
+find_all_hard_reg_sets (const_rtx insn, HARD_REG_SET *pset)
+{
+  rtx link;
+
+  CLEAR_HARD_REG_SET (*pset);
+  note_stores (PATTERN (insn), record_hard_reg_sets, pset);
+  if (CALL_P (insn))
+    IOR_HARD_REG_SET (*pset, call_used_reg_set);
+  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+    if (REG_NOTE_KIND (link) == REG_INC)
+      record_hard_reg_sets (XEXP (link, 0), NULL, pset);
+}
+
+/* A for_each_rtx subroutine of record_hard_reg_uses.  */
+static int
+record_hard_reg_uses_1 (rtx *px, void *data)
+{
+  rtx x = *px;
+  HARD_REG_SET *pused = (HARD_REG_SET *)data;
+
+  if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+    {
+      int nregs = hard_regno_nregs[REGNO (x)][GET_MODE (x)];
+      while (nregs-- > 0)
+       SET_HARD_REG_BIT (*pused, REGNO (x) + nregs);
+    }
+  return 0;
+}
+
+/* Like record_hard_reg_sets, but called through note_uses.  */
+void
+record_hard_reg_uses (rtx *px, void *data)
+{
+  for_each_rtx (px, record_hard_reg_uses_1, data);
+}
 \f
 /* Given an INSN, return a SET expression if this insn has only a single SET.
    It may also have CLOBBERs, USEs, or SET whose output
 \f
 /* Given an INSN, return a SET expression if this insn has only a single SET.
    It may also have CLOBBERs, USEs, or SET whose output
@@ -1868,6 +1918,7 @@ alloc_reg_note (enum reg_note kind, rtx datum, rtx list)
     case REG_CC_USER:
     case REG_LABEL_TARGET:
     case REG_LABEL_OPERAND:
     case REG_CC_USER:
     case REG_LABEL_TARGET:
     case REG_LABEL_OPERAND:
+    case REG_TM:
       /* These types of register notes use an INSN_LIST rather than an
         EXPR_LIST, so that copying is done right and dumps look
         better.  */
       /* These types of register notes use an INSN_LIST rather than an
         EXPR_LIST, so that copying is done right and dumps look
         better.  */
@@ -2279,7 +2330,7 @@ may_trap_p_1 (const_rtx x, unsigned flags)
          code_changed
          || !MEM_NOTRAP_P (x))
        {
          code_changed
          || !MEM_NOTRAP_P (x))
        {
-         HOST_WIDE_INT size = MEM_SIZE (x) ? INTVAL (MEM_SIZE (x)) : 0;
+         HOST_WIDE_INT size = MEM_SIZE_KNOWN_P (x) ? MEM_SIZE (x) : 0;
          return rtx_addr_can_trap_p_1 (XEXP (x, 0), 0, size,
                                        GET_MODE (x), code_changed);
        }
          return rtx_addr_can_trap_p_1 (XEXP (x, 0), 0, size,
                                        GET_MODE (x), code_changed);
        }
@@ -2660,8 +2711,11 @@ tablejump_p (const_rtx insn, rtx *labelp, rtx *tablep)
 {
   rtx label, table;
 
 {
   rtx label, table;
 
-  if (JUMP_P (insn)
-      && (label = JUMP_LABEL (insn)) != NULL_RTX
+  if (!JUMP_P (insn))
+    return false;
+
+  label = JUMP_LABEL (insn);
+  if (label != NULL_RTX && !ANY_RETURN_P (label)
       && (table = next_active_insn (label)) != NULL_RTX
       && JUMP_TABLE_DATA_P (table))
     {
       && (table = next_active_insn (label)) != NULL_RTX
       && JUMP_TABLE_DATA_P (table))
     {
@@ -3671,11 +3725,12 @@ label_is_jump_target_p (const_rtx label, const_rtx jump_insn)
    Another is in rtl generation, to pick the cheapest way to multiply.
    Other uses like the latter are expected in the future.
 
    Another is in rtl generation, to pick the cheapest way to multiply.
    Other uses like the latter are expected in the future.
 
-   SPEED parameter specify whether costs optimized for speed or size should
+   X appears as operand OPNO in an expression with code OUTER_CODE.
+   SPEED specifies whether costs optimized for speed or size should
    be returned.  */
 
 int
    be returned.  */
 
 int
-rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED, bool speed)
+rtx_cost (rtx x, enum rtx_code outer_code, int opno, bool speed)
 {
   int i, j;
   enum rtx_code code;
 {
   int i, j;
   enum rtx_code code;
@@ -3723,7 +3778,7 @@ rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED, bool speed)
       break;
 
     default:
       break;
 
     default:
-      if (targetm.rtx_costs (x, code, outer_code, &total, speed))
+      if (targetm.rtx_costs (x, code, outer_code, opno, &total, speed))
        return total;
       break;
     }
        return total;
       break;
     }
@@ -3734,22 +3789,23 @@ rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED, bool speed)
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     if (fmt[i] == 'e')
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     if (fmt[i] == 'e')
-      total += rtx_cost (XEXP (x, i), code, speed);
+      total += rtx_cost (XEXP (x, i), code, i, speed);
     else if (fmt[i] == 'E')
       for (j = 0; j < XVECLEN (x, i); j++)
     else if (fmt[i] == 'E')
       for (j = 0; j < XVECLEN (x, i); j++)
-       total += rtx_cost (XVECEXP (x, i, j), code, speed);
+       total += rtx_cost (XVECEXP (x, i, j), code, i, speed);
 
   return total;
 }
 
 /* Fill in the structure C with information about both speed and size rtx
 
   return total;
 }
 
 /* Fill in the structure C with information about both speed and size rtx
-   costs for X, with outer code OUTER.  */
+   costs for X, which is operand OPNO in an expression with code OUTER.  */
 
 void
 
 void
-get_full_rtx_cost (rtx x, enum rtx_code outer, struct full_rtx_costs *c)
+get_full_rtx_cost (rtx x, enum rtx_code outer, int opno,
+                  struct full_rtx_costs *c)
 {
 {
-  c->speed = rtx_cost (x, outer, true);
-  c->size = rtx_cost (x, outer, false);
+  c->speed = rtx_cost (x, outer, opno, true);
+  c->size = rtx_cost (x, outer, opno, false);
 }
 
 \f
 }
 
 \f
@@ -3777,7 +3833,7 @@ address_cost (rtx x, enum machine_mode mode, addr_space_t as, bool speed)
 int
 default_address_cost (rtx x, bool speed)
 {
 int
 default_address_cost (rtx x, bool speed)
 {
-  return rtx_cost (x, MEM, speed);
+  return rtx_cost (x, MEM, 0, speed);
 }
 \f
 
 }
 \f
 
@@ -4268,6 +4324,11 @@ nonzero_bits1 (const_rtx x, enum machine_mode mode, const_rtx known_x,
        nonzero = -1;
       break;
 
        nonzero = -1;
       break;
 
+    case CLRSB:
+      /* This is at most the number of bits in the mode minus 1.  */
+      nonzero = ((unsigned HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
+      break;
+
     case PARITY:
       nonzero = 1;
       break;
     case PARITY:
       nonzero = 1;
       break;
@@ -4779,7 +4840,7 @@ insn_rtx_cost (rtx pat, bool speed)
   else
     return 0;
 
   else
     return 0;
 
-  cost = rtx_cost (SET_SRC (set), SET, speed);
+  cost = set_src_cost (SET_SRC (set), speed);
   return cost > 0 ? cost : COSTS_N_INSNS (1);
 }
 
   return cost > 0 ? cost : COSTS_N_INSNS (1);
 }