OSDN Git Service

* varasm.c (default_elf_asm_output_limited_string): #ifdef
[pf3gnuchains/gcc-fork.git] / gcc / varasm.c
index 8c65696..b354846 100644 (file)
@@ -564,7 +564,7 @@ default_function_section (tree decl, enum node_frequency freq,
 /* Return the section for function DECL.
 
    If DECL is NULL_TREE, return the text section.  We can be passed
-   NULL_TREE under some circumstances by dbxout.c at least. 
+   NULL_TREE under some circumstances by dbxout.c at least.
 
    If FORCE_COLD is true, return cold function section ignoring
    the frequency info of cgraph_node.  */
@@ -1928,7 +1928,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
 
   /* Emulated TLS had better not get this far.  */
   gcc_checking_assert (targetm.have_tls || !DECL_THREAD_LOCAL_P (decl));
-              
+
   last_assemble_variable_decl = 0;
 
   /* Normally no need to say anything here for external references,
@@ -2104,7 +2104,8 @@ incorporeal_function_p (tree decl)
       const char *name;
 
       if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
-         && DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA)
+         && (DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA
+             || DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA_WITH_ALIGN))
        return true;
 
       name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
@@ -2391,7 +2392,7 @@ assemble_trampoline_template (void)
 
   initial_trampoline = gen_const_mem (BLKmode, symbol);
   set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
-  set_mem_size (initial_trampoline, GEN_INT (TRAMPOLINE_SIZE));
+  set_mem_size (initial_trampoline, TRAMPOLINE_SIZE);
 
   return initial_trampoline;
 }
@@ -2592,6 +2593,12 @@ decode_addr_const (tree exp, struct addr_const *value)
                     * tree_low_cst (TREE_OPERAND (target, 1), 0));
          target = TREE_OPERAND (target, 0);
        }
+      else if (TREE_CODE (target) == MEM_REF
+              && TREE_CODE (TREE_OPERAND (target, 0)) == ADDR_EXPR)
+       {
+         offset += mem_ref_offset (target).low;
+         target = TREE_OPERAND (TREE_OPERAND (target, 0), 0);
+       }
       else if (TREE_CODE (target) == INDIRECT_REF
               && TREE_CODE (TREE_OPERAND (target, 0)) == NOP_EXPR
               && TREE_CODE (TREE_OPERAND (TREE_OPERAND (target, 0), 0))
@@ -2845,7 +2852,7 @@ compare_constant (const tree t1, const tree t2)
              return 0;
            link2 = TREE_CHAIN (link2);
          }
-       
+
        return 1;
       }
 
@@ -3112,7 +3119,7 @@ build_constant_desc (tree exp)
   SET_SYMBOL_REF_DECL (symbol, decl);
   TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
 
-  rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
+  rtl = gen_const_mem (TYPE_MODE (TREE_TYPE (exp)), symbol);
   set_mem_attributes (rtl, exp, 1);
   set_mem_alias_set (rtl, 0);
   set_mem_alias_set (rtl, const_alias_set);
@@ -4628,9 +4635,10 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
 static unsigned HOST_WIDE_INT
 array_size_for_constructor (tree val)
 {
-  tree max_index, i;
+  tree max_index;
   unsigned HOST_WIDE_INT cnt;
   tree index, value, tmp;
+  double_int i;
 
   /* 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
@@ -4652,14 +4660,15 @@ array_size_for_constructor (tree val)
 
   /* Compute the total number of array elements.  */
   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, size_one_node);
+  i = double_int_sub (tree_to_double_int (max_index), tree_to_double_int (tmp));
+  i = double_int_add (i, double_int_one);
 
   /* Multiply by the array element unit size to find number of bytes.  */
-  i = size_binop (MULT_EXPR, i, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
+  i = double_int_mul (i, tree_to_double_int
+                          (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val)))));
 
-  return tree_low_cst (i, 1);
+  gcc_assert (double_int_fits_in_uhwi_p (i));
+  return i.low;
 }
 
 /* Other datastructures + helpers for output_constructor.  */
@@ -5745,7 +5754,7 @@ finish_aliases_1 (void)
               && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
        {
          error ("%q+D aliased to external symbol %qE",
-                p->decl, p->target);     
+                p->decl, p->target);
          p->emitted_diags |= ALIAS_DIAG_TO_EXTERN;
        }
     }
@@ -5811,7 +5820,7 @@ assemble_alias (tree decl, tree target)
          if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
            error_at (DECL_SOURCE_LOCATION (decl),
                      "ifunc is not supported in this configuration");
-         else  
+         else
            error_at (DECL_SOURCE_LOCATION (decl),
                      "only weak aliases are supported in this configuration");
          return;
@@ -5850,11 +5859,167 @@ assemble_alias (tree decl, tree target)
     }
 }
 
+/* Record and output a table of translations from original function
+   to its transaction aware clone.  Note that tm_pure functions are
+   considered to be their own clone.  */
+
+static GTY((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
+     htab_t tm_clone_hash;
+
+void
+record_tm_clone_pair (tree o, tree n)
+{
+  struct tree_map **slot, *h;
+
+  if (tm_clone_hash == NULL)
+    tm_clone_hash = htab_create_ggc (32, tree_map_hash, tree_map_eq, 0);
+
+  h = ggc_alloc_tree_map ();
+  h->hash = htab_hash_pointer (o);
+  h->base.from = o;
+  h->to = n;
+
+  slot = (struct tree_map **)
+    htab_find_slot_with_hash (tm_clone_hash, h, h->hash, INSERT);
+  *slot = h;
+}
+
+tree
+get_tm_clone_pair (tree o)
+{
+  if (tm_clone_hash)
+    {
+      struct tree_map *h, in;
+
+      in.base.from = o;
+      in.hash = htab_hash_pointer (o);
+      h = (struct tree_map *) htab_find_with_hash (tm_clone_hash,
+                                                  &in, in.hash);
+      if (h)
+       return h->to;
+    }
+  return NULL_TREE;
+}
+
+typedef struct tm_alias_pair
+{
+  unsigned int uid;
+  tree from;
+  tree to;
+} tm_alias_pair;
+
+DEF_VEC_O(tm_alias_pair);
+DEF_VEC_ALLOC_O(tm_alias_pair,heap);
+
+/* Helper function for finish_tm_clone_pairs.  Dump a hash table entry
+   into a VEC in INFO.  */
+
+static int
+dump_tm_clone_to_vec (void **slot, void *info)
+{
+  struct tree_map *map = (struct tree_map *) *slot;
+  VEC(tm_alias_pair,heap) **tm_alias_pairs
+    = (VEC(tm_alias_pair, heap) **) info;
+  tm_alias_pair *p;
+
+  p = VEC_safe_push (tm_alias_pair, heap, *tm_alias_pairs, NULL);
+  p->from = map->base.from;
+  p->to = map->to;
+  p->uid = DECL_UID (p->from);
+  return 1;
+}
+
+/* Dump the actual pairs to the .tm_clone_table section.  */
+
+static void
+dump_tm_clone_pairs (VEC(tm_alias_pair,heap) *tm_alias_pairs)
+{
+  unsigned i;
+  tm_alias_pair *p;
+  bool switched = false;
+
+  FOR_EACH_VEC_ELT (tm_alias_pair, tm_alias_pairs, i, p)
+    {
+      tree src = p->from;
+      tree dst = p->to;
+      struct cgraph_node *src_n = cgraph_get_node (src);
+      struct cgraph_node *dst_n = cgraph_get_node (dst);
+
+      /* The function ipa_tm_create_version() marks the clone as needed if
+        the original function was needed.  But we also mark the clone as
+        needed if we ever called the clone indirectly through
+        TM_GETTMCLONE.  If neither of these are true, we didn't generate
+        a clone, and we didn't call it indirectly... no sense keeping it
+        in the clone table.  */
+      if (!dst_n || !dst_n->needed)
+       continue;
+
+      /* This covers the case where we have optimized the original
+        function away, and only access the transactional clone.  */
+      if (!src_n || !src_n->needed)
+       continue;
+
+      if (!switched)
+       {
+         switch_to_section (get_named_section (NULL, ".tm_clone_table", 3));
+         assemble_align (POINTER_SIZE);
+         switched = true;
+       }
+
+      assemble_integer (XEXP (DECL_RTL (src), 0),
+                       POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+      assemble_integer (XEXP (DECL_RTL (dst), 0),
+                       POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+    }
+}
+
+/* Helper comparison function for qsorting by the DECL_UID stored in
+   alias_pair->emitted_diags.  */
+
+static int
+tm_alias_pair_cmp (const void *x, const void *y)
+{
+  const tm_alias_pair *p1 = (const tm_alias_pair *) x;
+  const tm_alias_pair *p2 = (const tm_alias_pair *) y;
+  if (p1->uid < p2->uid)
+    return -1;
+  if (p1->uid > p2->uid)
+    return 1;
+  return 0;
+}
+
+void
+finish_tm_clone_pairs (void)
+{
+  VEC(tm_alias_pair,heap) *tm_alias_pairs = NULL;
+
+  if (tm_clone_hash == NULL)
+    return;
+
+  /* We need a determenistic order for the .tm_clone_table, otherwise
+     we will get bootstrap comparison failures, so dump the hash table
+     to a vector, sort it, and dump the vector.  */
+
+  /* Dump the hashtable to a vector.  */
+  htab_traverse_noresize (tm_clone_hash, dump_tm_clone_to_vec,
+                         (void *) &tm_alias_pairs);
+  /* Sort it.  */
+  VEC_qsort (tm_alias_pair, tm_alias_pairs, tm_alias_pair_cmp);
+
+  /* Dump it.  */
+  dump_tm_clone_pairs (tm_alias_pairs);
+
+  htab_delete (tm_clone_hash);
+  tm_clone_hash = NULL;
+  VEC_free (tm_alias_pair, heap, tm_alias_pairs);
+}
+
+
 /* Emit an assembler directive to set symbol for DECL visibility to
    the visibility type VIS, which must not be VISIBILITY_DEFAULT.  */
 
 void
-default_assemble_visibility (tree decl ATTRIBUTE_UNUSED, 
+default_assemble_visibility (tree decl ATTRIBUTE_UNUSED,
                             int vis ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_GAS_HIDDEN
@@ -6151,6 +6316,8 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
 
   if (!(flags & SECTION_DEBUG))
     *f++ = 'a';
+  if (flags & SECTION_EXCLUDE)
+    *f++ = 'e';
   if (flags & SECTION_WRITE)
     *f++ = 'w';
   if (flags & SECTION_CODE)
@@ -6673,6 +6840,7 @@ static bool
 resolution_to_local_definition_p (enum ld_plugin_symbol_resolution resolution)
 {
   return (resolution == LDPR_PREVAILING_DEF
+         || resolution == LDPR_PREVAILING_DEF_IRONLY_EXP
          || resolution == LDPR_PREVAILING_DEF_IRONLY);
 }
 
@@ -6684,6 +6852,7 @@ resolution_local_p (enum ld_plugin_symbol_resolution resolution)
 {
   return (resolution == LDPR_PREVAILING_DEF
          || resolution == LDPR_PREVAILING_DEF_IRONLY
+         || resolution == LDPR_PREVAILING_DEF_IRONLY_EXP
          || resolution == LDPR_PREEMPTED_REG
          || resolution == LDPR_PREEMPTED_IR
          || resolution == LDPR_RESOLVED_IR
@@ -6707,7 +6876,7 @@ default_binds_local_p_1 (const_tree exp, int shlib)
   bool resolved_to_local_def = false;
 
   /* With resolution file in hands, take look into resolutions.
-     We can't just return true for resolved_localy symbols,
+     We can't just return true for resolved_locally symbols,
      because dynamic linking might overwrite symbols
      in shared libraries.  */
   if (TREE_CODE (exp) == VAR_DECL && TREE_PUBLIC (exp)
@@ -6816,7 +6985,7 @@ decl_binds_to_current_def_p (tree decl)
        return resolution_to_local_definition_p (node->resolution);
     }
   /* Otherwise we have to assume the worst for DECL_WEAK (hidden weaks
-     binds localy but still can be overwritten).
+     binds locally but still can be overwritten).
      This rely on fact that binds_local_p behave as decl_replaceable_p
      for all other declaration types.  */
   return !DECL_WEAK (decl);
@@ -7350,4 +7519,188 @@ make_debug_expr_from_rtl (const_rtx exp)
   return dval;
 }
 
+#ifdef ELF_ASCII_ESCAPES
+/* Default ASM_OUTPUT_LIMITED_STRING for ELF targets.  */
+
+void
+default_elf_asm_output_limited_string (FILE *f, const char *s)
+{
+  int escape;
+  unsigned char c;
+
+  fputs ("\t.string\t\"", f);
+  while (*s != '\0')
+    {
+      c = *s;
+      escape = ELF_ASCII_ESCAPES[c];
+      switch (escape)
+       {
+       case 0:
+         putc (c, f);
+         break;
+       case 1:
+         /* TODO: Print in hex with fast function, important for -flto. */
+         fprintf (f, "\\%03o", c);
+         break;
+       default:
+         putc ('\\', f);
+         putc (escape, f);
+         break;
+       }
+      s++;
+    }
+  putc ('\"', f);
+  putc ('\n', f);
+}
+
+/* Default ASM_OUTPUT_ASCII for ELF targets.  */
+
+void
+default_elf_asm_output_ascii (FILE *f, const char *s, unsigned int len)
+{
+  const char *limit = s + len;
+  const char *last_null = NULL;
+  unsigned bytes_in_chunk = 0;
+  unsigned char c;
+  int escape;
+
+  for (; s < limit; s++)
+    {
+      const char *p;
+
+      if (bytes_in_chunk >= 60)
+       {
+         putc ('\"', f);
+         putc ('\n', f);
+         bytes_in_chunk = 0;
+       }
+
+      if (s > last_null)
+       {
+         for (p = s; p < limit && *p != '\0'; p++)
+           continue;
+         last_null = p;
+       }
+      else
+       p = last_null;
+
+      if (p < limit && (p - s) <= (long) ELF_STRING_LIMIT)
+       {
+         if (bytes_in_chunk > 0)
+           {
+             putc ('\"', f);
+             putc ('\n', f);
+             bytes_in_chunk = 0;
+           }
+
+         default_elf_asm_output_limited_string (f, s);
+         s = p;
+       }
+      else
+       {
+         if (bytes_in_chunk == 0)
+           fputs (ASCII_DATA_ASM_OP "\"", f);
+
+         c = *s;
+         escape = ELF_ASCII_ESCAPES[c];
+         switch (escape)
+           {
+           case 0:
+             putc (c, f);
+             bytes_in_chunk++;
+             break;
+           case 1:
+             /* TODO: Print in hex with fast function, important for -flto. */
+             fprintf (f, "\\%03o", c);
+             bytes_in_chunk += 4;
+             break;
+           default:
+             putc ('\\', f);
+             putc (escape, f);
+             bytes_in_chunk += 2;
+             break;
+           }
+
+       }
+    }
+
+  if (bytes_in_chunk > 0)
+    {
+      putc ('\"', f);
+      putc ('\n', f);
+    }
+}
+#endif
+
+/* Default TARGET_ASM_INTERNAL_LABEL for ELF targets.  */
+
+void
+default_elf_internal_label (FILE *f, const char *prefix,
+                           unsigned long labelno)
+{
+  putc ('.', f);
+  fputs (prefix, f);
+  fprint_ul (f, labelno);
+  putc (':', f);
+  putc ('\n', f);
+}
+
+static GTY(()) section *elf_init_array_section;
+static GTY(()) section *elf_fini_array_section;
+
+static section *
+get_elf_initfini_array_priority_section (int priority,
+                                        bool constructor_p)
+{
+  section *sec;
+  if (priority != DEFAULT_INIT_PRIORITY)
+    {
+      char buf[18];
+      sprintf (buf, "%s.%.5u", 
+              constructor_p ? ".init_array" : ".fini_array",
+              priority);
+      sec = get_section (buf, SECTION_WRITE, NULL_TREE);
+    }
+  else
+    {
+      if (constructor_p)
+       {
+         if (elf_init_array_section == NULL)
+           elf_init_array_section
+             = get_unnamed_section (0, output_section_asm_op,
+                                    "\t.section\t.init_array");
+         sec = elf_init_array_section;
+       }
+      else
+       {
+         if (elf_fini_array_section == NULL)
+           elf_fini_array_section
+             = get_unnamed_section (0, output_section_asm_op,
+                                    "\t.section\t.fini_array");
+         sec = elf_fini_array_section;
+       }
+    }
+  return sec;
+}
+
+/* Use .init_array section for constructors. */
+
+void
+default_elf_init_array_asm_out_constructor (rtx symbol, int priority)
+{
+  section *sec = get_elf_initfini_array_priority_section (priority,
+                                                         true);
+  assemble_addr_to_section (symbol, sec);
+}
+
+/* Use .fini_array section for destructors. */
+
+void
+default_elf_fini_array_asm_out_destructor (rtx symbol, int priority)
+{
+  section *sec = get_elf_initfini_array_priority_section (priority,
+                                                         false);
+  assemble_addr_to_section (symbol, sec);
+}
+
 #include "gt-varasm.h"