OSDN Git Service

(arm_gen_constant, case IOR,XOR): Don't invert a constant if loading
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 4a46ec1..a8c15df 100644 (file)
@@ -1,5 +1,5 @@
 /* Output variables, constants and external declarations, for GNU compiler.
-   Copyright (C) 1987, 88, 89, 92, 93, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file handles generation of all the assembler code
@@ -32,8 +33,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
+#include "except.h"
 #include "function.h"
 #include "expr.h"
+#include "output.h"
 #include "hard-reg-set.h"
 #include "regs.h"
 #include "defaults.h"
@@ -41,6 +44,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "bytecode.h"
 
 #include "obstack.h"
+#include "c-pragma.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"
@@ -95,36 +99,62 @@ int size_directive_output;
 
 tree last_assemble_variable_decl;
 
+
+#ifdef HANDLE_PRAGMA_WEAK
+/* Any weak symbol declarations waiting to be emitted.  */
+
+struct weak_syms
+{
+  struct weak_syms *next;
+  char *name;
+  char *value;
+};
+
+static struct weak_syms *weak_decls;
+#endif
+
 /* Nonzero if at least one function definition has been seen.  */
-static int function_defined;
 
-extern FILE *asm_out_file;
+static int function_defined;
 
-static char *compare_constant_1 ();
-static void record_constant_1 ();
-static void output_constant_def_contents ();
-static int contains_pointers_p ();
-static void bc_output_ascii ();
-
-void output_constant_pool ();
-void assemble_name ();
-int output_addressed_constants ();
-void output_constant ();
-void output_constructor ();
-void output_byte_asm ();
-void text_section ();
-void readonly_data_section ();
-void data_section ();
-void named_section ();
-static void bc_assemble_integer ();
+struct addr_const;
+struct constant_descriptor;
+struct rtx_const;
+struct pool_constant;
+
+static void bc_make_decl_rtl           PROTO((tree, char *, int));
+static char *strip_reg_name            PROTO((char *));
+static void bc_output_ascii            PROTO((FILE *, char *, int));
+static int contains_pointers_p         PROTO((tree));
+static void decode_addr_const          PROTO((tree, struct addr_const *));
+static int const_hash                  PROTO((tree));
+static int compare_constant            PROTO((tree,
+                                              struct constant_descriptor *));
+static char *compare_constant_1                PROTO((tree, char *));
+static struct constant_descriptor *record_constant PROTO((tree));
+static void record_constant_1          PROTO((tree));
+static tree copy_constant              PROTO((tree));
+static void output_constant_def_contents  PROTO((tree, int, int));
+static void decode_rtx_const           PROTO((enum machine_mode, rtx,
+                                              struct rtx_const *));
+static int const_hash_rtx              PROTO((enum machine_mode, rtx));
+static int compare_constant_rtx                PROTO((enum machine_mode, rtx,
+                                              struct constant_descriptor *));
+static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
+                                                             rtx));
+static struct pool_constant *find_pool_constant PROTO((rtx));
+static int output_addressed_constants  PROTO((tree));
+static void bc_assemble_integer                PROTO((tree, int));
+static void output_constructor         PROTO((tree, int));
 \f
+static enum in_section { no_section, in_text, in_data, in_named
+#ifdef BSS_SECTION_ASM_OP
+  , in_bss
+#endif
 #ifdef EXTRA_SECTIONS
-static enum in_section {no_section, in_text, in_data, in_named, EXTRA_SECTIONS} in_section
-  = no_section;
-#else
-static enum in_section {no_section, in_text, in_data, in_named} in_section
-  = no_section;
+  , EXTRA_SECTIONS
 #endif
+} in_section = no_section;
 
 /* Return a non-zero value if DECL has a section attribute.  */
 #define IN_NAMED_SECTION(DECL) \
@@ -195,7 +225,7 @@ readonly_data_section ()
 #endif
 }
 
-/* Determine if we're in the text section. */
+/* Determine if we're in the text section.  */
 
 int
 in_text_section ()
@@ -203,19 +233,37 @@ in_text_section ()
   return in_section == in_text;
 }
 
-/* Tell assembler to change to named section.  */
+/* Determine if we're in the data section.  */
+
+int
+in_data_section ()
+{
+  return in_section == in_data;
+}
+
+/* Tell assembler to change to section NAME for DECL.
+   If DECL is NULL, just switch to section NAME.
+   If NAME is NULL, get the name from DECL.  */
 
 void
-named_section (name)
+named_section (decl, name)
+     tree decl;
      char *name;
 {
+  if (decl != NULL_TREE
+      && TREE_CODE_CLASS (TREE_CODE (decl)) != 'd')
+    abort ();
+  if (name == NULL)
+    name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+
   if (in_section != in_named || strcmp (name, in_named_name))
     {
-      in_named_name = name;
+      in_named_name = obstack_alloc (&permanent_obstack, strlen (name) + 1);
+      strcpy (in_named_name, name);
       in_section = in_named;
     
 #ifdef ASM_OUTPUT_SECTION_NAME
-      ASM_OUTPUT_SECTION_NAME (asm_out_file, name);
+      ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name);
 #else
       /* Section attributes are not supported if this macro isn't provided -
         some host formats don't support them at all.  The front-end should
@@ -224,6 +272,169 @@ named_section (name)
 #endif
     }
 }
+
+#ifdef BSS_SECTION_ASM_OP
+
+/* Tell the assembler to switch to the bss section.  */
+
+void
+bss_section ()
+{
+  if (in_section != in_bss)
+    {
+      if (output_bytecode)
+       bc_data ();
+      else
+       {
+#ifdef SHARED_BSS_SECTION_ASM_OP
+         if (flag_shared_data)
+           fprintf (asm_out_file, "%s\n", SHARED_BSS_SECTION_ASM_OP);
+         else
+#endif
+           fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
+       }
+
+      in_section = in_bss;
+    }
+}
+
+#ifdef ASM_OUTPUT_BSS
+
+/* Utility function for ASM_OUTPUT_BSS for targets to use if
+   they don't support alignments in .bss.
+   ??? It is believed that this function will work in most cases so such
+   support is localized here.  */
+
+static void
+asm_output_bss (file, decl, name, size, rounded)
+     FILE *file;
+     tree decl;
+     char *name;
+     int size, rounded;
+{
+  ASM_GLOBALIZE_LABEL (file, name);
+  bss_section ();
+#ifdef ASM_DECLARE_OBJECT_NAME
+  last_assemble_variable_decl = decl;
+  ASM_DECLARE_OBJECT_NAME (file, name, decl);
+#else
+  /* Standard thing is just output label for the object.  */
+  ASM_OUTPUT_LABEL (file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+  ASM_OUTPUT_SKIP (file, rounded);
+}
+
+#endif
+
+#ifdef ASM_OUTPUT_ALIGNED_BSS
+
+/* Utility function for targets to use in implementing
+   ASM_OUTPUT_ALIGNED_BSS.
+   ??? It is believed that this function will work in most cases so such
+   support is localized here.  */
+
+static void
+asm_output_aligned_bss (file, decl, name, size, align)
+     FILE *file;
+     tree decl;
+     char *name;
+     int size, align;
+{
+  ASM_GLOBALIZE_LABEL (file, name);
+  bss_section ();
+  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+#ifdef ASM_DECLARE_OBJECT_NAME
+  last_assemble_variable_decl = decl;
+  ASM_DECLARE_OBJECT_NAME (file, name, decl);
+#else
+  /* Standard thing is just output label for the object.  */
+  ASM_OUTPUT_LABEL (file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+  ASM_OUTPUT_SKIP (file, size ? size : 1);
+}
+
+#endif
+
+#endif /* BSS_SECTION_ASM_OP */
+
+/* Switch to the section for function DECL.
+
+   If DECL is NULL_TREE, switch to the text section.
+   ??? It's not clear that we will ever be passed NULL_TREE, but it's
+   safer to handle it.  */
+
+void
+function_section (decl)
+     tree decl;
+{
+  if (decl != NULL_TREE
+      && DECL_SECTION_NAME (decl) != NULL_TREE)
+    named_section (decl, (char *) 0);
+  else
+    text_section ();
+}
+
+/* Switch to section for variable DECL.
+
+   RELOC is the `reloc' argument to SELECT_SECTION.  */
+
+void
+variable_section (decl, reloc)
+     tree decl;
+     int reloc;
+{
+  if (IN_NAMED_SECTION (decl))
+    named_section (decl, NULL);
+  else
+    {
+      /* C++ can have const variables that get initialized from constructors,
+        and thus can not be in a readonly section.  We prevent this by
+        verifying that the initial value is constant for objects put in a
+        readonly section.
+
+        error_mark_node is used by the C front end to indicate that the
+        initializer has not been seen yet.  In this case, we assume that
+        the initializer must be constant.
+
+        C++ uses error_mark_node for variables that have complicated
+        initializers, but these variables go in BSS so we won't be called
+        for them.  */
+
+#ifdef SELECT_SECTION
+      SELECT_SECTION (decl, reloc);
+#else
+      if (TREE_READONLY (decl)
+         && ! TREE_THIS_VOLATILE (decl)
+         && DECL_INITIAL (decl)
+         && (DECL_INITIAL (decl) == error_mark_node
+             || TREE_CONSTANT (DECL_INITIAL (decl)))
+         && ! (flag_pic && reloc))
+       readonly_data_section ();
+      else
+       data_section ();
+#endif
+    }
+}
+
+/* Tell assembler to switch to the section for the exception handling
+   table.  */
+
+void
+exception_section ()
+{
+#ifdef ASM_OUTPUT_SECTION_NAME
+  named_section (NULL_TREE, ".gcc_except_table");
+#else
+  if (flag_pic)
+    data_section ();
+  else
+#if defined (EXCEPTION_SECTION)
+    EXCEPTION_SECTION ();
+#else
+    readonly_data_section ();
+#endif
+#endif
+}
 \f
 /* Create the rtl to represent a function, for a function definition.
    DECL is a FUNCTION_DECL node which describes which function.
@@ -282,7 +493,8 @@ make_function_rtl (decl)
    as the assembler symbol name.
    TOP_LEVEL is nonzero if this is a file-scope variable.
    This is never called for PARM_DECLs.  */
-void
+
+static void
 bc_make_decl_rtl (decl, asmspec, top_level)
      tree decl;
      char *asmspec;
@@ -293,9 +505,7 @@ bc_make_decl_rtl (decl, asmspec, top_level)
   if (DECL_RTL (decl) == 0)
     {
       /* Print an error message for register variables.  */
-      if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL)
-       error ("function declared `register'");
-      else if (DECL_REGISTER (decl))
+      if (DECL_REGISTER (decl))
        error ("global register variables not supported in the interpreter");
 
       /* Handle ordinary static variables and functions.  */
@@ -437,30 +647,34 @@ make_decl_rtl (decl, asmspec, top_level)
       DECL_RTL (decl) = 0;
 
       /* First detect errors in declaring global registers.  */
-      if (DECL_REGISTER (decl) && reg_number == -1)
+      if (TREE_CODE (decl) != FUNCTION_DECL
+         && DECL_REGISTER (decl) && reg_number == -1)
        error_with_decl (decl,
                         "register name not specified for `%s'");
-      else if (DECL_REGISTER (decl) && reg_number < 0)
+      else if (TREE_CODE (decl) != FUNCTION_DECL
+              && DECL_REGISTER (decl) && reg_number < 0)
        error_with_decl (decl,
                         "invalid register name for `%s'");
-      else if ((reg_number >= 0 || reg_number == -3) && ! DECL_REGISTER (decl))
+      else if ((reg_number >= 0 || reg_number == -3)
+              && (TREE_CODE (decl) == FUNCTION_DECL
+                  && ! DECL_REGISTER (decl)))
        error_with_decl (decl,
                         "register name given for non-register variable `%s'");
-      else if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL)
-       error ("function declared `register'");
-      else if (DECL_REGISTER (decl) && TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
-       error_with_decl (decl, "data type of `%s' isn't suitable for a register");
-      else if (DECL_REGISTER (decl)
-              && ! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
-       error_with_decl (decl, "register number for `%s' isn't suitable for the data type");
+      else if (TREE_CODE (decl) != FUNCTION_DECL
+              && DECL_REGISTER (decl)
+              && TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
+       error_with_decl (decl,
+                        "data type of `%s' isn't suitable for a register");
+      else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)
+              && ! HARD_REGNO_MODE_OK (reg_number,
+                                       TYPE_MODE (TREE_TYPE (decl))))
+       error_with_decl (decl,
+                        "register number for `%s' isn't suitable for data type");
       /* Now handle properly declared static register variables.  */
-      else if (DECL_REGISTER (decl))
+      else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
        {
          int nregs;
-#if 0 /* yylex should print the warning for this */
-         if (pedantic)
-           pedwarn ("ANSI C forbids global register variables");
-#endif
+
          if (DECL_INITIAL (decl) != 0 && top_level)
            {
              DECL_INITIAL (decl) = 0;
@@ -492,22 +706,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)
-       {
-         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_INITIAL (decl) == NULL_TREE
+              && DECL_COMMON (decl))
+          DECL_COMMON (decl) = 0;
 
       /* Now handle ordinary static variables and functions (in memory).
         Also handle vars declared register invalidly.  */
@@ -712,10 +917,24 @@ assemble_start_function (decl, fnname)
 
   output_constant_pool (fnname, decl);
 
-  if (IN_NAMED_SECTION (decl))
-    named_section (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)));
-  else
-    text_section ();
+#ifdef ASM_OUTPUT_SECTION_NAME
+  /* If the function is to be put in its own section and it's not in a section
+     already, indicate so.  */
+  if (flag_function_sections
+      && DECL_SECTION_NAME (decl) == NULL_TREE)
+    {
+#ifdef UNIQUE_SECTION
+      DECL_SECTION_NAME(decl) = UNIQUE_SECTION (decl);
+#else
+      char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+      /* Strip off any encoding in name.  */
+      STRIP_NAME_ENCODING (name, name);
+      DECL_SECTION_NAME (decl) = build_string (strlen (name), name);
+#endif
+    }
+#endif
+
+  function_section (decl);
 
   /* Tell assembler to move to target machine's alignment for functions.  */
   align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
@@ -747,8 +966,21 @@ assemble_start_function (decl, fnname)
 
   if (TREE_PUBLIC (decl))
     {
-      if (!first_global_object_name)
-       STRIP_NAME_ENCODING (first_global_object_name, fnname);
+      if (!first_global_object_name && ! DECL_WEAK (decl)
+         && ! DECL_ONE_ONLY (decl))
+       {
+         char *p;
+
+         STRIP_NAME_ENCODING (p, fnname);
+         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, fnname);
+      else
+#endif
       if (output_bytecode)
        BC_GLOBALIZE_LABEL (asm_out_file, fnname);
       else
@@ -756,15 +988,17 @@ assemble_start_function (decl, fnname)
     }
 
   /* Do any machine/system dependent processing of the function name */
-#ifdef ASM_DECLARE_FUNCTION_NAME
-  ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
-#else
-  /* Standard thing is just output label for the function.  */
   if (output_bytecode)
     BC_OUTPUT_LABEL (asm_out_file, fnname);
   else
-    ASM_OUTPUT_LABEL (asm_out_file, fnname);
+    {
+#ifdef ASM_DECLARE_FUNCTION_NAME
+      ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
+#else
+      /* Standard thing is just output label for the function.  */
+      ASM_OUTPUT_LABEL (asm_out_file, fnname);
 #endif /* ASM_DECLARE_FUNCTION_NAME */
+    }
 }
 
 /* Output assembler code associated with defining the size of the
@@ -904,6 +1138,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
      tree decl;
      int top_level;
      int at_end;
+     int dont_output_data;
 {
   register char *name;
   int align;
@@ -954,7 +1189,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
     }
 
   /* Normally no need to say anything here for external references,
-     since assemble_external is called by the langauge-specific code
+     since assemble_external is called by the language-specific code
      when a declaration is first seen.  */
 
   if (DECL_EXTERNAL (decl))
@@ -995,16 +1230,13 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   TREE_ASM_WRITTEN (decl) = 1;
 
-  /* If storage size is erroneously variable, just continue.
-     Error message was already made.  */
+  app_disable ();
 
-  if (DECL_SIZE (decl))
+  if (! dont_output_data)
     {
       if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
        goto finish;
 
-      app_disable ();
-
       /* This is better than explicit arithmetic, since it avoids overflow.  */
       size_tree = size_binop (CEIL_DIV_EXPR,
                              DECL_SIZE (decl), size_int (BITS_PER_UNIT));
@@ -1018,23 +1250,33 @@ 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.  */
 
-  /* ANSI specifies that a tentative definition which is not merged with
-     a non-tentative definition behaves exactly like a definition with an
-     initializer equal to zero.  (Section 3.7.2)
-     -fno-common gives strict ANSI behavior.  Usually you don't want it.
-     This matters only for variables with external linkage.  */
-  if ((! flag_no_common || ! TREE_PUBLIC (decl))
+  if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
+      /* If the target can't output uninitialized but not common global data
+        in .bss, then we have to use .data.  */
+#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
       && DECL_COMMON (decl)
-      && ! dont_output_data
-      && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
+#endif
+      && ! dont_output_data)
     {
       int size = TREE_INT_CST_LOW (size_tree);
       int rounded = size;
 
-      if (TREE_INT_CST_HIGH (size_tree) != 0)
-       error_with_decl (decl, "size of variable `%s' is too large");
       /* Don't allocate zero bytes of common,
         since that means "undefined external" in the linker.  */
       if (size == 0) rounded = 1;
@@ -1065,11 +1307,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
         while we are doing our final traversal of the chain of file-scope
         declarations.  */
 
-#if 0
+#if 0 /* ??? We should either delete this or add a comment describing what
+        it was intended to do and why we shouldn't delete it.  */
       if (flag_shared_data)
        data_section ();
 #endif
-      if (TREE_PUBLIC (decl))
+
+      if (TREE_PUBLIC (decl)
+#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS)
+         && DECL_COMMON (decl)
+#endif
+         )
        {
 #ifdef ASM_OUTPUT_SHARED_COMMON
          if (flag_shared_data)
@@ -1090,6 +1338,29 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 #endif
              }
        }
+#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS)
+      else if (TREE_PUBLIC (decl))
+       {
+#ifdef ASM_OUTPUT_SHARED_BSS
+         if (flag_shared_data)
+           ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded);
+         else
+#endif
+           if (output_bytecode)
+             {
+               BC_OUTPUT_BSS (asm_out_file, name, size, rounded);
+             }
+           else
+             {
+#ifdef ASM_OUTPUT_ALIGNED_BSS
+               ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size,
+                                       DECL_ALIGN (decl));
+#else
+               ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
+#endif
+             }
+       }
+#endif /* ASM_OUTPUT_BSS || ASM_OUTPUT_ALIGNED_BSS */
       else
        {
 #ifdef ASM_OUTPUT_SHARED_LOCAL
@@ -1114,13 +1385,18 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       goto finish;
     }
 
-  /* Handle initialized definitions.  */
+  /* Handle initialized definitions.
+     Also handle uninitialized global definitions if -fno-common and the
+     target doesn't support ASM_OUTPUT_BSS.  */
 
   /* First make the assembler name(s) global if appropriate.  */
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     {
-      if (!first_global_object_name)
-       STRIP_NAME_ENCODING(first_global_object_name, name);
+#ifdef ASM_WEAKEN_LABEL
+      if (DECL_WEAK (decl))
+       ASM_WEAKEN_LABEL (asm_out_file, name);
+      else
+#endif
       ASM_GLOBALIZE_LABEL (asm_out_file, name);
     }
 #if 0
@@ -1139,33 +1415,8 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   else if (DECL_INITIAL (decl))
     reloc = output_addressed_constants (DECL_INITIAL (decl));
 
-  /* Switch to the proper section for this data.  */
-  if (IN_NAMED_SECTION (decl))
-    named_section (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)));
-  else
-    {
-      /* C++ can have const variables that get initialized from constructors,
-        and thus can not be in a readonly section.  We prevent this by
-        verifying that the initial value is constant for objects put in a
-        readonly section.
-
-        error_mark_node is used by the C front end to indicate that the
-        initializer has not been seen yet.  In this case, we assume that
-        the initializer must be constant.  */
-#ifdef SELECT_SECTION
-      SELECT_SECTION (decl, reloc);
-#else
-      if (TREE_READONLY (decl)
-         && ! TREE_THIS_VOLATILE (decl)
-         && DECL_INITIAL (decl)
-         && (DECL_INITIAL (decl) == error_mark_node
-             || TREE_CONSTANT (DECL_INITIAL (decl)))
-         && ! (flag_pic && reloc))
-       readonly_data_section ();
-      else
-       data_section ();
-#endif
-    }
+  /* Switch to the appropriate section.  */
+  variable_section (decl, reloc);
 
   /* dbxout.c needs to know this.  */
   if (in_text_section ())
@@ -1200,22 +1451,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   /* If the debugging output changed sections, reselect the section
      that's supposed to be selected.  */
   if (in_section != saved_in_section)
-    {
-      /* Switch to the proper section for this data.  */
-#ifdef SELECT_SECTION
-      SELECT_SECTION (decl, reloc);
-#else
-      if (TREE_READONLY (decl)
-         && ! TREE_THIS_VOLATILE (decl)
-         && DECL_INITIAL (decl)
-         && (DECL_INITIAL (decl) == error_mark_node
-             || TREE_CONSTANT (DECL_INITIAL (decl)))
-         && ! (flag_pic && reloc))
-       readonly_data_section ();
-      else
-       data_section ();
-#endif
-    }
+    variable_section (decl, reloc);
 
   /* Compute and output the alignment of this data.  */
 
@@ -1260,26 +1496,27 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
     }
 
   /* Do any machine/system dependent processing of the object.  */
-#ifdef ASM_DECLARE_OBJECT_NAME
-  last_assemble_variable_decl = decl;
-  ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
-#else
-  /* Standard thing is just output label for the object.  */
   if (output_bytecode)
     BC_OUTPUT_LABEL (asm_out_file, name);
   else
-    ASM_OUTPUT_LABEL (asm_out_file, name);
+    {
+#ifdef ASM_DECLARE_OBJECT_NAME
+      last_assemble_variable_decl = decl;
+      ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
+#else
+      /* Standard thing is just output label for the object.  */
+      ASM_OUTPUT_LABEL (asm_out_file, name);
 #endif /* ASM_DECLARE_OBJECT_NAME */
+    }
 
   if (!dont_output_data)
     {
       if (DECL_INITIAL (decl))
        /* Output the actual data.  */
-       output_constant (DECL_INITIAL (decl),
-                        int_size_in_bytes (TREE_TYPE (decl)));
+       output_constant (DECL_INITIAL (decl), TREE_INT_CST_LOW (size_tree));
       else
        /* Leave space for it.  */
-       assemble_zeros (int_size_in_bytes (TREE_TYPE (decl)));
+       assemble_zeros (TREE_INT_CST_LOW (size_tree));
     }
 
  finish:
@@ -1298,22 +1535,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       dbxout_symbol (decl, 0);
 
       if (in_section != saved_in_section)
-       {
-         /* Switch to the proper section for this data.  */
-#ifdef SELECT_SECTION
-         SELECT_SECTION (decl, reloc);
-#else
-         if (TREE_READONLY (decl)
-             && ! TREE_THIS_VOLATILE (decl)
-             && DECL_INITIAL (decl)
-             && (DECL_INITIAL (decl) == error_mark_node
-                 || TREE_CONSTANT (DECL_INITIAL (decl)))
-             && ! (flag_pic && reloc))
-           readonly_data_section ();
-         else
-           data_section ();
-#endif
-       }
+       variable_section (decl, reloc);
     }
 #else
   /* There must be a statement after a label.  */
@@ -1358,16 +1580,17 @@ contains_pointers_p (type)
     }
 }
 
-/* Output text storage for constructor CONSTR. */
+/* Output text storage for constructor CONSTR.  */
 
 void
-bc_output_constructor (constr)
-  tree constr;
+bc_output_constructor (constr, size)
+     tree constr;
+     int size;
 {
   int i;
 
   /* Must always be a literal; non-literal constructors are handled
-     differently. */
+     differently.  */
 
   if (!TREE_CONSTANT (constr))
     abort ();
@@ -1376,16 +1599,17 @@ bc_output_constructor (constr)
   text_section ();
 
   /* Align */
-  for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++);
+  for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++)
+    ;
+
   if (i > 0)
     BC_OUTPUT_ALIGN (asm_out_file, i);
 
   /* Output data */
-  output_constant (constr, int_size_in_bytes (TREE_TYPE (constr)));
+  output_constant (constr, size);
 }
 
-
-/* Create storage for constructor CONSTR. */
+/* Create storage for constructor CONSTR.  */
 
 void
 bc_output_data_constructor (constr)
@@ -1401,11 +1625,10 @@ bc_output_data_constructor (constr)
   if (i > 0)
     BC_OUTPUT_ALIGN (asm_out_file, i);
 
-  /* The constructor is filled in at runtime. */
+  /* The constructor is filled in at runtime.  */
   BC_OUTPUT_SKIP (asm_out_file, int_size_in_bytes (TREE_TYPE (constr)));
 }
 
-
 /* Output something to declare an external symbol to the assembler.
    (Most assemblers don't need this, so we normally output nothing.)
    Do nothing if DECL is not external.  */
@@ -1486,14 +1709,18 @@ assemble_name (file, name)
      char *name;
 {
   char *real_name;
+  tree id;
 
   STRIP_NAME_ENCODING (real_name, name);
-  TREE_SYMBOL_REFERENCED (get_identifier (real_name)) = 1;
+
+  id = maybe_get_identifier (real_name);
+  if (id)
+    TREE_SYMBOL_REFERENCED (id) = 1;
 
   if (name[0] == '*')
     {
       if (output_bytecode)
-       bc_emit_labelref (name);
+       bc_emit_labelref (name, 0);
       else
        fputs (&name[1], file);
     }
@@ -1558,6 +1785,7 @@ assemble_static_space (size)
    This is done at most once per compilation.
    Returns an RTX for the address of the template.  */
 
+#ifdef TRAMPOLINE_TEMPLATE
 rtx
 assemble_trampoline_template ()
 {
@@ -1591,6 +1819,7 @@ assemble_trampoline_template ()
     = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
   return gen_rtx (SYMBOL_REF, Pmode, name);
 }
+#endif
 \f
 /* Assemble the integer constant X into an object of SIZE bytes.
    X must be either a CONST_INT or CONST_DOUBLE.
@@ -1605,7 +1834,7 @@ assemble_integer (x, size, force)
      int force;
 {
   /* First try to use the standard 1, 2, 4, 8, and 16 byte
-     ASM_OUTPUT... macros. */
+     ASM_OUTPUT... macros.  */
 
   switch (size)
     {
@@ -2049,6 +2278,7 @@ decode_addr_const (exp, value)
     case STRING_CST:
     case COMPLEX_CST:
     case CONSTRUCTOR:
+    case INTEGER_CST:
       x = TREE_CST_RTL (target);
       break;
 
@@ -2089,7 +2319,7 @@ static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
 
 /* Compute a hash code for a constant expression.  */
 
-int
+static int
 const_hash (exp)
      tree exp;
 {
@@ -2112,6 +2342,12 @@ const_hash (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;
@@ -2146,7 +2382,7 @@ const_hash (exp)
          hi = value.offset;
          p = XSTR (value.base, 0);
          for (i = 0; p[i] != 0; i++)
-           hi = ((hi * 613) + (unsigned)(p[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;
@@ -2164,7 +2400,7 @@ const_hash (exp)
   /* Compute hashing function */
   hi = len;
   for (i = 0; i < len; i++)
-    hi = ((hi * 613) + (unsigned)(p[i]));
+    hi = ((hi * 613) + (unsigned) (p[i]));
 
   hi &= (1 << HASHBITS) - 1;
   hi %= MAX_HASH_TABLE;
@@ -2237,6 +2473,15 @@ compare_constant_1 (exp, p)
       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;
@@ -2354,92 +2599,112 @@ record_constant_1 (exp)
 
   obstack_1grow (&permanent_obstack, (unsigned int) code);
 
-  if (code == INTEGER_CST)
+  switch (code)
     {
+    case INTEGER_CST:
       obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
       strp = (char *) &TREE_INT_CST_LOW (exp);
       len = 2 * sizeof TREE_INT_CST_LOW (exp);
-    }
-  else if (code == REAL_CST)
-    {
+      break;
+
+    case REAL_CST:
       obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp)));
       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;
+
       strp = TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
       obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp),
                    sizeof TREE_STRING_LENGTH (exp));
-    }
-  else if (code == COMPLEX_CST)
-    {
+      break;
+
+    case COMPLEX_CST:
       record_constant_1 (TREE_REALPART (exp));
       record_constant_1 (TREE_IMAGPART (exp));
       return;
-    }
-  else if (code == CONSTRUCTOR)
-    {
-      register tree link;
-      int length = list_length (CONSTRUCTOR_ELTS (exp));
-      tree type;
-
-      obstack_grow (&permanent_obstack, (char *) &length, 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;
-      obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
-
-      /* 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));
-         obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
+         int nbytes = int_size_in_bytes (TREE_TYPE (exp));
+         obstack_grow (&permanent_obstack, &nbytes, sizeof (nbytes));
+         obstack_blank (&permanent_obstack, nbytes);
+         get_set_constructor_bytes
+           (exp, (unsigned char *) permanent_obstack.next_free-nbytes,
+            nbytes);
+         return;
        }
-
-      for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+      else
        {
-         if (TREE_VALUE (link))
-           record_constant_1 (TREE_VALUE (link));
+         register tree link;
+         int length = list_length (CONSTRUCTOR_ELTS (exp));
+         tree type;
+
+         obstack_grow (&permanent_obstack, (char *) &length, 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;
+         obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
+
+         /* For arrays, insist that the size in bytes match.  */
+         if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
            {
-             tree zero = 0;
+             int size = int_size_in_bytes (TREE_TYPE (exp));
+             obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
+           }
 
-             obstack_grow (&permanent_obstack, (char *) &zero, sizeof zero);
+         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+           {
+             if (TREE_VALUE (link))
+               record_constant_1 (TREE_VALUE (link));
+             else
+               {
+                 tree zero = 0;
+
+                 obstack_grow (&permanent_obstack,
+                               (char *) &zero, sizeof zero);
+               }
            }
        }
-
       return;
-    }
-  else if (code == ADDR_EXPR)
-    {
-      struct addr_const value;
-      decode_addr_const (exp, &value);
-      /* Record the offset.  */
-      obstack_grow (&permanent_obstack,
-                   (char *) &value.offset, sizeof value.offset);
-      /* Record the symbol name.  */
-      obstack_grow (&permanent_obstack, XSTR (value.base, 0),
-                   strlen (XSTR (value.base, 0)) + 1);
+
+    case ADDR_EXPR:
+      {
+       struct addr_const value;
+
+       decode_addr_const (exp, &value);
+       /* Record the offset.  */
+       obstack_grow (&permanent_obstack,
+                     (char *) &value.offset, sizeof value.offset);
+       /* Record the symbol name.  */
+       obstack_grow (&permanent_obstack, XSTR (value.base, 0),
+                     strlen (XSTR (value.base, 0)) + 1);
+      }
       return;
-    }
-  else if (code == PLUS_EXPR || code == MINUS_EXPR)
-    {
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
       record_constant_1 (TREE_OPERAND (exp, 0));
       record_constant_1 (TREE_OPERAND (exp, 1));
       return;
-    }
-  else if (code == NOP_EXPR || code == CONVERT_EXPR)
-    {
+
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
       record_constant_1 (TREE_OPERAND (exp, 0));
       return;
+
+    default:
+      abort ();
     }
 
   /* Record constant contents.  */
@@ -2504,16 +2769,23 @@ copy_constant (exp)
 {
   switch (TREE_CODE (exp))
     {
+    case ADDR_EXPR:
+      /* For ADDR_EXPR, we do not want to copy the decl whose address
+        is requested.  We do want to copy constants though.  */
+      if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == 'c')
+       return build1 (TREE_CODE (exp), TREE_TYPE (exp),
+                      copy_constant (TREE_OPERAND (exp, 0)));
+      else
+       return copy_node (exp);
+
     case INTEGER_CST:
     case REAL_CST:
     case STRING_CST:
-    case ADDR_EXPR:
-      /* For ADDR_EXPR, we do not want to copy the decl
-        whose address is requested.  */
       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:
@@ -2536,6 +2808,9 @@ copy_constant (exp)
        CONSTRUCTOR_ELTS (copy) = list;
        for (tail = list; tail; tail = TREE_CHAIN (tail))
          TREE_VALUE (tail) = copy_constant (TREE_VALUE (tail));
+       if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
+         for (tail = list; tail; tail = TREE_CHAIN (tail))
+           TREE_PURPOSE (tail) = copy_constant (TREE_PURPOSE (tail));
 
        return copy;
       }
@@ -2567,9 +2842,6 @@ output_constant_def (exp)
   int reloc;
   register rtx def;
 
-  if (TREE_CODE (exp) == INTEGER_CST)
-    abort ();                  /* No TREE_CST_RTL slot in these.  */
-
   if (TREE_CST_RTL (exp))
     return TREE_CST_RTL (exp);
 
@@ -2673,7 +2945,7 @@ output_constant_def_contents (exp, reloc, labelno)
   int align;
 
   if (IN_NAMED_SECTION (exp))
-    named_section (TREE_STRING_POINTER (DECL_SECTION_NAME (exp)));
+    named_section (exp, NULL);
   else
     {
       /* First switch to text section, except for writable strings.  */
@@ -2794,7 +3066,7 @@ init_const_rtx_hash_table ()
   pool_offset = 0;
 }
 
-/* Save and restore it for a nested function.  */
+/* Save and restore status for a nested function.  */
 
 void
 save_varasm_status (p)
@@ -2832,6 +3104,7 @@ struct rtx_const
   union {
     union real_extract du;
     struct addr_const addr;
+    struct {HOST_WIDE_INT high, low;} di;
   } un;
 };
 
@@ -2854,7 +3127,7 @@ decode_rtx_const (mode, x, value)
       *p++ = 0;
   }
 
-  value->kind = RTX_INT;       /* Most usual kind. */
+  value->kind = RTX_INT;       /* Most usual kind.  */
   value->mode = mode;
 
   switch (GET_CODE (x))
@@ -2862,9 +3135,16 @@ decode_rtx_const (mode, x, value)
     case CONST_DOUBLE:
       value->kind = RTX_DOUBLE;
       if (GET_MODE (x) != VOIDmode)
-       value->mode = GET_MODE (x);
-      bcopy ((char *) &CONST_DOUBLE_LOW (x),
-            (char *) &value->un.du, sizeof value->un.du);
+       {
+         value->mode = GET_MODE (x);
+         bcopy ((char *) &CONST_DOUBLE_LOW (x),
+                (char *) &value->un.du, sizeof value->un.du);
+       }
+      else
+       {
+         value->un.di.low = CONST_DOUBLE_LOW (x);
+         value->un.di.high = CONST_DOUBLE_HIGH (x);
+       }
       break;
 
     case CONST_INT:
@@ -2932,7 +3212,7 @@ simplify_subtraction (x)
 
 /* Compute a hash code for a constant RTL expression.  */
 
-int
+static int
 const_hash_rtx (mode, x)
      enum machine_mode mode;
      rtx x;
@@ -3076,7 +3356,7 @@ force_const_mem (mode, x)
         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. */
+        no other RTX should be allocated in this situation.  */
       if (rtl_obstack != saveable_obstack
          && GET_CODE (x) == CONST)
        {
@@ -3282,7 +3562,7 @@ output_constant_pool (fnname, fndecl)
    and make sure assembler code with a label has been output for each one.
    Indicate whether an ADDR_EXPR has been encountered.  */
 
-int
+static int
 output_addressed_constants (exp)
      tree exp;
 {
@@ -3334,22 +3614,6 @@ output_addressed_constants (exp)
     }
   return reloc;
 }
-
-
-/* Output assembler for byte constant */
-void
-output_byte_asm (byte)
-  int byte;
-{
-  if (output_bytecode)
-    bc_emit_const ((char *) &byte, sizeof (char));
-#ifdef ASM_OUTPUT_BYTE
-  else
-    {
-      ASM_OUTPUT_BYTE (asm_out_file, byte);
-    }
-#endif
-}
 \f
 /* Output assembler code for constant EXP to FILE, with no label.
    This includes the pseudo-op such as ".int" or ".byte", and a newline.
@@ -3381,13 +3645,11 @@ output_constant (exp, size)
     return;
 
   /* Eliminate the NON_LVALUE_EXPR_EXPR that makes a cast not be an lvalue.
-     That way we get the constant (we hope) inside it.  Also, strip
-     off any NOP_EXPR that converts between two record or union types.  */
+     That way we get the constant (we hope) inside it.  Also, strip off any
+     NOP_EXPR that converts between two record, union, array, or set types.  */
   while ((TREE_CODE (exp) == NOP_EXPR 
          && (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
-             || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
-             || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE
-             || TREE_CODE (TREE_TYPE (exp)) == QUAL_UNION_TYPE))
+             || AGGREGATE_TYPE_P (TREE_TYPE (exp))))
         || TREE_CODE (exp) == NON_LVALUE_EXPR)
     exp = TREE_OPERAND (exp, 0);
 
@@ -3467,14 +3729,30 @@ output_constant (exp, size)
       else
        abort ();
       return;
+
+    case SET_TYPE:
+      if (TREE_CODE (exp) == INTEGER_CST)
+       assemble_integer (expand_expr (exp, NULL_RTX,
+                                      VOIDmode, EXPAND_INITIALIZER),
+                         size, 1);
+      else if (TREE_CODE (exp) == CONSTRUCTOR)
+       {
+         unsigned char *buffer = (unsigned char *) alloca (size);
+         if (get_set_constructor_bytes (exp, buffer, size))
+           abort ();
+         assemble_string ((char *) buffer, size);
+       }
+      else
+       error ("unknown set constructor type");
+      return;
     }
 
   if (size > 0)
     assemble_zeros (size);
 }
 
+/* Bytecode specific code to output assembler for integer.  */
 
-/* Bytecode specific code to output assembler for integer. */
 static void
 bc_assemble_integer (exp, size)
     tree exp;
@@ -3545,24 +3823,28 @@ bc_assemble_integer (exp, size)
        }
       else if (size == 8)
        {
-#if WORDS_BIG_ENDIAN
-         int i = TREE_INT_CST_HIGH (const_part);
-         bc_emit ((char *) &i, 4);
-         i = TREE_INT_CST_LOW (const_part);
-         bc_emit ((char *) &i, 4);
-#else
-         int i = TREE_INT_CST_LOW (const_part);
-         bc_emit ((char *) &i, 4);
-         i = TREE_INT_CST_HIGH (const_part);
-         bc_emit ((char *) &i, 4);
-#endif
+         if (WORDS_BIG_ENDIAN)
+           {
+             int i = TREE_INT_CST_HIGH (const_part);
+             bc_emit ((char *) &i, 4);
+             i = TREE_INT_CST_LOW (const_part);
+             bc_emit ((char *) &i, 4);
+           }
+         else
+           {
+             int i = TREE_INT_CST_LOW (const_part);
+             bc_emit ((char *) &i, 4);
+             i = TREE_INT_CST_HIGH (const_part);
+             bc_emit ((char *) &i, 4);
+           }
          size -= 8;
        }
     }
   else
     if (size == 4
        && TREE_CODE (TREE_OPERAND (addr_part, 0)) == VAR_DECL)
-      bc_emit_labelref (DECL_ASSEMBLER_NAME (TREE_OPERAND (addr_part, 0)),
+      bc_emit_labelref (IDENTIFIER_POINTER
+                       (DECL_ASSEMBLER_NAME (TREE_OPERAND (addr_part, 0))),
                        TREE_INT_CST_LOW (const_part));
     else
       abort ();                /* FIXME: there may be more cases.  */
@@ -3572,7 +3854,7 @@ bc_assemble_integer (exp, size)
    (aggregate constants).
    Generate at least SIZE bytes, padding if necessary.  */
 
-void
+static void
 output_constructor (exp, size)
      tree exp;
      int size;
@@ -3627,7 +3909,26 @@ output_constructor (exp, size)
       if (val != 0)
        STRIP_NOPS (val);
 
-      if (field == 0 || !DECL_BIT_FIELD (field))
+      if (index && TREE_CODE (index) == RANGE_EXPR)
+       {
+         register int fieldsize
+           = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
+         HOST_WIDE_INT lo_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 0));
+         HOST_WIDE_INT hi_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 1));
+         HOST_WIDE_INT index;
+         for (index = lo_index; index <= hi_index; index++)
+           {
+             /* Output the element's initial value.  */
+             if (val == 0)
+               assemble_zeros (fieldsize);
+             else
+               output_constant (val, fieldsize);
+
+             /* Count its size.  */
+             total_bytes += fieldsize;
+           }
+       }
+      else if (field == 0 || !DECL_BIT_FIELD (field))
        {
          /* An element that is not a bit-field.  */
 
@@ -3741,7 +4042,8 @@ output_constructor (exp, size)
          while (next_offset < end_offset)
            {
              int this_time;
-             int shift, value;
+             int shift;
+             HOST_WIDE_INT value;
              int next_byte = next_offset / BITS_PER_UNIT;
              int next_bit = next_offset % BITS_PER_UNIT;
 
@@ -3758,64 +4060,68 @@ output_constructor (exp, size)
                 (all part of the same byte).  */
              this_time = MIN (end_offset - next_offset,
                               BITS_PER_UNIT - next_bit);
-#if BYTES_BIG_ENDIAN
-             /* On big-endian machine, take the most significant bits
-                first (of the bits that are significant)
-                and put them into bytes from the most significant end.  */
-             shift = end_offset - next_offset - this_time;
-             /* Don't try to take a bunch of bits that cross
-                the word boundary in the INTEGER_CST.  */
-             if (shift < HOST_BITS_PER_WIDE_INT
-                 && shift + this_time > HOST_BITS_PER_WIDE_INT)
-               {
-                 this_time -= (HOST_BITS_PER_WIDE_INT - shift);
-                 shift = HOST_BITS_PER_WIDE_INT;
-               }
-
-             /* Now get the bits from the appropriate constant word.  */
-             if (shift < HOST_BITS_PER_WIDE_INT)
+             if (BYTES_BIG_ENDIAN)
                {
-                 value = TREE_INT_CST_LOW (val);
-               }
-             else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
-               {
-                 value = TREE_INT_CST_HIGH (val);
-                 shift -= HOST_BITS_PER_WIDE_INT;
+                 /* On big-endian machine, take the most significant bits
+                    first (of the bits that are significant)
+                    and put them into bytes from the most significant end.  */
+                 shift = end_offset - next_offset - this_time;
+                 /* Don't try to take a bunch of bits that cross
+                    the word boundary in the INTEGER_CST.  */
+                 if (shift < HOST_BITS_PER_WIDE_INT
+                     && shift + this_time > HOST_BITS_PER_WIDE_INT)
+                   {
+                     this_time -= (HOST_BITS_PER_WIDE_INT - shift);
+                     shift = HOST_BITS_PER_WIDE_INT;
+                   }
+
+                 /* Now get the bits from the appropriate constant word.  */
+                 if (shift < HOST_BITS_PER_WIDE_INT)
+                   {
+                     value = TREE_INT_CST_LOW (val);
+                   }
+                 else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+                   {
+                     value = TREE_INT_CST_HIGH (val);
+                     shift -= HOST_BITS_PER_WIDE_INT;
+                   }
+                 else
+                   abort ();
+                 byte |= (((value >> shift)
+                           & (((HOST_WIDE_INT) 1 << this_time) - 1))
+                          << (BITS_PER_UNIT - this_time - next_bit));
                }
              else
-               abort ();
-             byte |= (((value >> shift)
-                       & (((HOST_WIDE_INT) 1 << this_time) - 1))
-                      << (BITS_PER_UNIT - this_time - next_bit));
-#else
-             /* On little-endian machines,
-                take first the least significant bits of the value
-                and pack them starting at the least significant
-                bits of the bytes.  */
-             shift = (next_offset
-                      - TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)));
-             /* Don't try to take a bunch of bits that cross
-                the word boundary in the INTEGER_CST.  */
-             if (shift < HOST_BITS_PER_WIDE_INT
-                 && shift + this_time > HOST_BITS_PER_WIDE_INT)
                {
-                 this_time -= (HOST_BITS_PER_WIDE_INT - shift);
-                 shift = HOST_BITS_PER_WIDE_INT;
+                 /* On little-endian machines,
+                    take first the least significant bits of the value
+                    and pack them starting at the least significant
+                    bits of the bytes.  */
+                 shift = (next_offset
+                          - TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)));
+                 /* Don't try to take a bunch of bits that cross
+                    the word boundary in the INTEGER_CST.  */
+                 if (shift < HOST_BITS_PER_WIDE_INT
+                     && shift + this_time > HOST_BITS_PER_WIDE_INT)
+                   {
+                     this_time -= (HOST_BITS_PER_WIDE_INT - shift);
+                     shift = HOST_BITS_PER_WIDE_INT;
+                   }
+
+                 /* Now get the bits from the appropriate constant word.  */
+                 if (shift < HOST_BITS_PER_INT)
+                   value = TREE_INT_CST_LOW (val);
+                 else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
+                   {
+                     value = TREE_INT_CST_HIGH (val);
+                     shift -= HOST_BITS_PER_WIDE_INT;
+                   }
+                 else
+                   abort ();
+                 byte |= (((value >> shift)
+                           & (((HOST_WIDE_INT) 1 << this_time) - 1))
+                          << next_bit);
                }
-
-             /* Now get the bits from the appropriate constant word.  */
-             if (shift < HOST_BITS_PER_INT)
-               value = TREE_INT_CST_LOW (val);
-             else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
-               {
-                 value = TREE_INT_CST_HIGH (val);
-                 shift -= HOST_BITS_PER_WIDE_INT;
-               }
-             else
-               abort ();
-             byte |= ((value >> shift)
-                      & (((HOST_WIDE_INT) 1 << this_time) - 1)) << next_bit;
-#endif
              next_offset += this_time;
              byte_buffer_in_use = 1;
            }
@@ -3830,53 +4136,157 @@ output_constructor (exp, size)
     assemble_zeros (size - total_bytes);
 }
 
-
-#ifdef HANDLE_SYSV_PRAGMA
-
-/* Support #pragma weak by default if WEAK_ASM_OP and ASM_OUTPUT_DEF
-   are defined.  */
-#if defined (WEAK_ASM_OP) && defined (ASM_OUTPUT_DEF)
-
-/* See c-pragma.c for an identical definition.  */
-enum pragma_state
-{
-  ps_start,
-  ps_done,
-  ps_bad,
-  ps_weak,
-  ps_name,
-  ps_equals,
-  ps_value,
-  ps_pack,
-  ps_left,
-  ps_align,
-  ps_right
-};
-
 /* Output asm to handle ``#pragma weak'' */
+
 void
-handle_pragma_weak (what, asm_out_file, name, value)
+handle_pragma_weak (what, name, value)
      enum pragma_state what;
-     FILE *asm_out_file;
      char *name, *value;
 {
+#ifdef HANDLE_PRAGMA_WEAK
   if (what == ps_name || what == ps_value)
     {
-      fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
+      struct weak_syms *weak =
+       (struct weak_syms *)permalloc (sizeof (struct weak_syms));
+      weak->next = weak_decls;
+      weak->name = permalloc (strlen (name) + 1);
+      strcpy (weak->name, name);
+
+      if (what != ps_value)
+       weak->value = NULL_PTR;
 
-      if (output_bytecode)
-       BC_OUTPUT_LABELREF (asm_out_file, name);
       else
-       ASM_OUTPUT_LABELREF (asm_out_file, name);
+       {
+         weak->value = permalloc (strlen (value) + 1);
+         strcpy (weak->value, value);
+       }
 
-      fputc ('\n', asm_out_file);
-      if (what == ps_value)
-       ASM_OUTPUT_DEF (asm_out_file, name, value);
+      weak_decls = weak;
     }
   else if (! (what == ps_done || what == ps_start))
     warning ("malformed `#pragma weak'");
+#endif /* HANDLE_PRAGMA_WEAK */
+}
+
+/* Declare DECL to be a weak symbol.  */
+
+void
+declare_weak (decl)
+     tree decl;
+{
+  if (! TREE_PUBLIC (decl))
+    error_with_decl (decl, "weak declaration of `%s' must be public");
+  else if (TREE_ASM_WRITTEN (decl))
+    error_with_decl (decl, "weak declaration of `%s' must precede definition");
+  else if (SUPPORTS_WEAK)
+    DECL_WEAK (decl) = 1;
 }
 
-#endif /* HANDLE_PRAGMA_WEAK or (WEAK_ASM_OP and SET_ASM_OP) */
+/* Emit any pending weak declarations.  */
+
+void
+weak_finish ()
+{
+#ifdef HANDLE_PRAGMA_WEAK
+  if (HANDLE_PRAGMA_WEAK)
+    {
+      struct weak_syms *t;
+      for (t = weak_decls; t; t = t->next)
+       {
+         ASM_WEAKEN_LABEL (asm_out_file, t->name);
+         if (t->value)
+           ASM_OUTPUT_DEF (asm_out_file, t->name, t->value);
+       }
+    }
+#endif
+}
+
+void
+assemble_alias (decl, target)
+     tree decl, target;
+{
+  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))
+    {
+#ifdef ASM_WEAKEN_LABEL
+      if (DECL_WEAK (decl))
+       ASM_WEAKEN_LABEL (asm_out_file, name);
+      else
+#endif
+      if (output_bytecode)
+       BC_GLOBALIZE_LABEL (asm_out_file, name);
+      else
+       ASM_GLOBALIZE_LABEL (asm_out_file, name);
+    }
+
+  ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
+  TREE_ASM_WRITTEN (decl) = 1;
+#else
+#ifdef ASM_OUTPUT_WEAK_ALIAS
+  if (! DECL_WEAK (decl))
+    warning ("only weak aliases are supported in this configuration");
 
-#endif /* WEAK_ASM_OP && ASM_OUTPUT_DEF */
+  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 ();
+}