OSDN Git Service

2002-03-03 Aldy Hernandez <aldyh@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 6a3fb7c..187429e 100644 (file)
@@ -1,6 +1,6 @@
 /* Output variables, constants and external declarations, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -42,6 +42,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "obstack.h"
 #include "hashtab.h"
 #include "c-pragma.h"
+#include "c-tree.h"
 #include "ggc.h"
 #include "langhooks.h"
 #include "tm_p.h"
@@ -133,7 +134,7 @@ tree last_assemble_variable_decl;
    So giving constant the alias set for the type will allow such
    initializations to appear to conflict with the load of the constant.  We
    avoid this by giving all constants an alias set for just constants.
-   Since there will be no stores to that a alias set, nothing will ever
+   Since there will be no stores to that alias set, nothing will ever
    conflict with them.  */
 
 static HOST_WIDE_INT const_alias_set;
@@ -166,9 +167,11 @@ static unsigned HOST_WIDE_INT array_size_for_constructor PARAMS ((tree));
 static unsigned min_align              PARAMS ((unsigned, unsigned));
 static void output_constructor         PARAMS ((tree, HOST_WIDE_INT,
                                                 unsigned int));
-#ifdef ASM_WEAKEN_LABEL
+static void mark_weak_decls            PARAMS ((void *));
+#if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
 static void remove_from_pending_weak_list      PARAMS ((const char *));
 #endif
+static void maybe_assemble_visibility  PARAMS ((tree));
 static int in_named_entry_eq           PARAMS ((const PTR, const PTR));
 static hashval_t in_named_entry_hash   PARAMS ((const PTR));
 #ifdef ASM_OUTPUT_BSS
@@ -445,11 +448,15 @@ named_section (decl, name, reloc)
   flags = (* targetm.section_type_flags) (decl, name, reloc);
 
   /* Sanity check user variables for flag changes.  Non-user
-     section flag changes will abort in named_section_flags.  */
+     section flag changes will abort in named_section_flags.
+     However, don't complain if SECTION_OVERRIDE is set.
+     We trust that the setter knows that it is safe to ignore
+     the default flags for this decl.  */
   if (decl && ! set_named_section_flags (name, flags))
     {
-      error_with_decl (decl, "%s causes a section type conflict");
       flags = get_named_section_flags (name);
+      if ((flags & SECTION_OVERRIDE) == 0)
+       error_with_decl (decl, "%s causes a section type conflict");
     }
 
   named_section_flags (name, flags);
@@ -840,21 +847,16 @@ make_decl_rtl (decl, asmspec)
     {
       /* 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));
-       }
+       SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
+                                              DECL_MODE (decl), 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);
+#ifdef ENCODE_SECTION_INFO
+      ENCODE_SECTION_INFO (decl, false);
 #endif
       return;
     }
@@ -900,14 +902,11 @@ make_decl_rtl (decl, asmspec)
 
          /* If the user specified one of the eliminables registers here,
             e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
-            confused with that register and be eliminated.  Although this
-            usage is somewhat suspect, we nevertheless use the following
-            kludge to avoid setting DECL_RTL to frame_pointer_rtx.  */
-
-         SET_DECL_RTL (decl,
-                       gen_rtx_REG (DECL_MODE (decl),
-                                    FIRST_PSEUDO_REGISTER));
-         REGNO (DECL_RTL (decl)) = reg_number;
+            confused with that register and be eliminated.  This usage is
+            somewhat suspect...  */
+
+         SET_DECL_RTL (decl, gen_rtx_raw_REG (DECL_MODE (decl), reg_number));
+         ORIGINAL_REGNO (DECL_RTL (decl)) = reg_number;
          REG_USERVAR_P (DECL_RTL (decl)) = 1;
 
          if (TREE_STATIC (decl))
@@ -983,7 +982,7 @@ make_decl_rtl (decl, asmspec)
      If the name is changed, the macro ASM_OUTPUT_LABELREF
      will have to know how to strip this information.  */
 #ifdef ENCODE_SECTION_INFO
-  ENCODE_SECTION_INFO (decl);
+  ENCODE_SECTION_INFO (decl, true);
 #endif
 }
 
@@ -1238,10 +1237,14 @@ assemble_start_function (decl, fnname)
            weak_global_object_name = name;
        }
 
-#ifdef ASM_WEAKEN_LABEL
+#if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
       if (DECL_WEAK (decl))
        {
+#ifdef ASM_WEAKEN_DECL
+         ASM_WEAKEN_DECL (asm_out_file, decl, fnname, 0);
+#else
          ASM_WEAKEN_LABEL (asm_out_file, fnname);
+#endif
          /* Remove this function from the pending weak list so that
             we do not emit multiple .weak directives for it.  */
          remove_from_pending_weak_list
@@ -1250,6 +1253,8 @@ assemble_start_function (decl, fnname)
       else
 #endif
       ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
+
+      maybe_assemble_visibility (decl);
     }
 
   /* Do any machine/system dependent processing of the function name */
@@ -1601,9 +1606,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   DECL_ALIGN (decl) = align;
   set_mem_align (decl_rtl, align);
 
+  if (TREE_PUBLIC (decl))
+    maybe_assemble_visibility (decl);
+
   /* Handle uninitialized definitions.  */
 
-  if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
+  if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node
+#if defined ASM_EMIT_BSS
+       || (flag_zero_initialized_in_bss
+          && initializer_zerop (DECL_INITIAL (decl)))
+#endif
+       )
       /* If the target can't output uninitialized but not common global data
         in .bss, then we have to use .data.  */
 #if ! defined ASM_EMIT_BSS
@@ -1645,10 +1658,14 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
   /* First make the assembler name(s) global if appropriate.  */
   if (TREE_PUBLIC (decl) && DECL_NAME (decl))
     {
-#ifdef ASM_WEAKEN_LABEL
+#if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
       if (DECL_WEAK (decl))
        {
+#ifdef ASM_WEAKEN_DECL
+         ASM_WEAKEN_DECL (asm_out_file, decl, name, 0);
+#else
          ASM_WEAKEN_LABEL (asm_out_file, name);
+#endif
           /* Remove this variable from the pending weak list so that
              we do not emit multiple .weak directives for it.  */
          remove_from_pending_weak_list
@@ -2366,7 +2383,9 @@ decode_addr_const (exp, value)
     case COMPLEX_CST:
     case CONSTRUCTOR:
     case INTEGER_CST:
-      x = TREE_CST_RTL (target);
+      /* This constant should have been output already, but we can't simply
+        use TREE_CST_RTL since INTEGER_CST doesn't have one.  */
+      x = output_constant_def (target, 1);
       break;
 
     default:
@@ -2381,7 +2400,8 @@ decode_addr_const (exp, value)
   value->offset = offset;
 }
 \f
-enum kind { RTX_DOUBLE, RTX_INT };
+/* We do RTX_UNSPEC + XINT (blah), so nothing can go after RTX_UNSPEC.  */
+enum kind { RTX_UNKNOWN, RTX_DOUBLE, RTX_INT, RTX_VECTOR, RTX_UNSPEC };
 struct rtx_const
 {
   ENUM_BITFIELD(kind) kind : 16;
@@ -2390,6 +2410,10 @@ struct rtx_const
     union real_extract du;
     struct addr_const addr;
     struct {HOST_WIDE_INT high, low;} di;
+
+    /* The max vector size we have is 8 wide.  This should be enough.  */
+    HOST_WIDE_INT veclo[16];
+    HOST_WIDE_INT vechi[16];
   } un;
 };
 
@@ -2428,7 +2452,7 @@ static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
    they are actually used.  This will be if something takes its address or if
    there is a usage of the string in the RTL of a function.  */
 
-#define STRHASH(x) ((hashval_t)((long)(x) >> 3))
+#define STRHASH(x) ((hashval_t) ((long) (x) >> 3))
 
 struct deferred_string
 {
@@ -2593,7 +2617,7 @@ const_hash (exp)
        else if (GET_CODE (value.base) == LABEL_REF)
          hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
        else
-         abort();
+         abort ();
 
        hi &= (1 << HASHBITS) - 1;
        hi %= MAX_HASH_TABLE;
@@ -2687,7 +2711,7 @@ compare_constant_1 (exp, p)
       if ((enum machine_mode) *p++ != TYPE_MODE (TREE_TYPE (exp)))
        return 0;
 
-      strp = (const unsigned char *)TREE_STRING_POINTER (exp);
+      strp = (const unsigned char *) TREE_STRING_POINTER (exp);
       len = TREE_STRING_LENGTH (exp);
       if (memcmp ((char *) &TREE_STRING_LENGTH (exp), p,
                  sizeof TREE_STRING_LENGTH (exp)))
@@ -3299,7 +3323,7 @@ output_constant_def (exp, defer)
      encoded in it.  */
   if (! found)
     {
-      ENCODE_SECTION_INFO (exp);
+      ENCODE_SECTION_INFO (exp, true);
       desc->rtl = rtl;
       desc->label = XSTR (XEXP (desc->rtl, 0), 0);
     }
@@ -3579,6 +3603,34 @@ decode_rtx_const (mode, x, value)
        }
       break;
 
+    case CONST_VECTOR:
+      {
+       int units, i;
+       rtx elt;
+
+       units = CONST_VECTOR_NUNITS (x);
+       value->kind = RTX_VECTOR;
+       value->mode = mode;
+
+       for (i = 0; i < units; ++i)
+         {
+           elt = CONST_VECTOR_ELT (x, i);
+           if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
+             {
+               value->un.veclo[i] = (HOST_WIDE_INT) INTVAL (elt);
+               value->un.vechi[i] = 0;
+             }
+           else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+             {
+               value->un.veclo[i] = (HOST_WIDE_INT) CONST_DOUBLE_LOW (elt);
+               value->un.vechi[i] = (HOST_WIDE_INT) CONST_DOUBLE_HIGH (elt);
+             }
+           else
+             abort ();
+         }
+      }
+      break;
+
     case CONST_INT:
       value->un.addr.offset = INTVAL (x);
       break;
@@ -3609,10 +3661,28 @@ decode_rtx_const (mode, x, value)
       break;
 
     default:
-      abort ();
+      value->kind = RTX_UNKNOWN;
+      break;
+    }
+
+  if (value->kind == RTX_INT && value->un.addr.base != 0
+      && GET_CODE (value->un.addr.base) == UNSPEC)
+    {      
+      /* For a simple UNSPEC, the base is set to the
+        operand, the kind field is set to the index of
+        the unspec expression. 
+        Together with the code below, in case that
+        the operand is a SYMBOL_REF or LABEL_REF, 
+        the address of the string or the code_label 
+        is taken as base.  */
+      if (XVECLEN (value->un.addr.base, 0) == 1)
+        {
+         value->kind = RTX_UNSPEC + XINT (value->un.addr.base, 1);
+         value->un.addr.base = XVECEXP (value->un.addr.base, 0, 0);
+       }
     }
 
-  if (value->kind == RTX_INT && value->un.addr.base != 0)
+  if (value->kind > RTX_DOUBLE && value->un.addr.base != 0)
     switch (GET_CODE (value->un.addr.base))
       {
       case SYMBOL_REF:
@@ -3642,8 +3712,11 @@ simplify_subtraction (x)
   decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
   decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
 
-  if (val0.un.addr.base == val1.un.addr.base)
+  if (val0.kind > RTX_DOUBLE
+      && val0.kind == val1.kind
+      && val0.un.addr.base == val1.un.addr.base)
     return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
+
   return x;
 }
 
@@ -3845,6 +3918,19 @@ get_pool_constant (addr)
   return (find_pool_constant (cfun, addr))->constant;
 }
 
+/* Given a constant pool SYMBOL_REF, return the corresponding constant
+   and whether it has been output or not.  */
+
+rtx
+get_pool_constant_mark (addr, pmarked)
+     rtx addr;
+     bool *pmarked;
+{
+  struct pool_constant *pool = find_pool_constant (cfun, addr);
+  *pmarked = (pool->mark != 0);
+  return pool->constant;
+}
+
 /* Likewise, but for the constant pool of a specific function.  */
 
 rtx
@@ -3985,6 +4071,46 @@ output_constant_pool (fnname, fndecl)
          assemble_integer (x, GET_MODE_SIZE (pool->mode), pool->align, 1);
          break;
 
+       case MODE_VECTOR_FLOAT:
+         {
+           int i, units;
+           rtx elt;
+
+           if (GET_CODE (x) != CONST_VECTOR)
+             abort ();
+
+           units = CONST_VECTOR_NUNITS (x);
+
+           for (i = 0; i < units; i++)
+             {
+               elt = CONST_VECTOR_ELT (x, i);
+               memcpy ((char *) &u,
+                       (char *) &CONST_DOUBLE_LOW (elt),
+                       sizeof u);
+               assemble_real (u.d, GET_MODE_INNER (pool->mode), pool->align);
+             }
+         }
+         break;
+
+        case MODE_VECTOR_INT:
+         {
+           int i, units;
+           rtx elt;
+
+           if (GET_CODE (x) != CONST_VECTOR)
+             abort ();
+
+           units = CONST_VECTOR_NUNITS (x);
+
+           for (i = 0; i < units; i++)
+             {
+               elt = CONST_VECTOR_ELT (x, i);
+               assemble_integer (elt, GET_MODE_UNIT_SIZE (pool->mode),
+                                 pool->align, 1);
+             }
+         }
+         break;
+
        default:
          abort ();
        }
@@ -4233,6 +4359,7 @@ initializer_constant_valid_p (value, endtype)
       return TREE_STATIC (value) ? null_pointer_node : 0;
 
     case INTEGER_CST:
+    case VECTOR_CST:
     case REAL_CST:
     case STRING_CST:
     case COMPLEX_CST:
@@ -4351,8 +4478,37 @@ initializer_constant_valid_p (value, endtype)
          tree op0, op1;
          op0 = TREE_OPERAND (value, 0);
          op1 = TREE_OPERAND (value, 1);
-         STRIP_NOPS (op0);
-         STRIP_NOPS (op1);
+
+         /* Like STRIP_NOPS except allow the operand mode to widen.
+            This works around a feature of fold that simplfies
+            (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
+            that the narrower operation is cheaper.  */
+
+         while (TREE_CODE (op0) == NOP_EXPR
+                || TREE_CODE (op0) == CONVERT_EXPR
+                || TREE_CODE (op0) == NON_LVALUE_EXPR)
+           {
+             tree inner = TREE_OPERAND (op0, 0);
+             if (inner == error_mark_node
+                 || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+                 || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
+                     > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+               break;
+             op0 = inner;
+           }
+
+         while (TREE_CODE (op1) == NOP_EXPR
+                || TREE_CODE (op1) == CONVERT_EXPR
+                || TREE_CODE (op1) == NON_LVALUE_EXPR)
+           {
+             tree inner = TREE_OPERAND (op1, 0);
+             if (inner == error_mark_node
+                 || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+                 || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
+                     > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+               break;
+             op1 = inner;
+           }
 
          if (TREE_CODE (op0) == ADDR_EXPR
              && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
@@ -4468,6 +4624,7 @@ output_constant (exp, size, align)
       break;
 
     case ARRAY_TYPE:
+    case VECTOR_TYPE:
       if (TREE_CODE (exp) == CONSTRUCTOR)
        {
          output_constructor (exp, size, align);
@@ -4873,17 +5030,31 @@ output_constructor (exp, size, align)
 struct weak_syms
 {
   struct weak_syms * next;
+  tree decl;
   const char * name;
   const char * value;
 };
 
 static struct weak_syms * weak_decls;
 
+/* Mark weak_decls for garbage collection.  */
+
+static void
+mark_weak_decls (arg)
+     void *arg;
+{
+  struct weak_syms *t;
+
+  for (t = *(struct weak_syms **) arg; t != NULL; t = t->next)
+    ggc_mark_tree (t->decl);
+}
+
 /* Add function NAME to the weak symbols list.  VALUE is a weak alias
    associated with NAME.  */
 
 int
-add_weak (name, value)
+add_weak (decl, name, value)
+     tree decl;
      const char *name;
      const char *value;
 {
@@ -4895,6 +5066,7 @@ add_weak (name, value)
     return 0;
 
   weak->next = weak_decls;
+  weak->decl = decl;
   weak->name = name;
   weak->value = value;
   weak_decls = weak;
@@ -4913,7 +5085,7 @@ declare_weak (decl)
   else if (TREE_ASM_WRITTEN (decl))
     error_with_decl (decl, "weak declaration of `%s' must precede definition");
   else if (SUPPORTS_WEAK)
-    add_weak (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), NULL);
+    add_weak (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), NULL);
   else
     warning_with_decl (decl, "weak declaration of `%s' not supported");
 
@@ -4928,8 +5100,18 @@ weak_finish ()
   if (SUPPORTS_WEAK)
     {
       struct weak_syms *t;
-      for (t = weak_decls; t; t = t->next)
+      for (t = weak_decls; t != NULL; t = t->next)
        {
+#ifdef ASM_WEAKEN_DECL
+         tree decl = t->decl;
+         if (decl == NULL_TREE)
+           {
+             tree name = get_identifier (t->name);
+             if (name)
+               decl = lookup_name (name);
+           }
+         ASM_WEAKEN_DECL (asm_out_file, decl, t->name, t->value);
+#else
 #ifdef ASM_OUTPUT_WEAK_ALIAS
          ASM_OUTPUT_WEAK_ALIAS (asm_out_file, t->name, t->value);
 #else
@@ -4939,6 +5121,7 @@ weak_finish ()
          ASM_WEAKEN_LABEL (asm_out_file, t->name);
 #endif
 #endif
+#endif
        }
     }
 }
@@ -4946,7 +5129,7 @@ weak_finish ()
 /* 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
+#if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
 static void
 remove_from_pending_weak_list (name)
      const char *name;
@@ -4966,7 +5149,7 @@ remove_from_pending_weak_list (name)
         p = &(t->next);
     }
 }
-#endif /* ASM_WEAKEN_LABEL */
+#endif /* defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL) */
 
 /* Emit an assembler directive to make the symbol for DECL an alias to
    the symbol for TARGET.  */
@@ -4988,10 +5171,14 @@ assemble_alias (decl, target)
 
   if (TREE_PUBLIC (decl))
     {
-#ifdef ASM_WEAKEN_LABEL
+#if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
       if (DECL_WEAK (decl))
-       {
+       {
+#ifdef ASM_WEAKEN_DECL
+         ASM_WEAKEN_DECL (asm_out_file, decl, name, 0);
+#else
          ASM_WEAKEN_LABEL (asm_out_file, name);
+#endif
          /* Remove this function from the pending weak list so that
             we do not emit multiple .weak directives for it.  */
          remove_from_pending_weak_list
@@ -5000,6 +5187,8 @@ assemble_alias (decl, target)
       else
 #endif
        ASM_GLOBALIZE_LABEL (asm_out_file, name);
+
+      maybe_assemble_visibility (decl);
     }
 
 #ifdef ASM_OUTPUT_DEF_FROM_DECLS
@@ -5008,12 +5197,16 @@ assemble_alias (decl, target)
   ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
 #endif
   TREE_ASM_WRITTEN (decl) = 1;
-#else
-#ifdef ASM_OUTPUT_WEAK_ALIAS
+#else /* !ASM_OUTPUT_DEF */
+#if defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
   if (! DECL_WEAK (decl))
     warning ("only weak aliases are supported in this configuration");
 
+#ifdef ASM_WEAKEN_DECL
+  ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
+#else
   ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
+#endif
   TREE_ASM_WRITTEN (decl) = 1;
 #else
   warning ("alias definitions not supported in this configuration; ignored");
@@ -5021,6 +5214,40 @@ assemble_alias (decl, target)
 #endif
 }
 
+/* Emit an assembler directive to set symbol for DECL visibility to
+   VISIBILITY_TYPE.  */
+
+void
+assemble_visibility (decl, visibility_type)
+     tree decl;
+     const char *visibility_type ATTRIBUTE_UNUSED;
+{
+  const char *name;
+
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
+#ifdef HAVE_GAS_HIDDEN
+  fprintf (asm_out_file, "\t.%s\t%s\n", visibility_type, name);
+#else
+  warning ("visibility attribute not supported in this configuration; ignored");
+#endif
+}
+
+/* A helper function to call assemble_visibility when needed for a decl.  */
+
+static void
+maybe_assemble_visibility (decl)
+     tree decl;
+{
+  tree visibility = lookup_attribute ("visibility", DECL_ATTRIBUTES (decl));
+  if (visibility)
+    {
+      const char *type
+       = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (visibility)));
+      assemble_visibility (decl, type);
+    }
+}
+
 /* Returns 1 if the target configuration supports defining public symbols
    so that one of them will be chosen at link time instead of generating a
    multiply-defined symbol error, whether through the use of weak symbols or
@@ -5074,6 +5301,7 @@ init_varasm_once ()
                mark_const_hash_entry);
   ggc_add_root (&const_str_htab, 1, sizeof const_str_htab,
                mark_const_str_htab);
+  ggc_add_root (&weak_decls, 1, sizeof weak_decls, mark_weak_decls);
 
   const_alias_set = new_alias_set ();
 }