OSDN Git Service

* target-def.h: Remove usage of OBJECT_FORMAT_ROSE.
[pf3gnuchains/gcc-fork.git] / gcc / rtlanal.c
index 030682e..c0b3a0b 100644 (file)
@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 static int global_reg_mentioned_p_1 PARAMS ((rtx *, void *));
 static void set_of_1           PARAMS ((rtx, rtx, void *));
 static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
+static int rtx_referenced_p_1  PARAMS ((rtx *, void *));
 static int computed_jump_p_1   PARAMS ((rtx));
 static void parms_set          PARAMS ((rtx, rtx, void *));
 static bool hoist_test_store           PARAMS ((rtx, rtx, regset));
@@ -465,13 +466,7 @@ get_jump_table_offset (insn, earliest)
   rtx old_y;
   int i;
 
-  if (GET_CODE (insn) != JUMP_INSN
-      || ! (label = JUMP_LABEL (insn))
-      || ! (table = NEXT_INSN (label))
-      || GET_CODE (table) != JUMP_INSN
-      || (GET_CODE (PATTERN (table)) != ADDR_VEC
-         && GET_CODE (PATTERN (table)) != ADDR_DIFF_VEC)
-      || ! (set = single_set (insn)))
+  if (!tablejump_p (insn, &label, &table) || !(set = single_set (insn)))
     return NULL_RTX;
 
   x = SET_SRC (set);
@@ -641,7 +636,6 @@ int
 global_reg_mentioned_p (x)
      rtx x;
 {
-
   if (INSN_P (x))
     {
       if (GET_CODE (x) == CALL_INSN)
@@ -760,8 +754,6 @@ reg_mentioned_p (reg, in)
       return 0;
 
     case CONST_INT:
-      return GET_CODE (reg) == CONST_INT && INTVAL (in) == INTVAL (reg);
-
     case CONST_VECTOR:
     case CONST_DOUBLE:
       /* These are kept unique for a given value.  */
@@ -1326,19 +1318,17 @@ set_noop_p (set)
   rtx src = SET_SRC (set);
   rtx dst = SET_DEST (set);
 
-  if (side_effects_p (src) || side_effects_p (dst))
-    return 0;
-
-  if (GET_CODE (dst) == MEM && GET_CODE (src) == MEM)
-    return rtx_equal_p (dst, src);
-
   if (dst == pc_rtx && src == pc_rtx)
     return 1;
 
+  if (GET_CODE (dst) == MEM && GET_CODE (src) == MEM)
+    return rtx_equal_p (dst, src) && !side_effects_p (dst);
+
   if (GET_CODE (dst) == SIGN_EXTRACT
       || GET_CODE (dst) == ZERO_EXTRACT)
     return rtx_equal_p (XEXP (dst, 0), src)
-          && ! BYTES_BIG_ENDIAN && XEXP (dst, 2) == const0_rtx;
+          && ! BYTES_BIG_ENDIAN && XEXP (dst, 2) == const0_rtx
+          && !side_effects_p (src);
 
   if (GET_CODE (dst) == STRICT_LOW_PART)
     dst = XEXP (dst, 0);
@@ -1558,7 +1548,7 @@ refers_to_regno_p (regno, endregno, x, loc)
       else if (fmt[i] == 'E')
        {
          int j;
-         for (j = XVECLEN (x, i) - 1; j >=0; j--)
+         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;
@@ -1580,7 +1570,9 @@ reg_overlap_mentioned_p (x, in)
   unsigned int regno, endregno;
 
   /* Overly conservative.  */
-  if (GET_CODE (x) == STRICT_LOW_PART)
+  if (GET_CODE (x) == STRICT_LOW_PART
+      || GET_CODE (x) == ZERO_EXTRACT
+      || GET_CODE (x) == SIGN_EXTRACT)
     x = XEXP (x, 0);
 
   /* If either argument is a constant, then modifying X can not affect IN.  */
@@ -2017,14 +2009,19 @@ rtx
 find_reg_equal_equiv_note (insn)
      rtx insn;
 {
-  rtx note;
+  rtx link;
 
-  if (single_set (insn) == 0)
+  if (!INSN_P (insn))
     return 0;
-  else if ((note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
-    return note;
-  else
-    return find_reg_note (insn, REG_EQUAL, NULL_RTX);
+  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+    if (REG_NOTE_KIND (link) == REG_EQUAL
+       || REG_NOTE_KIND (link) == REG_EQUIV)
+      {
+       if (single_set (insn) == 0)
+         return 0;
+       return link;
+      }
+  return NULL;
 }
 
 /* Return true if DATUM, or any overlap of DATUM, of kind CODE is found
@@ -2462,6 +2459,8 @@ may_trap_p (x)
 
       /* Memory ref can trap unless it's a static var or a stack slot.  */
     case MEM:
+      if (MEM_NOTRAP_P (x))
+       return 0;
       return rtx_addr_can_trap_p (XEXP (x, 0));
 
       /* Division by a non-constant might trap.  */
@@ -2517,6 +2516,12 @@ may_trap_p (x)
        return 1;
       break;
 
+    case FIX:
+      /* Conversion of floating point might trap.  */
+      if (flag_trapping_math && HONOR_NANS (GET_MODE (XEXP (x, 0))))
+       return 1;
+      break;
+
     case NEG:
     case ABS:
       /* These operations don't trap even with floating point.  */
@@ -2785,6 +2790,137 @@ replace_regs (x, reg_map, nregs, replace_dest)
   return x;
 }
 
+/* Replace occurrences of the old label in *X with the new one.
+   DATA is a REPLACE_LABEL_DATA containing the old and new labels.  */
+
+int
+replace_label (x, data)
+     rtx *x;
+     void *data;
+{
+  rtx l = *x;
+  rtx tmp;
+  rtx old_label = ((replace_label_data *) data)->r1;
+  rtx new_label = ((replace_label_data *) data)->r2;
+  bool update_label_nuses = ((replace_label_data *) data)->update_label_nuses;
+
+  if (l == NULL_RTX)
+    return 0;
+
+  if (GET_CODE (l) == MEM
+      && (tmp = XEXP (l, 0)) != NULL_RTX
+      && GET_CODE (tmp) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (tmp))
+    {
+      rtx c = get_pool_constant (tmp);
+      if (rtx_referenced_p (old_label, c))
+       {
+         rtx new_c, new_l;
+         replace_label_data *d = (replace_label_data *) data;
+         
+         /* Create a copy of constant C; replace the label inside
+            but do not update LABEL_NUSES because uses in constant pool
+            are not counted.  */
+         new_c = copy_rtx (c);
+         d->update_label_nuses = false;
+         for_each_rtx (&new_c, replace_label, data);
+         d->update_label_nuses = update_label_nuses;
+
+         /* Add the new constant NEW_C to constant pool and replace
+            the old reference to constant by new reference.  */
+         new_l = force_const_mem (get_pool_mode (tmp), new_c);
+         *x = replace_rtx (l, l, new_l);
+       }
+      return 0;
+    }
+
+  /* If this is a JUMP_INSN, then we also need to fix the JUMP_LABEL
+     field.  This is not handled by for_each_rtx because it doesn't
+     handle unprinted ('0') fields.  */
+  if (GET_CODE (l) == JUMP_INSN && JUMP_LABEL (l) == old_label)
+    JUMP_LABEL (l) = new_label;
+
+  if ((GET_CODE (l) == LABEL_REF
+       || GET_CODE (l) == INSN_LIST)
+      && XEXP (l, 0) == old_label)
+    {
+      XEXP (l, 0) = new_label;
+      if (update_label_nuses)
+       {
+         ++LABEL_NUSES (new_label);
+         --LABEL_NUSES (old_label);
+       }
+      return 0;
+    }
+
+  return 0;
+}
+
+/* When *BODY is equal to X or X is directly referenced by *BODY
+   return nonzero, thus FOR_EACH_RTX stops traversing and returns nonzero
+   too, otherwise FOR_EACH_RTX continues traversing *BODY.  */
+
+static int
+rtx_referenced_p_1 (body, x)
+     rtx *body;
+     void *x;
+{
+  rtx y = (rtx) x;
+
+  if (*body == NULL_RTX)
+    return y == NULL_RTX;
+
+  /* Return true if a label_ref *BODY refers to label Y.  */
+  if (GET_CODE (*body) == LABEL_REF && GET_CODE (y) == CODE_LABEL)
+    return XEXP (*body, 0) == y;
+
+  /* If *BODY is a reference to pool constant traverse the constant.  */
+  if (GET_CODE (*body) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (*body))
+    return rtx_referenced_p (y, get_pool_constant (*body));
+
+  /* By default, compare the RTL expressions.  */
+  return rtx_equal_p (*body, y);
+}
+
+/* Return true if X is referenced in BODY.  */
+
+int
+rtx_referenced_p (x, body)
+     rtx x;
+     rtx body;
+{
+  return for_each_rtx (&body, rtx_referenced_p_1, x);
+}
+
+/* If INSN is a jump to jumptable insn rturn true and store the label (which
+   INSN jumps to) to *LABEL and the tablejump insn to *TABLE.
+   LABEL and TABLE may be NULL.  */
+
+bool
+tablejump_p (insn, label, table)
+     rtx insn;
+     rtx *label;
+     rtx *table;
+{
+  rtx l, t;
+
+  if (onlyjump_p (insn)
+      && (l = JUMP_LABEL (insn)) != NULL_RTX
+      && (t = NEXT_INSN (l)) != NULL_RTX
+      && GET_CODE (t) == JUMP_INSN
+      && (GET_CODE (PATTERN (t)) == ADDR_VEC
+         || GET_CODE (PATTERN (t)) == ADDR_DIFF_VEC))
+    {
+      if (label)
+       *label = l;
+      if (table)
+       *table = t;
+      return true;
+    }
+  return false;
+}
+
 /* A subroutine of computed_jump_p, return 1 if X contains a REG or MEM or
    constant that is not in the constant pool and not in the condition
    of an IF_THEN_ELSE.  */
@@ -3138,7 +3274,7 @@ insns_safe_to_move_p (from, to, new_to)
   return 0;
 }
 
-/* Return nonzero if IN contains a piece of rtl that has the address LOC */
+/* Return nonzero if IN contains a piece of rtl that has the address LOC */
 int
 loc_mentioned_in_p (loc, in)
      rtx *loc, in;
@@ -3252,6 +3388,74 @@ subreg_regno_offset (xregno, xmode, offset, ymode)
   return (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode;
 }
 
+/* This function returns true when the offset is representable via
+   subreg_offset in the given regno.
+   xregno - A regno of an inner hard subreg_reg (or what will become one).
+   xmode  - The mode of xregno.
+   offset - The byte offset.
+   ymode  - The mode of a top level SUBREG (or what may become one).
+   RETURN - The regno offset which would be used.  */
+bool
+subreg_offset_representable_p (xregno, xmode, offset, ymode)
+     unsigned int xregno;
+     enum machine_mode xmode;
+     unsigned int offset;
+     enum machine_mode ymode;
+{
+  int nregs_xmode, nregs_ymode;
+  int mode_multiple, nregs_multiple;
+  int y_offset;
+
+  if (xregno >= FIRST_PSEUDO_REGISTER)
+    abort ();
+
+  nregs_xmode = HARD_REGNO_NREGS (xregno, xmode);
+  nregs_ymode = HARD_REGNO_NREGS (xregno, ymode);
+
+  /* paradoxical subregs are always valid.  */
+  if (offset == 0
+      && nregs_ymode > nregs_xmode
+      && (GET_MODE_SIZE (ymode) > UNITS_PER_WORD
+         ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
+    return true;
+
+  /* Lowpart subregs are always valid.  */
+  if (offset == subreg_lowpart_offset (ymode, xmode))
+    return true;
+
+#ifdef ENABLE_CHECKING
+  /* This should always pass, otherwise we don't know how to verify the
+     constraint.  These conditions may be relaxed but subreg_offset would
+     need to be redesigned.  */
+  if (GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)
+      || GET_MODE_SIZE (ymode) % nregs_ymode
+      || nregs_xmode % nregs_ymode)
+    abort ();
+#endif
+
+  /* The XMODE value can be seen as a vector of NREGS_XMODE
+     values.  The subreg must represent an lowpart of given field.
+     Compute what field it is.  */
+  offset -= subreg_lowpart_offset (ymode, 
+                                  mode_for_size (GET_MODE_BITSIZE (xmode)
+                                                 / nregs_xmode,
+                                                 MODE_INT, 0));
+
+  /* size of ymode must not be greater than the size of xmode.  */
+  mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
+  if (mode_multiple == 0)
+    abort ();
+
+  y_offset = offset / GET_MODE_SIZE (ymode);
+  nregs_multiple =  nregs_xmode / nregs_ymode;
+#ifdef ENABLE_CHECKING
+  if (offset % GET_MODE_SIZE (ymode)
+      || mode_multiple % nregs_multiple)
+    abort ();
+#endif
+  return (!(y_offset % (mode_multiple / nregs_multiple)));
+}
+
 /* Return the final regno that a subreg expression refers to.  */
 unsigned int
 subreg_regno (x)
@@ -3420,7 +3624,7 @@ hoist_test_store (x, val, live)
   /* Pseudo registers can be allways replaced by another pseudo to avoid
      the side effect, for hard register we must ensure that they are dead.
      Eventually we may want to add code to try turn pseudos to hards, but it
-     is unlikely usefull.  */
+     is unlikely useful.  */
 
   if (REGNO (x) < FIRST_PSEUDO_REGISTER)
     {
@@ -3632,7 +3836,7 @@ hoist_insn_to_edge (insn, e, val, new)
   if (e->insns == NULL_RTX)
     {
       start_sequence ();
-      emit_note (NULL, NOTE_INSN_DELETED);
+      emit_note (NOTE_INSN_DELETED);
     }
   else
     push_to_sequence (e->insns);