OSDN Git Service

* expr.c (move_block_from_reg): Try using an integral mov operation first.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index a135409..c422fbc 100644 (file)
@@ -52,6 +52,10 @@ Boston, MA 02111-1307, USA.  */
 
 #include <ctype.h>
 
+#ifndef TRAMPOLINE_ALIGNMENT
+#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
+#endif
+
 #ifndef ASM_STABS_OP
 #define ASM_STABS_OP ".stabs"
 #endif
@@ -143,6 +147,8 @@ static int compare_constant_rtx             PROTO((enum machine_mode, rtx,
 static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
                                                              rtx));
 static struct pool_constant *find_pool_constant PROTO((rtx));
+static void mark_constant_pool         PROTO((void));
+static void mark_constants             PROTO((rtx));
 static int output_addressed_constants  PROTO((tree));
 static void output_after_function_constants PROTO((void));
 static void bc_assemble_integer                PROTO((tree, int));
@@ -1823,7 +1829,7 @@ assemble_trampoline_template ()
 #endif
 
   /* Write the assembler code to define one.  */
-  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+  align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
   if (align > 0)
     ASM_OUTPUT_ALIGN (asm_out_file, align);
 
@@ -2344,75 +2350,95 @@ const_hash (exp)
   register int len, hi, i;
   register enum tree_code code = TREE_CODE (exp);
 
-  if (code == INTEGER_CST)
+  /* Either set P and LEN to the address and len of something to hash and
+     exit the switch or return a value.  */
+
+  switch (code)
     {
+    case INTEGER_CST:
       p = (char *) &TREE_INT_CST_LOW (exp);
       len = 2 * sizeof TREE_INT_CST_LOW (exp);
-    }
-  else if (code == REAL_CST)
-    {
+      break;
+
+    case REAL_CST:
       p = (char *) &TREE_REAL_CST (exp);
       len = sizeof TREE_REAL_CST (exp);
-    }
-  else if (code == STRING_CST)
-    p = TREE_STRING_POINTER (exp), len = TREE_STRING_LENGTH (exp);
-  else if (code == COMPLEX_CST)
-    return const_hash (TREE_REALPART (exp)) * 5
-      + const_hash (TREE_IMAGPART (exp));
-  else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-    {
-      len = int_size_in_bytes (TREE_TYPE (exp));
-      p = (char *) alloca (len);
-      get_set_constructor_bytes (exp, (unsigned char *) p, len);
-    }
-  else if (code == CONSTRUCTOR)
-    {
-      register tree link;
-
-      /* For record type, include the type in the hashing.
-        We do not do so for array types
-        because (1) the sizes of the elements are sufficient
-        and (2) distinct array types can have the same constructor.
-        Instead, we include the array size because the constructor could
-        be shorter.  */
-      if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
-       hi = ((HOST_WIDE_INT) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
-         % MAX_HASH_TABLE;
-      else
-       hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
-              & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
+      break;
 
-      for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
-       if (TREE_VALUE (link))
-         hi = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
+    case STRING_CST:
+      p = TREE_STRING_POINTER (exp);
+      len = TREE_STRING_LENGTH (exp);
+      break;
 
-      return hi;
-    }
-  else if (code == ADDR_EXPR)
-    {
-      struct addr_const value;
-      decode_addr_const (exp, &value);
-      if (GET_CODE (value.base) == SYMBOL_REF)
+    case COMPLEX_CST:
+      return (const_hash (TREE_REALPART (exp)) * 5
+             + const_hash (TREE_IMAGPART (exp)));
+
+    case CONSTRUCTOR:
+      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
        {
-         /* Don't hash the address of the SYMBOL_REF;
-            only use the offset and the symbol name.  */
-         hi = value.offset;
-         p = XSTR (value.base, 0);
-         for (i = 0; p[i] != 0; i++)
-           hi = ((hi * 613) + (unsigned) (p[i]));
+         len = int_size_in_bytes (TREE_TYPE (exp));
+         p = (char *) alloca (len);
+         get_set_constructor_bytes (exp, (unsigned char *) p, len);
+         break;
        }
-      else if (GET_CODE (value.base) == LABEL_REF)
-       hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+      else
+       {
+         register tree link;
 
-      hi &= (1 << HASHBITS) - 1;
-      hi %= MAX_HASH_TABLE;
+         /* For record type, include the type in the hashing.
+            We do not do so for array types
+            because (1) the sizes of the elements are sufficient
+            and (2) distinct array types can have the same constructor.
+            Instead, we include the array size because the constructor could
+            be shorter.  */
+         if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+           hi = ((HOST_WIDE_INT) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
+             % MAX_HASH_TABLE;
+         else
+           hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
+                 & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
+
+         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+           if (TREE_VALUE (link))
+             hi
+               = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
+
+         return hi;
+       }
+
+    case ADDR_EXPR:
+      {
+       struct addr_const value;
+
+       decode_addr_const (exp, &value);
+       if (GET_CODE (value.base) == SYMBOL_REF)
+         {
+           /* Don't hash the address of the SYMBOL_REF;
+              only use the offset and the symbol name.  */
+           hi = value.offset;
+           p = XSTR (value.base, 0);
+           for (i = 0; p[i] != 0; i++)
+             hi = ((hi * 613) + (unsigned) (p[i]));
+         }
+       else if (GET_CODE (value.base) == LABEL_REF)
+         hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+
+       hi &= (1 << HASHBITS) - 1;
+       hi %= MAX_HASH_TABLE;
+      }
       return hi;
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      return (const_hash (TREE_OPERAND (exp, 0)) * 9
+             + const_hash (TREE_OPERAND (exp, 1)));
+
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
+      return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
     }
-  else if (code == PLUS_EXPR || code == MINUS_EXPR)
-    return const_hash (TREE_OPERAND (exp, 0)) * 9
-      +  const_hash (TREE_OPERAND (exp, 1));
-  else if (code == NOP_EXPR || code == CONVERT_EXPR)
-    return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
 
   /* Compute hashing function */
   hi = len;
@@ -2456,122 +2482,146 @@ compare_constant_1 (exp, p)
   if (code != (enum tree_code) *p++)
     return 0;
 
-  if (code == INTEGER_CST)
+  /* Either set STRP, P and LEN to pointers and length to compare and exit the
+     switch, or return the result of the comparison.  */
+
+  switch (code)
     {
+    case INTEGER_CST:
       /* Integer constants are the same only if the same width of type.  */
       if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
        return 0;
+
       strp = (char *) &TREE_INT_CST_LOW (exp);
       len = 2 * sizeof TREE_INT_CST_LOW (exp);
-    }
-  else if (code == REAL_CST)
-    {
+      break;
+
+    case REAL_CST:
       /* Real constants are the same only if the same width of type.  */
       if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
        return 0;
+
       strp = (char *) &TREE_REAL_CST (exp);
       len = sizeof TREE_REAL_CST (exp);
-    }
-  else if (code == STRING_CST)
-    {
+      break;
+
+    case STRING_CST:
       if (flag_writable_strings)
        return 0;
+
       strp = TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
       if (bcmp ((char *) &TREE_STRING_LENGTH (exp), p,
                sizeof TREE_STRING_LENGTH (exp)))
        return 0;
+
       p += sizeof TREE_STRING_LENGTH (exp);
-    }
-  else if (code == COMPLEX_CST)
-    {
-      p = compare_constant_1 (TREE_REALPART (exp), p);
-      if (p == 0) return 0;
-      p = compare_constant_1 (TREE_IMAGPART (exp), p);
-      return p;
-    }
-  else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
-    {
-      int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
-      strp = (char *) alloca (len);
-      get_set_constructor_bytes (exp, (unsigned char *) strp, len);
-      if (bcmp ((char *) &xlen, p, sizeof xlen))
-       return 0;
-      p += sizeof xlen;
-    }
-  else if (code == CONSTRUCTOR)
-    {
-      register tree link;
-      int length = list_length (CONSTRUCTOR_ELTS (exp));
-      tree type;
+      break;
 
-      if (bcmp ((char *) &length, p, sizeof length))
+    case COMPLEX_CST:
+      p = compare_constant_1 (TREE_REALPART (exp), p);
+      if (p == 0)
        return 0;
-      p += sizeof length;
 
-      /* For record constructors, insist that the types match.
-        For arrays, just verify both constructors are for arrays.  */
-      if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
-       type = TREE_TYPE (exp);
-      else
-       type = 0;
-      if (bcmp ((char *) &type, p, sizeof type))
-       return 0;
-      p += sizeof type;
+      return compare_constant_1 (TREE_IMAGPART (exp), p);
 
-      /* For arrays, insist that the size in bytes match.  */
-      if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+    case CONSTRUCTOR:
+      if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
        {
-         int size = int_size_in_bytes (TREE_TYPE (exp));
-         if (bcmp ((char *) &size, p, sizeof size))
+         int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
+
+         strp = (char *) alloca (len);
+         get_set_constructor_bytes (exp, (unsigned char *) strp, len);
+         if (bcmp ((char *) &xlen, p, sizeof xlen))
            return 0;
-         p += sizeof size;
-       }
 
-      for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+         p += sizeof xlen;
+         break;
+       }
+      else
        {
-         if (TREE_VALUE (link))
+         register tree link;
+         int length = list_length (CONSTRUCTOR_ELTS (exp));
+         tree type;
+
+         if (bcmp ((char *) &length, p, sizeof length))
+           return 0;
+
+         p += sizeof length;
+
+         /* For record constructors, insist that the types match.
+            For arrays, just verify both constructors are for arrays.  */
+         if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+           type = TREE_TYPE (exp);
+         else
+           type = 0;
+
+         if (bcmp ((char *) &type, p, sizeof type))
+           return 0;
+
+         p += sizeof type;
+
+         /* For arrays, insist that the size in bytes match.  */
+         if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
            {
-             if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
+             int size = int_size_in_bytes (TREE_TYPE (exp));
+             if (bcmp ((char *) &size, p, sizeof size))
                return 0;
+
+             p += sizeof size;
            }
-         else
+
+         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
            {
-             tree zero = 0;
+             if (TREE_VALUE (link))
+               {
+                 if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
+                   return 0;
+               }
+             else
+               {
+                 tree zero = 0;
 
-             if (bcmp ((char *) &zero, p, sizeof zero))
-               return 0;
-             p += sizeof zero;
+                 if (bcmp ((char *) &zero, p, sizeof zero))
+                   return 0;
+
+                 p += sizeof zero;
+               }
            }
+
+         return p;
        }
 
-      return p;
-    }
-  else if (code == ADDR_EXPR)
-    {
-      struct addr_const value;
-      decode_addr_const (exp, &value);
-      strp = (char *) &value.offset;
-      len = sizeof value.offset;
-      /* Compare the offset.  */
-      while (--len >= 0)
-       if (*p++ != *strp++)
-         return 0;
-      /* Compare symbol name.  */
-      strp = XSTR (value.base, 0);
-      len = strlen (strp) + 1;
-    }
-  else if (code == PLUS_EXPR || code == MINUS_EXPR)
-    {
-      p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
-      if (p == 0) return 0;
-      p = compare_constant_1 (TREE_OPERAND (exp, 1), p);
-      return p;
-    }
-  else if (code == NOP_EXPR || code == CONVERT_EXPR)
-    {
+    case ADDR_EXPR:
+      {
+       struct addr_const value;
+
+       decode_addr_const (exp, &value);
+       strp = (char *) &value.offset;
+       len = sizeof value.offset;
+       /* Compare the offset.  */
+       while (--len >= 0)
+         if (*p++ != *strp++)
+           return 0;
+
+       /* Compare symbol name.  */
+       strp = XSTR (value.base, 0);
+       len = strlen (strp) + 1;
+      }
+      break;
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
       p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
-      return p;
+      if (p == 0)
+       return 0;
+
+      return compare_constant_1 (TREE_OPERAND (exp, 1), p);
+
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
+      return compare_constant_1 (TREE_OPERAND (exp, 0), p);
     }
 
   /* Compare constant contents.  */
@@ -2834,6 +2884,7 @@ copy_constant (exp)
 
     case NOP_EXPR:
     case CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
       return build1 (TREE_CODE (exp), TREE_TYPE (exp),
                     copy_constant (TREE_OPERAND (exp, 0)));
 
@@ -3071,6 +3122,7 @@ struct pool_constant
   int labelno;
   int align;
   int offset;
+  int mark;
 };
 
 /* Pointers to first and last constant in pool.  */
@@ -3407,19 +3459,25 @@ force_const_mem (mode, x)
       pool_offset &= ~ (align - 1);
 
       /* If RTL is not being placed into the saveable obstack, make a
-        copy of X that is in the saveable obstack in case we are being
-        called from combine or some other phase that discards memory
-        it allocates.  We need only do this if it is a CONST, since
-        no other RTX should be allocated in this situation.  */
+        copy of X that is in the saveable obstack in case we are
+        being called from combine or some other phase that discards
+        memory it allocates.  We used to only do this if it is a
+        CONST; however, reload can allocate a CONST_INT when
+        eliminating registers.  */
       if (rtl_obstack != saveable_obstack
-         && GET_CODE (x) == CONST)
+         && (GET_CODE (x) == CONST || GET_CODE (x) == CONST_INT))
        {
          push_obstacks_nochange ();
          rtl_in_saveable_obstack ();
 
-         x = gen_rtx (CONST, GET_MODE (x), 
-                      gen_rtx (PLUS, GET_MODE (x), 
-                               XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1)));
+         if (GET_CODE (x) == CONST)
+           x = gen_rtx (CONST, GET_MODE (x), 
+                        gen_rtx (PLUS, GET_MODE (x), 
+                                 XEXP (XEXP (x, 0), 0),
+                                 XEXP (XEXP (x, 0), 1)));
+         else
+           x = GEN_INT (INTVAL (x));
+
          pop_obstacks ();
        }
 
@@ -3432,6 +3490,7 @@ force_const_mem (mode, x)
       pool->labelno = const_labelno;
       pool->align = align;
       pool->offset = pool_offset;
+      pool->mark = 1;
       pool->next = 0;
 
       if (last_pool == 0)
@@ -3545,6 +3604,12 @@ output_constant_pool (fnname, fndecl)
   rtx x;
   union real_extract u;
 
+  /* It is possible for gcc to call force_const_mem and then to later
+     discard the instructions which refer to the constant.  In such a
+     case we do not need to output the constant.  */
+  if (optimize >= 0 && flag_expensive_optimizations)
+    mark_constant_pool ();
+
 #ifdef ASM_OUTPUT_POOL_PROLOGUE
   ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
 #endif
@@ -3553,6 +3618,9 @@ output_constant_pool (fnname, fndecl)
     {
       x = pool->constant;
 
+      if (! pool->mark)
+       continue;
+
       /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
         whose CODE_LABEL has been deleted.  This can occur if a jump table
         is eliminated by optimization.  If so, write a constant of zero
@@ -3615,6 +3683,93 @@ output_constant_pool (fnname, fndecl)
   /* Done with this pool.  */
   first_pool = last_pool = 0;
 }
+
+/* Look through the instructions for this function, and mark all the
+   entries in the constant pool which are actually being used.  */
+
+static void
+mark_constant_pool ()
+{
+  register rtx insn;
+  struct pool_constant *pool;
+
+  if (first_pool == 0)
+    return;
+
+  for (pool = first_pool; pool; pool = pool->next)
+    pool->mark = 0;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      mark_constants (PATTERN (insn));
+
+  for (insn = current_function_epilogue_delay_list;
+       insn;
+       insn = XEXP (insn, 1))
+    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      mark_constants (PATTERN (insn));
+}
+
+static void
+mark_constants (x)
+     register rtx x;
+{
+  register int i;
+  register char *format_ptr;
+
+  if (x == 0)
+    return;
+
+  if (GET_CODE (x) == SYMBOL_REF)
+    {
+      if (CONSTANT_POOL_ADDRESS_P (x))
+       find_pool_constant (x)->mark = 1;
+      return;
+    }
+
+  /* Insns may appear inside a SEQUENCE.  Only check the patterns of
+     insns, not any notes that may be attached.  We don't want to mark
+     a constant just because it happens to appear in a REG_EQUIV note.  */
+  if (GET_RTX_CLASS (GET_CODE (x)) == 'i')
+    {
+      mark_constants (PATTERN (x));
+      return;
+    }
+
+  format_ptr = GET_RTX_FORMAT (GET_CODE (x));
+
+  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
+    {
+      switch (*format_ptr++)
+       {
+       case 'e':
+         mark_constants (XEXP (x, i));
+         break;
+
+       case 'E':
+         if (XVEC (x, i) != 0)
+           {
+             register int j;
+
+             for (j = 0; j < XVECLEN (x, i); j++)
+               mark_constants (XVECEXP (x, i, j));
+           }
+         break;
+
+       case 'S':
+       case 's':
+       case '0':
+       case 'i':
+       case 'w':
+       case 'n':
+       case 'u':
+         break;
+
+       default:
+         abort ();
+       }
+    }
+}
 \f
 /* Find all the constants whose addresses are referenced inside of EXP,
    and make sure assembler code with a label has been output for each one.
@@ -3827,7 +3982,8 @@ bc_assemble_integer (exp, size)
   
   exp = fold (exp);
   
-  while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR)
+  while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
+        || TREE_CODE (exp) == NON_LVALUE_EXPR)
     exp = TREE_OPERAND (exp, 0);
   if (TREE_CODE (exp) == INTEGER_CST)
     {
@@ -3838,11 +3994,13 @@ bc_assemble_integer (exp, size)
     {
       const_part = TREE_OPERAND (exp, 0);
       while (TREE_CODE (const_part) == NOP_EXPR
-            || TREE_CODE (const_part) == CONVERT_EXPR)
+            || TREE_CODE (const_part) == CONVERT_EXPR
+            || TREE_CODE (const_part) == NON_LVALUE_EXPR)
        const_part = TREE_OPERAND (const_part, 0);
       addr_part = TREE_OPERAND (exp, 1);
       while (TREE_CODE (addr_part) == NOP_EXPR
-            || TREE_CODE (addr_part) == CONVERT_EXPR)
+            || TREE_CODE (addr_part) == CONVERT_EXPR
+            || TREE_CODE (addr_part) == NON_LVALUE_EXPR)
        addr_part = TREE_OPERAND (addr_part, 0);
       if (TREE_CODE (const_part) != INTEGER_CST)
        tmp = const_part, const_part = addr_part, addr_part = tmp;