re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / rtlanal.c
index 2fad919b08975448bb600fe52983f0ce534fbf76..86b3b622f89384afb3823b0215de9579da96d96b 100644 (file)
@@ -1,5 +1,5 @@
 /* Analyze RTL for GNU compiler.
-   Copyright (C) 1987-2014 Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -32,15 +32,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm_p.h"
 #include "flags.h"
 #include "regs.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
-#include "input.h"
 #include "function.h"
 #include "predict.h"
 #include "basic-block.h"
 #include "df.h"
+#include "symtab.h"
 #include "tree.h"
 #include "emit-rtl.h"  /* FIXME: Can go away once crtl is moved to rtl.h.  */
 #include "addresses.h"
@@ -101,7 +97,10 @@ generic_subrtx_iterator <T>::add_single_to_queue (array_type &array,
          return base;
        }
       gcc_checking_assert (i == LOCAL_ELEMS);
-      vec_safe_grow (array.heap, i + 1);
+      /* A previous iteration might also have moved from the stack to the
+        heap, in which case the heap array will already be big enough.  */
+      if (vec_safe_length (array.heap) <= i)
+       vec_safe_grow (array.heap, i + 1);
       base = array.heap->address ();
       memcpy (base, array.stack, sizeof (array.stack));
       base[LOCAL_ELEMS] = x;
@@ -997,6 +996,17 @@ reg_set_between_p (const_rtx reg, const rtx_insn *from_insn,
 int
 reg_set_p (const_rtx reg, const_rtx insn)
 {
+  /* After delay slot handling, call and branch insns might be in a
+     sequence.  Check all the elements there.  */
+  if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
+    {
+      for (int i = 0; i < XVECLEN (PATTERN (insn), 0); ++i)
+       if (reg_set_p (reg, XVECEXP (PATTERN (insn), 0, i)))
+         return true;
+
+      return false;
+    }
+
   /* We can be passed an insn or part of one.  If we are passed an insn,
      check if a side-effect of the insn clobbers REG.  */
   if (INSN_P (insn)
@@ -1008,7 +1018,7 @@ reg_set_p (const_rtx reg, const_rtx insn)
                                               GET_MODE (reg), REGNO (reg)))
                  || MEM_P (reg)
                  || find_reg_fusage (insn, CLOBBER, reg)))))
-    return 1;
+    return true;
 
   return set_of (reg, insn) != NULL_RTX;
 }
@@ -1183,7 +1193,7 @@ record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
 /* 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, bool implicit)
+find_all_hard_reg_sets (const rtx_insn *insn, HARD_REG_SET *pset, bool implicit)
 {
   rtx link;
 
@@ -1354,7 +1364,7 @@ set_noop_p (const_rtx set)
    value to itself.  */
 
 int
-noop_move_p (const_rtx insn)
+noop_move_p (const rtx_insn *insn)
 {
   rtx pat = PATTERN (insn);
 
@@ -1402,7 +1412,7 @@ noop_move_p (const_rtx insn)
    References contained within the substructure at LOC do not count.
    LOC may be zero, meaning don't ignore anything.  */
 
-int
+bool
 refers_to_regno_p (unsigned int regno, unsigned int endregno, const_rtx x,
                   rtx *loc)
 {
@@ -1415,7 +1425,7 @@ refers_to_regno_p (unsigned int regno, unsigned int endregno, const_rtx x,
   /* The contents of a REG_NONNEG note is always zero, so we must come here
      upon repeat in case the last REG_NOTE is a REG_NONNEG note.  */
   if (x == 0)
-    return 0;
+    return false;
 
   code = GET_CODE (x);
 
@@ -1428,12 +1438,11 @@ refers_to_regno_p (unsigned int regno, unsigned int endregno, const_rtx x,
         clobber a virtual register.  In fact, we could be more precise,
         but it isn't worth it.  */
       if ((x_regno == STACK_POINTER_REGNUM
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-          || x_regno == ARG_POINTER_REGNUM
-#endif
+          || (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+              && x_regno == ARG_POINTER_REGNUM)
           || x_regno == FRAME_POINTER_REGNUM)
          && regno >= FIRST_VIRTUAL_REGISTER && regno <= LAST_VIRTUAL_REGISTER)
-       return 1;
+       return true;
 
       return endregno > x_regno && regno < END_REGNO (x);
 
@@ -1466,10 +1475,10 @@ refers_to_regno_p (unsigned int regno, unsigned int endregno, const_rtx x,
                                     SUBREG_REG (SET_DEST (x)), loc))
              || (!REG_P (SET_DEST (x))
                  && refers_to_regno_p (regno, endregno, SET_DEST (x), loc))))
-       return 1;
+       return true;
 
       if (code == CLOBBER || loc == &SET_SRC (x))
-       return 0;
+       return false;
       x = SET_SRC (x);
       goto repeat;
 
@@ -1491,7 +1500,7 @@ refers_to_regno_p (unsigned int regno, unsigned int endregno, const_rtx x,
            }
          else
            if (refers_to_regno_p (regno, endregno, XEXP (x, i), loc))
-             return 1;
+             return true;
        }
       else if (fmt[i] == 'E')
        {
@@ -1499,10 +1508,10 @@ refers_to_regno_p (unsigned int regno, unsigned int endregno, const_rtx x,
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            if (loc != &XVECEXP (x, i, j)
                && refers_to_regno_p (regno, endregno, XVECEXP (x, i, j), loc))
-             return 1;
+             return true;
        }
     }
-  return 0;
+  return false;
 }
 
 /* Nonzero if modifying X will affect IN.  If X is a register or a SUBREG,
@@ -2001,7 +2010,7 @@ find_reg_fusage (const_rtx insn, enum rtx_code code, const_rtx datum)
 
       if (regno < FIRST_PSEUDO_REGISTER)
        {
-         unsigned int end_regno = END_HARD_REGNO (datum);
+         unsigned int end_regno = END_REGNO (datum);
          unsigned int i;
 
          for (i = regno; i < end_regno; i++)
@@ -2035,7 +2044,7 @@ find_regno_fusage (const_rtx insn, enum rtx_code code, unsigned int regno)
       if (GET_CODE (op = XEXP (link, 0)) == code
          && REG_P (reg = XEXP (op, 0))
          && REGNO (reg) <= regno
-         && END_HARD_REGNO (reg) > regno)
+         && END_REGNO (reg) > regno)
        return 1;
     }
 
@@ -2103,7 +2112,7 @@ add_int_reg_note (rtx insn, enum reg_note kind, int datum)
 /* Add a register note like NOTE to INSN.  */
 
 void
-add_shallow_copy_of_reg_note (rtx insn, rtx note)
+add_shallow_copy_of_reg_note (rtx_insn *insn, rtx note)
 {
   if (GET_CODE (note) == INT_LIST)
     add_int_reg_note (insn, REG_NOTE_KIND (note), XINT (note, 0));
@@ -2145,7 +2154,7 @@ remove_note (rtx insn, const_rtx note)
 /* Remove REG_EQUAL and/or REG_EQUIV notes if INSN has such notes.  */
 
 void
-remove_reg_equal_equiv_notes (rtx insn)
+remove_reg_equal_equiv_notes (rtx_insn *insn)
 {
   rtx *loc;
 
@@ -2191,16 +2200,16 @@ remove_reg_equal_equiv_notes_for_regno (unsigned int regno)
    return 1 if it is found.  A simple equality test is used to determine if
    NODE matches.  */
 
-int
-in_expr_list_p (const_rtx listp, const_rtx node)
+bool
+in_insn_list_p (const rtx_insn_list *listp, const rtx_insn *node)
 {
   const_rtx x;
 
   for (x = listp; x; x = XEXP (x, 1))
     if (node == XEXP (x, 0))
-      return 1;
+      return true;
 
-  return 0;
+  return false;
 }
 
 /* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and
@@ -2212,7 +2221,7 @@ void
 remove_node_from_expr_list (const_rtx node, rtx_expr_list **listp)
 {
   rtx_expr_list *temp = *listp;
-  rtx prev = NULL_RTX;
+  rtx_expr_list *prev = NULL;
 
   while (temp)
     {
@@ -2241,7 +2250,7 @@ void
 remove_node_from_insn_list (const rtx_insn *node, rtx_insn_list **listp)
 {
   rtx_insn_list *temp = *listp;
-  rtx prev = NULL;
+  rtx_insn_list *prev = NULL;
 
   while (temp)
     {
@@ -2900,7 +2909,8 @@ rtx_referenced_p (const_rtx x, const_rtx body)
 bool
 tablejump_p (const rtx_insn *insn, rtx *labelp, rtx_jump_table_data **tablep)
 {
-  rtx label, table;
+  rtx label;
+  rtx_insn *table;
 
   if (!JUMP_P (insn))
     return false;
@@ -2976,7 +2986,7 @@ computed_jump_p_1 (const_rtx x)
    we can recognize them by a (use (label_ref)).  */
 
 int
-computed_jump_p (const_rtx insn)
+computed_jump_p (const rtx_insn *insn)
 {
   int i;
   if (JUMP_P (insn))
@@ -3122,17 +3132,16 @@ regno_use_in (unsigned int regno, rtx x)
 }
 
 /* Return a value indicating whether OP, an operand of a commutative
-   operation, is preferred as the first or second operand.  The higher
-   the value, the stronger the preference for being the first operand.
-   We use negative values to indicate a preference for the first operand
-   and positive values for the second operand.  */
+   operation, is preferred as the first or second operand.  The more
+   positive the value, the stronger the preference for being the first
+   operand.  */
 
 int
 commutative_operand_precedence (rtx op)
 {
   enum rtx_code code = GET_CODE (op);
 
-  /* Constants always come the second operand.  Prefer "nice" constants.  */
+  /* Constants always become the second operand.  Prefer "nice" constants.  */
   if (code == CONST_INT)
     return -8;
   if (code == CONST_WIDE_INT)
@@ -3426,6 +3435,22 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
          info->offset = offset / regsize_xmode;
          return;
        }
+      /* Quick exit for the simple and common case of extracting whole
+        subregisters from a multiregister value.  */
+      /* ??? It would be better to integrate this into the code below,
+        if we can generalize the concept enough and figure out how
+        odd-sized modes can coexist with the other weird cases we support.  */
+      if (!rknown
+         && WORDS_BIG_ENDIAN == REG_WORDS_BIG_ENDIAN
+         && regsize_xmode == regsize_ymode
+         && (offset % regsize_ymode) == 0)
+       {
+         info->representable_p = true;
+         info->nregs = nregs_ymode;
+         info->offset = offset / regsize_ymode;
+         gcc_assert (info->offset + info->nregs <= nregs_xmode);
+         return;
+       }
     }
 
   /* Lowpart subregs are otherwise valid.  */
@@ -5005,7 +5030,6 @@ canonicalize_condition (rtx_insn *insn, rtx cond, int reverse,
       /* Set nonzero when we find something of interest.  */
       rtx x = 0;
 
-#ifdef HAVE_cc0
       /* If comparison with cc0, import actual comparison from compare
         insn.  */
       if (op0 == cc0_rtx)
@@ -5021,7 +5045,6 @@ canonicalize_condition (rtx_insn *insn, rtx cond, int reverse,
          if (earliest)
            *earliest = prev;
        }
-#endif
 
       /* If this is a COMPARE, pick up the two things being compared.  */
       if (GET_CODE (op0) == COMPARE)
@@ -5674,7 +5697,8 @@ get_index_term (rtx *inner)
     inner = strip_address_mutations (&XEXP (*inner, 0));
   if (REG_P (*inner)
       || MEM_P (*inner)
-      || GET_CODE (*inner) == SUBREG)
+      || GET_CODE (*inner) == SUBREG
+      || GET_CODE (*inner) == SCRATCH)
     return inner;
   return 0;
 }