OSDN Git Service

* varasm.c (make_decl_rtl): Skip initial '*' when setting
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 7f2970f..18b6487 100644 (file)
@@ -1,5 +1,6 @@
 /* Output variables, constants and external declarations, for GNU compiler.
-   Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
+   1998, 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -27,13 +28,11 @@ Boston, MA 02111-1307, USA.  */
    and are responsible for combining constants with the same value.  */
 
 #include "config.h"
-#include <stdio.h>
+#include "system.h"
 #include <setjmp.h>
-/* #include <stab.h> */
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
-#include "except.h"
 #include "function.h"
 #include "expr.h"
 #include "output.h"
@@ -41,17 +40,18 @@ Boston, MA 02111-1307, USA.  */
 #include "regs.h"
 #include "defaults.h"
 #include "real.h"
-#include "bytecode.h"
-
+#include "toplev.h"
+#include "dbxout.h"
+#include "sdbout.h"
 #include "obstack.h"
 #include "c-pragma.h"
+#include "ggc.h"
+#include "tm_p.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"
 #endif
 
-#include <ctype.h>
-
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
 #endif
@@ -72,20 +72,13 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #define CHKR_PREFIX_SIZE (sizeof (CHKR_PREFIX) - 1)
 
-/* This macro gets just the user-specified name
-   out of the string in a SYMBOL_REF.  On most machines,
-   we discard the * if any and that's all.  */
-#ifndef STRIP_NAME_ENCODING
-#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \
-  (VAR) = ((SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*'))
-#endif
-
 /* File in which assembler code is being written.  */
 
 extern FILE *asm_out_file;
 
 /* The (assembler) name of the first globally-visible object output.  */
 char *first_global_object_name;
+char *weak_global_object_name;
 
 extern struct obstack *current_obstack;
 extern struct obstack *saveable_obstack;
@@ -93,6 +86,48 @@ extern struct obstack *rtl_obstack;
 extern struct obstack permanent_obstack;
 #define obstack_chunk_alloc xmalloc
 
+struct addr_const;
+struct constant_descriptor;
+struct rtx_const;
+struct pool_constant;
+
+#define MAX_RTX_HASH_TABLE 61
+
+struct varasm_status
+{
+  /* Hash facility for making memory-constants
+     from constant rtl-expressions.  It is used on RISC machines
+     where immediate integer arguments and constant addresses are restricted
+     so that such constants must be stored in memory.
+
+     This pool of constants is reinitialized for each function
+     so each function gets its own constants-pool that comes right before
+     it.  */
+  struct constant_descriptor **x_const_rtx_hash_table;
+  struct pool_sym **x_const_rtx_sym_hash_table;
+
+  /* Pointers to first and last constant in pool.  */
+  struct pool_constant *x_first_pool, *x_last_pool;
+
+  /* Current offset in constant pool (does not include any machine-specific
+     header.  */
+  int x_pool_offset;
+
+  /* Chain of all CONST_DOUBLE rtx's constructed for the current function.
+     They are chained through the CONST_DOUBLE_CHAIN.
+     A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain.
+     In that case, CONST_DOUBLE_MEM is either a MEM,
+     or const0_rtx if no MEM has been made for this CONST_DOUBLE yet.  */
+  rtx x_const_double_chain;
+};
+
+#define const_rtx_hash_table (cfun->varasm->x_const_rtx_hash_table)
+#define const_rtx_sym_hash_table (cfun->varasm->x_const_rtx_sym_hash_table)
+#define first_pool (cfun->varasm->x_first_pool)
+#define last_pool (cfun->varasm->x_last_pool)
+#define pool_offset (cfun->varasm->x_pool_offset)
+#define const_double_chain (cfun->varasm->x_const_double_chain)
+
 /* Number for making the label on the next
    constant that is stored in memory.  */
 
@@ -115,56 +150,46 @@ 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;
-
-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,
+static const char *strip_reg_name      PARAMS ((const char *));
+static int contains_pointers_p         PARAMS ((tree));
+static void decode_addr_const          PARAMS ((tree, struct addr_const *));
+static int const_hash                  PARAMS ((tree));
+static int compare_constant            PARAMS ((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,
+static char *compare_constant_1                PARAMS ((tree, char *));
+static struct constant_descriptor *record_constant PARAMS ((tree));
+static void record_constant_1          PARAMS ((tree));
+static tree copy_constant              PARAMS ((tree));
+static void output_constant_def_contents  PARAMS ((tree, int, int));
+static void decode_rtx_const           PARAMS ((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,
+static int const_hash_rtx              PARAMS ((enum machine_mode, rtx));
+static int compare_constant_rtx                PARAMS ((enum machine_mode, rtx,
                                               struct constant_descriptor *));
-static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
+static struct constant_descriptor *record_constant_rtx PARAMS ((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));
+static struct pool_constant *find_pool_constant PARAMS ((struct function *, rtx));
+static void mark_constant_pool         PARAMS ((void));
+static void mark_constants             PARAMS ((rtx));
+static int output_addressed_constants  PARAMS ((tree));
+static void output_after_function_constants PARAMS ((void));
+static void output_constructor         PARAMS ((tree, int));
+#ifdef ASM_WEAKEN_LABEL
+static void remove_from_pending_weak_list      PARAMS ((char *));
+#endif
+#ifdef ASM_OUTPUT_BSS
+static void asm_output_bss             PARAMS ((FILE *, tree, const char *, int, int));
+#endif
+#ifdef BSS_SECTION_ASM_OP
+#ifdef ASM_OUTPUT_ALIGNED_BSS
+static void asm_output_aligned_bss     PARAMS ((FILE *, tree, const char *,
+                                                int, int));
+#endif
+#endif /* BSS_SECTION_ASM_OP */
+static void mark_pool_constant          PARAMS ((struct pool_constant *));
+static void mark_pool_sym_hash_table   PARAMS ((struct pool_sym **));
+static void mark_const_hash_entry      PARAMS ((void *));
+static void asm_emit_uninitialised     PARAMS ((tree, const char*, int, int));
 \f
 static enum in_section { no_section, in_text, in_data, in_named
 #ifdef BSS_SECTION_ASM_OP
@@ -179,10 +204,12 @@ static enum in_section { no_section, in_text, in_data, in_named
 } in_section = no_section;
 
 /* Return a non-zero value if DECL has a section attribute.  */
+#ifndef IN_NAMED_SECTION
 #define IN_NAMED_SECTION(DECL) \
   ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
    && DECL_SECTION_NAME (DECL) != NULL_TREE)
-
+#endif
+     
 /* Text of section name when in_section == in_named.  */
 static char *in_named_name;
 
@@ -198,11 +225,7 @@ text_section ()
 {
   if (in_section != in_text)
     {
-      if (output_bytecode)
-       bc_text ();
-      else
-       fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
-
+      fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
       in_section = in_text;
     }
 }
@@ -214,25 +237,29 @@ data_section ()
 {
   if (in_section != in_data)
     {
-      if (output_bytecode)
-       bc_data ();
-      else
+      if (flag_shared_data)
        {
-         if (flag_shared_data)
-           {
 #ifdef SHARED_SECTION_ASM_OP
-             fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
+         fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
 #else
-             fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
+         fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
 #endif
-           }
-         else
-           fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
        }
+      else
+       fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
 
       in_section = in_data;
     }
 }
+/* Tell assembler to ALWAYS switch to data section, in case
+   it's not sure where it it.  */
+
+void
+force_data_section ()
+{
+  in_section = no_section;
+  data_section ();
+}
 
 /* Tell assembler to switch to read-only data section.  This is normally
    the text section.  */
@@ -271,8 +298,8 @@ in_data_section ()
 void
 named_section (decl, name, reloc)
      tree decl;
-     char *name;
-     int reloc;
+     const char *name;
+     int reloc ATTRIBUTE_UNUSED;
 {
   if (decl != NULL_TREE
       && TREE_CODE_CLASS (TREE_CODE (decl)) != 'd')
@@ -291,8 +318,7 @@ named_section (decl, name, reloc)
       abort ();
 #endif
 
-      in_named_name = obstack_alloc (&permanent_obstack, strlen (name) + 1);
-      strcpy (in_named_name, name);
+      in_named_name = ggc_alloc_string (name, -1);
       in_section = in_named;
     }
 }
@@ -302,7 +328,8 @@ named_section (decl, name, reloc)
 #define UNIQUE_SECTION(DECL,RELOC)                             \
 do {                                                           \
   int len;                                                     \
-  char *name, *string;                                         \
+  const char *name;                                            \
+  char *string;                                                        \
                                                                \
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL));      \
   /* Strip off any encoding in name.  */                       \
@@ -329,17 +356,12 @@ 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
+      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);
-       }
+       fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
 
       in_section = in_bss;
     }
@@ -355,9 +377,9 @@ bss_section ()
 static void
 asm_output_bss (file, decl, name, size, rounded)
      FILE *file;
-     tree decl;
-     char *name;
-     int size, rounded;
+     tree decl ATTRIBUTE_UNUSED;
+     const char *name;
+     int size ATTRIBUTE_UNUSED, rounded;
 {
   ASM_GLOBALIZE_LABEL (file, name);
   bss_section ();
@@ -384,7 +406,7 @@ static void
 asm_output_aligned_bss (file, decl, name, size, align)
      FILE *file;
      tree decl;
-     char *name;
+     const char *name;
      int size, align;
 {
   ASM_GLOBALIZE_LABEL (file, name);
@@ -501,18 +523,10 @@ make_function_rtl (decl)
   char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   char *new_name = name;
 
-  if (output_bytecode)
-    {
-      if (DECL_RTL (decl) == 0)
-       DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
-      
-      /* Record that at least one function has been defined.  */
-      function_defined = 1;
-      return;
-    }
-
-  /* Rename a nested function to avoid conflicts.  */
+  /* Rename a nested function to avoid conflicts, unless it's a member of
+     a local class, in which case the class name is already unique.  */
   if (decl_function_context (decl) != 0
+      && ! TYPE_P (DECL_CONTEXT (decl))
       && DECL_INITIAL (decl) != 0
       && DECL_RTL (decl) == 0)
     {
@@ -520,7 +534,7 @@ make_function_rtl (decl)
 
       name = IDENTIFIER_POINTER (DECL_NAME (decl));
       ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
-      name = obstack_copy0 (saveable_obstack, label, strlen (label));
+      name = ggc_alloc_string (label, -1);
       var_labelno++;
     }
   else
@@ -531,18 +545,21 @@ make_function_rtl (decl)
          is not prefixed.  */
       if (flag_prefix_function_name)
         {
-          new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE + 1);
-          strcpy (new_name, CHKR_PREFIX);
-          strcpy (new_name + CHKR_PREFIX_SIZE, name);
-          name = obstack_copy0 (saveable_obstack, new_name, strlen (new_name));
+         size_t name_len = strlen (name);
+
+          new_name = ggc_alloc_string (NULL, name_len + CHKR_PREFIX_SIZE);
+         memcpy (new_name, CHKR_PREFIX, CHKR_PREFIX_SIZE);
+         memcpy (new_name + CHKR_PREFIX_SIZE, name, name_len + 1);
+          name = new_name;
         }
     }
 
   if (DECL_RTL (decl) == 0)
     {
+      DECL_ASSEMBLER_NAME (decl) = get_identifier (name);
       DECL_RTL (decl)
-       = gen_rtx (MEM, DECL_MODE (decl),
-                  gen_rtx (SYMBOL_REF, Pmode, name));
+       = gen_rtx_MEM (DECL_MODE (decl),
+                      gen_rtx_SYMBOL_REF (Pmode, name));
 
       /* Optionally set flags or add text to the name to record information
         such as that it is a function name.  If the name is changed, the macro
@@ -551,57 +568,27 @@ make_function_rtl (decl)
       ENCODE_SECTION_INFO (decl);
 #endif
     }
-
-  /* Record at least one function has been defined.  */
-  function_defined = 1;
-}
-
-/* Create the DECL_RTL for a declaration for a static or external
-   variable or static or external function.
-   ASMSPEC, if not 0, is the string which the user specified
-   as the assembler symbol name.
-   TOP_LEVEL is nonzero if this is a file-scope variable.
-   This is never called for PARM_DECLs.  */
-
-static void
-bc_make_decl_rtl (decl, asmspec, top_level)
-     tree decl;
-     char *asmspec;
-     int top_level;
-{
-  register char *name = TREE_STRING_POINTER (DECL_ASSEMBLER_NAME (decl));
-
-  if (DECL_RTL (decl) == 0)
+  else
     {
-      /* Print an error message for register variables.  */
-      if (DECL_REGISTER (decl))
-       error ("global register variables not supported in the interpreter");
-
-      /* Handle ordinary static variables and functions.  */
-      if (DECL_RTL (decl) == 0)
-       {
-         /* Can't use just the variable's own name for a variable
-            whose scope is less than the whole file.
-            Concatenate a distinguishing number.  */
-         if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0)
-           {
-             char *label;
-
-             ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
-             name = obstack_copy0 (saveable_obstack, label, strlen (label));
-             var_labelno++;
-           }
-
-         DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
-       }
+      /* ??? Another way to do this would be to do what halfpic.c does
+        and maintain a hashed table of such critters.  */
+      /* ??? Another way to do this would be to pass a flag bit to
+        ENCODE_SECTION_INFO saying whether this is a new decl or not.  */
+      /* Let the target reassign the RTL if it wants.
+        This is necessary, for example, when one machine specific
+        decl attribute overrides another.  */
+#ifdef REDO_SECTION_INFO_P
+      if (REDO_SECTION_INFO_P (decl))
+       ENCODE_SECTION_INFO (decl);
+#endif
     }
 }
 
 /* Given NAME, a putative register name, discard any customary prefixes.  */
 
-static char *
+static const char *
 strip_reg_name (name)
-     char *name;
+  const char *name;
 {
 #ifdef REGISTER_PREFIX
   if (!strncmp (name, REGISTER_PREFIX, strlen (REGISTER_PREFIX)))
@@ -622,7 +609,7 @@ strip_reg_name (name)
 
 int
 decode_reg_name (asmspec)
-     char *asmspec;
+  const char *asmspec;
 {
   if (asmspec != 0)
     {
@@ -651,10 +638,10 @@ decode_reg_name (asmspec)
 
 #ifdef ADDITIONAL_REGISTER_NAMES
       {
-       static struct { char *name; int number; } table[]
+       static struct { const char *name; int number; } table[]
          = ADDITIONAL_REGISTER_NAMES;
 
-       for (i = 0; i < sizeof (table) / sizeof (table[0]); i++)
+       for (i = 0; i < (int)(sizeof (table) / sizeof (table[0])); i++)
          if (! strcmp (asmspec, table[i].name))
            return table[i].number;
       }
@@ -683,18 +670,12 @@ decode_reg_name (asmspec)
 void
 make_decl_rtl (decl, asmspec, top_level)
      tree decl;
-     char *asmspec;
+     const char *asmspec;
      int top_level;
 {
   register char *name = 0;
   int reg_number;
 
-  if (output_bytecode)
-    {
-      bc_make_decl_rtl (decl, asmspec, top_level);
-      return;
-    }
-
   reg_number = decode_reg_name (asmspec);
 
   if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)
@@ -703,18 +684,17 @@ make_decl_rtl (decl, asmspec, top_level)
   if (reg_number == -2)
     {
       /* ASMSPEC is given, and not the name of a register.  */
-      name = (char *) obstack_alloc (saveable_obstack,
-                                    strlen (asmspec) + 2);
+      size_t len = strlen (asmspec);
+
+      name = ggc_alloc_string (NULL, len + 1);
       name[0] = '*';
-      strcpy (&name[1], asmspec);
+      memcpy (&name[1], asmspec, len + 1);
     }
 
   /* For a duplicate declaration, we can be called twice on the
      same DECL node.  Don't discard the RTL already made.  */
   if (DECL_RTL (decl) == 0)
     {
-      DECL_RTL (decl) = 0;
-
       /* First detect errors in declaring global registers.  */
       if (TREE_CODE (decl) != FUNCTION_DECL
          && DECL_REGISTER (decl) && reg_number == -1)
@@ -749,9 +729,6 @@ make_decl_rtl (decl, asmspec, top_level)
              DECL_INITIAL (decl) = 0;
              error ("global register variable has initial value");
            }
-         if (fixed_regs[reg_number] == 0
-             && function_defined && top_level)
-           error ("global register variable follows a function definition");
          if (TREE_THIS_VOLATILE (decl))
            warning ("volatile register variables don't work as you might wish");
 
@@ -762,7 +739,7 @@ make_decl_rtl (decl, asmspec, top_level)
             kludge to avoid setting DECL_RTL to frame_pointer_rtx.  */
 
          DECL_RTL (decl)
-           = gen_rtx (REG, DECL_MODE (decl), FIRST_PSEUDO_REGISTER);
+           = gen_rtx_REG (DECL_MODE (decl), FIRST_PSEUDO_REGISTER);
          REGNO (DECL_RTL (decl)) = reg_number;
          REG_USERVAR_P (DECL_RTL (decl)) = 1;
 
@@ -770,6 +747,9 @@ make_decl_rtl (decl, asmspec, top_level)
            {
              /* Make this register global, so not usable for anything
                 else.  */
+#ifdef ASM_DECLARE_REGISTER_GLOBAL
+             ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name);
+#endif
              nregs = HARD_REGNO_NREGS (reg_number, DECL_MODE (decl));
              while (nregs > 0)
                globalize_reg (reg_number + --nregs);
@@ -788,14 +768,17 @@ make_decl_rtl (decl, asmspec, top_level)
       if (DECL_RTL (decl) == 0)
        {
          /* Can't use just the variable's own name for a variable
-            whose scope is less than the whole file.
+            whose scope is less than the whole file, unless it's a member
+            of a local class (which will already be unambiguous).
             Concatenate a distinguishing number.  */
-         if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0)
+         if (!top_level && !TREE_PUBLIC (decl)
+             && ! (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
+             && asmspec == 0)
            {
              char *label;
 
              ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
-             name = obstack_copy0 (saveable_obstack, label, strlen (label));
+             name = ggc_alloc_string (label, -1);
              var_labelno++;
            }
 
@@ -807,17 +790,20 @@ make_decl_rtl (decl, asmspec, top_level)
             prefixed.  */
          if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL)
            {
+             size_t name_len = strlen (name);
              char *new_name;
-             new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE 
-                                         + 1);
-             strcpy (new_name, CHKR_PREFIX);
-             strcpy (new_name + CHKR_PREFIX_SIZE, name);
-             name = obstack_copy0 (saveable_obstack,
-                                  new_name, strlen (new_name));
+
+             new_name = ggc_alloc_string (NULL, name_len + CHKR_PREFIX_SIZE);
+             memcpy (new_name, CHKR_PREFIX, CHKR_PREFIX_SIZE);
+             memcpy (new_name + CHKR_PREFIX_SIZE, name, name_len + 1);
+             name = new_name;
            }
 
-         DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl),
-                                    gen_rtx (SYMBOL_REF, Pmode, name));
+         DECL_ASSEMBLER_NAME (decl)
+           = get_identifier (name[0] == '*' ? name + 1 : name);
+         DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl),
+                                        gen_rtx_SYMBOL_REF (Pmode, name));
+         MEM_ALIAS_SET (DECL_RTL (decl)) = get_alias_set (decl);
 
          /* If this variable is to be treated as volatile, show its
             tree node has side effects.  If it has side effects, either
@@ -826,13 +812,17 @@ make_decl_rtl (decl, asmspec, top_level)
          if (flag_volatile_global && TREE_CODE (decl) == VAR_DECL
              && TREE_PUBLIC (decl))
            TREE_SIDE_EFFECTS (decl) = 1;
+         else if (flag_volatile_static && TREE_CODE (decl) == VAR_DECL
+              && (TREE_PUBLIC (decl) || TREE_STATIC (decl)))
+           TREE_SIDE_EFFECTS (decl) = 1;
+
          if (TREE_SIDE_EFFECTS (decl))
            MEM_VOLATILE_P (DECL_RTL (decl)) = 1;
 
          if (TREE_READONLY (decl))
            RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;
-         MEM_IN_STRUCT_P (DECL_RTL (decl))
-           = AGGREGATE_TYPE_P (TREE_TYPE (decl));
+         MEM_SET_IN_STRUCT_P (DECL_RTL (decl),
+                              AGGREGATE_TYPE_P (TREE_TYPE (decl)));
 
          /* Optionally set flags or add text to the name to record information
             such as that it is a function name.
@@ -843,11 +833,26 @@ make_decl_rtl (decl, asmspec, top_level)
 #endif
        }
     }
-  /* If the old RTL had the wrong mode, fix the mode.  */
-  else if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
+  else
     {
-      rtx rtl = DECL_RTL (decl);
-      PUT_MODE (rtl, DECL_MODE (decl));
+      /* If the old RTL had the wrong mode, fix the mode.  */
+      if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
+       {
+         rtx rtl = DECL_RTL (decl);
+         PUT_MODE (rtl, DECL_MODE (decl));
+       }
+
+      /* ??? Another way to do this would be to do what halfpic.c does
+        and maintain a hashed table of such critters.  */
+      /* ??? Another way to do this would be to pass a flag bit to
+        ENCODE_SECTION_INFO saying whether this is a new decl or not.  */
+      /* Let the target reassign the RTL if it wants.
+        This is necessary, for example, when one machine specific
+        decl attribute overrides another.  */
+#ifdef REDO_SECTION_INFO_P
+      if (REDO_SECTION_INFO_P (decl))
+       ENCODE_SECTION_INFO (decl);
+#endif
     }
 }
 
@@ -889,12 +894,6 @@ void
 assemble_asm (string)
      tree string;
 {
-  if (output_bytecode)
-    {
-      error ("asm statements not allowed in interpreter");
-      return;
-    }
-
   app_enable ();
 
   if (TREE_CODE (string) == ADDR_EXPR)
@@ -926,7 +925,7 @@ assemble_asm (string)
 
 void
 assemble_destructor (name)
-     char *name;
+     const char *name;
 {
 #ifdef ASM_OUTPUT_DESTRUCTOR
   ASM_OUTPUT_DESTRUCTOR (asm_out_file, name);
@@ -946,7 +945,7 @@ assemble_destructor (name)
 
 void
 assemble_constructor (name)
-     char *name;
+     const char *name;
 {
 #ifdef ASM_OUTPUT_CONSTRUCTOR
   ASM_OUTPUT_CONSTRUCTOR (asm_out_file, name);
@@ -967,7 +966,7 @@ assemble_constructor (name)
 
 void
 assemble_gc_entry (name)
-     char *name;
+     const char *name;
 {
 #ifdef ASM_OUTPUT_GC_ENTRY
   ASM_OUTPUT_GC_ENTRY (asm_out_file, name);
@@ -1000,7 +999,7 @@ assemble_gc_entry (name)
 void
 assemble_start_function (decl, fnname)
      tree decl;
-     char *fnname;
+     const char *fnname;
 {
   int align;
 
@@ -1025,11 +1024,19 @@ assemble_start_function (decl, fnname)
   /* Tell assembler to move to target machine's alignment for functions.  */
   align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
   if (align > 0)
+    ASM_OUTPUT_ALIGN (asm_out_file, align);
+
+  /* Handle a user-specified function alignment.
+     Note that we still need to align to FUNCTION_BOUNDARY, as above,
+     because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all.  */
+  if (align_functions_log > align)
     {
-      if (output_bytecode)
-       BC_OUTPUT_ALIGN (asm_out_file, align);
-      else
-       ASM_OUTPUT_ALIGN (asm_out_file, align);
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
+      ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file, 
+                                align_functions_log, align_functions-1);
+#else
+      ASM_OUTPUT_ALIGN (asm_out_file, align_functions_log);
+#endif
     }
 
 #ifdef ASM_OUTPUT_FUNCTION_PREFIX
@@ -1052,39 +1059,42 @@ assemble_start_function (decl, fnname)
 
   if (TREE_PUBLIC (decl))
     {
-      if (!first_global_object_name && ! DECL_WEAK (decl)
-         && ! DECL_ONE_ONLY (decl))
+      if (! first_global_object_name)
        {
-         char *p;
+         const char *p;
+         char **name;
+
+         if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
+           name = &first_global_object_name;
+         else
+           name = &weak_global_object_name;
 
          STRIP_NAME_ENCODING (p, fnname);
-         first_global_object_name = permalloc (strlen (p) + 1);
-         strcpy (first_global_object_name, p);
+         *name = permalloc (strlen (p) + 1);
+         strcpy (*name, p);
        }
 
 #ifdef ASM_WEAKEN_LABEL
       if (DECL_WEAK (decl))
-       ASM_WEAKEN_LABEL (asm_out_file, fnname);
+       {
+         ASM_WEAKEN_LABEL (asm_out_file, fnname);
+         /* Remove this function from the pending weak list so that
+            we do not emit multiple .weak directives for it.  */
+         remove_from_pending_weak_list
+           (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+       }
       else
 #endif
-      if (output_bytecode)
-       BC_GLOBALIZE_LABEL (asm_out_file, fnname);
-      else
-       ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
+      ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
     }
 
   /* Do any machine/system dependent processing of the function name */
-  if (output_bytecode)
-    BC_OUTPUT_LABEL (asm_out_file, fnname);
-  else
-    {
 #ifdef ASM_DECLARE_FUNCTION_NAME
-      ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
+  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);
+  /* 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
@@ -1093,7 +1103,7 @@ assemble_start_function (decl, fnname)
 void
 assemble_end_function (decl, fnname)
      tree decl;
-     char *fnname;
+     const char *fnname;
 {
 #ifdef ASM_DECLARE_FUNCTION_SIZE
   ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
@@ -1114,11 +1124,9 @@ void
 assemble_zeros (size)
      int size;
 {
-  if (output_bytecode)
-    {
-      bc_emit_const_skip (size);
-      return;
-    }
+  /* Do no output if -fsyntax-only.  */
+  if (flag_syntax_only)
+    return;
 
 #ifdef ASM_NO_SKIP_IN_TEXT
   /* The `space' pseudo in the text section outputs nop insns rather than 0s,
@@ -1153,12 +1161,7 @@ assemble_zeros (size)
   else
 #endif
     if (size > 0)
-      {
-       if (output_bytecode)
-         BC_OUTPUT_SKIP (asm_out_file, size);
-       else
-         ASM_OUTPUT_SKIP (asm_out_file, size);
-      }
+      ASM_OUTPUT_SKIP (asm_out_file, size);
 }
 
 /* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
@@ -1175,19 +1178,12 @@ assemble_align (align)
 
 void
 assemble_string (p, size)
-     char *p;
+     const char *p;
      int size;
 {
-  register int i;
   int pos = 0;
   int maximum = 2000;
 
-  if (output_bytecode)
-    {
-      bc_emit (p, size);
-      return;
-    }
-
   /* If the string is very long, split it up.  */
 
   while (pos < size)
@@ -1196,27 +1192,127 @@ assemble_string (p, size)
       if (thissize > maximum)
        thissize = maximum;
 
-      if (output_bytecode)
-       bc_output_ascii (asm_out_file, p, thissize);
-      else
-       {
-         ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
-       }
+      ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
 
       pos += thissize;
       p += thissize;
     }
 }
 
+\f
+#if defined  ASM_OUTPUT_ALIGNED_DECL_LOCAL
+#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
+  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, DECL_ALIGN (decl))
+#else
+#if defined  ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
+  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl))
+#else
+#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
+  ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded)
+#endif
+#endif
+
+#if defined ASM_OUTPUT_ALIGNED_BSS
+#define ASM_EMIT_BSS(decl, name, size, rounded) \
+  ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl))
+#else
+#if defined ASM_OUTPUT_BSS
+#define ASM_EMIT_BSS(decl, name, size, rounded) \
+  ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded)
+#else
+#undef  ASM_EMIT_BSS
+#endif
+#endif
+
+#if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
+#define ASM_EMIT_COMMON(decl, name, size, rounded) \
+  ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, DECL_ALIGN (decl))
+#else
+#if defined ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_EMIT_COMMON(decl, name, size, rounded) \
+  ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl))
+#else
+#define ASM_EMIT_COMMON(decl, name, size, rounded) \
+  ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded)
+#endif
+#endif
+
 static void
-bc_output_ascii (file, p, size)
-     FILE *file;
-     char *p;
-     int size;
+asm_emit_uninitialised (decl, name, size, rounded)
+     tree decl;
+     const char * name;
+     int size ATTRIBUTE_UNUSED;
+     int rounded ATTRIBUTE_UNUSED;
 {
-  BC_OUTPUT_ASCII (file, p, size);
+  enum
+  {
+    asm_dest_common,
+    asm_dest_bss,
+    asm_dest_local
+  }
+  destination = asm_dest_local;
+  
+  if (TREE_PUBLIC (decl))
+    {
+#if defined ASM_EMIT_BSS
+      if (! DECL_COMMON (decl))
+       destination = asm_dest_bss;
+      else
+#endif      
+       destination = asm_dest_common;
+    }
+
+  if (flag_shared_data)
+    {
+      switch (destination)
+       {
+#ifdef ASM_OUTPUT_SHARED_BSS
+       case asm_dest_bss:
+         ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded);
+         return;
+#endif
+#ifdef ASM_OUTPUT_SHARED_COMMON
+       case asm_dest_common:
+         ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
+         return;
+#endif
+#ifdef ASM_OUTPUT_SHARED_LOCAL
+       case asm_dest_local:
+         ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
+         return;
+#endif
+       default:
+         break;
+       }
+    }
+
+#ifdef ASM_OUTPUT_SECTION_NAME
+  /* We already know that DECL_SECTION_NAME() == NULL.  */
+  if (flag_data_sections != 0 || UNIQUE_SECTION_P (decl))
+    UNIQUE_SECTION (decl, NULL);
+#endif
+  
+  switch (destination)
+    {
+#ifdef ASM_EMIT_BSS
+    case asm_dest_bss:
+      ASM_EMIT_BSS (decl, name, size, rounded);
+      break;
+#endif
+    case asm_dest_common:
+      ASM_EMIT_COMMON (decl, name, size, rounded);
+      break;
+    case asm_dest_local:
+      ASM_EMIT_LOCAL (decl, name, size, rounded);
+      break;
+    default:
+      abort ();
+    }
+
+  return;
 }
-\f
+
 /* Assemble everything that is needed for a variable or function declaration.
    Not used for automatic variables, and not used for function definitions.
    Should not be called for variables of incomplete structure type.
@@ -1230,21 +1326,18 @@ bc_output_ascii (file, p, size)
 void
 assemble_variable (decl, top_level, at_end, dont_output_data)
      tree decl;
-     int top_level;
-     int at_end;
+     int top_level ATTRIBUTE_UNUSED;
+     int at_end ATTRIBUTE_UNUSED;
      int dont_output_data;
 {
-  register char *name;
-  int align;
-  tree size_tree;
+  register const char *name;
+  unsigned int align;
+  tree size_tree = NULL_TREE;
   int reloc = 0;
   enum in_section saved_in_section;
 
   last_assemble_variable_decl = 0;
 
-  if (output_bytecode)
-    return;
-
   if (GET_CODE (DECL_RTL (decl)) == REG)
     {
       /* Do output symbol info for global register variables, but do nothing
@@ -1254,22 +1347,23 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
        return;
       TREE_ASM_WRITTEN (decl) = 1;
 
-      if (!output_bytecode)
-       {
+      /* Do no output if -fsyntax-only.  */
+      if (flag_syntax_only)
+       return;
+
 #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
-         /* File-scope global variables are output here.  */
-         if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
-             && top_level)
-           dbxout_symbol (decl, 0);
+      /* File-scope global variables are output here.  */
+      if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
+          && top_level)
+       dbxout_symbol (decl, 0);
 #endif
 #ifdef SDB_DEBUGGING_INFO
-         if (write_symbols == SDB_DEBUG && top_level
-             /* Leave initialized global vars for end of compilation;
-                see comment in compile_file.  */
-             && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
-           sdbout_symbol (decl, 0);
+      if (write_symbols == SDB_DEBUG && top_level
+         /* Leave initialized global vars for end of compilation;
+            see comment in compile_file.  */
+         && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
+       sdbout_symbol (decl, 0);
 #endif
-       }
 
       /* Don't output any DWARF debugging information for variables here.
         In the case of local variables, the information for them is output
@@ -1324,22 +1418,23 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   TREE_ASM_WRITTEN (decl) = 1;
 
+  /* Do no output if -fsyntax-only.  */
+  if (flag_syntax_only)
+    return;
+
   app_disable ();
 
   if (! dont_output_data)
     {
-      int size;
+      unsigned int size;
 
-      if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+      if (TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST)
        goto finish;
 
-      /* 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));
-
+      size_tree = DECL_SIZE_UNIT (decl);
       size = TREE_INT_CST_LOW (size_tree);
-      if (TREE_INT_CST_HIGH (size_tree) != 0
-         || size != TREE_INT_CST_LOW (size_tree))
+
+      if (compare_tree_int (size_tree, size) != 0)
        {
          error_with_decl (decl, "size of variable `%s' is too large");
          goto finish;
@@ -1347,7 +1442,6 @@ 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
@@ -1355,21 +1449,59 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       && ! DECL_WEAK (decl)
       && ! DECL_ONE_ONLY (decl))
     {
-      char *p;
+      const char *p;
 
       STRIP_NAME_ENCODING (p, name);
       first_global_object_name = permalloc (strlen (p) + 1);
       strcpy (first_global_object_name, p);
     }
 
+  /* Compute the alignment of this data.  */
+
+  align = DECL_ALIGN (decl);
+
+  /* In the case for initialing an array whose length isn't specified,
+     where we have not yet been able to do the layout,
+     figure out the proper alignment now.  */
+  if (dont_output_data && DECL_SIZE (decl) == 0
+      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+    align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
+
+  /* Some object file formats have a maximum alignment which they support.
+     In particular, a.out format supports a maximum alignment of 4.  */
+#ifndef MAX_OFILE_ALIGNMENT
+#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
+#endif
+  if (align > MAX_OFILE_ALIGNMENT)
+    {
+      warning_with_decl (decl,
+       "alignment of `%s' is greater than maximum object file alignment. Using %d.",
+                    MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
+      align = MAX_OFILE_ALIGNMENT;
+    }
+
+  /* On some machines, it is good to increase alignment sometimes.  */
+#ifdef DATA_ALIGNMENT
+  align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
+#endif
+#ifdef CONSTANT_ALIGNMENT
+  if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
+    align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
+#endif
+
+  /* Reset the alignment in case we have made it tighter, so we can benefit
+     from it in get_pointer_alignment.  */
+  DECL_ALIGN (decl) = align;
+
   /* Handle uninitialized definitions.  */
 
   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)
+#if ! defined ASM_EMIT_BSS
       && DECL_COMMON (decl)
 #endif
+      && DECL_SECTION_NAME (decl) == NULL_TREE
       && ! dont_output_data)
     {
       int size = TREE_INT_CST_LOW (size_tree);
@@ -1383,7 +1515,13 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
       rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
                 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-
+      
+#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
+      if ((DECL_ALIGN (decl) / BITS_PER_UNIT) > (unsigned int) rounded)
+         warning_with_decl 
+           (decl, "requested alignment for %s is greater than implemented alignment of %d.",rounded);
+#endif
+       
 #ifdef DBX_DEBUGGING_INFO
       /* File-scope global variables are output here.  */
       if (write_symbols == DBX_DEBUG && top_level)
@@ -1410,86 +1548,8 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
       if (flag_shared_data)
        data_section ();
 #endif
+      asm_emit_uninitialised (decl, name, size, rounded);
 
-      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)
-           ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
-         else
-#endif
-           if (output_bytecode)
-             {
-               BC_OUTPUT_COMMON (asm_out_file, name, size, rounded);
-             }
-           else
-             {
-#ifdef ASM_OUTPUT_ALIGNED_DECL_COMMON
-               ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size,
-                                                  DECL_ALIGN (decl));
-#else
-#ifdef ASM_OUTPUT_ALIGNED_COMMON
-               ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
-                                          DECL_ALIGN (decl));
-#else
-               ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
-#endif
-#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
-         if (flag_shared_data)
-           ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
-         else
-#endif
-           if (output_bytecode)
-             {
-               BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
-             }
-           else
-             {
-#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
-               ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size,
-                                                 DECL_ALIGN (decl));
-#else
-#ifdef ASM_OUTPUT_ALIGNED_LOCAL
-               ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
-                                         DECL_ALIGN (decl));
-#else
-               ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
-#endif
-#endif
-             }
-       }
       goto finish;
     }
 
@@ -1501,8 +1561,14 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     {
 #ifdef ASM_WEAKEN_LABEL
-      if (DECL_WEAK (decl))
-       ASM_WEAKEN_LABEL (asm_out_file, name);
+      if (DECL_WEAK (decl)) 
+       {
+         ASM_WEAKEN_LABEL (asm_out_file, name);
+          /* Remove this variable from the pending weak list so that
+             we do not emit multiple .weak directives for it.  */
+         remove_from_pending_weak_list
+           (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+       }
       else
 #endif
       ASM_GLOBALIZE_LABEL (asm_out_file, name);
@@ -1524,7 +1590,8 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
     reloc = output_addressed_constants (DECL_INITIAL (decl));
 
 #ifdef ASM_OUTPUT_SECTION_NAME
-  if (UNIQUE_SECTION_P (decl))
+  if ((flag_data_sections != 0 && DECL_SECTION_NAME (decl) == NULL_TREE)
+      || UNIQUE_SECTION_P (decl))
     UNIQUE_SECTION (decl, reloc);
 #endif
 
@@ -1566,61 +1633,19 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   if (in_section != saved_in_section)
     variable_section (decl, reloc);
 
-  /* Compute and output the alignment of this data.  */
-
-  align = DECL_ALIGN (decl);
-  /* In the case for initialing an array whose length isn't specified,
-     where we have not yet been able to do the layout,
-     figure out the proper alignment now.  */
-  if (dont_output_data && DECL_SIZE (decl) == 0
-      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
-    align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
-
-  /* Some object file formats have a maximum alignment which they support.
-     In particular, a.out format supports a maximum alignment of 4.  */
-#ifndef MAX_OFILE_ALIGNMENT
-#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
-#endif
-  if (align > MAX_OFILE_ALIGNMENT)
-    {
-      warning_with_decl (decl,
-         "alignment of `%s' is greater than maximum object file alignment");
-      align = MAX_OFILE_ALIGNMENT;
-    }
-#ifdef DATA_ALIGNMENT
-  /* On some machines, it is good to increase alignment sometimes.  */
-  align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
-#endif
-#ifdef CONSTANT_ALIGNMENT
-  if (DECL_INITIAL (decl))
-    align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
-#endif
-
-  /* Reset the alignment in case we have made it tighter, so we can benefit
-     from it in get_pointer_alignment.  */
-  DECL_ALIGN (decl) = align;
-
+  /* Output the alignment of this data.  */
   if (align > BITS_PER_UNIT)
-    {
-      if (output_bytecode)
-       BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
-      else
-       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
-    }
+    ASM_OUTPUT_ALIGN (asm_out_file,
+                     floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));
 
   /* Do any machine/system dependent processing of the object.  */
-  if (output_bytecode)
-    BC_OUTPUT_LABEL (asm_out_file, name);
-  else
-    {
 #ifdef ASM_DECLARE_OBJECT_NAME
-      last_assemble_variable_decl = decl;
-      ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
+  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);
+  /* 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)
     {
@@ -1693,66 +1718,14 @@ contains_pointers_p (type)
     }
 }
 
-/* Output text storage for constructor CONSTR.  */
-
-void
-bc_output_constructor (constr, size)
-     tree constr;
-     int size;
-{
-  int i;
-
-  /* Must always be a literal; non-literal constructors are handled
-     differently.  */
-
-  if (!TREE_CONSTANT (constr))
-    abort ();
-
-  /* Always const */
-  text_section ();
-
-  /* Align */
-  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, size);
-}
-
-/* Create storage for constructor CONSTR.  */
-
-void
-bc_output_data_constructor (constr)
-    tree constr;
-{
-  int i;
-
-  /* Put in data section */
-  data_section ();
-
-  /* Align */
-  for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++);
-  if (i > 0)
-    BC_OUTPUT_ALIGN (asm_out_file, i);
-
-  /* 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.  */
 
 void
 assemble_external (decl)
-     tree decl;
+     tree decl ATTRIBUTE_UNUSED;
 {
-  if (output_bytecode)
-    return;
-
 #ifdef ASM_OUTPUT_EXTERNAL
   if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
       && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
@@ -1774,17 +1747,14 @@ assemble_external (decl)
 
 void
 assemble_external_libcall (fun)
-     rtx fun;
+     rtx fun ATTRIBUTE_UNUSED;
 {
 #ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
-  if (!output_bytecode)
+  /* Declare library function name external when first used, if nec.  */
+  if (! SYMBOL_REF_USED (fun))
     {
-      /* Declare library function name external when first used, if nec.  */
-      if (! SYMBOL_REF_USED (fun))
-       {
-         SYMBOL_REF_USED (fun) = 1;
-         ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
-       }
+      SYMBOL_REF_USED (fun) = 1;
+      ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
     }
 #endif
 }
@@ -1793,7 +1763,7 @@ assemble_external_libcall (fun)
 
 void
 assemble_global (name)
-     char *name;
+     const char *name;
 {
   ASM_GLOBALIZE_LABEL (asm_out_file, name);
 }
@@ -1802,12 +1772,9 @@ assemble_global (name)
 
 void
 assemble_label (name)
-     char *name;
+     const char *name;
 {
-  if (output_bytecode)
-    BC_OUTPUT_LABEL (asm_out_file, name);
-  else
-    ASM_OUTPUT_LABEL (asm_out_file, name);
+  ASM_OUTPUT_LABEL (asm_out_file, name);
 }
 
 /* Output to FILE a reference to the assembler name of a C-level name NAME.
@@ -1819,9 +1786,9 @@ assemble_label (name)
 void
 assemble_name (file, name)
      FILE *file;
-     char *name;
+     const char *name;
 {
-  char *real_name;
+  const char *real_name;
   tree id;
 
   STRIP_NAME_ENCODING (real_name, name);
@@ -1834,19 +1801,9 @@ assemble_name (file, name)
     TREE_SYMBOL_REFERENCED (id) = 1;
 
   if (name[0] == '*')
-    {
-      if (output_bytecode)
-       bc_emit_labelref (name, 0);
-      else
-       fputs (&name[1], file);
-    }
+    fputs (&name[1], file);
   else
-    {
-      if (output_bytecode)
-       BC_OUTPUT_LABELREF (file, name);
-      else
-       ASM_OUTPUT_LABELREF (file, name);
-    }
+    ASM_OUTPUT_LABELREF (file, name);
 }
 
 /* Allocate SIZE bytes writable static space with a gensym name
@@ -1859,11 +1816,6 @@ assemble_static_space (size)
   char name[12];
   char *namestring;
   rtx x;
-  /* Round size up to multiple of BIGGEST_ALIGNMENT bits
-     so that each uninitialized object starts on such a boundary.  */
-  int rounded = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
-                / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-                * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
 
 #if 0
   if (flag_shared_data)
@@ -1872,33 +1824,29 @@ assemble_static_space (size)
 
   ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
   ++const_labelno;
+  namestring = ggc_alloc_string (name, -1);
 
-  namestring = (char *) obstack_alloc (saveable_obstack,
-                                      strlen (name) + 2);
-  strcpy (namestring, name);
+  x = gen_rtx_SYMBOL_REF (Pmode, namestring);
 
-  if (output_bytecode)
-    x = bc_gen_rtx (namestring, 0, (struct bc_label *) 0);
-  else
-    x = gen_rtx (SYMBOL_REF, Pmode, namestring);
-
-  if (output_bytecode)
-    {
-      BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
-    }
-  else
-    {
 #ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
-      ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
-                                 BIGGEST_ALIGNMENT);
+  ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
+                                BIGGEST_ALIGNMENT);
 #else
 #ifdef ASM_OUTPUT_ALIGNED_LOCAL
-      ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
+  ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
 #else
-      ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+  {
+    /* Round size up to multiple of BIGGEST_ALIGNMENT bits
+       so that each uninitialized object starts on such a boundary.  */
+    /* Variable `rounded' might or might not be used in ASM_OUTPUT_LOCAL. */
+    int rounded ATTRIBUTE_UNUSED
+      = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
+        / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+        * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+    ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+  }
 #endif
 #endif
-    }
   return x;
 }
 
@@ -1914,10 +1862,6 @@ assemble_trampoline_template ()
   char *name;
   int align;
 
-  /* Shouldn't get here */
-  if (output_bytecode)
-    abort ();
-
   /* By default, put trampoline templates in read-only data section.  */
 
 #ifdef TRAMPOLINE_SECTION
@@ -1936,9 +1880,8 @@ assemble_trampoline_template ()
 
   /* Record the rtl to refer to it.  */
   ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
-  name
-    = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
-  return gen_rtx (SYMBOL_REF, Pmode, name);
+  name = ggc_alloc_string (label, -1);
+  return gen_rtx_SYMBOL_REF (Pmode, name);
 }
 #endif
 \f
@@ -2105,17 +2048,6 @@ assemble_real (d, mode)
 /* Here we combine duplicate floating constants to make
    CONST_DOUBLE rtx's, and force those out to memory when necessary.  */
 
-/* Chain of all CONST_DOUBLE rtx's constructed for the current function.
-   They are chained through the CONST_DOUBLE_CHAIN.
-   A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain.
-   In that case, CONST_DOUBLE_MEM is either a MEM,
-   or const0_rtx if no MEM has been made for this CONST_DOUBLE yet.
-
-   (CONST_DOUBLE_MEM is used only for top-level functions.
-   See force_const_mem for explanation.)  */
-
-static rtx const_double_chain;
-
 /* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair of ints.
    For an integer, I0 is the low-order word and I1 is the high-order word.
    For a real number, I0 is the word with the low address
@@ -2127,7 +2059,6 @@ immed_double_const (i0, i1, mode)
      enum machine_mode mode;
 {
   register rtx r;
-  int in_current_obstack;
 
   if (GET_MODE_CLASS (mode) == MODE_INT
       || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
@@ -2178,7 +2109,7 @@ immed_double_const (i0, i1, mode)
         is being broken.  */
 
       if (width <= HOST_BITS_PER_WIDE_INT)
-       i1 = (i0 < 0) ? ~0 : 0;
+       i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0;
 
       /* If this integer fits in one word, return a CONST_INT.  */
       if ((i1 == 0 && i0 >= 0)
@@ -2191,11 +2122,11 @@ immed_double_const (i0, i1, mode)
 
   /* Search the chain for an existing CONST_DOUBLE with the right value.
      If one is found, return it.  */
-
-  for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
-    if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1
-       && GET_MODE (r) == mode)
-      return r;
+  if (cfun != 0)
+    for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
+      if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1
+         && GET_MODE (r) == mode)
+       return r;
 
   /* No; make a new one and add it to the chain.
 
@@ -2207,12 +2138,11 @@ immed_double_const (i0, i1, mode)
 
   push_obstacks_nochange ();
   rtl_in_saveable_obstack ();
-  r = gen_rtx (CONST_DOUBLE, mode, NULL_RTX, i0, i1);
+  r = gen_rtx_CONST_DOUBLE (mode, NULL_RTX, i0, i1);
   pop_obstacks ();
 
-  /* Don't touch const_double_chain in nested function; see force_const_mem.
-     Also, don't touch it if not inside any function.  */
-  if (outer_function_chain == 0 && current_function_decl != 0)
+  /* Don't touch const_double_chain if not inside any function.  */
+  if (current_function_decl != 0)
     {
       CONST_DOUBLE_CHAIN (r) = const_double_chain;
       const_double_chain = r;
@@ -2236,7 +2166,6 @@ immed_real_const_1 (d, mode)
 {
   union real_extract u;
   register rtx r;
-  int in_current_obstack;
 
   /* Get the desired `double' value as a sequence of ints
      since that is how they are stored in a CONST_DOUBLE.  */
@@ -2254,6 +2183,8 @@ immed_real_const_1 (d, mode)
   else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
     return CONST1_RTX (mode);
 
+  if (sizeof u == sizeof (HOST_WIDE_INT))
+    return immed_double_const (u.i[0], 0, mode);
   if (sizeof u == 2 * sizeof (HOST_WIDE_INT))
     return immed_double_const (u.i[0], u.i[1], mode);
 
@@ -2263,11 +2194,11 @@ immed_real_const_1 (d, mode)
 
   /* Search the chain for an existing CONST_DOUBLE with the right value.
      If one is found, return it.  */
-
-  for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
-    if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
-       && GET_MODE (r) == mode)
-      return r;
+  if (cfun != 0)
+    for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
+      if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
+         && GET_MODE (r) == mode)
+       return r;
 
   /* No; make a new one and add it to the chain.
 
@@ -2276,17 +2207,15 @@ immed_real_const_1 (d, mode)
      we will be leaving this constant on the chain, so we cannot tolerate
      freed memory.  So switch to saveable_obstack for this allocation
      and then switch back if we were in current_obstack.  */
-
   push_obstacks_nochange ();
   rtl_in_saveable_obstack ();
   r = rtx_alloc (CONST_DOUBLE);
+  pop_obstacks ();
   PUT_MODE (r, mode);
   bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (r), sizeof u);
-  pop_obstacks ();
 
-  /* Don't touch const_double_chain in nested function; see force_const_mem.
-     Also, don't touch it if not inside any function.  */
-  if (outer_function_chain == 0 && current_function_decl != 0)
+  /* Don't touch const_double_chain if not inside any function.  */
+  if (current_function_decl != 0)
     {
       CONST_DOUBLE_CHAIN (r) = const_double_chain;
       const_double_chain = r;
@@ -2320,11 +2249,6 @@ clear_const_double_mem ()
 {
   register rtx r, next;
 
-  /* Don't touch CONST_DOUBLE_MEM for nested functions.
-     See force_const_mem for explanation.  */
-  if (outer_function_chain != 0)
-    return;
-
   for (r = const_double_chain; r; r = next)
     {
       next = CONST_DOUBLE_CHAIN (r);
@@ -2385,13 +2309,9 @@ decode_addr_const (exp, value)
       break;
 
     case LABEL_DECL:
-      if (output_bytecode)
-       /* FIXME: this may not be correct, check it */
-       x = bc_gen_rtx (TREE_STRING_POINTER (target), 0, (struct bc_label *) 0);
-      else
-       x = gen_rtx (MEM, FUNCTION_MODE,
-                    gen_rtx (LABEL_REF, VOIDmode,
-                             label_rtx (TREE_OPERAND (exp, 0))));
+      x = gen_rtx_MEM (FUNCTION_MODE,
+                      gen_rtx_LABEL_REF (VOIDmode,
+                                         label_rtx (TREE_OPERAND (exp, 0))));
       break;
 
     case REAL_CST:
@@ -2406,12 +2326,9 @@ decode_addr_const (exp, value)
       abort ();
     }
 
-  if (!output_bytecode)
-    {
-      if (GET_CODE (x) != MEM)
-       abort ();
-      x = XEXP (x, 0);
-    }
+  if (GET_CODE (x) != MEM)
+    abort ();
+  x = XEXP (x, 0);
 
   value->base = x;
   value->offset = offset;
@@ -2430,6 +2347,7 @@ struct constant_descriptor
 {
   struct constant_descriptor *next;
   char *label;
+  rtx rtl;
   char contents[1];
 };
 
@@ -2437,13 +2355,29 @@ struct constant_descriptor
 #define MAX_HASH_TABLE 1009
 static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
 
+/* Mark a const_hash_table descriptor for GC.  */
+
+static void 
+mark_const_hash_entry (ptr)
+     void *ptr;
+{
+  struct constant_descriptor *desc = * (struct constant_descriptor **) ptr;
+
+  while (desc)
+    {
+      ggc_mark_string (desc->label);
+      ggc_mark_rtx (desc->rtl);
+      desc = desc->next;
+    }
+}
+
 /* Compute a hash code for a constant expression.  */
 
 static int
 const_hash (exp)
      tree exp;
 {
-  register char *p;
+  register const char *p;
   register int len, hi, i;
   register enum tree_code code = TREE_CODE (exp);
 
@@ -2474,9 +2408,12 @@ const_hash (exp)
     case CONSTRUCTOR:
       if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
        {
+         char *tmp;
+
          len = int_size_in_bytes (TREE_TYPE (exp));
-         p = (char *) alloca (len);
-         get_set_constructor_bytes (exp, (unsigned char *) p, len);
+         tmp = (char *) alloca (len);
+         get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
+         p = tmp;
          break;
        }
       else
@@ -2490,7 +2427,7 @@ const_hash (exp)
             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))
+           hi = ((unsigned long) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
              % MAX_HASH_TABLE;
          else
            hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
@@ -2520,6 +2457,8 @@ const_hash (exp)
          }
        else if (GET_CODE (value.base) == LABEL_REF)
          hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+       else
+         abort();
 
        hi &= (1 << HASHBITS) - 1;
        hi %= MAX_HASH_TABLE;
@@ -2575,7 +2514,7 @@ compare_constant_1 (exp, p)
      tree exp;
      char *p;
 {
-  register char *strp;
+  register const char *strp;
   register int len;
   register enum tree_code code = TREE_CODE (exp);
 
@@ -2609,7 +2548,7 @@ compare_constant_1 (exp, p)
       if (flag_writable_strings)
        return 0;
 
-      if (*p++ != TYPE_MODE (TREE_TYPE (exp)))
+      if ((enum machine_mode) *p++ != TYPE_MODE (TREE_TYPE (exp)))
        return 0;
 
       strp = TREE_STRING_POINTER (exp);
@@ -2632,9 +2571,10 @@ compare_constant_1 (exp, p)
       if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
        {
          int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
+         unsigned char *tmp = (unsigned char *) alloca (len);
 
-         strp = (char *) alloca (len);
-         get_set_constructor_bytes (exp, (unsigned char *) strp, len);
+         get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
+         strp = tmp;
          if (bcmp ((char *) &xlen, p, sizeof xlen))
            return 0;
 
@@ -2646,6 +2586,12 @@ compare_constant_1 (exp, p)
          register tree link;
          int length = list_length (CONSTRUCTOR_ELTS (exp));
          tree type;
+         enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+         int have_purpose = 0;
+
+         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+           if (TREE_PURPOSE (link))
+             have_purpose = 1;
 
          if (bcmp ((char *) &length, p, sizeof length))
            return 0;
@@ -2653,7 +2599,9 @@ compare_constant_1 (exp, p)
          p += sizeof length;
 
          /* For record constructors, insist that the types match.
-            For arrays, just verify both constructors are for arrays.  */
+            For arrays, just verify both constructors are for arrays. 
+            Then insist that either both or none have any TREE_PURPOSE
+            values.  */
          if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
            type = TREE_TYPE (exp);
          else
@@ -2662,28 +2610,66 @@ compare_constant_1 (exp, p)
          if (bcmp ((char *) &type, p, sizeof type))
            return 0;
 
+         if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+           {
+             if (bcmp ((char *) &mode, p, sizeof mode))
+               return 0;
+
+             p += sizeof mode;
+           }
+
          p += sizeof type;
 
+         if (bcmp ((char *) &have_purpose, p, sizeof have_purpose))
+           return 0;
+
+         p += sizeof have_purpose;
+
          /* For arrays, insist that the size in bytes match.  */
          if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
            {
-             int size = int_size_in_bytes (TREE_TYPE (exp));
+             HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+
              if (bcmp ((char *) &size, p, sizeof size))
                return 0;
 
-             p += sizeof size;
-           }
+             p += sizeof size;
+           }
+
+         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+           {
+             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 (TREE_PURPOSE (link)
+                 && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
+               {
+                 if (bcmp ((char *) &TREE_PURPOSE (link), p,
+                           sizeof TREE_PURPOSE (link)))
+                   return 0;
 
-         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
-           {
-             if (TREE_VALUE (link))
+                 p += sizeof TREE_PURPOSE (link);
+               }
+             else if (TREE_PURPOSE (link))
                {
-                 if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
+                 if ((p = compare_constant_1 (TREE_PURPOSE (link), p)) == 0)
                    return 0;
                }
-             else
+             else if (have_purpose)
                {
-                 tree zero = 0;
+                 int zero = 0;
 
                  if (bcmp ((char *) &zero, p, sizeof zero))
                    return 0;
@@ -2715,6 +2701,7 @@ compare_constant_1 (exp, p)
 
     case PLUS_EXPR:
     case MINUS_EXPR:
+    case RANGE_EXPR:
       p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
       if (p == 0)
        return 0;
@@ -2747,12 +2734,14 @@ record_constant (exp)
 {
   struct constant_descriptor *next = 0;
   char *label = 0;
+  rtx rtl = 0;
 
-  /* Make a struct constant_descriptor.  The first two pointers will
+  /* Make a struct constant_descriptor.  The first three pointers will
      be filled in later.  Here we just leave space for them.  */
 
   obstack_grow (&permanent_obstack, (char *) &next, sizeof next);
   obstack_grow (&permanent_obstack, (char *) &label, sizeof label);
+  obstack_grow (&permanent_obstack, (char *) &rtl, sizeof rtl);
   record_constant_1 (exp);
   return (struct constant_descriptor *) obstack_finish (&permanent_obstack);
 }
@@ -2817,22 +2806,36 @@ record_constant_1 (exp)
        {
          register tree link;
          int length = list_length (CONSTRUCTOR_ELTS (exp));
+         enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
          tree type;
+         int have_purpose = 0;
+
+         for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+           if (TREE_PURPOSE (link))
+             have_purpose = 1;
 
          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.  */
+            For arrays, just verify both constructors are for arrays
+            of the same mode.  Then insist that either both or none
+            have any TREE_PURPOSE values.  */
          if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
            type = TREE_TYPE (exp);
          else
            type = 0;
+
          obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
+         if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+           obstack_grow (&permanent_obstack, &mode, sizeof mode);
+                         
+         obstack_grow (&permanent_obstack, (char *) &have_purpose,
+                       sizeof have_purpose);
 
          /* For arrays, insist that the size in bytes match.  */
          if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
            {
-             int size = int_size_in_bytes (TREE_TYPE (exp));
+             HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
              obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
            }
 
@@ -2847,6 +2850,21 @@ record_constant_1 (exp)
                  obstack_grow (&permanent_obstack,
                                (char *) &zero, sizeof zero);
                }
+
+             if (TREE_PURPOSE (link)
+                 && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
+               obstack_grow (&permanent_obstack,
+                             (char *) &TREE_PURPOSE (link),
+                             sizeof TREE_PURPOSE (link));
+             else if (TREE_PURPOSE (link))
+               record_constant_1 (TREE_PURPOSE (link));
+             else if (have_purpose)
+               {
+                 int zero = 0;
+
+                 obstack_grow (&permanent_obstack,
+                               (char *) &zero, sizeof zero);
+               }
            }
        }
       return;
@@ -2867,6 +2885,7 @@ record_constant_1 (exp)
 
     case PLUS_EXPR:
     case MINUS_EXPR:
+    case RANGE_EXPR:
       record_constant_1 (TREE_OPERAND (exp, 0));
       record_constant_1 (TREE_OPERAND (exp, 1));
       return;
@@ -3034,9 +3053,8 @@ output_constant_def (exp)
   register int hash;
   register struct constant_descriptor *desc;
   char label[256];
-  char *found = 0;
   int reloc;
-  register rtx def;
+  int found = 1;
 
   if (TREE_CST_RTL (exp))
     return TREE_CST_RTL (exp);
@@ -3054,12 +3072,9 @@ output_constant_def (exp)
       
   for (desc = const_hash_table[hash]; desc; desc = desc->next)
     if (compare_constant (exp, desc))
-      {
-       found = desc->label;
-       break;
-      }
+      break;
       
-  if (found == 0)
+  if (desc == 0)
     {
       /* No constant equal to EXP is known to have been output.
         Make a constant descriptor to enter EXP in the hash table.
@@ -3071,31 +3086,32 @@ output_constant_def (exp)
 
       desc = record_constant (exp);
       desc->next = const_hash_table[hash];
-      desc->label
-       = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
+      desc->label = ggc_alloc_string (label, -1);
       const_hash_table[hash] = desc;
-    }
-  else
-    {
-      /* Create a string containing the label name, in LABEL.  */
-      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
-    }
   
-  /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
+      /* We have a symbol name; construct the SYMBOL_REF and the MEM
+        in the permanent obstack.  We could also construct this in the
+        obstack of EXP and put it into TREE_CST_RTL, but we have no way
+        of knowing what obstack it is (e.g., it might be in a function
+        obstack of a function we are nested inside).  */
 
-  push_obstacks_nochange ();
-  if (TREE_PERMANENT (exp))
-    end_temporary_allocation ();
+      push_obstacks_nochange ();
+      end_temporary_allocation ();
 
-  def = gen_rtx (SYMBOL_REF, Pmode, desc->label);
-      
-  TREE_CST_RTL (exp)
-    = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
-  RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
-  if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
-    MEM_IN_STRUCT_P (TREE_CST_RTL (exp)) = 1;
+      desc->rtl
+       = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
+                      gen_rtx_SYMBOL_REF (Pmode, desc->label));
 
-  pop_obstacks ();
+      RTX_UNCHANGING_P (desc->rtl) = 1;
+      if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
+       MEM_SET_IN_STRUCT_P (desc->rtl, 1);
+
+      pop_obstacks ();
+
+      found = 0;
+    }
+
+  TREE_CST_RTL (exp) = desc->rtl;
 
   /* Optionally set flags or add text to the name to record information
      such as that it is a function name.  If the name is changed, the macro
@@ -3106,7 +3122,7 @@ output_constant_def (exp)
 
   /* If this is the first time we've seen this particular constant,
      output it (or defer its output for later).  */
-  if (found == 0)
+  if (! found)
     {
       int after_function = 0;
 
@@ -3139,7 +3155,12 @@ output_constant_def (exp)
            }
        }
       else
-       output_constant_def_contents (exp, reloc, const_labelno++);
+       {
+         /* Do no output if -fsyntax-only.  */
+         if (! flag_syntax_only)
+           output_constant_def_contents (exp, reloc, const_labelno);
+         ++const_labelno;
+       }
     }
 
   return TREE_CST_RTL (exp);
@@ -3179,16 +3200,7 @@ output_constant_def_contents (exp, reloc, labelno)
 #endif
 
   if (align > BITS_PER_UNIT)
-    {
-      if (!output_bytecode)
-       {
-         ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
-       }
-      else
-       {
-         BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
-       }
-    }
+    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
 
   /* Output the label itself.  */
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
@@ -3201,20 +3213,6 @@ output_constant_def_contents (exp, reloc, labelno)
 
 }
 \f
-/* Similar hash facility for making memory-constants
-   from constant rtl-expressions.  It is used on RISC machines
-   where immediate integer arguments and constant addresses are restricted
-   so that such constants must be stored in memory.
-
-   This pool of constants is reinitialized for each function
-   so each function gets its own constants-pool that comes right before it.
-
-   All structures allocated here are discarded when functions are saved for
-   inlining, so they do not need to be allocated permanently.  */
-
-#define MAX_RTX_HASH_TABLE 61
-static struct constant_descriptor **const_rtx_hash_table;
-
 /* Structure to represent sufficient information about a constant so that
    it can be output when the constant pool is output, so that function
    integration can be done, and to simplify handling on machines that reference
@@ -3232,15 +3230,6 @@ struct pool_constant
   int mark;
 };
 
-/* Pointers to first and last constant in pool.  */
-
-static struct pool_constant *first_pool, *last_pool;
-
-/* Current offset in constant pool (does not include any machine-specific
-   header.  */
-
-static int pool_offset;
-
 /* Structure used to maintain hash table mapping symbols used to their
    corresponding constants.  */
 
@@ -3251,63 +3240,93 @@ struct pool_sym
   struct pool_sym *next;
 };
 
-static struct pool_sym **const_rtx_sym_hash_table;
-
 /* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
    The argument is XSTR (... , 0)  */
 
 #define SYMHASH(LABEL) \
-  ((((HOST_WIDE_INT) (LABEL)) & ((1 << HASHBITS) - 1))  % MAX_RTX_HASH_TABLE)
+  ((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1))  % MAX_RTX_HASH_TABLE)
 \f
-/* Initialize constant pool hashing for next function.  */
+/* Initialize constant pool hashing for a new function.  */
 
 void
-init_const_rtx_hash_table ()
+init_varasm_status (f)
+     struct function *f;
 {
-  const_rtx_hash_table
+  struct varasm_status *p;
+  p = (struct varasm_status *) xmalloc (sizeof (struct varasm_status));
+  f->varasm = p;
+  p->x_const_rtx_hash_table
     = ((struct constant_descriptor **)
-       oballoc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)));
-  const_rtx_sym_hash_table
+       xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)));
+  p->x_const_rtx_sym_hash_table
     = ((struct pool_sym **)
-       oballoc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
-  bzero ((char *) const_rtx_hash_table,
+       xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
+  bzero ((char *) p->x_const_rtx_hash_table,
         MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *));
-  bzero ((char *) const_rtx_sym_hash_table,
+  bzero ((char *) p->x_const_rtx_sym_hash_table,
         MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *));
 
-  first_pool = last_pool = 0;
-  pool_offset = 0;
+  p->x_first_pool = p->x_last_pool = 0;
+  p->x_pool_offset = 0;
+  p->x_const_double_chain = 0;
+}
+
+/* Mark PC for GC.  */
+
+static void 
+mark_pool_constant (pc)
+     struct pool_constant *pc;
+{
+  while (pc)
+    {
+      ggc_mark_rtx (pc->constant);
+      pc = pc->next;
+    }
 }
 
-/* Save and restore status for a nested function.  */
+/* Mark PPS for GC.  */
+
+static void
+mark_pool_sym_hash_table (pps)
+     struct pool_sym **pps;
+{
+  struct pool_sym *ps;
+  int i;
+
+  for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
+    for (ps = pps[i]; ps ; ps = ps->next)
+      ggc_mark_string (ps->label);
+}
+
+/* Mark P for GC.  */
 
 void
-save_varasm_status (p, context)
-     struct function *p;
-     tree context;
+mark_varasm_status (p)
+     struct varasm_status *p;
 {
-  p->const_rtx_hash_table = const_rtx_hash_table;
-  p->const_rtx_sym_hash_table = const_rtx_sym_hash_table;
-  p->first_pool = first_pool;
-  p->last_pool = last_pool;
-  p->pool_offset = pool_offset;
-  p->const_double_chain = const_double_chain;
-
-  /* If we are pushing to toplevel, we can't reuse const_double_chain.  */
-  if (context == NULL_TREE)
-    const_double_chain = 0;
+  if (p == NULL)
+    return;
+
+  mark_pool_constant (p->x_first_pool);
+  mark_pool_sym_hash_table (p->x_const_rtx_sym_hash_table);
+  ggc_mark_rtx (p->x_const_double_chain);
 }
 
+/* Clear out all parts of the state in F that can safely be discarded
+   after the function has been compiled, to let garbage collection
+   reclaim the memory.  */
+
 void
-restore_varasm_status (p)
-     struct function *p;
+free_varasm_status (f)
+     struct function *f;
 {
-  const_rtx_hash_table = p->const_rtx_hash_table;
-  const_rtx_sym_hash_table = p->const_rtx_sym_hash_table;
-  first_pool = p->first_pool;
-  last_pool = p->last_pool;
-  pool_offset = p->pool_offset;
-  const_double_chain = p->const_double_chain;
+  struct varasm_status *p;
+
+  p = f->varasm;
+  free (p->x_const_rtx_hash_table);
+  free (p->x_const_rtx_sym_hash_table);
+  free (p);
+  f->varasm = NULL;
 }
 \f
 enum kind { RTX_DOUBLE, RTX_INT };
@@ -3405,10 +3424,13 @@ decode_rtx_const (mode, x, value)
     switch (GET_CODE (value->un.addr.base))
       {
       case SYMBOL_REF:
-      case LABEL_REF:
        /* Use the string's address, not the SYMBOL_REF's address,
-          for the sake of addresses of library routines.
-          For a LABEL_REF, compare labels.  */
+          for the sake of addresses of library routines.  */
+       value->un.addr.base = (rtx) XSTR (value->un.addr.base, 0);
+       break;
+
+      case LABEL_REF:
+       /* For a LABEL_REF, compare labels.  */
        value->un.addr.base = XEXP (value->un.addr.base, 0);
        
       default:
@@ -3440,7 +3462,8 @@ const_hash_rtx (mode, x)
      enum machine_mode mode;
      rtx x;
 {
-  register int hi, i;
+  register int hi;
+  register size_t i;
 
   struct rtx_const value;
   decode_rtx_const (mode, x, &value);
@@ -3491,6 +3514,7 @@ record_constant_rtx (mode, x)
 {
   struct constant_descriptor *ptr;
   char *label;
+  rtx rtl;
   struct rtx_const value;
 
   decode_rtx_const (mode, x, &value);
@@ -3500,6 +3524,7 @@ record_constant_rtx (mode, x)
      memory allocated from function_obstack (current_obstack).  */
   obstack_grow (saveable_obstack, &ptr, sizeof ptr);
   obstack_grow (saveable_obstack, &label, sizeof label);
+  obstack_grow (saveable_obstack, &rtl, sizeof rtl);
 
   /* Record constant contents.  */
   obstack_grow (saveable_obstack, &value, sizeof value);
@@ -3529,15 +3554,10 @@ force_const_mem (mode, x)
      modes in an alternating fashion, we will allocate a lot of different
      memory locations, but this should be extremely rare.  */
 
-  /* Don't use CONST_DOUBLE_MEM in a nested function.
-     Nested functions have their own constant pools,
-     so they can't share the same values in CONST_DOUBLE_MEM
-     with the containing function.  */
-  if (outer_function_chain == 0)
-    if (GET_CODE (x) == CONST_DOUBLE
-       && GET_CODE (CONST_DOUBLE_MEM (x)) == MEM
-       && GET_MODE (CONST_DOUBLE_MEM (x)) == mode)
-      return CONST_DOUBLE_MEM (x);
+  if (GET_CODE (x) == CONST_DOUBLE
+      && GET_CODE (CONST_DOUBLE_MEM (x)) == MEM
+      && GET_MODE (CONST_DOUBLE_MEM (x)) == mode)
+    return CONST_DOUBLE_MEM (x);
 
   /* Compute hash code of X.  Search the descriptors for that hash code
      to see if any of them describes X.  If yes, the descriptor records
@@ -3571,6 +3591,10 @@ force_const_mem (mode, x)
       align = (mode == VOIDmode) ? UNITS_PER_WORD : GET_MODE_SIZE (mode);
       if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
        align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+#ifdef CONSTANT_ALIGNMENT
+      align = CONSTANT_ALIGNMENT (make_tree (type_for_mode (mode, 0), x),
+                                align * BITS_PER_UNIT) / BITS_PER_UNIT;
+#endif
 
       pool_offset += align - 1;
       pool_offset &= ~ (align - 1);
@@ -3588,10 +3612,10 @@ force_const_mem (mode, x)
          rtl_in_saveable_obstack ();
 
          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)));
+           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));
 
@@ -3623,8 +3647,7 @@ force_const_mem (mode, x)
 
       ++const_labelno;
 
-      desc->label = found
-       = (char *) obstack_copy0 (saveable_obstack, label, strlen (label));
+      desc->label = found = ggc_alloc_string (label, -1);
 
       /* Add label to symbol hash table.  */
       hash = SYMHASH (found);
@@ -3637,23 +3660,22 @@ force_const_mem (mode, x)
 
   /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */
 
-  def = gen_rtx (MEM, mode, gen_rtx (SYMBOL_REF, Pmode, found));
+  def = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, found));
 
   RTX_UNCHANGING_P (def) = 1;
   /* Mark the symbol_ref as belonging to this constants pool.  */
   CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1;
   current_function_uses_const_pool = 1;
 
-  if (outer_function_chain == 0)
-    if (GET_CODE (x) == CONST_DOUBLE)
-      {
-       if (CONST_DOUBLE_MEM (x) == cc0_rtx)
-         {
-           CONST_DOUBLE_CHAIN (x) = const_double_chain;
-           const_double_chain = x;
-         }
-       CONST_DOUBLE_MEM (x) = def;
-      }
+  if (GET_CODE (x) == CONST_DOUBLE)
+    {
+      if (CONST_DOUBLE_MEM (x) == cc0_rtx)
+       {
+         CONST_DOUBLE_CHAIN (x) = const_double_chain;
+         const_double_chain = x;
+       }
+      CONST_DOUBLE_MEM (x) = def;
+    }
 
   return def;
 }
@@ -3662,13 +3684,14 @@ force_const_mem (mode, x)
    the corresponding pool_constant structure.  */
 
 static struct pool_constant *
-find_pool_constant (addr)
+find_pool_constant (f, addr)
+     struct function *f;
      rtx addr;
 {
   struct pool_sym *sym;
-  char *label = XSTR (addr, 0);
+  const char *label = XSTR (addr, 0);
 
-  for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next)
+  for (sym = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next)
     if (sym->label == label)
       return sym->pool;
 
@@ -3681,7 +3704,17 @@ rtx
 get_pool_constant (addr)
      rtx addr;
 {
-  return (find_pool_constant (addr))->constant;
+  return (find_pool_constant (cfun, addr))->constant;
+}
+
+/* Likewise, but for the constant pool of a specific function.  */
+
+rtx
+get_pool_constant_for_function (f, addr)
+     struct function *f;
+     rtx addr;
+{
+  return (find_pool_constant (f, addr))->constant;
 }
 
 /* Similar, return the mode.  */
@@ -3690,7 +3723,15 @@ enum machine_mode
 get_pool_mode (addr)
      rtx addr;
 {
-  return (find_pool_constant (addr))->mode;
+  return (find_pool_constant (cfun, addr))->mode;
+}
+
+enum machine_mode
+get_pool_mode_for_function (f, addr)
+     struct function *f;
+     rtx addr;
+{
+  return (find_pool_constant (f, addr))->mode;
 }
 
 /* Similar, return the offset in the constant pool.  */
@@ -3699,7 +3740,7 @@ int
 get_pool_offset (addr)
      rtx addr;
 {
-  return (find_pool_constant (addr))->offset;
+  return (find_pool_constant (cfun, addr))->offset;
 }
 
 /* Return the size of the constant pool.  */
@@ -3714,8 +3755,8 @@ get_pool_size ()
 
 void
 output_constant_pool (fnname, fndecl)
-     char *fnname;
-     tree fndecl;
+  const char *fnname ATTRIBUTE_UNUSED;
+  tree fndecl ATTRIBUTE_UNUSED;
 {
   struct pool_constant *pool;
   rtx x;
@@ -3724,8 +3765,7 @@ output_constant_pool (fnname, fndecl)
   /* 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 ();
+  mark_constant_pool ();
 
 #ifdef ASM_OUTPUT_POOL_PROLOGUE
   ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
@@ -3765,7 +3805,7 @@ output_constant_pool (fnname, fndecl)
 #endif
 
       if (pool->align > 1)
-       ASM_OUTPUT_ALIGN (asm_out_file, exact_log2 (pool->align));
+       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (pool->align));
 
       /* Output the label.  */
       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", pool->labelno);
@@ -3790,7 +3830,10 @@ output_constant_pool (fnname, fndecl)
          abort ();
        }
 
+#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
     done: ;
+#endif
+
     }
 
 #ifdef ASM_OUTPUT_POOL_EPILOGUE
@@ -3825,6 +3868,36 @@ mark_constant_pool ()
        insn = XEXP (insn, 1))
     if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
       mark_constants (PATTERN (insn));
+
+  /* It's possible that the only reference to a symbol is in a symbol
+     that's in the constant pool.  This happens in Fortran under some
+     situations.  (When the constant contains the address of another
+     constant, and only the first is used directly in an insn.) 
+     This is potentially suboptimal if there's ever a possibility of
+     backwards (in pool order) 2'd level references.  However, it's
+     not clear that 2'd level references can happen. */
+  for (pool = first_pool; pool; pool = pool->next)
+    {
+      struct pool_sym *sym;
+      const char *label;
+
+      /* skip unmarked entries; no insn refers to them. */
+      if (!pool->mark)
+         continue;
+
+      /* Skip everything except SYMBOL_REFs.  */
+      if (GET_CODE (pool->constant) != SYMBOL_REF)
+       continue;
+      label = XSTR (pool->constant, 0);
+
+      /* Be sure the symbol's value is marked. */
+      for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym; 
+           sym = sym->next)
+         if (sym->label == label)
+           sym->pool->mark = 1;
+      /* If we didn't find it, there's something truly wrong here, but it
+        will be announced by the assembler. */
+    }
 }
 
 static void
@@ -3832,7 +3905,7 @@ mark_constants (x)
      register rtx x;
 {
   register int i;
-  register char *format_ptr;
+  register const char *format_ptr;
 
   if (x == 0)
     return;
@@ -3840,14 +3913,11 @@ mark_constants (x)
   if (GET_CODE (x) == SYMBOL_REF)
     {
       if (CONSTANT_POOL_ADDRESS_P (x))
-       find_pool_constant (x)->mark = 1;
+       find_pool_constant (cfun, x)->mark = 1;
       return;
     }
   /* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be
-     a MEM, but does not constitute a use of that MEM.  This is particularly
-     important inside a nested function, because CONST_DOUBLE_MEM may be
-     a reference to a MEM in the parent's constant pool.  See the comment
-     in force_const_mem.  */
+     a MEM, but does not constitute a use of that MEM.  */
   else if (GET_CODE (x) == CONST_DOUBLE)
     return;
 
@@ -3952,6 +4022,166 @@ output_addressed_constants (exp)
   return reloc;
 }
 \f
+/* Return nonzero if VALUE is a valid constant-valued expression
+   for use in initializing a static variable; one that can be an
+   element of a "constant" initializer.
+
+   Return null_pointer_node if the value is absolute;
+   if it is relocatable, return the variable that determines the relocation.
+   We assume that VALUE has been folded as much as possible;
+   therefore, we do not need to check for such things as
+   arithmetic-combinations of integers.  */
+
+tree
+initializer_constant_valid_p (value, endtype)
+     tree value;
+     tree endtype;
+{
+  /* Give the front-end a chance to convert VALUE to something that
+     looks more like a constant to the back-end.  */
+  if (lang_expand_constant)
+    value = (*lang_expand_constant) (value);
+
+  switch (TREE_CODE (value))
+    {
+    case CONSTRUCTOR:
+      if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
+          || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
+         && TREE_CONSTANT (value)
+         && CONSTRUCTOR_ELTS (value))
+       return
+         initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
+                                       endtype);
+       
+      return TREE_STATIC (value) ? null_pointer_node : 0;
+
+    case INTEGER_CST:
+    case REAL_CST:
+    case STRING_CST:
+    case COMPLEX_CST:
+      return null_pointer_node;
+
+    case ADDR_EXPR:
+      return TREE_OPERAND (value, 0);
+
+    case NON_LVALUE_EXPR:
+      return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+    case CONVERT_EXPR:
+    case NOP_EXPR:
+      /* Allow conversions between pointer types.  */
+      if (POINTER_TYPE_P (TREE_TYPE (value))
+         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+      /* Allow conversions between real types.  */
+      if (FLOAT_TYPE_P (TREE_TYPE (value))
+         && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+      /* Allow length-preserving conversions between integer types.  */
+      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
+         && (TYPE_PRECISION (TREE_TYPE (value))
+             == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+      /* Allow conversions between other integer types only if
+        explicit value.  */
+      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+       {
+         tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                                    endtype);
+         if (inner == null_pointer_node)
+           return null_pointer_node;
+         break;
+       }
+
+      /* Allow (int) &foo provided int is as wide as a pointer.  */
+      if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
+         && (TYPE_PRECISION (TREE_TYPE (value))
+             >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                            endtype);
+
+      /* Likewise conversions from int to pointers, but also allow
+        conversions from 0.  */
+      if (POINTER_TYPE_P (TREE_TYPE (value))
+         && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+       {
+         if (integer_zerop (TREE_OPERAND (value, 0)))
+           return null_pointer_node;
+         else if (TYPE_PRECISION (TREE_TYPE (value))
+                  <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
+           return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                                endtype);
+       }
+
+      /* Allow conversions to union types if the value inside is okay.  */
+      if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                            endtype);
+      break;
+
+    case PLUS_EXPR:
+      if (! INTEGRAL_TYPE_P (endtype)
+         || TYPE_PRECISION (endtype) >= POINTER_SIZE)
+        {
+         tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                                     endtype);
+         tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+                                                     endtype);
+         /* If either term is absolute, use the other terms relocation.  */
+         if (valid0 == null_pointer_node)
+           return valid1;
+         if (valid1 == null_pointer_node)
+           return valid0;
+        }
+      break;
+
+    case MINUS_EXPR:
+      if (! INTEGRAL_TYPE_P (endtype)
+         || TYPE_PRECISION (endtype) >= POINTER_SIZE)
+       {
+         tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                                     endtype);
+         tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+                                                     endtype);
+         /* Win if second argument is absolute.  */
+         if (valid1 == null_pointer_node)
+           return valid0;
+         /* Win if both arguments have the same relocation.
+            Then the value is absolute.  */
+         if (valid0 == valid1 && valid0 != 0)
+           return null_pointer_node;
+       }
+
+      /* Support differences between labels.  */
+      if (INTEGRAL_TYPE_P (endtype))
+       {
+         tree op0, op1;
+         op0 = TREE_OPERAND (value, 0);
+         op1 = TREE_OPERAND (value, 1);
+         STRIP_NOPS (op0);
+         STRIP_NOPS (op1);
+
+         if (TREE_CODE (op0) == ADDR_EXPR
+             && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
+             && TREE_CODE (op1) == ADDR_EXPR
+             && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
+           return null_pointer_node;
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  return 0;
+}
+\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.
    Assumes output_addressed_constants has been done on EXP already.
@@ -3976,28 +4206,37 @@ output_constant (exp, size)
      register int size;
 {
   register enum tree_code code = TREE_CODE (TREE_TYPE (exp));
-  rtx x;
 
-  if (size == 0)
+  /* Some front-ends use constants other than the standard
+     language-indepdent varieties, but which may still be output
+     directly.  Give the front-end a chance to convert EXP to a
+     language-independent representation.  */
+  if (lang_expand_constant)
+    exp = (*lang_expand_constant) (exp);
+
+  if (size == 0 || flag_syntax_only)
     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, union, array, or set types.  */
+     NOP_EXPR that converts between two record, union, array, or set types
+     or a CONVERT_EXPR that converts to a union TYPE.  */
   while ((TREE_CODE (exp) == NOP_EXPR 
          && (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
              || AGGREGATE_TYPE_P (TREE_TYPE (exp))))
+        || (TREE_CODE (exp) == CONVERT_EXPR
+            && code == UNION_TYPE)
         || TREE_CODE (exp) == NON_LVALUE_EXPR)
-    exp = TREE_OPERAND (exp, 0);
+    {
+      exp = TREE_OPERAND (exp, 0);
+      code = TREE_CODE (TREE_TYPE (exp));
+    }
 
   /* Allow a constructor with no elements for any data type.
      This means to fill the space with zeros.  */
   if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
     {
-      if (output_bytecode)
-       bc_emit_const_skip (size);
-      else
-       assemble_zeros (size);
+      assemble_zeros (size);
       return;
     }
 
@@ -4091,107 +4330,6 @@ output_constant (exp, size)
     assemble_zeros (size);
 }
 
-/* Bytecode specific code to output assembler for integer.  */
-
-static void
-bc_assemble_integer (exp, size)
-    tree exp;
-    int size;
-{
-  tree const_part;
-  tree addr_part;
-  tree tmp;
-
-  /* FIXME: is this fold() business going to be as good as the
-     expand_expr() using EXPAND_SUM above in the RTL case?  I
-     hate RMS.
-     FIXME: Copied as is from BC-GCC1; may need work. Don't hate. -bson */
-  
-  exp = fold (exp);
-  
-  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)
-    {
-      const_part = exp;
-      addr_part = 0;
-    }
-  else if (TREE_CODE (exp) == PLUS_EXPR)
-    {
-      const_part = TREE_OPERAND (exp, 0);
-      while (TREE_CODE (const_part) == NOP_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) == 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;
-      if (TREE_CODE (const_part) != INTEGER_CST
-         || TREE_CODE (addr_part) != ADDR_EXPR)
-       abort ();               /* FIXME: we really haven't considered
-                                  all the possible cases here.  */
-    }
-  else if (TREE_CODE (exp) == ADDR_EXPR)
-    {
-      const_part = integer_zero_node;
-      addr_part = exp;
-    }
-  else
-    abort ();          /* FIXME: ditto previous.  */
-  
-  if (addr_part == 0)
-    {
-      if (size == 1)
-       {
-         char c = TREE_INT_CST_LOW (const_part);
-         bc_emit (&c, 1);
-         size -= 1;
-       }
-      else if (size == 2)
-       {
-         short s = TREE_INT_CST_LOW (const_part);
-         bc_emit ((char *) &s, 2);
-         size -= 2;
-       }
-      else if (size == 4)
-       {
-         int i = TREE_INT_CST_LOW (const_part);
-         bc_emit ((char *) &i, 4);
-         size -= 4;
-       }
-      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);
-           }
-         size -= 8;
-       }
-    }
-  else
-    if (size == 4
-       && TREE_CODE (TREE_OPERAND (addr_part, 0)) == VAR_DECL)
-      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.  */
-}
 \f
 /* Subroutine of output_constant, used for CONSTRUCTORs
    (aggregate constants).
@@ -4209,7 +4347,7 @@ output_constructor (exp, size)
   int total_bytes = 0;
   /* Non-zero means BYTE contains part of a byte, to be output.  */
   int byte_buffer_in_use = 0;
-  register int byte;
+  register int byte = 0;
 
   if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
     abort ();
@@ -4226,7 +4364,11 @@ output_constructor (exp, size)
      FIELD goes through the structure fields, if the constant is a structure.
      if the constant is a union, then we override this,
      by getting the field from the TREE_LIST element.
-     But the constant could also be an array.  Then FIELD is zero.  */
+     But the constant could also be an array.  Then FIELD is zero.
+
+     There is always a maximum of one element in the chain LINK for unions
+     (even if the initializer in a source program incorrectly contains
+     more one). */
   for (link = CONSTRUCTOR_ELTS (exp);
        link;
        link = TREE_CHAIN (link),
@@ -4299,31 +4441,17 @@ output_constructor (exp, size)
             if each element has the proper size.  */
          if ((field != 0 || index != 0) && bitpos != total_bytes)
            {
-             if (!output_bytecode)
-               assemble_zeros (bitpos - total_bytes);
-             else
-               bc_emit_const_skip (bitpos - total_bytes);
+             assemble_zeros (bitpos - total_bytes);
              total_bytes = bitpos;
            }
 
          /* Determine size this element should occupy.  */
          if (field)
            {
-             if (TREE_CODE (DECL_SIZE (field)) != INTEGER_CST)
+             if (TREE_CODE (DECL_SIZE_UNIT (field)) != INTEGER_CST)
                abort ();
-             if (TREE_INT_CST_LOW (DECL_SIZE (field)) > 100000)
-               {
-                 /* This avoids overflow trouble.  */
-                 tree size_tree = size_binop (CEIL_DIV_EXPR,
-                                              DECL_SIZE (field),
-                                              size_int (BITS_PER_UNIT));
-                 fieldsize = TREE_INT_CST_LOW (size_tree);
-               }
-             else
-               {
-                 fieldsize = TREE_INT_CST_LOW (DECL_SIZE (field));
-                 fieldsize = (fieldsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
-               }
+
+             fieldsize = TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
            }
          else
            fieldsize = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
@@ -4410,11 +4538,13 @@ output_constructor (exp, size)
                     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.  */
+                    the word boundary in the INTEGER_CST. We can
+                    only select bits from the LOW or HIGH part
+                    not from both.  */
                  if (shift < HOST_BITS_PER_WIDE_INT
                      && shift + this_time > HOST_BITS_PER_WIDE_INT)
                    {
-                     this_time -= (HOST_BITS_PER_WIDE_INT - shift);
+                     this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
                      shift = HOST_BITS_PER_WIDE_INT;
                    }
 
@@ -4430,8 +4560,10 @@ output_constructor (exp, size)
                    }
                  else
                    abort ();
+                 /* Get the result. This works only when:
+                    1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
                  byte |= (((value >> shift)
-                           & (((HOST_WIDE_INT) 1 << this_time) - 1))
+                           & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
                           << (BITS_PER_UNIT - this_time - next_bit));
                }
              else
@@ -4443,12 +4575,13 @@ output_constructor (exp, size)
                  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.  */
+                    the word boundary in the INTEGER_CST. We can
+                    only select bits from the LOW or HIGH part
+                    not from both.  */
                  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;
+                     this_time = (HOST_BITS_PER_WIDE_INT - shift);
                    }
 
                  /* Now get the bits from the appropriate constant word.  */
@@ -4461,8 +4594,10 @@ output_constructor (exp, size)
                    }
                  else
                    abort ();
+                 /* Get the result. This works only when:
+                    1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
                  byte |= (((value >> shift)
-                           & (((HOST_WIDE_INT) 1 << this_time) - 1))
+                           & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
                           << next_bit);
                }
              next_offset += this_time;
@@ -4479,37 +4614,30 @@ output_constructor (exp, size)
     assemble_zeros (size - total_bytes);
 }
 
-/* Output asm to handle ``#pragma weak'' */
-
-void
-handle_pragma_weak (what, name, value)
-     enum pragma_state what;
-     char *name, *value;
-{
 #ifdef HANDLE_PRAGMA_WEAK
-  if (what == ps_name || what == ps_value)
-    {
-      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);
+/* Add function NAME to the weak symbols list.  VALUE is a weak alias
+   associatd with NAME.  */
+   
+int
+add_weak (name, value)
+     char *name;
+     char *value;
+{
+  struct weak_syms *weak;
 
-      if (what != ps_value)
-       weak->value = NULL_PTR;
+  weak = (struct weak_syms *) permalloc (sizeof (struct weak_syms));
 
-      else
-       {
-         weak->value = permalloc (strlen (value) + 1);
-         strcpy (weak->value, value);
-       }
+  if (weak == NULL)
+    return 0;
 
-      weak_decls = weak;
-    }
-  else if (! (what == ps_done || what == ps_start))
-    warning ("malformed `#pragma weak'");
-#endif /* HANDLE_PRAGMA_WEAK */
+  weak->next = weak_decls;
+  weak->name = name;
+  weak->value = value;
+  weak_decls = weak;
+
+  return 1;
 }
+#endif /* HANDLE_PRAGMA_WEAK */
 
 /* Declare DECL to be a weak symbol.  */
 
@@ -4523,10 +4651,17 @@ declare_weak (decl)
     error_with_decl (decl, "weak declaration of `%s' must precede definition");
   else if (SUPPORTS_WEAK)
     DECL_WEAK (decl) = 1;
+#ifdef HANDLE_PRAGMA_WEAK
+   add_weak (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), NULL);
+#endif
 }
 
 /* Emit any pending weak declarations.  */
 
+#ifdef HANDLE_PRAGMA_WEAK
+struct weak_syms * weak_decls;
+#endif
+
 void
 weak_finish ()
 {
@@ -4536,19 +4671,44 @@ weak_finish ()
       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);
+         if (t->name)
+           {
+             ASM_WEAKEN_LABEL (asm_out_file, t->name);
+             if (t->value)
+               ASM_OUTPUT_DEF (asm_out_file, t->name, t->value);
+           }
+       }
+    }
+#endif
+}
+
+/* Remove NAME from the pending list of weak symbols.  This prevents
+   the compiler from emitting multiple .weak directives which confuses
+   some assemblers.  */
+#ifdef ASM_WEAKEN_LABEL
+static void
+remove_from_pending_weak_list (name)
+     char *name ATTRIBUTE_UNUSED;
+{
+#ifdef HANDLE_PRAGMA_WEAK
+  if (HANDLE_PRAGMA_WEAK)
+    {
+      struct weak_syms *t;
+      for (t = weak_decls; t; t = t->next)
+       {
+         if (t->name && strcmp (name, t->name) == 0)
+           t->name = NULL;
        }
     }
 #endif
 }
+#endif
 
 void
 assemble_alias (decl, target)
-     tree decl, target;
+     tree decl, target ATTRIBUTE_UNUSED;
 {
-  char *name;
+  const char *name;
 
   make_decl_rtl (decl, (char *) 0, 1);
   name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
@@ -4560,16 +4720,23 @@ assemble_alias (decl, target)
     {
 #ifdef ASM_WEAKEN_LABEL
       if (DECL_WEAK (decl))
-       ASM_WEAKEN_LABEL (asm_out_file, name);
+       {
+         ASM_WEAKEN_LABEL (asm_out_file, name);
+         /* Remove this function from the pending weak list so that
+            we do not emit multiple .weak directives for it.  */
+         remove_from_pending_weak_list
+           (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+       }
       else
 #endif
-      if (output_bytecode)
-       BC_GLOBALIZE_LABEL (asm_out_file, name);
-      else
        ASM_GLOBALIZE_LABEL (asm_out_file, name);
     }
 
+#ifdef ASM_OUTPUT_DEF_FROM_DECLS
+  ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
+#else
   ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
+#endif
   TREE_ASM_WRITTEN (decl) = 1;
 #else
 #ifdef ASM_OUTPUT_WEAK_ALIAS
@@ -4633,3 +4800,11 @@ make_decl_one_only (decl)
   else
     abort ();
 }
+
+void
+init_varasm_once ()
+{
+  ggc_add_root (const_hash_table, MAX_HASH_TABLE, sizeof const_hash_table[0],
+               mark_const_hash_entry);
+  ggc_add_string_root (&in_named_name, 1);
+}