OSDN Git Service

* expr.c (move_block_from_reg): Try using an integral mov operation first.
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index a2a17a9..c422fbc 100644 (file)
@@ -1,5 +1,5 @@
 /* Output variables, constants and external declarations, for GNU compiler.
-   Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -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,7 +147,10 @@ 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));
 static void output_constructor         PROTO((tree, int));
 \f
@@ -278,7 +285,7 @@ named_section (decl, name)
 /* Tell the assembler to switch to the bss section.  */
 
 void
-bss_section (decl, name)
+bss_section ()
 {
   if (in_section != in_bss)
     {
@@ -706,23 +713,13 @@ make_decl_rtl (decl, asmspec, top_level)
                globalize_reg (reg_number + --nregs);
            }
        }
-      /* Specifying a section attribute on an uninitialized variable does not
-        (and cannot) cause it to be put in the given section.  The linker
-        can only put initialized objects in specific sections, everything
-        else goes in bss for the linker to sort out later (otherwise the
-        linker would give a duplicate definition error for each compilation
-        unit that behaved thusly).  So warn the user.  */
+      /* Specifying a section attribute on a variable forces it into a
+         non-.bss section, and thus it cannot be common. */
       else if (TREE_CODE (decl) == VAR_DECL
               && DECL_SECTION_NAME (decl) != NULL_TREE
               && DECL_INITIAL (decl) == NULL_TREE
               && DECL_COMMON (decl))
-       {
-         warning_with_decl (decl,
-                            "section attribute ignored for uninitialized variable `%s'");
-         /* Remove the section name so subsequent declarations won't see it.
-            We are ignoring it, remember.  */
-         DECL_SECTION_NAME (decl) = NULL_TREE;
-       }
+          DECL_COMMON (decl) = 0;
 
       /* Now handle ordinary static variables and functions (in memory).
         Also handle vars declared register invalidly.  */
@@ -909,6 +906,16 @@ assemble_gc_entry (name)
 #endif
 }
 \f
+/* CONSTANT_POOL_BEFORE_FUNCTION may be defined as an expression with
+   a non-zero value if the constant pool should be output before the
+   start of the function, or a zero value if the pool should output
+   after the end of the function.  The default is to put it before the
+   start.  */
+
+#ifndef CONSTANT_POOL_BEFORE_FUNCTION
+#define CONSTANT_POOL_BEFORE_FUNCTION 1
+#endif
+
 /* Output assembler code for the constant pool of a function and associated
    with defining the name of the function.  DECL describes the function.
    NAME is the function's name.  For the constant pool, we use the current
@@ -925,7 +932,8 @@ assemble_start_function (decl, fnname)
 
   app_disable ();
 
-  output_constant_pool (fnname, decl);
+  if (CONSTANT_POOL_BEFORE_FUNCTION)
+    output_constant_pool (fnname, decl);
 
 #ifdef ASM_OUTPUT_SECTION_NAME
   /* If the function is to be put in its own section and it's not in a section
@@ -976,7 +984,8 @@ assemble_start_function (decl, fnname)
 
   if (TREE_PUBLIC (decl))
     {
-      if (!first_global_object_name)
+      if (!first_global_object_name && ! DECL_WEAK (decl)
+         && ! DECL_ONE_ONLY (decl))
        {
          char *p;
 
@@ -1021,6 +1030,11 @@ assemble_end_function (decl, fnname)
 #ifdef ASM_DECLARE_FUNCTION_SIZE
   ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
 #endif
+  if (! CONSTANT_POOL_BEFORE_FUNCTION)
+    output_constant_pool (fnname, decl);
+
+  /* Output any constants which should appear after the function.  */
+  output_after_function_constants ();
 }
 \f
 /* Assemble code to leave SIZE bytes of zeros.  */
@@ -1259,6 +1273,20 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
 
+  if (TREE_PUBLIC (decl) && DECL_NAME (decl)
+      && ! first_global_object_name
+      && ! (DECL_COMMON (decl) && (DECL_INITIAL (decl) == 0
+                                  || DECL_INITIAL (decl) == error_mark_node))
+      && ! DECL_WEAK (decl)
+      && ! DECL_ONE_ONLY (decl))
+    {
+      char *p;
+
+      STRIP_NAME_ENCODING (p, name);
+      first_global_object_name = permalloc (strlen (p) + 1);
+      strcpy (first_global_object_name, p);
+    }
+
   /* Handle uninitialized definitions.  */
 
   if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
@@ -1387,15 +1415,6 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   /* First make the assembler name(s) global if appropriate.  */
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     {
-      if (!first_global_object_name)
-       {
-         char *p;
-
-         STRIP_NAME_ENCODING (p, name);
-         first_global_object_name = permalloc (strlen (p) + 1);
-         strcpy (first_global_object_name, p);
-       }
-
 #ifdef ASM_WEAKEN_LABEL
       if (DECL_WEAK (decl))
        ASM_WEAKEN_LABEL (asm_out_file, name);
@@ -1713,15 +1732,13 @@ assemble_name (file, name)
      char *name;
 {
   char *real_name;
-  int save_warn_id_clash = warn_id_clash;
+  tree id;
 
   STRIP_NAME_ENCODING (real_name, name);
 
-  /* Don't warn about an identifier name length clash on this name, since
-     it can be a user symbol suffixed by a number.  */
-  warn_id_clash = 0;
-  TREE_SYMBOL_REFERENCED (get_identifier (real_name)) = 1;
-  warn_id_clash = save_warn_id_clash;
+  id = maybe_get_identifier (real_name);
+  if (id)
+    TREE_SYMBOL_REFERENCED (id) = 1;
 
   if (name[0] == '*')
     {
@@ -1812,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);
 
@@ -2333,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;
+
+    case STRING_CST:
+      p = TREE_STRING_POINTER (exp);
+      len = TREE_STRING_LENGTH (exp);
+      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 COMPLEX_CST:
+      return (const_hash (TREE_REALPART (exp)) * 5
+             + const_hash (TREE_IMAGPART (exp)));
 
-      return hi;
-    }
-  else if (code == ADDR_EXPR)
-    {
-      struct addr_const value;
-      decode_addr_const (exp, &value);
-      if (GET_CODE (value.base) == SYMBOL_REF)
+    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
+       {
+         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;
+
+         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;
        }
-      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;
+    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;
@@ -2445,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.  */
@@ -2730,6 +2791,10 @@ struct deferred_constant
 
 static struct deferred_constant *deferred_constants;
 
+/* Another list of constants which should be output after the
+   function.  */
+static struct deferred_constant *after_function_constants;
+
 /* Nonzero means defer output of addressed subconstants
    (i.e., those for which output_constant_def is called.)  */
 static int defer_addressed_constants_flag;
@@ -2765,6 +2830,23 @@ output_deferred_addressed_constants ()
   deferred_constants = 0;
 }
 
+/* Output any constants which should appear after a function.  */
+
+static void
+output_after_function_constants ()
+{
+  struct deferred_constant *p, *next;
+
+  for (p = after_function_constants; p; p = next)
+    {
+      output_constant_def_contents (p->exp, p->reloc, p->labelno);
+      next = p->next;
+      free (p);
+    }
+
+  after_function_constants = 0;
+}
+
 /* Make a copy of the whole tree structure for a constant.
    This handles the same types of nodes that compare_constant
    and record_constant handle.  */
@@ -2790,7 +2872,8 @@ copy_constant (exp)
       return copy_node (exp);
 
     case COMPLEX_CST:
-      return build_complex (copy_constant (TREE_REALPART (exp)),
+      return build_complex (TREE_TYPE (exp),
+                           copy_constant (TREE_REALPART (exp)),
                            copy_constant (TREE_IMAGPART (exp)));
 
     case PLUS_EXPR:
@@ -2801,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)));
 
@@ -2917,7 +3001,15 @@ output_constant_def (exp)
      output it (or defer its output for later).  */
   if (found == 0)
     {
-      if (defer_addressed_constants_flag)
+      int after_function = 0;
+
+#ifdef CONSTANT_AFTER_FUNCTION_P
+      if (current_function_decl != 0
+         && CONSTANT_AFTER_FUNCTION_P (exp))
+       after_function = 1;
+#endif
+
+      if (defer_addressed_constants_flag || after_function)
        {
          struct deferred_constant *p;
          p = (struct deferred_constant *) xmalloc (sizeof (struct deferred_constant));
@@ -2928,8 +3020,16 @@ output_constant_def (exp)
          pop_obstacks ();
          p->reloc = reloc;
          p->labelno = const_labelno++;
-         p->next = deferred_constants;
-         deferred_constants = p;
+         if (after_function)
+           {
+             p->next = after_function_constants;
+             after_function_constants = p;
+           }
+         else
+           {
+             p->next = deferred_constants;
+             deferred_constants = p;
+           }
        }
       else
        output_constant_def_contents (exp, reloc, const_labelno++);
@@ -3022,6 +3122,7 @@ struct pool_constant
   int labelno;
   int align;
   int offset;
+  int mark;
 };
 
 /* Pointers to first and last constant in pool.  */
@@ -3358,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 ();
        }
 
@@ -3383,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)
@@ -3496,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
@@ -3504,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
@@ -3559,9 +3676,100 @@ output_constant_pool (fnname, fndecl)
     done: ;
     }
 
+#ifdef ASM_OUTPUT_POOL_EPILOGUE
+  ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset);
+#endif
+
   /* 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.
@@ -3774,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)
     {
@@ -3785,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;
@@ -4210,12 +4421,12 @@ void
 assemble_alias (decl, target)
      tree decl, target;
 {
-#ifdef ASM_OUTPUT_DEF
   char *name;
 
   make_decl_rtl (decl, (char *) 0, 1);
   name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
 
+#ifdef ASM_OUTPUT_DEF
   /* Make name accessible from other files, if appropriate.  */
 
   if (TREE_PUBLIC (decl))
@@ -4234,6 +4445,64 @@ assemble_alias (decl, target)
   ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
   TREE_ASM_WRITTEN (decl) = 1;
 #else
-  warning ("alias definitions not supported in this configuration");
+#ifdef ASM_OUTPUT_WEAK_ALIAS
+  if (! DECL_WEAK (decl))
+    warning ("only weak aliases are supported in this configuration");
+
+  ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
+  TREE_ASM_WRITTEN (decl) = 1;
+#else
+  warning ("alias definitions not supported in this configuration; ignored");
+#endif
+#endif
+}
+
+/* This determines whether or not we support link-once semantics.  */
+#ifndef SUPPORTS_ONE_ONLY
+#ifdef MAKE_DECL_ONE_ONLY
+#define SUPPORTS_ONE_ONLY 1
+#else
+#define SUPPORTS_ONE_ONLY 0
+#endif
+#endif
+
+/* Returns 1 if the target configuration supports defining public symbols
+   so that one of them will be chosen at link time instead of generating a
+   multiply-defined symbol error, whether through the use of weak symbols or
+   a target-specific mechanism for having duplicates discarded.  */
+
+int
+supports_one_only ()
+{
+  if (SUPPORTS_ONE_ONLY)
+    return 1;
+  return SUPPORTS_WEAK;
+}
+
+/* Set up DECL as a public symbol that can be defined in multiple
+   translation units without generating a linker error.  */
+
+void
+make_decl_one_only (decl)
+     tree decl;
+{
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
+    abort ();
+
+  TREE_PUBLIC (decl) = 1;
+
+  if (TREE_CODE (decl) == VAR_DECL
+      && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
+    DECL_COMMON (decl) = 1;
+  else if (SUPPORTS_ONE_ONLY)
+    {
+#ifdef MAKE_DECL_ONE_ONLY
+      MAKE_DECL_ONE_ONLY (decl);
 #endif
+      DECL_ONE_ONLY (decl) = 1;
+    }
+  else if (SUPPORTS_WEAK)
+    DECL_WEAK (decl) = 1;
+  else
+    abort ();
 }