#include "tm_p.h"
#include "debug.h"
#include "target.h"
+#include "common/common-target.h"
#include "targhooks.h"
#include "tree-mudflap.h"
#include "cgraph.h"
if (decl == 0)
decl = sect->named.decl;
gcc_assert (decl);
- error ("%+D causes a section type conflict", decl);
+ error ("%+D causes a section type conflict with %D",
+ decl, sect->named.decl);
+ if (decl != sect->named.decl)
+ inform (DECL_SOURCE_LOCATION (sect->named.decl),
+ "%qD was declared here", sect->named.decl);
/* Make sure we don't error about one section multiple times. */
sect->common.flags |= SECTION_OVERRIDE;
}
int flag_function_or_data_sections)
{
if (DECL_SECTION_NAME (decl) == NULL_TREE
- && targetm.have_named_sections
+ && targetm_common.have_named_sections
&& (flag_function_or_data_sections
|| DECL_ONE_ONLY (decl)))
{
{
if (decl != NULL_TREE
&& DECL_SECTION_NAME (decl) != NULL_TREE
- && targetm.have_named_sections)
+ && targetm_common.have_named_sections)
return get_named_section (decl, NULL, 0);
else
return text_section;
#endif
if (!flag_reorder_functions
- || !targetm.have_named_sections)
+ || !targetm_common.have_named_sections)
return NULL;
/* Startup code should go to startup subsection unless it is
unlikely executed (this happens especially with function splitting
/* 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. */
const char *str;
HOST_WIDE_INT i;
int j, unit;
- char name[30];
+ const char *prefix = targetm.asm_out.mergeable_rodata_prefix;
+ char *name = (char *) alloca (strlen (prefix) + 30);
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl)));
modesize = GET_MODE_BITSIZE (mode);
}
if (i == len - unit)
{
- sprintf (name, ".rodata.str%d.%d", modesize / 8,
- (int) (align / 8));
+ sprintf (name, "%s.str%d.%d", prefix,
+ modesize / 8, (int) (align / 8));
flags |= (modesize / 8) | SECTION_MERGE | SECTION_STRINGS;
return get_section (name, flags, NULL);
}
&& align <= 256
&& (align & (align - 1)) == 0)
{
- char name[24];
+ const char *prefix = targetm.asm_out.mergeable_rodata_prefix;
+ char *name = (char *) alloca (strlen (prefix) + 30);
- sprintf (name, ".rodata.cst%d", (int) (align / 8));
+ sprintf (name, "%s.cst%d", prefix, (int) (align / 8));
flags |= (align / 8) | SECTION_MERGE;
return get_section (name, flags, NULL);
}
#endif
nregs = hard_regno_nregs[reg_number][DECL_MODE (decl)];
while (nregs > 0)
- globalize_reg (reg_number + --nregs);
+ globalize_reg (decl, reg_number + --nregs);
}
/* As a register variable, it has no section. */
}
}
+/* If not using flag_reorder_blocks_and_partition, decide early whether the
+ current function goes into the cold section, so that targets can use
+ current_function_section during RTL expansion. DECL describes the
+ function. */
+
+void
+decide_function_section (tree decl)
+{
+ first_function_block_is_cold = false;
+
+ if (flag_reorder_blocks_and_partition)
+ /* We will decide in assemble_start_function. */
+ return;
+
+ if (DECL_SECTION_NAME (decl))
+ {
+ struct cgraph_node *node = cgraph_get_node (current_function_decl);
+ /* Calls to function_section rely on first_function_block_is_cold
+ being accurate. */
+ first_function_block_is_cold = (node
+ && node->frequency
+ == NODE_FREQUENCY_UNLIKELY_EXECUTED);
+ }
+
+ in_cold_section_p = first_function_block_is_cold;
+}
+
/* Output assembler code for the constant pool of a function and associated
with defining the name of the function. DECL describes the function.
NAME is the function's name. For the constant pool, we use the current
char tmp_label[100];
bool hot_label_written = false;
- first_function_block_is_cold = false;
if (flag_reorder_blocks_and_partition)
{
ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno);
if (flag_reorder_blocks_and_partition)
{
+ first_function_block_is_cold = false;
+
switch_to_section (unlikely_text_section ());
assemble_align (DECL_ALIGN (decl));
ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.cold_section_label);
hot_label_written = true;
first_function_block_is_cold = true;
}
- }
- else if (DECL_SECTION_NAME (decl))
- {
- struct cgraph_node *node = cgraph_get_node (current_function_decl);
- /* Calls to function_section rely on first_function_block_is_cold
- being accurate. */
- first_function_block_is_cold = (node
- && node->frequency
- == NODE_FREQUENCY_UNLIKELY_EXECUTED);
+ in_cold_section_p = first_function_block_is_cold;
}
- in_cold_section_p = first_function_block_is_cold;
/* Switch to the correct text section for the start of the function. */
/* 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,
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));
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;
}
* 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))
return 0;
link2 = TREE_CHAIN (link2);
}
-
+
return 1;
}
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);
void **slot;
/* If we're not allowed to drop X into the constant pool, don't. */
- if (targetm.cannot_force_const_mem (x))
+ if (targetm.cannot_force_const_mem (mode, x))
return NULL_RTX;
/* Record that this function has used a constant pool entry. */
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
/* 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. */
unsigned int align2;
if (local->index != NULL_TREE)
- fieldpos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (local->val)), 1)
- * ((tree_low_cst (local->index, 0)
- - tree_low_cst (local->min_index, 0))));
+ {
+ double_int idx = double_int_sub (tree_to_double_int (local->index),
+ tree_to_double_int (local->min_index));
+ gcc_assert (double_int_fits_in_shwi_p (idx));
+ fieldpos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (local->val)), 1)
+ * idx.low);
+ }
else if (local->field != NULL_TREE)
fieldpos = int_byte_position (local->field);
else
better be last. */
gcc_assert (!fieldsize || !DECL_CHAIN (local->field));
}
- else if (DECL_SIZE_UNIT (local->field))
- {
- /* ??? This can't be right. If the decl size overflows
- a host integer we will silently emit no data. */
- if (host_integerp (DECL_SIZE_UNIT (local->field), 1))
- fieldsize = tree_low_cst (DECL_SIZE_UNIT (local->field), 1);
- }
+ else
+ fieldsize = tree_low_cst (DECL_SIZE_UNIT (local->field), 1);
}
else
fieldsize = int_size_in_bytes (TREE_TYPE (local->type));
else if (TREE_CODE (local.type) == ARRAY_TYPE)
local.index = ce->index;
-#ifdef ASM_COMMENT_START
if (local.field && flag_verbose_asm)
fprintf (asm_out_file, "%s %s:\n",
ASM_COMMENT_START,
DECL_NAME (local.field)
? IDENTIFIER_POINTER (DECL_NAME (local.field))
: "<anonymous>");
-#endif
/* Eliminate the marker that makes a cast not be an lvalue. */
if (local.val != NULL_TREE)
&& ! 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;
}
}
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;
}
}
+/* 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
if (!(flags & SECTION_DEBUG))
*f++ = 'a';
+ if (flags & SECTION_EXCLUDE)
+ *f++ = 'e';
if (flags & SECTION_WRITE)
*f++ = 'w';
if (flags & SECTION_CODE)
type = "progbits";
format = ",@%s";
-#ifdef ASM_COMMENT_START
/* On platforms that use "@" as the assembly comment character,
use "%" instead. */
if (strcmp (ASM_COMMENT_START, "@") == 0)
format = ",%%%s";
-#endif
fprintf (asm_out_file, format, type);
if (flags & SECTION_ENTSIZE)
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);
}
{
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
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)
}
else if (TREE_CODE (exp) == FUNCTION_DECL && TREE_PUBLIC (exp))
{
- struct cgraph_node *node = cgraph_get_node_or_alias (exp);
+ struct cgraph_node *node = cgraph_get_node (exp);
if (node
&& resolution_local_p (node->resolution))
resolved_locally = true;
}
else if (TREE_CODE (decl) == FUNCTION_DECL)
{
- struct cgraph_node *node = cgraph_get_node_or_alias (decl);
+ struct cgraph_node *node = cgraph_get_node (decl);
if (node
&& node->resolution != LDPR_UNKNOWN)
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);
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"