OSDN Git Service

* varasm.c (make_decl_rtl): Skip initial '*' when setting
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index d8559d4..18b6487 100644 (file)
@@ -1,5 +1,6 @@
 /* Output variables, constants and external declarations, for GNU compiler.
-   Copyright (C) 1987, 88, 89, 92-98, 1999 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.
 
@@ -120,12 +121,12 @@ struct varasm_status
   rtx x_const_double_chain;
 };
 
-#define const_rtx_hash_table (current_function->varasm->x_const_rtx_hash_table)
-#define const_rtx_sym_hash_table (current_function->varasm->x_const_rtx_sym_hash_table)
-#define first_pool (current_function->varasm->x_first_pool)
-#define last_pool (current_function->varasm->x_last_pool)
-#define pool_offset (current_function->varasm->x_pool_offset)
-#define const_double_chain (current_function->varasm->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.  */
@@ -149,48 +150,46 @@ int size_directive_output;
 
 tree last_assemble_variable_decl;
 
-/* Nonzero if at least one function definition has been seen.  */
-
-static int function_defined;
-
-static const char *strip_reg_name      PROTO((const char *));
-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((struct function *, 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 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      PROTO ((char *));
+static void remove_from_pending_weak_list      PARAMS ((char *));
 #endif
 #ifdef ASM_OUTPUT_BSS
-static void asm_output_bss             PROTO((FILE *, tree, char *, int, int));
+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     PROTO((FILE *, tree, char *, int, int));
+static void asm_output_aligned_bss     PARAMS ((FILE *, tree, const char *,
+                                                int, int));
 #endif
 #endif /* BSS_SECTION_ASM_OP */
-static void mark_pool_constant          PROTO((struct pool_constant *));
-static void mark_pool_sym_hash_table   PROTO((struct pool_sym **));
-static void mark_const_hash_entry      PROTO((void *));
+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
@@ -205,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;
 
@@ -376,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 ();
@@ -405,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);
@@ -522,8 +523,10 @@ make_function_rtl (decl)
   char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   char *new_name = name;
 
-  /* 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)
     {
@@ -553,6 +556,7 @@ make_function_rtl (decl)
 
   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));
@@ -578,9 +582,6 @@ make_function_rtl (decl)
        ENCODE_SECTION_INFO (decl);
 #endif
     }
-
-  /* Record at least one function has been defined.  */
-  function_defined = 1;
 }
 
 /* Given NAME, a putative register name, discard any customary prefixes.  */
@@ -728,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");
 
@@ -770,9 +768,12 @@ 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;
 
@@ -798,6 +799,8 @@ make_decl_rtl (decl, asmspec, top_level)
              name = new_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);
@@ -922,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);
@@ -942,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);
@@ -963,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);
@@ -996,7 +999,7 @@ assemble_gc_entry (name)
 void
 assemble_start_function (decl, fnname)
      tree decl;
-     char *fnname;
+     const char *fnname;
 {
   int align;
 
@@ -1100,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);
@@ -1197,6 +1200,119 @@ assemble_string (p, size)
 }
 
 \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
+asm_emit_uninitialised (decl, name, size, rounded)
+     tree decl;
+     const char * name;
+     int size ATTRIBUTE_UNUSED;
+     int rounded ATTRIBUTE_UNUSED;
+{
+  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;
+}
+
 /* 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.
@@ -1211,10 +1327,10 @@ void
 assemble_variable (decl, top_level, at_end, dont_output_data)
      tree decl;
      int top_level ATTRIBUTE_UNUSED;
-     int at_end;
+     int at_end ATTRIBUTE_UNUSED;
      int dont_output_data;
 {
-  register char *name;
+  register const char *name;
   unsigned int align;
   tree size_tree = NULL_TREE;
   int reloc = 0;
@@ -1310,18 +1426,15 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
 
   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;
@@ -1329,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
@@ -1386,10 +1498,10 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   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) == 0
+      && DECL_SECTION_NAME (decl) == NULL_TREE
       && ! dont_output_data)
     {
       int size = TREE_INT_CST_LOW (size_tree);
@@ -1405,7 +1517,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
                 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
       
 #if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
-      if ( (DECL_ALIGN (decl) / BITS_PER_UNIT) > rounded)
+      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
@@ -1436,71 +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
-             {
-#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
-             {
-#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
-             {
-#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;
     }
 
@@ -1541,8 +1590,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
     reloc = output_addressed_constants (DECL_INITIAL (decl));
 
 #ifdef ASM_OUTPUT_SECTION_NAME
-  if ((flag_data_sections != 0
-       && DECL_SECTION_NAME (decl) == NULL_TREE)
+  if ((flag_data_sections != 0 && DECL_SECTION_NAME (decl) == NULL_TREE)
       || UNIQUE_SECTION_P (decl))
     UNIQUE_SECTION (decl, reloc);
 #endif
@@ -1715,7 +1763,7 @@ assemble_external_libcall (fun)
 
 void
 assemble_global (name)
-     char *name;
+     const char *name;
 {
   ASM_GLOBALIZE_LABEL (asm_out_file, name);
 }
@@ -1724,7 +1772,7 @@ assemble_global (name)
 
 void
 assemble_label (name)
-     char *name;
+     const char *name;
 {
   ASM_OUTPUT_LABEL (asm_out_file, name);
 }
@@ -2074,7 +2122,7 @@ immed_double_const (i0, i1, mode)
 
   /* Search the chain for an existing CONST_DOUBLE with the right value.
      If one is found, return it.  */
-  if (current_function != 0)
+  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)
@@ -2146,7 +2194,7 @@ immed_real_const_1 (d, mode)
 
   /* Search the chain for an existing CONST_DOUBLE with the right value.
      If one is found, return it.  */
-  if (current_function != 0)
+  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)
@@ -2299,6 +2347,7 @@ struct constant_descriptor
 {
   struct constant_descriptor *next;
   char *label;
+  rtx rtl;
   char contents[1];
 };
 
@@ -2317,6 +2366,7 @@ mark_const_hash_entry (ptr)
   while (desc)
     {
       ggc_mark_string (desc->label);
+      ggc_mark_rtx (desc->rtl);
       desc = desc->next;
     }
 }
@@ -2327,7 +2377,7 @@ 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);
 
@@ -2358,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
@@ -2461,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);
 
@@ -2495,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);
@@ -2518,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;
 
@@ -2532,6 +2586,7 @@ 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))
@@ -2555,6 +2610,14 @@ 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))
@@ -2671,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);
 }
@@ -2741,6 +2806,7 @@ 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;
 
@@ -2751,14 +2817,18 @@ record_constant_1 (exp)
          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
-            Then insist that either both or none have any TREE_PURPOSE
-            values.  */
+            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);
 
@@ -2983,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);
@@ -3003,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.
@@ -3022,23 +3088,30 @@ output_constant_def (exp)
       desc->next = const_hash_table[hash];
       desc->label = ggc_alloc_string (label, -1);
       const_hash_table[hash] = desc;
-    }
   
-  /* 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_SET_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
@@ -3049,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;
 
@@ -3351,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:
@@ -3438,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);
@@ -3447,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);
@@ -3611,7 +3689,7 @@ find_pool_constant (f, addr)
      rtx addr;
 {
   struct pool_sym *sym;
-  char *label = XSTR (addr, 0);
+  const char *label = XSTR (addr, 0);
 
   for (sym = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next)
     if (sym->label == label)
@@ -3626,7 +3704,7 @@ rtx
 get_pool_constant (addr)
      rtx addr;
 {
-  return (find_pool_constant (current_function, addr))->constant;
+  return (find_pool_constant (cfun, addr))->constant;
 }
 
 /* Likewise, but for the constant pool of a specific function.  */
@@ -3645,7 +3723,7 @@ enum machine_mode
 get_pool_mode (addr)
      rtx addr;
 {
-  return (find_pool_constant (current_function, addr))->mode;
+  return (find_pool_constant (cfun, addr))->mode;
 }
 
 enum machine_mode
@@ -3662,7 +3740,7 @@ int
 get_pool_offset (addr)
      rtx addr;
 {
-  return (find_pool_constant (current_function, addr))->offset;
+  return (find_pool_constant (cfun, addr))->offset;
 }
 
 /* Return the size of the constant pool.  */
@@ -3677,7 +3755,7 @@ get_pool_size ()
 
 void
 output_constant_pool (fnname, fndecl)
-  char *fnname ATTRIBUTE_UNUSED;
+  const char *fnname ATTRIBUTE_UNUSED;
   tree fndecl ATTRIBUTE_UNUSED;
 {
   struct pool_constant *pool;
@@ -3801,7 +3879,7 @@ mark_constant_pool ()
   for (pool = first_pool; pool; pool = pool->next)
     {
       struct pool_sym *sym;
-      char *label;
+      const char *label;
 
       /* skip unmarked entries; no insn refers to them. */
       if (!pool->mark)
@@ -3835,7 +3913,7 @@ mark_constants (x)
   if (GET_CODE (x) == SYMBOL_REF)
     {
       if (CONSTANT_POOL_ADDRESS_P (x))
-       find_pool_constant (current_function, x)->mark = 1;
+       find_pool_constant (cfun, x)->mark = 1;
       return;
     }
   /* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be
@@ -3944,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.
@@ -3981,12 +4219,18 @@ output_constant (exp, size)
 
   /* 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.  */
@@ -4103,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 ();
@@ -4204,21 +4448,10 @@ output_constructor (exp, size)
          /* 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)));
@@ -4305,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;
                    }
 
@@ -4325,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
@@ -4338,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.  */
@@ -4356,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;
@@ -4468,7 +4708,7 @@ void
 assemble_alias (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);
@@ -4564,7 +4804,7 @@ make_decl_one_only (decl)
 void
 init_varasm_once ()
 {
-  ggc_add_root (const_hash_table, MAX_HASH_TABLE, sizeof(const_hash_table[0]),
+  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);
 }