OSDN Git Service

2011-09-02 Vincent Celier <celier@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 8c843a7..c94e743 100644 (file)
@@ -256,8 +256,8 @@ mem_attrs_htab_hash (const void *x)
 
   return (p->alias ^ (p->align * 1000)
          ^ (p->addrspace * 4000)
-         ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000)
-         ^ ((p->size ? INTVAL (p->size) : 0) * 2500000)
+         ^ ((p->offset_known_p ? p->offset : 0) * 50000)
+         ^ ((p->size_known_p ? p->size : 0) * 2500000)
          ^ (size_t) iterative_hash_expr (p->expr, 0));
 }
 
@@ -266,8 +266,12 @@ mem_attrs_htab_hash (const void *x)
 static bool
 mem_attrs_eq_p (const struct mem_attrs *p, const struct mem_attrs *q)
 {
-  return (p->alias == q->alias && p->offset == q->offset
-         && p->size == q->size && p->align == q->align
+  return (p->alias == q->alias
+         && p->offset_known_p == q->offset_known_p
+         && (!p->offset_known_p || p->offset == q->offset)
+         && p->size_known_p == q->size_known_p
+         && (!p->size_known_p || p->size == q->size)
+         && p->align == q->align
          && p->addrspace == q->addrspace
          && (p->expr == q->expr
              || (p->expr != NULL_TREE && q->expr != NULL_TREE
@@ -969,9 +973,9 @@ set_reg_attrs_from_value (rtx reg, rtx x)
   offset = byte_lowpart_offset (GET_MODE (reg), GET_MODE (x));
   if (MEM_P (x))
     {
-      if (MEM_OFFSET (x) && CONST_INT_P (MEM_OFFSET (x)))
-       REG_ATTRS (reg)
-         = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
+      if (MEM_OFFSET_KNOWN_P (x))
+       REG_ATTRS (reg) = get_reg_attrs (MEM_EXPR (x),
+                                        MEM_OFFSET (x) + offset);
       if (MEM_POINTER (x))
        mark_reg_pointer (reg, 0);
     }
@@ -1460,14 +1464,13 @@ get_mem_align_offset (rtx mem, unsigned int align)
   unsigned HOST_WIDE_INT offset;
 
   /* This function can't use
-     if (!MEM_EXPR (mem) || !MEM_OFFSET (mem)
-        || !CONST_INT_P (MEM_OFFSET (mem))
+     if (!MEM_EXPR (mem) || !MEM_OFFSET_KNOWN_P (mem)
         || (MAX (MEM_ALIGN (mem),
-                 get_object_alignment (MEM_EXPR (mem), align))
+                 MAX (align, get_object_alignment (MEM_EXPR (mem))))
             < align))
        return -1;
      else
-       return (- INTVAL (MEM_OFFSET (mem))) & (align / BITS_PER_UNIT - 1);
+       return (- MEM_OFFSET (mem)) & (align / BITS_PER_UNIT - 1);
      for two reasons:
      - COMPONENT_REFs in MEM_EXPR can have NULL first operand,
        for <variable>.  get_inner_reference doesn't handle it and
@@ -1477,12 +1480,10 @@ get_mem_align_offset (rtx mem, unsigned int align)
        isn't sufficiently aligned, the object it is in might be.  */
   gcc_assert (MEM_P (mem));
   expr = MEM_EXPR (mem);
-  if (expr == NULL_TREE
-      || MEM_OFFSET (mem) == NULL_RTX
-      || !CONST_INT_P (MEM_OFFSET (mem)))
+  if (expr == NULL_TREE || !MEM_OFFSET_KNOWN_P (mem))
     return -1;
 
-  offset = INTVAL (MEM_OFFSET (mem));
+  offset = MEM_OFFSET (mem);
   if (DECL_P (expr))
     {
       if (DECL_ALIGN (expr) < align)
@@ -1588,7 +1589,9 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
       /* ??? Can this ever happen?  Calling this routine on a MEM that
         already carries memory attributes should probably be invalid.  */
       attrs.expr = refattrs->expr;
+      attrs.offset_known_p = refattrs->offset_known_p;
       attrs.offset = refattrs->offset;
+      attrs.size_known_p = refattrs->size_known_p;
       attrs.size = refattrs->size;
       attrs.align = refattrs->align;
     }
@@ -1598,9 +1601,10 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
     {
       defattrs = mode_mem_attrs[(int) GET_MODE (ref)];
       gcc_assert (!defattrs->expr);
-      gcc_assert (!defattrs->offset);
+      gcc_assert (!defattrs->offset_known_p);
 
       /* Respect mode size.  */
+      attrs.size_known_p = defattrs->size_known_p;
       attrs.size = defattrs->size;
       /* ??? Is this really necessary?  We probably should always get
         the size from the type below.  */
@@ -1659,7 +1663,10 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
 
   /* If the size is known, we can set that.  */
   if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
-    attrs.size = GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (type), 1));
+    {
+      attrs.size_known_p = true;
+      attrs.size = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+    }
 
   /* If T is not a type, we may be able to deduce some more information about
      the expression.  */
@@ -1697,11 +1704,16 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
       if (DECL_P (t))
        {
          attrs.expr = t;
-         attrs.offset = const0_rtx;
+         attrs.offset_known_p = true;
+         attrs.offset = 0;
          apply_bitpos = bitpos;
-         attrs.size = (DECL_SIZE_UNIT (t)
-                       && host_integerp (DECL_SIZE_UNIT (t), 1)
-                       ? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0);
+         if (DECL_SIZE_UNIT (t) && host_integerp (DECL_SIZE_UNIT (t), 1))
+           {
+             attrs.size_known_p = true;
+             attrs.size = tree_low_cst (DECL_SIZE_UNIT (t), 1);
+           }
+         else
+           attrs.size_known_p = false;
          attrs.align = DECL_ALIGN (t);
          align_computed = true;
        }
@@ -1724,7 +1736,8 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
               && ! DECL_BIT_FIELD (TREE_OPERAND (t, 1)))
        {
          attrs.expr = t;
-         attrs.offset = const0_rtx;
+         attrs.offset_known_p = true;
+         attrs.offset = 0;
          apply_bitpos = bitpos;
          /* ??? Any reason the field size would be different than
             the size we got from the type?  */
@@ -1765,7 +1778,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
          if (DECL_P (t2))
            {
              attrs.expr = t2;
-             attrs.offset = NULL;
+             attrs.offset_known_p = false;
              if (host_integerp (off_tree, 1))
                {
                  HOST_WIDE_INT ioff = tree_low_cst (off_tree, 1);
@@ -1774,17 +1787,19 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
                  if (aoff && (unsigned HOST_WIDE_INT) aoff < attrs.align)
                    attrs.align = aoff;
                  align_computed = true;
-                 attrs.offset = GEN_INT (ioff);
+                 attrs.offset_known_p = true;
+                 attrs.offset = ioff;
                  apply_bitpos = bitpos;
                }
            }
          else if (TREE_CODE (t2) == COMPONENT_REF)
            {
              attrs.expr = t2;
-             attrs.offset = NULL;
+             attrs.offset_known_p = false;
              if (host_integerp (off_tree, 1))
                {
-                 attrs.offset = GEN_INT (tree_low_cst (off_tree, 1));
+                 attrs.offset_known_p = true;
+                 attrs.offset = tree_low_cst (off_tree, 1);
                  apply_bitpos = bitpos;
                }
              /* ??? Any reason the field size would be different than
@@ -1795,7 +1810,8 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
          else if (TREE_CODE (t) == MEM_REF)
            {
              attrs.expr = t;
-             attrs.offset = const0_rtx;
+             attrs.offset_known_p = true;
+             attrs.offset = 0;
              apply_bitpos = bitpos;
            }
        }
@@ -1805,13 +1821,14 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
               || TREE_CODE (t) == TARGET_MEM_REF)
        {
          attrs.expr = t;
-         attrs.offset = const0_rtx;
+         attrs.offset_known_p = true;
+         attrs.offset = 0;
          apply_bitpos = bitpos;
        }
 
-      if (!align_computed && !INDIRECT_REF_P (t))
+      if (!align_computed)
        {
-         unsigned int obj_align = get_object_alignment (t, BIGGEST_ALIGNMENT);
+         unsigned int obj_align = get_object_alignment (t);
          attrs.align = MAX (attrs.align, obj_align);
        }
     }
@@ -1821,13 +1838,14 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
      object to contain the negative offset.  */
   if (apply_bitpos)
     {
-      attrs.offset = plus_constant (attrs.offset,
-                                   -(apply_bitpos / BITS_PER_UNIT));
-      if (attrs.size)
-       attrs.size = plus_constant (attrs.size, apply_bitpos / BITS_PER_UNIT);
+      gcc_assert (attrs.offset_known_p);
+      attrs.offset -= apply_bitpos / BITS_PER_UNIT;
+      if (attrs.size_known_p)
+       attrs.size += apply_bitpos / BITS_PER_UNIT;
     }
 
   /* Now set the attributes we computed above.  */
+  attrs.addrspace = TYPE_ADDR_SPACE (type);
   set_mem_attrs (ref, &attrs);
 
   /* If this is already known to be a scalar or aggregate, we are done.  */
@@ -1901,26 +1919,52 @@ set_mem_expr (rtx mem, tree expr)
 /* Set the offset of MEM to OFFSET.  */
 
 void
-set_mem_offset (rtx mem, rtx offset)
+set_mem_offset (rtx mem, HOST_WIDE_INT offset)
 {
   struct mem_attrs attrs;
 
   attrs = *get_mem_attrs (mem);
+  attrs.offset_known_p = true;
   attrs.offset = offset;
   set_mem_attrs (mem, &attrs);
 }
 
+/* Clear the offset of MEM.  */
+
+void
+clear_mem_offset (rtx mem)
+{
+  struct mem_attrs attrs;
+
+  attrs = *get_mem_attrs (mem);
+  attrs.offset_known_p = false;
+  set_mem_attrs (mem, &attrs);
+}
+
 /* Set the size of MEM to SIZE.  */
 
 void
-set_mem_size (rtx mem, rtx size)
+set_mem_size (rtx mem, HOST_WIDE_INT size)
 {
   struct mem_attrs attrs;
 
   attrs = *get_mem_attrs (mem);
+  attrs.size_known_p = true;
   attrs.size = size;
   set_mem_attrs (mem, &attrs);
 }
+
+/* Clear the size of MEM.  */
+
+void
+clear_mem_size (rtx mem)
+{
+  struct mem_attrs attrs;
+
+  attrs = *get_mem_attrs (mem);
+  attrs.size_known_p = false;
+  set_mem_attrs (mem, &attrs);
+}
 \f
 /* Return a memory reference like MEMREF, but with its mode changed to MODE
    and its address changed to ADDR.  (VOIDmode means don't change the mode.
@@ -1972,8 +2016,9 @@ change_address (rtx memref, enum machine_mode mode, rtx addr)
 
   attrs = *get_mem_attrs (memref);
   defattrs = mode_mem_attrs[(int) mmode];
-  attrs.expr = defattrs->expr;
-  attrs.offset = defattrs->offset;
+  attrs.expr = NULL_TREE;
+  attrs.offset_known_p = false;
+  attrs.size_known_p = defattrs->size_known_p;
   attrs.size = defattrs->size;
   attrs.align = defattrs->align;
 
@@ -2055,8 +2100,8 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
 
   /* Compute the new values of the memory attributes due to this adjustment.
      We add the offsets and update the alignment.  */
-  if (attrs.offset)
-    attrs.offset = GEN_INT (offset + INTVAL (attrs.offset));
+  if (attrs.offset_known_p)
+    attrs.offset += offset;
 
   /* Compute the new alignment by taking the MIN of the alignment and the
      lowest-order set bit in OFFSET, but don't change the alignment if OFFSET
@@ -2069,10 +2114,13 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
 
   /* We can compute the size in a number of ways.  */
   defattrs = mode_mem_attrs[(int) GET_MODE (new_rtx)];
-  if (defattrs->size)
-    attrs.size = defattrs->size;
-  else if (attrs.size)
-    attrs.size = plus_constant (attrs.size, -offset);
+  if (defattrs->size_known_p)
+    {
+      attrs.size_known_p = true;
+      attrs.size = defattrs->size;
+    }
+  else if (attrs.size_known_p)
+    attrs.size -= offset;
 
   set_mem_attrs (new_rtx, &attrs);
 
@@ -2103,7 +2151,7 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2)
 {
   rtx new_rtx, addr = XEXP (memref, 0);
   enum machine_mode address_mode;
-  struct mem_attrs attrs;
+  struct mem_attrs attrs, *defattrs;
 
   attrs = *get_mem_attrs (memref);
   address_mode = targetm.addr_space.address_mode (attrs.addrspace);
@@ -2134,8 +2182,10 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2)
 
   /* Update the alignment to reflect the offset.  Reset the offset, which
      we don't know.  */
-  attrs.offset = 0;
-  attrs.size = mode_mem_attrs[(int) GET_MODE (new_rtx)]->size;
+  defattrs = mode_mem_attrs[(int) GET_MODE (new_rtx)];
+  attrs.offset_known_p = false;
+  attrs.size_known_p = defattrs->size_known_p;
+  attrs.size = defattrs->size;
   attrs.align = MIN (attrs.align, pow2 * BITS_PER_UNIT);
   set_mem_attrs (new_rtx, &attrs);
   return new_rtx;
@@ -2183,7 +2233,7 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
 
   /* If we don't know what offset we were at within the expression, then
      we can't know if we've overstepped the bounds.  */
-  if (! attrs.offset)
+  if (! attrs.offset_known_p)
     attrs.expr = NULL_TREE;
 
   while (attrs.expr)
@@ -2203,7 +2253,7 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
             otherwise strip back to the containing structure.  */
          if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST
              && compare_tree_int (DECL_SIZE_UNIT (field), size) >= 0
-             && INTVAL (attrs.offset) >= 0)
+             && attrs.offset >= 0)
            break;
 
          if (! host_integerp (offset, 1))
@@ -2213,18 +2263,16 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
            }
 
          attrs.expr = TREE_OPERAND (attrs.expr, 0);
-         attrs.offset
-           = (GEN_INT (INTVAL (attrs.offset)
-                       + tree_low_cst (offset, 1)
-                       + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
-                          / BITS_PER_UNIT)));
+         attrs.offset += tree_low_cst (offset, 1);
+         attrs.offset += (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+                          / BITS_PER_UNIT);
        }
       /* Similarly for the decl.  */
       else if (DECL_P (attrs.expr)
               && DECL_SIZE_UNIT (attrs.expr)
               && TREE_CODE (DECL_SIZE_UNIT (attrs.expr)) == INTEGER_CST
               && compare_tree_int (DECL_SIZE_UNIT (attrs.expr), size) >= 0
-              && (! attrs.offset || INTVAL (attrs.offset) >= 0))
+              && (! attrs.offset_known_p || attrs.offset >= 0))
        break;
       else
        {
@@ -2236,12 +2284,13 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
     }
 
   if (! attrs.expr)
-    attrs.offset = NULL_RTX;
+    attrs.offset_known_p = false;
 
   /* The widened memory may alias other stuff, so zap the alias set.  */
   /* ??? Maybe use get_alias_set on any remaining expression.  */
   attrs.alias = 0;
-  attrs.size = GEN_INT (size);
+  attrs.size_known_p = true;
+  attrs.size = size;
   set_mem_attrs (new_rtx, &attrs);
   return new_rtx;
 }
@@ -2298,10 +2347,11 @@ set_mem_attrs_for_spill (rtx mem)
        (mem:MODE (plus (reg sfp) (const_int offset)))
      with perhaps the plus missing for offset = 0.  */
   addr = XEXP (mem, 0);
-  attrs.offset = const0_rtx;
+  attrs.offset_known_p = true;
+  attrs.offset = 0;
   if (GET_CODE (addr) == PLUS
       && CONST_INT_P (XEXP (addr, 1)))
-    attrs.offset = XEXP (addr, 1);
+    attrs.offset = INTVAL (XEXP (addr, 1));
 
   set_mem_attrs (mem, &attrs);
   MEM_NOTRAP_P (mem) = 1;
@@ -2394,6 +2444,8 @@ unshare_all_rtl_again (rtx insn)
       {
        reset_used_flags (PATTERN (p));
        reset_used_flags (REG_NOTES (p));
+       if (CALL_P (p))
+         reset_used_flags (CALL_INSN_FUNCTION_USAGE (p));
       }
 
   /* Make sure that virtual stack slots are not shared.  */
@@ -2468,6 +2520,7 @@ verify_rtx_sharing (rtx orig, rtx insn)
     case PC:
     case CC0:
     case RETURN:
+    case SIMPLE_RETURN:
     case SCRATCH:
       return;
       /* SCRATCH must be shared because they represent distinct values.  */
@@ -2560,6 +2613,8 @@ verify_rtl_sharing (void)
       {
        reset_used_flags (PATTERN (p));
        reset_used_flags (REG_NOTES (p));
+       if (CALL_P (p))
+         reset_used_flags (CALL_INSN_FUNCTION_USAGE (p));
        if (GET_CODE (PATTERN (p)) == SEQUENCE)
          {
            int i;
@@ -2571,6 +2626,8 @@ verify_rtl_sharing (void)
                gcc_assert (INSN_P (q));
                reset_used_flags (PATTERN (q));
                reset_used_flags (REG_NOTES (q));
+               if (CALL_P (q))
+                 reset_used_flags (CALL_INSN_FUNCTION_USAGE (q));
              }
          }
       }
@@ -2580,6 +2637,8 @@ verify_rtl_sharing (void)
       {
        verify_rtx_sharing (PATTERN (p), p);
        verify_rtx_sharing (REG_NOTES (p), p);
+       if (CALL_P (p))
+         verify_rtx_sharing (CALL_INSN_FUNCTION_USAGE (p), p);
       }
 
   timevar_pop (TV_VERIFY_RTL_SHARING);
@@ -2596,6 +2655,9 @@ unshare_all_rtl_in_chain (rtx insn)
       {
        PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
        REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
+       if (CALL_P (insn))
+         CALL_INSN_FUNCTION_USAGE (insn)
+           = copy_rtx_if_shared (CALL_INSN_FUNCTION_USAGE (insn));
       }
 }
 
@@ -2674,6 +2736,8 @@ repeat:
     case CODE_LABEL:
     case PC:
     case CC0:
+    case RETURN:
+    case SIMPLE_RETURN:
     case SCRATCH:
       /* SCRATCH must be shared because they represent distinct values.  */
       return;
@@ -2793,6 +2857,8 @@ repeat:
     case CODE_LABEL:
     case PC:
     case CC0:
+    case RETURN:
+    case SIMPLE_RETURN:
       return;
 
     case DEBUG_INSN:
@@ -3272,14 +3338,17 @@ prev_label (rtx insn)
   return insn;
 }
 
-/* Return the last label to mark the same position as LABEL.  Return null
-   if LABEL itself is null.  */
+/* Return the last label to mark the same position as LABEL.  Return LABEL
+   itself if it is null or any return rtx.  */
 
 rtx
 skip_consecutive_labels (rtx label)
 {
   rtx insn;
 
+  if (label && ANY_RETURN_P (label))
+    return label;
+
   for (insn = label; insn != 0 && !INSN_P (insn); insn = NEXT_INSN (insn))
     if (LABEL_P (insn))
       label = insn;
@@ -3561,6 +3630,10 @@ try_split (rtx pat, rtx trial, int last)
          break;
 #endif
 
+       case REG_ARGS_SIZE:
+         fixup_args_size_notes (NULL_RTX, insn_last, INTVAL (XEXP (note, 0)));
+         break;
+
        default:
          break;
        }
@@ -4949,7 +5022,7 @@ classify_insn (rtx x)
     return CODE_LABEL;
   if (GET_CODE (x) == CALL)
     return CALL_INSN;
-  if (GET_CODE (x) == RETURN)
+  if (ANY_RETURN_P (x))
     return JUMP_INSN;
   if (GET_CODE (x) == SET)
     {
@@ -5204,6 +5277,8 @@ copy_insn_1 (rtx orig)
     case CODE_LABEL:
     case PC:
     case CC0:
+    case RETURN:
+    case SIMPLE_RETURN:
       return orig;
     case CLOBBER:
       if (REG_P (XEXP (orig, 0)) && REGNO (XEXP (orig, 0)) < FIRST_PSEUDO_REGISTER)
@@ -5461,6 +5536,7 @@ init_emit_regs (void)
   /* Assign register numbers to the globally defined register rtx.  */
   pc_rtx = gen_rtx_fmt_ (PC, VOIDmode);
   ret_rtx = gen_rtx_fmt_ (RETURN, VOIDmode);
+  simple_return_rtx = gen_rtx_fmt_ (SIMPLE_RETURN, VOIDmode);
   cc0_rtx = gen_rtx_fmt_ (CC0, VOIDmode);
   stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM);
   frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);
@@ -5501,7 +5577,8 @@ init_emit_regs (void)
       attrs->addrspace = ADDR_SPACE_GENERIC;
       if (mode != BLKmode)
        {
-         attrs->size = GEN_INT (GET_MODE_SIZE (mode));
+         attrs->size_known_p = true;
+         attrs->size = GET_MODE_SIZE (mode);
          if (STRICT_ALIGNMENT)
            attrs->align = GET_MODE_ALIGNMENT (mode);
        }