OSDN Git Service

2006-12-05 H.J. Lu <hongjiu.lu@intel.com>
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 4835c30..819add8 100644 (file)
@@ -139,6 +139,7 @@ static void asm_output_aligned_bss (FILE *, tree, const char *,
 #endif
 #endif /* BSS_SECTION_ASM_OP */
 static void mark_weak (tree);
+static void output_constant_pool (const char *, tree);
 \f
 /* Well-known sections, each one associated with some sort of *_ASM_OP.  */
 section *text_section;
@@ -196,6 +197,9 @@ static GTY((param_is (struct object_block))) htab_t object_block_htab;
 /* The next number to use for internal anchor labels.  */
 static GTY(()) int anchor_labelno;
 
+/* A pool of constants that can be shared between functions.  */
+static GTY(()) struct rtx_constant_pool *shared_constant_pool;
+
 /* Helper routines for maintaining section_htab.  */
 
 static int
@@ -651,16 +655,20 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
                          unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
                          unsigned int flags ATTRIBUTE_UNUSED)
 {
+  HOST_WIDE_INT len;
+
   if (HAVE_GAS_SHF_MERGE && flag_merge_constants
       && TREE_CODE (decl) == STRING_CST
       && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
       && align <= 256
-      && TREE_STRING_LENGTH (decl) >= int_size_in_bytes (TREE_TYPE (decl)))
+      && (len = int_size_in_bytes (TREE_TYPE (decl))) > 0
+      && TREE_STRING_LENGTH (decl) >= len)
     {
       enum machine_mode mode;
       unsigned int modesize;
       const char *str;
-      int i, j, len, unit;
+      HOST_WIDE_INT i;
+      int j, unit;
       char name[30];
 
       mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl)));
@@ -672,7 +680,6 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
            align = modesize;
 
          str = TREE_STRING_POINTER (decl);
-         len = TREE_STRING_LENGTH (decl);
          unit = GET_MODE_SIZE (mode);
 
          /* Check for embedded NUL characters.  */
@@ -824,6 +831,48 @@ bss_initializer_p (tree decl)
              && initializer_zerop (DECL_INITIAL (decl))));
 }
 
+/* Compute the alignment of variable specified by DECL.
+   DONT_OUTPUT_DATA is from assemble_variable.  */
+
+void
+align_variable (tree decl, bool dont_output_data)
+{
+  unsigned int 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.  */
+  if (align > MAX_OFILE_ALIGNMENT)
+    {
+      warning (0, "alignment of %q+D is greater than maximum object "
+               "file alignment.  Using %d", decl,
+              MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
+      align = MAX_OFILE_ALIGNMENT;
+    }
+
+  /* On some machines, it is good to increase alignment sometimes.  */
+  if (! DECL_USER_ALIGN (decl))
+    {
+#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;
+}
+
 /* Return the section into which the given VAR_DECL or CONST_DECL
    should be placed.  PREFER_NOSWITCH_P is true if a noswitch
    section should be used wherever possible.  */
@@ -895,6 +944,8 @@ get_block_for_decl (tree decl)
 
   /* Find out which section should contain DECL.  We cannot put it into
      an object block if it requires a standalone definition.  */
+  if (TREE_CODE (decl) == VAR_DECL)
+      align_variable (decl, 0);
   sect = get_variable_section (decl, true);
   if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
     return NULL;
@@ -1259,7 +1310,8 @@ notice_global_symbol (tree decl)
   const char **type = &first_global_object_name;
 
   if (first_global_object_name
-      || !TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)
+      || !TREE_PUBLIC (decl)
+      || DECL_EXTERNAL (decl)
       || !DECL_NAME (decl)
       || (TREE_CODE (decl) != FUNCTION_DECL
          && (TREE_CODE (decl) != VAR_DECL
@@ -1435,7 +1487,7 @@ assemble_start_function (tree decl, const char *fnname)
    function.  DECL describes the function.  NAME is the function's name.  */
 
 void
-assemble_end_function (tree decl, const char *fnname)
+assemble_end_function (tree decl, const char *fnname ATTRIBUTE_UNUSED)
 {
 #ifdef ASM_DECLARE_FUNCTION_SIZE
   /* We could have switched section in the middle of the function.  */
@@ -1678,7 +1730,6 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
                   int at_end ATTRIBUTE_UNUSED, int dont_output_data)
 {
   const char *name;
-  unsigned int align;
   rtx decl_rtl, symbol;
   section *sect;
 
@@ -1759,41 +1810,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   /* 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.  */
-  if (align > MAX_OFILE_ALIGNMENT)
-    {
-      warning (0, "alignment of %q+D is greater than maximum object "
-               "file alignment.  Using %d", decl,
-              MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
-      align = MAX_OFILE_ALIGNMENT;
-    }
-
-  /* On some machines, it is good to increase alignment sometimes.  */
-  if (! DECL_USER_ALIGN (decl))
-    {
-#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;
-  set_mem_align (decl_rtl, align);
+  align_variable (decl, dont_output_data);
+  set_mem_align (decl_rtl, DECL_ALIGN (decl));
 
   if (TREE_PUBLIC (decl))
     maybe_assemble_visibility (decl);
@@ -1813,7 +1831,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
     output_addressed_constants (DECL_INITIAL (decl));
 
   /* dbxout.c needs to know this.  */
-  if (in_section && (in_section->common.flags & SECTION_CODE) != 0)
+  if (sect && (sect->common.flags & SECTION_CODE) != 0)
     DECL_IN_TEXT_SECTION (decl) = 1;
 
   /* If the decl is part of an object_block, make sure that the decl
@@ -1829,7 +1847,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   else
     {
       switch_to_section (sect);
-      if (align > BITS_PER_UNIT)
+      if (DECL_ALIGN (decl) > BITS_PER_UNIT)
        ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
       assemble_variable_contents (decl, name, dont_output_data);
     }
@@ -2731,7 +2749,7 @@ copy_constant (tree exp)
       {
        tree t = lang_hooks.expand_constant (exp);
 
-       gcc_assert (t == exp);
+       gcc_assert (t != exp);
        return copy_constant (t);
       }
     }
@@ -3121,25 +3139,34 @@ const_rtx_hash (rtx x)
 }
 
 \f
+/* Create and return a new rtx constant pool.  */
+
+static struct rtx_constant_pool *
+create_constant_pool (void)
+{
+  struct rtx_constant_pool *pool;
+
+  pool = ggc_alloc (sizeof (struct rtx_constant_pool));
+  pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
+                                         const_desc_rtx_eq, NULL);
+  pool->first = NULL;
+  pool->last = NULL;
+  pool->offset = 0;
+  return pool;
+}
+
 /* Initialize constant pool hashing for a new function.  */
 
 void
 init_varasm_status (struct function *f)
 {
   struct varasm_status *p;
-  struct rtx_constant_pool *pool;
 
   p = ggc_alloc (sizeof (struct varasm_status));
   f->varasm = p;
 
-  pool = ggc_alloc (sizeof (struct rtx_constant_pool));
-  p->pool = pool;
+  p->pool = create_constant_pool ();
   p->deferred_constants = 0;
-
-  pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
-                                         const_desc_rtx_eq, NULL);
-  pool->first = pool->last = NULL;
-  pool->offset = 0;
 }
 \f
 /* Given a MINUS expression, simplify it if both sides
@@ -3159,7 +3186,7 @@ rtx
 force_const_mem (enum machine_mode mode, rtx x)
 {
   struct constant_descriptor_rtx *desc, tmp;
-  struct rtx_constant_pool *pool = cfun->varasm->pool;
+  struct rtx_constant_pool *pool;
   char label[256];
   rtx def, symbol;
   hashval_t hash;
@@ -3170,6 +3197,14 @@ force_const_mem (enum machine_mode mode, rtx x)
   if (targetm.cannot_force_const_mem (x))
     return NULL_RTX;
 
+  /* Record that this function has used a constant pool entry.  */
+  current_function_uses_const_pool = 1;
+
+  /* Decide which pool to use.  */
+  pool = (targetm.use_blocks_for_constant_p (mode, x)
+         ? shared_constant_pool
+         : cfun->varasm->pool);
+
   /* Lookup the value in the hashtable.  */
   tmp.constant = x;
   tmp.mode = mode;
@@ -3232,7 +3267,6 @@ force_const_mem (enum machine_mode mode, rtx x)
   SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
   CONSTANT_POOL_ADDRESS_P (symbol) = 1;
   SET_SYMBOL_REF_CONSTANT (symbol, desc);
-  current_function_uses_const_pool = 1;
 
   /* Construct the MEM.  */
   desc->mem = def = gen_const_mem (mode, symbol);
@@ -3403,9 +3437,8 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc,
    be used with for_each_rtx to mark all SYMBOL_REFs in an rtx.  */
 
 static int
-mark_constant (rtx *current_rtx, void *data)
+mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED)
 {
-  struct rtx_constant_pool *pool = data;
   rtx x = *current_rtx;
 
   if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
@@ -3417,7 +3450,7 @@ mark_constant (rtx *current_rtx, void *data)
       if (desc->mark == 0)
        {
          desc->mark = 1;
-         for_each_rtx (&desc->constant, mark_constant, pool);
+         for_each_rtx (&desc->constant, mark_constant, NULL);
        }
     }
   else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
@@ -3439,7 +3472,7 @@ mark_constant (rtx *current_rtx, void *data)
    deferred strings that are used.  */
 
 static void
-mark_constants (struct rtx_constant_pool *pool, rtx insn)
+mark_constants (rtx insn)
 {
   if (!INSN_P (insn))
     return;
@@ -3455,11 +3488,11 @@ mark_constants (struct rtx_constant_pool *pool, rtx insn)
        {
          rtx subinsn = XVECEXP (seq, 0, i);
          if (INSN_P (subinsn))
-           for_each_rtx (&PATTERN (subinsn), mark_constant, pool);
+           for_each_rtx (&PATTERN (subinsn), mark_constant, NULL);
        }
     }
   else
-    for_each_rtx (&PATTERN (insn), mark_constant, pool);
+    for_each_rtx (&PATTERN (insn), mark_constant, NULL);
 }
 
 /* Look through the instructions for this function, and mark all the
@@ -3467,40 +3500,29 @@ mark_constants (struct rtx_constant_pool *pool, rtx insn)
    which have indeed been used.  */
 
 static void
-mark_constant_pool (struct rtx_constant_pool *pool)
+mark_constant_pool (void)
 {
   rtx insn, link;
 
-  if (pool->first == 0 && n_deferred_constants == 0)
+  if (!current_function_uses_const_pool && n_deferred_constants == 0)
     return;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    mark_constants (pool, insn);
+    mark_constants (insn);
 
   for (link = current_function_epilogue_delay_list;
        link;
        link = XEXP (link, 1))
-    mark_constants (pool, XEXP (link, 0));
+    mark_constants (XEXP (link, 0));
 }
 
-/* Write all the constants in the constant pool.  */
+/* Write all the constants in POOL.  */
 
-void
-output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
-                     tree fndecl ATTRIBUTE_UNUSED)
+static void
+output_constant_pool_contents (struct rtx_constant_pool *pool)
 {
-  struct rtx_constant_pool *pool = cfun->varasm->pool;
   struct constant_descriptor_rtx *desc;
 
-  /* 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.  */
-  mark_constant_pool (pool);
-
-#ifdef ASM_OUTPUT_POOL_PROLOGUE
-  ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
-#endif
-
   for (desc = pool->first; desc ; desc = desc->next)
     if (desc->mark)
       {
@@ -3518,12 +3540,41 @@ output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
            output_constant_pool_1 (desc, desc->align);
          }
       }
+}
+
+/* Mark all constants that are used in the current function, then write
+   out the function's private constant pool.  */
+
+static void
+output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
+                     tree fndecl ATTRIBUTE_UNUSED)
+{
+  struct rtx_constant_pool *pool = cfun->varasm->pool;
+
+  /* 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.  */
+  mark_constant_pool ();
+
+#ifdef ASM_OUTPUT_POOL_PROLOGUE
+  ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
+#endif
+
+  output_constant_pool_contents (pool);
 
 #ifdef ASM_OUTPUT_POOL_EPILOGUE
   ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
 #endif
 }
 \f
+/* Write the contents of the shared constant pool.  */
+
+void
+output_shared_constant_pool (void)
+{
+  output_constant_pool_contents (shared_constant_pool);
+}
+\f
 /* Determine what kind of relocations EXP may need.  */
 
 int
@@ -3648,6 +3699,20 @@ output_addressed_constants (tree exp)
     }
 }
 \f
+/* Whether a constructor CTOR is a valid static constant initializer if all
+   its elements are.  This used to be internal to initializer_constant_valid_p
+   and has been exposed to let other functions like categorize_ctor_elements
+   evaluate the property while walking a constructor for other purposes.  */
+
+bool
+constructor_static_from_elts_p (tree ctor)
+{
+  return (TREE_CONSTANT (ctor)
+         && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
+             || TREE_CODE (TREE_TYPE (ctor)) == RECORD_TYPE)
+         && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
+}
+
 /* 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.
@@ -3668,10 +3733,7 @@ initializer_constant_valid_p (tree value, tree endtype)
   switch (TREE_CODE (value))
     {
     case CONSTRUCTOR:
-      if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
-          || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
-         && TREE_CONSTANT (value)
-         && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (value)))
+      if (constructor_static_from_elts_p (value))
        {
          unsigned HOST_WIDE_INT idx;
          tree elt;
@@ -3977,15 +4039,18 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
       if (type_size > op_size
          && TREE_CODE (exp) != VIEW_CONVERT_EXPR
          && TREE_CODE (TREE_TYPE (exp)) != UNION_TYPE)
-       internal_error ("no-op convert from %wd to %wd bytes in initializer",
-                       op_size, type_size);
-
-      exp = TREE_OPERAND (exp, 0);
+       /* Keep the conversion. */
+       break;
+      else
+       exp = TREE_OPERAND (exp, 0);
     }
 
   code = TREE_CODE (TREE_TYPE (exp));
   thissize = int_size_in_bytes (TREE_TYPE (exp));
 
+  /* Give the front end another chance to expand constants.  */
+  exp = lang_hooks.expand_constant (exp);
+
   /* Allow a constructor with no elements for any data type.
      This means to fill the space with zeros.  */
   if (TREE_CODE (exp) == CONSTRUCTOR
@@ -4063,8 +4128,12 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
 
            link = TREE_VECTOR_CST_ELTS (exp);
            output_constant (TREE_VALUE (link), elt_size, align);
+           thissize = elt_size;
            while ((link = TREE_CHAIN (link)) != NULL)
-             output_constant (TREE_VALUE (link), elt_size, nalign);
+             {
+               output_constant (TREE_VALUE (link), elt_size, nalign);
+               thissize += elt_size;
+             }
            break;
          }
        default:
@@ -4099,7 +4168,7 @@ array_size_for_constructor (tree val)
 {
   tree max_index, i;
   unsigned HOST_WIDE_INT cnt;
-  tree index, value;
+  tree index, value, tmp;
 
   /* This code used to attempt to handle string constants that are not
      arrays of single-bytes, but nothing else does, so there's no point in
@@ -4120,9 +4189,9 @@ array_size_for_constructor (tree val)
     return 0;
 
   /* Compute the total number of array elements.  */
-  i = size_binop (MINUS_EXPR, convert (sizetype, max_index),
-                 convert (sizetype,
-                          TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
+  tmp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)));
+  i = size_binop (MINUS_EXPR, fold_convert (sizetype, max_index),
+                 fold_convert (sizetype, tmp));
   i = size_binop (PLUS_EXPR, i, build_int_cst (sizetype, 1));
 
   /* Multiply by the array element unit size to find number of bytes.  */
@@ -4695,16 +4764,16 @@ globalize_decl (tree decl)
            p = &TREE_CHAIN (t);
        }
 
-       /* Remove weakrefs to the same target from the pending weakref
-          list, for the same reason.  */
-       for (p = &weakref_targets; (t = *p) ; )
-         {
-           if (DECL_ASSEMBLER_NAME (decl)
-               == ultimate_transparent_alias_target (&TREE_VALUE (t)))
-             *p = TREE_CHAIN (t);
-           else
-             p = &TREE_CHAIN (t);
-         }
+      /* Remove weakrefs to the same target from the pending weakref
+        list, for the same reason.  */
+      for (p = &weakref_targets; (t = *p) ; )
+       {
+         if (DECL_ASSEMBLER_NAME (decl)
+             == ultimate_transparent_alias_target (&TREE_VALUE (t)))
+           *p = TREE_CHAIN (t);
+         else
+           p = &TREE_CHAIN (t);
+       }
 
       return;
     }
@@ -4982,7 +5051,7 @@ void
 default_assemble_visibility (tree decl, int vis)
 {
   static const char * const visibility_types[] = {
-    NULL, "internal", "hidden", "protected"
+    NULL, "protected", "hidden", "internal"
   };
 
   const char *name, *type;
@@ -5063,6 +5132,7 @@ init_varasm_once (void)
                                     const_desc_eq, NULL);
 
   const_alias_set = new_alias_set ();
+  shared_constant_pool = create_constant_pool ();
 
 #ifdef TEXT_SECTION_ASM_OP
   text_section = get_unnamed_section (SECTION_CODE, output_section_asm_op,