OSDN Git Service

2001-11-11 H.J. Lu <hjl@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 45fd406..9242e79 100644 (file)
@@ -55,6 +55,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "basic-block.h"
 #include "ggc.h"
 #include "debug.h"
+#include "langhooks.h"
 
 /* Commonly used modes.  */
 
@@ -192,7 +193,8 @@ static int mem_attrs_htab_eq            PARAMS ((const void *,
                                                 const void *));
 static void mem_attrs_mark             PARAMS ((const void *));
 static mem_attrs *get_mem_attrs                PARAMS ((HOST_WIDE_INT, tree, rtx,
-                                                rtx, unsigned int));
+                                                rtx, unsigned int,
+                                                enum machine_mode));
 
 /* Probability of the conditional branch currently proceeded by try_split.
    Set to -1 otherwise.  */
@@ -269,19 +271,29 @@ mem_attrs_mark (x)
 }
 
 /* Allocate a new mem_attrs structure and insert it into the hash table if
-   one identical to it is not already in the table.  */
+   one identical to it is not already in the table.  We are doing this for
+   MEM of mode MODE.  */
 
 static mem_attrs *
-get_mem_attrs (alias, decl, offset, size, align)
+get_mem_attrs (alias, decl, offset, size, align, mode)
      HOST_WIDE_INT alias;
      tree decl;
      rtx offset;
      rtx size;
      unsigned int align;
+     enum machine_mode mode;
 {
   mem_attrs attrs;
   void **slot;
 
+  /* If everything is the default, we can just return zero.  */
+  if (alias == 0 && decl == 0 && offset == 0
+      && (size == 0
+         || (mode != BLKmode && GET_MODE_SIZE (mode) == INTVAL (size)))
+      && (align == 1
+         || (mode != BLKmode && align == GET_MODE_ALIGNMENT (mode))))
+    return 0;
+
   attrs.alias = alias;
   attrs.decl = decl;
   attrs.offset = offset;
@@ -344,21 +356,19 @@ gen_rtx_CONST_INT (mode, arg)
    only at run-time.  */
 
 rtx
-gen_rtx_CONST_DOUBLE (mode, arg0, arg1, arg2)
+gen_rtx_CONST_DOUBLE (mode, arg0, arg1)
      enum machine_mode mode;
-     rtx arg0;
-     HOST_WIDE_INT arg1, arg2;
+     HOST_WIDE_INT arg0, arg1;
 {
   rtx r = rtx_alloc (CONST_DOUBLE);
   int i;
 
   PUT_MODE (r, mode);
-  XEXP (r, 0) = arg0;
-  X0EXP (r, 1) = NULL_RTX;
+  X0EXP (r, 0) = NULL_RTX;
+  XWINT (r, 1) = arg0;
   XWINT (r, 2) = arg1;
-  XWINT (r, 3) = arg2;
 
-  for (i = GET_RTX_LENGTH (CONST_DOUBLE) - 1; i > 3; --i)
+  for (i = GET_RTX_LENGTH (CONST_DOUBLE) - 1; i > 2; --i)
     XWINT (r, i) = 0;
 
   return r;
@@ -505,10 +515,10 @@ gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
 
     case CONST_DOUBLE:
       {
-       rtx arg0 = va_arg (p, rtx);
+       HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
        HOST_WIDE_INT arg1 = va_arg (p, HOST_WIDE_INT);
-       HOST_WIDE_INT arg2 = va_arg (p, HOST_WIDE_INT);
-        rt_val = gen_rtx_CONST_DOUBLE (mode, arg0, arg1, arg2);
+
+        rt_val = gen_rtx_CONST_DOUBLE (mode, arg0, arg1);
       }
       break;
 
@@ -1651,6 +1661,11 @@ set_mem_attributes (ref, t, objectp)
      tree t;
      int objectp;
 {
+  HOST_WIDE_INT alias = MEM_ALIAS_SET (ref);
+  tree decl = MEM_DECL (ref);
+  rtx offset = MEM_OFFSET (ref);
+  rtx size = MEM_SIZE (ref);
+  unsigned int align = MEM_ALIGN (ref);
   tree type;
 
   /* It can happen that type_for_mode was given a mode for which there
@@ -1669,66 +1684,79 @@ set_mem_attributes (ref, t, objectp)
     abort ();
 
   /* Get the alias set from the expression or type (perhaps using a
-     front-end routine).  */
-  set_mem_alias_set (ref, get_alias_set (t));
+     front-end routine) and use it.  */
+  alias = get_alias_set (t);
 
   MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type);
   MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);
   RTX_UNCHANGING_P (ref)
-    |= (lang_hooks.honor_readonly
-       && (TYPE_READONLY (type) || TREE_READONLY (t)));
+    |= ((lang_hooks.honor_readonly
+        && (TYPE_READONLY (type) || TREE_READONLY (t)))
+       || (! TYPE_P (t) && TREE_CONSTANT (t)));
 
-  /* If we are making an object of this type, we know that it is a scalar if
-     the type is not an aggregate.  */
-  if (objectp && ! AGGREGATE_TYPE_P (type))
+  /* If we are making an object of this type, or if this is a DECL, we know
+     that it is a scalar if the type is not an aggregate.  */
+  if ((objectp || DECL_P (t)) && ! AGGREGATE_TYPE_P (type))
     MEM_SCALAR_P (ref) = 1;
 
   /* If the size is known, we can set that.  */
   if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
-    MEM_ATTRS (ref)
-      = get_mem_attrs (MEM_ALIAS_SET (ref), MEM_DECL (ref), MEM_OFFSET (ref),
-                      GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (type), 1)),
-                      MEM_ALIGN (ref));
-
-  /* If T is a type, there's nothing more we can do.  Otherwise, we may be able
-     to deduce some more information about the expression.  */
-  if (TYPE_P (t))
-    return;
+    size = GEN_INT (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.  */
+  if (! TYPE_P (t))
+    {
+      maybe_set_unchanging (ref, t);
+      if (TREE_THIS_VOLATILE (t))
+       MEM_VOLATILE_P (ref) = 1;
+
+      /* Now remove any NOPs: they don't change what the underlying object is.
+        Likewise for SAVE_EXPR.  */
+      while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
+            || TREE_CODE (t) == NON_LVALUE_EXPR || TREE_CODE (t) == SAVE_EXPR)
+       t = TREE_OPERAND (t, 0);
+
+      /* If this expression can't be addressed (e.g., it contains a reference
+        to a non-addressable field), show we don't change its alias set.  */
+      if (! can_address_p (t))
+       MEM_KEEP_ALIAS_SET_P (ref) = 1;
+
+      /* If this is a decl, set the attributes of the MEM from it.  */
+      if (DECL_P (t))
+       {
+         decl = t;
+         offset = GEN_INT (0);
+         size = (DECL_SIZE_UNIT (t)
+                 && host_integerp (DECL_SIZE_UNIT (t), 1)
+                 ? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0);
+         align =  DECL_ALIGN (t);
+       }
 
-  maybe_set_unchanging (ref, t);
-  if (TREE_THIS_VOLATILE (t))
-    MEM_VOLATILE_P (ref) = 1;
-
-  /* Now remove any NOPs: they don't change what the underlying object is.
-     Likewise for SAVE_EXPR.  */
-  while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
-        || TREE_CODE (t) == NON_LVALUE_EXPR || TREE_CODE (t) == SAVE_EXPR)
-    t = TREE_OPERAND (t, 0);
-
-  /* If this is a decl, set the attributes of the MEM from it.  */
-  if (DECL_P (t))
-    MEM_ATTRS (ref)
-      = get_mem_attrs
-       (MEM_ALIAS_SET (ref), t, GEN_INT (0),
-        (TYPE_SIZE_UNIT (TREE_TYPE (t))
-         && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (t)), 1))
-        ? GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (t)), 1))
-        : 0, DECL_ALIGN (t) / BITS_PER_UNIT);
-
-  /* If this is an INDIRECT_REF, we know its alignment.  */
-  if (TREE_CODE (t) == INDIRECT_REF)
-    set_mem_align (ref, TYPE_ALIGN (type) / BITS_PER_UNIT);
-
-  /* Now see if we can say more about whether it's an aggregate or
-     scalar.  If we already know it's an aggregate, don't bother.  */
-  if (MEM_IN_STRUCT_P (ref))
+      /* If this is an INDIRECT_REF, we know its alignment.  */
+      else if (TREE_CODE (t) == INDIRECT_REF)
+       align = TYPE_ALIGN (type);
+
+      /* Likewise for constants.  */
+      else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
+       {
+         align = TYPE_ALIGN (type);
+#ifdef CONSTANT_ALIGNMENT
+         align = CONSTANT_ALIGNMENT (t, align);
+#endif
+       }
+    }
+
+  /* Now set the attributes we computed above.  */
+  MEM_ATTRS (ref)
+    = get_mem_attrs (alias, decl, offset, size, align, GET_MODE (ref));
+
+  /* If this is already known to be a scalar or aggregate, we are done.  */
+  if (MEM_IN_STRUCT_P (ref) || MEM_SCALAR_P (ref))
     return;
 
-  /* Since we already know the type isn't an aggregate, if this is a decl,
-     it must be a scalar.  Or if it is a reference into an aggregate,
-     this is part of an aggregate.   Otherwise we don't know.  */
-  if (DECL_P (t))
-    MEM_SCALAR_P (ref) = 1;
+  /* If it is a reference into an aggregate, this is part of an aggregate.
+     Otherwise we don't know.  */
   else if (TREE_CODE (t) == COMPONENT_REF || TREE_CODE (t) == ARRAY_REF
           || TREE_CODE (t) == ARRAY_RANGE_REF
           || TREE_CODE (t) == BIT_FIELD_REF)
@@ -1749,10 +1777,11 @@ set_mem_alias_set (mem, set)
 #endif
 
   MEM_ATTRS (mem) = get_mem_attrs (set, MEM_DECL (mem), MEM_OFFSET (mem),
-                                  MEM_SIZE (mem), MEM_ALIGN (mem));
+                                  MEM_SIZE (mem), MEM_ALIGN (mem),
+                                  GET_MODE (mem));
 }
 
-/* Set the alignment of MEM to ALIGN.  */
+/* Set the alignment of MEM to ALIGN bits.  */
 
 void
 set_mem_align (mem, align)
@@ -1760,7 +1789,20 @@ set_mem_align (mem, align)
      unsigned int align;
 {
   MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_DECL (mem),
-                                  MEM_OFFSET (mem), MEM_SIZE (mem), align);
+                                  MEM_OFFSET (mem), MEM_SIZE (mem), align,
+                                  GET_MODE (mem));
+}
+
+/* Set the decl for MEM to DECL.  */
+
+void
+set_mem_decl (mem, decl)
+     rtx mem;
+     tree decl;
+{
+  MEM_ATTRS (mem)
+    = get_mem_attrs (MEM_ALIAS_SET (mem), decl, MEM_OFFSET (mem),
+                    MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem));
 }
 \f
 /* Return a memory reference like MEMREF, but with its mode changed to MODE
@@ -1820,7 +1862,8 @@ change_address (memref, mode, addr)
     = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0,
                     mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode)),
                     (mmode == BLKmode ? 1
-                     : GET_MODE_ALIGNMENT (mmode) / BITS_PER_UNIT));
+                     : GET_MODE_ALIGNMENT (mmode) / BITS_PER_UNIT),
+                    mmode);
 
   return new;
 }
@@ -1839,6 +1882,7 @@ adjust_address_1 (memref, mode, offset, validate)
   rtx addr = XEXP (memref, 0);
   rtx new;
   rtx memoffset = MEM_OFFSET (memref);
+  rtx size = 0;
   unsigned int memalign = MEM_ALIGN (memref);
 
   /* If MEMREF is a LO_SUM and the offset is within the alignment of the
@@ -1866,22 +1910,25 @@ adjust_address_1 (memref, mode, offset, validate)
      lowest-order set bit in OFFSET, but don't change the alignment if OFFSET
      if zero.  */
   if (offset != 0)
-    memalign = MIN (memalign, offset & -offset);
+    memalign = MIN (memalign, (offset & -offset) * BITS_PER_UNIT);
 
-  MEM_ATTRS (new)
-    = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_DECL (memref), memoffset,
-                    mode == BLKmode
-                    ? 0 : GEN_INT (GET_MODE_SIZE (mode)), memalign);
+  /* We can compute the size in a number of ways.  */
+  if (mode != BLKmode)
+    size = GEN_INT (GET_MODE_SIZE (mode));
+  else if (MEM_SIZE (memref))
+    size = plus_constant (MEM_SIZE (memref), -offset);
+
+  MEM_ATTRS (new) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_DECL (memref),
+                                  memoffset, size, memalign, GET_MODE (new));
 
   /* At some point, we should validate that this offset is within the object,
      if all the appropriate values are known.  */
   return new;
 }
 
-/* Return a memory reference like MEMREF, but with its address changed to
-   ADDR.  The caller is asserting that the actual piece of memory pointed
-   to is the same, just the form of the address is being changed, such as
-   by putting something into a register.  */
+/* Return a memory reference like MEMREF, but whose address is changed by
+   adding OFFSET, an RTX, to it.  POW2 is the highest power of two factor
+   known to be in OFFSET (possibly 1).  */
 
 rtx
 offset_address (memref, offset, pow2)
@@ -1896,7 +1943,9 @@ offset_address (memref, offset, pow2)
   /* Update the alignment to reflect the offset.  Reset the offset, which
      we don't know.  */
   MEM_ATTRS (new) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_DECL (memref),
-                                  0, 0, MIN (MEM_ALIGN (memref), pow2));
+                                  0, 0, MIN (MEM_ALIGN (memref),
+                                             pow2 * BITS_PER_UNIT),
+                                  GET_MODE (new));
   return new;
 }
   
@@ -3932,7 +3981,7 @@ force_next_line_note ()
 /* Place a note of KIND on insn INSN with DATUM as the datum. If a
    note of this type already exists, remove it first.  */
 
-void
+rtx
 set_unique_reg_note (insn, kind, datum)
      rtx insn;
      enum reg_note kind;
@@ -3940,11 +3989,20 @@ set_unique_reg_note (insn, kind, datum)
 {
   rtx note = find_reg_note (insn, kind, NULL_RTX);
 
-  /* First remove the note if there already is one.  */
+  /* Don't add ASM_OPERAND REG_EQUAL/REG_EQUIV notes.
+     It serves no useful purpose and breaks eliminate_regs.  */
+  if ((kind == REG_EQUAL || kind == REG_EQUIV)
+      && GET_CODE (datum) == ASM_OPERANDS)
+    return NULL_RTX;
+
   if (note)
-    remove_note (insn, note);
+    {
+      XEXP (note, 0) = datum;
+      return note;
+    }
 
   REG_NOTES (insn) = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
+  return REG_NOTES (insn);
 }
 \f
 /* Return an indication of which type of insn should have X as a body.
@@ -4633,7 +4691,6 @@ init_emit_once (line_numbers)
            CONST_DOUBLE_HIGH (tem) = 0;
 
          memcpy (&CONST_DOUBLE_LOW (tem), &u, sizeof u);
-         CONST_DOUBLE_MEM (tem) = cc0_rtx;
          CONST_DOUBLE_CHAIN (tem) = NULL_RTX;
          PUT_MODE (tem, mode);