#include "hard-reg-set.h"
#include "regs.h"
#include "output.h"
+#include "diagnostic-core.h"
#include "toplev.h"
#include "hashtab.h"
#include "ggc.h"
#include "cfglayout.h"
#include "basic-block.h"
#include "tree-iterator.h"
+#include "pointer-set.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data
static alias_set_type const_alias_set;
+/* Whether we saw any functions with no_split_stack. */
+
+static bool saw_no_split_stack;
+
static const char *strip_reg_name (const char *);
static int contains_pointers_p (tree);
#ifdef ASM_OUTPUT_EXTERNAL
/* A pool of constants that can be shared between functions. */
static GTY(()) struct rtx_constant_pool *shared_constant_pool;
-/* TLS emulation. */
-
-static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
- htab_t emutls_htab;
-static GTY (()) tree emutls_object_type;
-/* Emulated TLS objects have the TLS model TLS_MODEL_EMULATED. This
- macro can be used on them to distinguish the control variable from
- the initialization template. */
-#define DECL_EMUTLS_VAR_P(D) (TREE_TYPE (D) == emutls_object_type)
-
-#if !defined (NO_DOT_IN_LABEL)
-# define EMUTLS_SEPARATOR "."
-#elif !defined (NO_DOLLAR_IN_LABEL)
-# define EMUTLS_SEPARATOR "$"
-#else
-# define EMUTLS_SEPARATOR "_"
-#endif
-
-/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
- IDENTIFIER_NODE NAME's name. */
-
-static tree
-prefix_name (const char *prefix, tree name)
-{
- unsigned plen = strlen (prefix);
- unsigned nlen = strlen (IDENTIFIER_POINTER (name));
- char *toname = (char *) alloca (plen + nlen + 1);
-
- memcpy (toname, prefix, plen);
- memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
-
- return get_identifier (toname);
-}
-
-/* Create an identifier for the struct __emutls_object, given an identifier
- of the DECL_ASSEMBLY_NAME of the original object. */
-
-static tree
-get_emutls_object_name (tree name)
-{
- const char *prefix = (targetm.emutls.var_prefix
- ? targetm.emutls.var_prefix
- : "__emutls_v" EMUTLS_SEPARATOR);
- return prefix_name (prefix, name);
-}
-
-tree
-default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
-{
- tree word_type_node, field, next_field;
-
- field = build_decl (UNKNOWN_LOCATION,
- FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
- DECL_CONTEXT (field) = type;
- next_field = field;
-
- field = build_decl (UNKNOWN_LOCATION,
- FIELD_DECL, get_identifier ("__offset"),
- ptr_type_node);
- DECL_CONTEXT (field) = type;
- TREE_CHAIN (field) = next_field;
- next_field = field;
-
- word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
- field = build_decl (UNKNOWN_LOCATION,
- FIELD_DECL, get_identifier ("__align"),
- word_type_node);
- DECL_CONTEXT (field) = type;
- TREE_CHAIN (field) = next_field;
- next_field = field;
-
- field = build_decl (UNKNOWN_LOCATION,
- FIELD_DECL, get_identifier ("__size"), word_type_node);
- DECL_CONTEXT (field) = type;
- TREE_CHAIN (field) = next_field;
-
- return field;
-}
-
-/* Create the structure for struct __emutls_object. This should match the
- structure at the top of emutls.c, modulo the union there. */
-
-static tree
-get_emutls_object_type (void)
-{
- tree type, type_name, field;
-
- type = emutls_object_type;
- if (type)
- return type;
-
- emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
- type_name = NULL;
- field = targetm.emutls.var_fields (type, &type_name);
- if (!type_name)
- type_name = get_identifier ("__emutls_object");
- type_name = build_decl (UNKNOWN_LOCATION,
- TYPE_DECL, type_name, type);
- TYPE_NAME (type) = type_name;
- TYPE_FIELDS (type) = field;
- layout_type (type);
-
- return type;
-}
-
-/* Create a read-only variable like DECL, with the same DECL_INITIAL.
- This will be used for initializing the emulated tls data area. */
-
-static tree
-get_emutls_init_templ_addr (tree decl)
-{
- tree name, to;
-
- if (targetm.emutls.register_common && !DECL_INITIAL (decl)
- && !DECL_SECTION_NAME (decl))
- return null_pointer_node;
-
- name = DECL_ASSEMBLER_NAME (decl);
- if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
- {
- const char *prefix = (targetm.emutls.tmpl_prefix
- ? targetm.emutls.tmpl_prefix
- : "__emutls_t" EMUTLS_SEPARATOR);
- name = prefix_name (prefix, name);
- }
-
- to = build_decl (DECL_SOURCE_LOCATION (decl),
- VAR_DECL, name, TREE_TYPE (decl));
- SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
-
- DECL_ARTIFICIAL (to) = 1;
- TREE_USED (to) = TREE_USED (decl);
- TREE_READONLY (to) = 1;
- DECL_IGNORED_P (to) = 1;
- DECL_CONTEXT (to) = DECL_CONTEXT (decl);
- DECL_SECTION_NAME (to) = DECL_SECTION_NAME (decl);
- DECL_PRESERVE_P (to) = DECL_PRESERVE_P (decl);
-
- DECL_WEAK (to) = DECL_WEAK (decl);
- if (DECL_ONE_ONLY (decl))
- {
- make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
- TREE_STATIC (to) = TREE_STATIC (decl);
- TREE_PUBLIC (to) = TREE_PUBLIC (decl);
- DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
- }
- else
- TREE_STATIC (to) = 1;
-
- DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
- DECL_INITIAL (to) = DECL_INITIAL (decl);
- DECL_INITIAL (decl) = NULL;
-
- varpool_finalize_decl (to);
- return build_fold_addr_expr (to);
-}
-
-/* When emulating tls, we use a control structure for use by the runtime.
- Create and return this structure. */
-
-tree
-emutls_decl (tree decl)
-{
- tree name, to;
- struct tree_map *h, in;
- void **loc;
-
- if (targetm.have_tls || decl == NULL || decl == error_mark_node
- || TREE_CODE (decl) != VAR_DECL || ! DECL_THREAD_LOCAL_P (decl))
- return decl;
-
- /* Look up the object in the hash; return the control structure if
- it has already been created. */
- if (! emutls_htab)
- emutls_htab = htab_create_ggc (512, tree_map_hash, tree_map_eq, 0);
-
- name = DECL_ASSEMBLER_NAME (decl);
-
- /* Note that we use the hash of the decl's name, rather than a hash
- of the decl's pointer. In emutls_finish we iterate through the
- hash table, and we want this traversal to be predictable. */
- in.hash = IDENTIFIER_HASH_VALUE (name);
- in.base.from = decl;
- loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT);
- h = (struct tree_map *) *loc;
- if (h != NULL)
- to = h->to;
- else
- {
- to = build_decl (DECL_SOURCE_LOCATION (decl),
- VAR_DECL, get_emutls_object_name (name),
- get_emutls_object_type ());
-
- h = ggc_alloc_tree_map ();
- h->hash = in.hash;
- h->base.from = decl;
- h->to = to;
- *(struct tree_map **) loc = h;
-
- DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
- DECL_ARTIFICIAL (to) = 1;
- DECL_IGNORED_P (to) = 1;
- /* FIXME: work around PR44132. */
- DECL_PRESERVE_P (to) = 1;
- TREE_READONLY (to) = 0;
- SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
- if (DECL_ONE_ONLY (decl))
- make_decl_one_only (to, DECL_ASSEMBLER_NAME (to));
- DECL_CONTEXT (to) = DECL_CONTEXT (decl);
- if (targetm.emutls.var_align_fixed)
- /* If we're not allowed to change the proxy object's
- alignment, pretend it's been set by the user. */
- DECL_USER_ALIGN (to) = 1;
- }
-
- /* Note that these fields may need to be updated from time to time from
- the original decl. Consider:
- extern __thread int i;
- int foo() { return i; }
- __thread int i = 1;
- in which I goes from external to locally defined and initialized. */
- DECL_DLLIMPORT_P (to) = DECL_DLLIMPORT_P (decl);
- DECL_ATTRIBUTES (to) = targetm.merge_decl_attributes (decl, to);
-
- TREE_STATIC (to) = TREE_STATIC (decl);
- TREE_USED (to) = TREE_USED (decl);
- TREE_PUBLIC (to) = TREE_PUBLIC (decl);
- DECL_EXTERNAL (to) = DECL_EXTERNAL (decl);
- DECL_COMMON (to) = DECL_COMMON (decl);
- DECL_WEAK (to) = DECL_WEAK (decl);
- DECL_VISIBILITY (to) = DECL_VISIBILITY (decl);
- DECL_VISIBILITY_SPECIFIED (to) = DECL_VISIBILITY_SPECIFIED (decl);
-
- /* Fortran might pass this to us. */
- DECL_RESTRICTED_P (to) = DECL_RESTRICTED_P (decl);
-
- return to;
-}
-
-static int
-emutls_common_1 (void **loc, void *xstmts)
-{
- struct tree_map *h = *(struct tree_map **) loc;
- tree args, x, *pstmts = (tree *) xstmts;
- tree word_type_node;
-
- if (! DECL_COMMON (h->base.from)
- || (DECL_INITIAL (h->base.from)
- && DECL_INITIAL (h->base.from) != error_mark_node))
- return 1;
-
- word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
-
- /* The idea was to call get_emutls_init_templ_addr here, but if we
- do this and there is an initializer, -fanchor_section loses,
- because it would be too late to ensure the template is
- output. */
- x = null_pointer_node;
- args = tree_cons (NULL, x, NULL);
- x = build_int_cst (word_type_node, DECL_ALIGN_UNIT (h->base.from));
- args = tree_cons (NULL, x, args);
- x = fold_convert (word_type_node, DECL_SIZE_UNIT (h->base.from));
- args = tree_cons (NULL, x, args);
- x = build_fold_addr_expr (h->to);
- args = tree_cons (NULL, x, args);
-
- x = built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON];
- x = build_function_call_expr (UNKNOWN_LOCATION, x, args);
-
- append_to_statement_list (x, pstmts);
- return 1;
-}
-
-/* Callback to finalize one emutls control variable. */
-
-static int
-emutls_finalize_control_var (void **loc,
- void *unused ATTRIBUTE_UNUSED)
-{
- struct tree_map *h = *(struct tree_map **) loc;
- if (h != NULL)
- {
- struct varpool_node *node = varpool_node (h->to);
- /* Because varpool_finalize_decl () has side-effects,
- only apply to un-finalized vars. */
- if (node && !node->finalized)
- varpool_finalize_decl (h->to);
- }
- return 1;
-}
-
-/* Finalize emutls control vars and add a static constructor if
- required. */
-
-void
-emutls_finish (void)
-{
- if (emutls_htab == NULL)
- return;
- htab_traverse_noresize (emutls_htab,
- emutls_finalize_control_var, NULL);
-
- if (targetm.emutls.register_common)
- {
- tree body = NULL_TREE;
-
- htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
- if (body == NULL_TREE)
- return;
-
- cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
- }
-}
-
/* Helper routines for maintaining section_htab. */
static int
return symbol;
}
-static void
-initialize_cold_section_name (void)
-{
- const char *stripped_name;
- char *name, *buffer;
- tree dsn;
-
- gcc_assert (cfun && current_function_decl);
- if (crtl->subsections.unlikely_text_section_name)
- return;
-
- dsn = DECL_SECTION_NAME (current_function_decl);
- if (flag_function_sections && dsn)
- {
- name = (char *) alloca (TREE_STRING_LENGTH (dsn) + 1);
- memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1);
-
- stripped_name = targetm.strip_name_encoding (name);
-
- buffer = ACONCAT ((stripped_name, "_unlikely", NULL));
- crtl->subsections.unlikely_text_section_name = ggc_strdup (buffer);
- }
- else
- crtl->subsections.unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
-}
-
-/* Tell assembler to switch to unlikely-to-be-executed text section. */
-
-section *
-unlikely_text_section (void)
-{
- if (cfun)
- {
- if (!crtl->subsections.unlikely_text_section_name)
- initialize_cold_section_name ();
-
- return get_named_section (NULL, crtl->subsections.unlikely_text_section_name, 0);
- }
- else
- return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
-}
-
-/* When called within a function context, return true if the function
- has been assigned a cold text section and if SECT is that section.
- When called outside a function context, return true if SECT is the
- default cold section. */
-
-bool
-unlikely_text_section_p (section *sect)
-{
- const char *name;
-
- if (cfun)
- name = crtl->subsections.unlikely_text_section_name;
- else
- name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
-
- return (name
- && sect
- && SECTION_STYLE (sect) == SECTION_NAMED
- && strcmp (name, sect->named.name) == 0);
-}
-
/* Return a section with a particular name and with whatever SECTION_*
flags section_type_flags deems appropriate. The name of the section
is taken from NAME if nonnull, otherwise it is taken from DECL's
&& targetm.have_named_sections
&& (flag_function_or_data_sections
|| DECL_ONE_ONLY (decl)))
- targetm.asm_out.unique_section (decl, reloc);
+ {
+ targetm.asm_out.unique_section (decl, reloc);
+ DECL_HAS_IMPLICIT_SECTION_NAME_P (decl) = true;
+ }
}
#ifdef BSS_SECTION_ASM_OP
??? It is believed that this function will work in most cases so such
support is localized here. */
-static void
+static void ATTRIBUTE_UNUSED
asm_output_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
const char *name,
unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
}
#endif
+/* Return section for TEXT_SECTION_NAME if DECL or DECL_SECTION_NAME (DECL)
+ is NULL.
+
+ When DECL_SECTION_NAME is non-NULL and it is implicit section and
+ NAMED_SECTION_SUFFIX is non-NULL, then produce section called
+ concatenate the name with NAMED_SECTION_SUFFIX.
+ Otherwise produce "TEXT_SECTION_NAME.IMPLICIT_NAME". */
+
+section *
+get_named_text_section (tree decl,
+ const char *text_section_name,
+ const char *named_section_suffix)
+{
+ if (decl && DECL_SECTION_NAME (decl))
+ {
+ if (named_section_suffix)
+ {
+ tree dsn = DECL_SECTION_NAME (decl);
+ const char *stripped_name;
+ char *name, *buffer;
+
+ name = (char *) alloca (TREE_STRING_LENGTH (dsn) + 1);
+ memcpy (name, TREE_STRING_POINTER (dsn),
+ TREE_STRING_LENGTH (dsn) + 1);
+
+ stripped_name = targetm.strip_name_encoding (name);
+
+ buffer = ACONCAT ((stripped_name, named_section_suffix, NULL));
+ return get_named_section (decl, buffer, 0);
+ }
+ else if (DECL_HAS_IMPLICIT_SECTION_NAME_P (decl))
+ {
+ const char *name;
+
+ /* Do not try to split gnu_linkonce functions. This gets somewhat
+ slipperly. */
+ if (DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP)
+ return NULL;
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ name = targetm.strip_name_encoding (name);
+ return get_named_section (decl, ACONCAT ((text_section_name, ".",
+ name, NULL)), 0);
+ }
+ else
+ return NULL;
+ }
+ return get_named_section (decl, text_section_name, 0);
+}
+
+/* Choose named function section based on its frequency. */
+
+section *
+default_function_section (tree decl, enum node_frequency freq,
+ bool startup, bool exit)
+{
+ /* Startup code should go to startup subsection unless it is
+ unlikely executed (this happens especially with function splitting
+ where we can split away unnecesary parts of static constructors. */
+ if (startup && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED)
+ return get_named_text_section (decl, ".text.startup", NULL);
+
+ /* Similarly for exit. */
+ if (exit && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED)
+ return get_named_text_section (decl, ".text.exit", NULL);
+
+ /* Group cold functions together, similarly for hot code. */
+ switch (freq)
+ {
+ case NODE_FREQUENCY_UNLIKELY_EXECUTED:
+ return get_named_text_section (decl, ".text.unlikely", NULL);
+ case NODE_FREQUENCY_HOT:
+ return get_named_text_section (decl, ".text.hot", NULL);
+ default:
+ return NULL;
+ }
+}
+
/* 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.
-section *
-function_section (tree decl)
+ If FORCE_COLD is true, return cold function section ignoring
+ the frequency info of cgraph_node. */
+
+static section *
+function_section_1 (tree decl, bool force_cold)
{
- int reloc = 0;
+ section *section = NULL;
+ enum node_frequency freq = NODE_FREQUENCY_NORMAL;
+ bool startup = false, exit = false;
- if (first_function_block_is_cold)
- reloc = 1;
+ if (decl)
+ {
+ struct cgraph_node *node = cgraph_node (decl);
+
+ freq = node->frequency;
+ startup = node->only_called_at_startup;
+ exit = node->only_called_at_exit;
+ }
+ if (force_cold)
+ freq = NODE_FREQUENCY_UNLIKELY_EXECUTED;
#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
if (decl != NULL_TREE
&& DECL_SECTION_NAME (decl) != NULL_TREE)
- return reloc ? unlikely_text_section ()
- : get_named_section (decl, NULL, 0);
+ {
+ if (targetm.asm_out.function_section)
+ section = targetm.asm_out.function_section (decl, freq,
+ startup, exit);
+ if (section)
+ return section;
+ return get_named_section (decl, NULL, 0);
+ }
else
- return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+ return targetm.asm_out.select_section
+ (decl, freq == NODE_FREQUENCY_UNLIKELY_EXECUTED,
+ DECL_ALIGN (decl));
#else
- return reloc ? unlikely_text_section () : hot_function_section (decl);
+ if (targetm.asm_out.function_section)
+ section = targetm.asm_out.function_section (decl, freq, startup, exit);
+ if (section)
+ return section;
+ return hot_function_section (decl);
#endif
}
+/* 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. */
+
+section *
+function_section (tree decl)
+{
+ /* Handle cases where function splitting code decides
+ to put function entry point into unlikely executed section
+ despite the fact that the function itself is not cold
+ (i.e. it is called rarely but contains a hot loop that is
+ better to live in hot subsection for the code locality). */
+ return function_section_1 (decl,
+ first_function_block_is_cold);
+}
+
+/* Return the section for the current function, take IN_COLD_SECTION_P
+ into account. */
+
section *
current_function_section (void)
{
-#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
- if (current_function_decl != NULL_TREE
- && DECL_SECTION_NAME (current_function_decl) != NULL_TREE)
- return in_cold_section_p ? unlikely_text_section ()
- : get_named_section (current_function_decl,
- NULL, 0);
- else
- return targetm.asm_out.select_section (current_function_decl,
- in_cold_section_p,
- DECL_ALIGN (current_function_decl));
-#else
- return (in_cold_section_p
- ? unlikely_text_section ()
- : hot_function_section (current_function_decl));
-#endif
+ return function_section_1 (current_function_decl, in_cold_section_p);
+}
+
+/* Tell assembler to switch to unlikely-to-be-executed text section. */
+
+section *
+unlikely_text_section (void)
+{
+ return function_section_1 (current_function_decl, true);
+}
+
+/* When called within a function context, return true if the function
+ has been assigned a cold text section and if SECT is that section.
+ When called outside a function context, return true if SECT is the
+ default cold section. */
+
+bool
+unlikely_text_section_p (section *sect)
+{
+ return sect == function_section_1 (current_function_decl, true);
}
/* Return the read-only data section associated with function DECL. */
Prefixes such as % are optional. */
int
-decode_reg_name (const char *asmspec)
+decode_reg_name_and_count (const char *asmspec, int *pnregs)
{
+ /* Presume just one register is clobbered. */
+ *pnregs = 1;
+
if (asmspec != 0)
{
int i;
&& ! strcmp (asmspec, strip_reg_name (reg_names[i])))
return i;
+#ifdef OVERLAPPING_REGISTER_NAMES
+ {
+ static const struct
+ {
+ const char *const name;
+ const int number;
+ const int nregs;
+ } table[] = OVERLAPPING_REGISTER_NAMES;
+
+ for (i = 0; i < (int) ARRAY_SIZE (table); i++)
+ if (table[i].name[0]
+ && ! strcmp (asmspec, table[i].name))
+ {
+ *pnregs = table[i].nregs;
+ return table[i].number;
+ }
+ }
+#endif /* OVERLAPPING_REGISTER_NAMES */
+
#ifdef ADDITIONAL_REGISTER_NAMES
{
static const struct { const char *const name; const int number; } table[]
return -1;
}
+
+int
+decode_reg_name (const char *name)
+{
+ int count;
+ return decode_reg_name_and_count (name, &count);
+}
+
\f
/* Return true if DECL's initializer is suitable for a BSS section. */
&& ADDR_SPACE_GENERIC_P (as));
if (DECL_THREAD_LOCAL_P (decl))
return tls_comm_section;
- /* This cannot be common bss for an emulated TLS object without
- a register_common hook. */
- else if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED
- && !targetm.emutls.register_common)
- ;
else if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
return comm_section;
}
if (DECL_INITIAL (decl) == decl)
return false;
- /* If this decl is an alias, then we don't want to emit a definition. */
+ /* If this decl is an alias, then we don't want to emit a
+ definition. */
if (lookup_attribute ("alias", DECL_ATTRIBUTES (decl)))
return false;
char tmp_label[100];
bool hot_label_written = false;
- crtl->subsections.unlikely_text_section_name = NULL;
-
first_function_block_is_cold = false;
if (flag_reorder_blocks_and_partition)
{
else if (DECL_SECTION_NAME (decl))
{
/* Calls to function_section rely on first_function_block_is_cold
- being accurate. The first block may be cold even if we aren't
- doing partitioning, if the entire function was decided by
- choose_function_section (predict.c) to be cold. */
-
- initialize_cold_section_name ();
-
- if (crtl->subsections.unlikely_text_section_name
- && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
- crtl->subsections.unlikely_text_section_name) == 0)
- first_function_block_is_cold = true;
+ being accurate. */
+ first_function_block_is_cold
+ = (cgraph_node (current_function_decl)->frequency
+ == NODE_FREQUENCY_UNLIKELY_EXECUTED);
}
in_cold_section_p = first_function_block_is_cold;
ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
#else
/* Standard thing is just output label for the function. */
- ASM_OUTPUT_LABEL (asm_out_file, fnname);
+ ASM_OUTPUT_FUNCTION_LABEL (asm_out_file, fnname, current_function_decl);
#endif /* ASM_DECLARE_FUNCTION_NAME */
+
+ if (lookup_attribute ("no_split_stack", DECL_ATTRIBUTES (decl)))
+ saw_no_split_stack = true;
}
/* Output assembler code associated with defining the size of the
}
}
-/* Initialize emulated tls object TO, which refers to TLS variable
- DECL and is initialized by PROXY. */
-
-tree
-default_emutls_var_init (tree to, tree decl, tree proxy)
-{
- VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
- constructor_elt *elt;
- tree type = TREE_TYPE (to);
- tree field = TYPE_FIELDS (type);
-
- elt = VEC_quick_push (constructor_elt, v, NULL);
- elt->index = field;
- elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
-
- elt = VEC_quick_push (constructor_elt, v, NULL);
- field = TREE_CHAIN (field);
- elt->index = field;
- elt->value = build_int_cst (TREE_TYPE (field),
- DECL_ALIGN_UNIT (decl));
-
- elt = VEC_quick_push (constructor_elt, v, NULL);
- field = TREE_CHAIN (field);
- elt->index = field;
- elt->value = null_pointer_node;
-
- elt = VEC_quick_push (constructor_elt, v, NULL);
- field = TREE_CHAIN (field);
- elt->index = field;
- elt->value = proxy;
-
- return build_constructor (type, v);
-}
-
/* 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.
rtx decl_rtl, symbol;
section *sect;
- if (! targetm.have_tls
- && TREE_CODE (decl) == VAR_DECL
- && DECL_THREAD_LOCAL_P (decl))
- {
- tree to = emutls_decl (decl);
-
- /* If this variable is defined locally, then we need to initialize the
- control structure with size and alignment information. We do this
- at the last moment because tentative definitions can take a locally
- defined but uninitialized variable and initialize it later, which
- would result in incorrect contents. */
- if (! DECL_EXTERNAL (to)
- && (! DECL_COMMON (to)
- || (DECL_INITIAL (decl)
- && DECL_INITIAL (decl) != error_mark_node)))
- {
- DECL_INITIAL (to) = targetm.emutls.var_init
- (to, decl, get_emutls_init_templ_addr (decl));
-
- /* Make sure the template is marked as needed early enough.
- Without this, if the variable is placed in a
- section-anchored block, the template will only be marked
- when it's too late. */
- record_references_in_initializer (to, false);
- }
-
- decl = to;
- }
+ /* This function is supposed to handle VARIABLES. Ensure we have one. */
+ gcc_assert (TREE_CODE (decl) == VAR_DECL);
+ /* 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,
if (DECL_EXTERNAL (decl))
return;
- /* Output no assembler code for a function declaration.
- Only definitions of functions output anything. */
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
- return;
-
/* Do nothing for global register variables. */
if (DECL_RTL_SET_P (decl) && REG_P (DECL_RTL (decl)))
{
{
tree fields;
/* For a type that has fields, see if the fields have pointers. */
- for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
+ for (fields = TYPE_FIELDS (type); fields; fields = DECL_CHAIN (fields))
if (TREE_CODE (fields) == FIELD_DECL
&& contains_pointers_p (TREE_TYPE (fields)))
return 1;
/* We want to output annotation for weak and external symbols at
very last to check if they are references or not. */
- if (SUPPORTS_WEAK
+ if (TARGET_SUPPORTS_WEAK
&& DECL_WEAK (decl)
/* TREE_STATIC is a weird and abused creature which is not
generally the right test for whether an entity has been
output_addressed_constants (exp);
/* We are no longer deferring this constant. */
- TREE_ASM_WRITTEN (exp) = 1;
+ TREE_ASM_WRITTEN (decl) = TREE_ASM_WRITTEN (exp) = 1;
/* If the constant is part of an object block, make sure that the
decl has been positioned within its block, but do not write out
{
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)));
+ || TREE_CODE (TREE_TYPE (ctor)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE));
}
static tree initializer_constant_valid_p_1 (tree value, tree endtype,
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));
+ i = size_binop (PLUS_EXPR, i, size_one_node);
/* 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))));
fieldsize = array_size_for_constructor (local->val);
/* Given a non-empty initialization, this field had
better be last. */
- gcc_assert (!fieldsize || !TREE_CHAIN (local->field));
+ gcc_assert (!fieldsize || !DECL_CHAIN (local->field));
}
else if (DECL_SIZE_UNIT (local->field))
{
for (cnt = 0;
VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
- cnt++, local.field = local.field ? TREE_CHAIN (local.field) : 0)
+ cnt++, local.field = local.field ? DECL_CHAIN (local.field) : 0)
{
local.val = ce->value;
local.index = NULL_TREE;
{
if (DECL_WEAK (newdecl) == DECL_WEAK (olddecl))
{
- if (DECL_WEAK (newdecl) && SUPPORTS_WEAK)
+ if (DECL_WEAK (newdecl) && TARGET_SUPPORTS_WEAK)
{
tree *pwd;
/* We put the NEWDECL on the weak_decls list at some point
warning (0, "weak declaration of %q+D after first use results "
"in unspecified behavior", newdecl);
- if (SUPPORTS_WEAK)
+ if (TARGET_SUPPORTS_WEAK)
{
/* We put the NEWDECL on the weak_decls list at some point.
Replace it with the OLDDECL. */
error ("weak declaration of %q+D must be public", decl);
else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
error ("weak declaration of %q+D must precede definition", decl);
- else if (!SUPPORTS_WEAK)
+ else if (!TARGET_SUPPORTS_WEAK)
warning (0, "weak declaration of %q+D not supported", decl);
mark_weak (decl);
static void
do_assemble_alias (tree decl, tree target)
{
+ /* Emulated TLS had better not get this var. */
+ gcc_assert(!(!targetm.have_tls
+ && TREE_CODE (decl) == VAR_DECL
+ && DECL_THREAD_LOCAL_P (decl)));
+
if (TREE_ASM_WRITTEN (decl))
return;
{
ultimate_transparent_alias_target (&target);
- if (!targetm.have_tls
- && TREE_CODE (decl) == VAR_DECL
- && DECL_THREAD_LOCAL_P (decl))
- {
- decl = emutls_decl (decl);
- target = get_emutls_object_name (target);
- }
-
if (!TREE_SYMBOL_REFERENCED (target))
weakref_targets = tree_cons (decl, target, weakref_targets);
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
IDENTIFIER_POINTER (target));
#else
- if (!SUPPORTS_WEAK)
+ if (!TARGET_SUPPORTS_WEAK)
{
error_at (DECL_SOURCE_LOCATION (decl),
"weakref is not supported in this configuration");
return;
}
- if (!targetm.have_tls
- && TREE_CODE (decl) == VAR_DECL
- && DECL_THREAD_LOCAL_P (decl))
- {
- decl = emutls_decl (decl);
- target = get_emutls_object_name (target);
- }
-
#ifdef ASM_OUTPUT_DEF
/* Make name accessible from other files, if appropriate. */
globalize_decl (decl);
maybe_assemble_visibility (decl);
}
+ if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
+ {
+#if defined (ASM_OUTPUT_TYPE_DIRECTIVE) && HAVE_GNU_INDIRECT_FUNCTION
+ ASM_OUTPUT_TYPE_DIRECTIVE
+ (asm_out_file, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ IFUNC_ASM_TYPE);
+#else
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "ifunc is not supported in this configuration");
+#endif
+ }
# ifdef ASM_OUTPUT_DEF_FROM_DECLS
ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
}
+/* Compute the set of indentifier nodes that is generated by aliases
+ whose targets are reachable. */
+
+static struct pointer_set_t *
+compute_visible_aliases (void)
+{
+ struct pointer_set_t *visible;
+ unsigned i;
+ alias_pair *p;
+ bool changed;
+
+ /* We have to compute the set of visible nodes including aliases
+ themselves. */
+ visible = pointer_set_create ();
+ do
+ {
+ changed = false;
+ for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ++i)
+ {
+ struct cgraph_node *fnode = NULL;
+ struct varpool_node *vnode = NULL;
+ fnode = cgraph_node_for_asm (p->target);
+ vnode = (fnode == NULL) ? varpool_node_for_asm (p->target) : NULL;
+ if ((fnode
+ || vnode
+ || pointer_set_contains (visible, p->target))
+ && !pointer_set_insert (visible, DECL_ASSEMBLER_NAME (p->decl)))
+ changed = true;
+ }
+ }
+ while (changed);
+
+ return visible;
+}
+
/* Remove the alias pairing for functions that are no longer in the call
graph. */
void
remove_unreachable_alias_pairs (void)
{
+ struct pointer_set_t *visible;
unsigned i;
alias_pair *p;
if (alias_pairs == NULL)
return;
+ /* We have to compute the set of visible nodes including aliases
+ themselves. */
+ visible = compute_visible_aliases ();
+
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); )
{
if (!DECL_EXTERNAL (p->decl))
struct varpool_node *vnode = NULL;
fnode = cgraph_node_for_asm (p->target);
vnode = (fnode == NULL) ? varpool_node_for_asm (p->target) : NULL;
- if (fnode == NULL && vnode == NULL)
+ if (!fnode
+ && !vnode
+ && !pointer_set_contains (visible, p->target))
{
VEC_unordered_remove (alias_pair, alias_pairs, i);
continue;
i++;
}
+
+ pointer_set_destroy (visible);
}
void
finish_aliases_1 (void)
{
+ struct pointer_set_t *visible;
unsigned i;
alias_pair *p;
- for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
+ if (alias_pairs == NULL)
+ return;
+
+ /* We have to compute the set of visible nodes including aliases
+ themselves. */
+ visible = compute_visible_aliases ();
+
+ FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
{
tree target_decl;
target_decl = find_decl_and_mark_needed (p->decl, p->target);
if (target_decl == NULL)
{
- if (! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
- error ("%q+D aliased to undefined symbol %qE",
- p->decl, p->target);
+ if (pointer_set_contains (visible, p->target))
+ continue;
+
+ if (! (p->emitted_diags & ALIAS_DIAG_TO_UNDEF)
+ && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
+ {
+ error ("%q+D aliased to undefined symbol %qE",
+ p->decl, p->target);
+ p->emitted_diags |= ALIAS_DIAG_TO_UNDEF;
+ }
}
- else if (DECL_EXTERNAL (target_decl)
- /* We use local aliases for C++ thunks to force the tailcall
- to bind locally. Of course this is a hack - to keep it
- working do the following (which is not strictly correct). */
- && (! TREE_CODE (target_decl) == FUNCTION_DECL
- || ! DECL_VIRTUAL_P (target_decl))
+ else if (! (p->emitted_diags & ALIAS_DIAG_TO_EXTERN)
+ && DECL_EXTERNAL (target_decl)
+ /* We use local aliases for C++ thunks to force the tailcall
+ to bind locally. This is a hack - to keep it working do
+ the following (which is not strictly correct). */
+ && (! TREE_CODE (target_decl) == FUNCTION_DECL
+ || ! DECL_VIRTUAL_P (target_decl))
&& ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
- error ("%q+D aliased to external symbol %qE",
- p->decl, p->target);
+ {
+ error ("%q+D aliased to external symbol %qE",
+ p->decl, p->target);
+ p->emitted_diags |= ALIAS_DIAG_TO_EXTERN;
+ }
}
+
+ pointer_set_destroy (visible);
}
/* Second pass of completing pending aliases. Emit the actual assembly.
unsigned i;
alias_pair *p;
- for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
+ FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
do_assemble_alias (p->decl, p->target);
VEC_truncate (alias_pair, alias_pairs, 0);
# else
if (!DECL_WEAK (decl))
{
- error_at (DECL_SOURCE_LOCATION (decl),
- "only weak aliases are supported in this configuration");
+ if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "ifunc is not supported in this configuration");
+ else
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "only weak aliases are supported in this configuration");
return;
}
# endif
alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
p->decl = decl;
p->target = target;
+ p->emitted_diags = ALIAS_DIAG_NONE;
}
}
if (vis != VISIBILITY_DEFAULT)
{
- targetm.asm_out.visibility (decl, vis);
+ targetm.asm_out.assemble_visibility (decl, vis);
return 1;
}
else
{
if (SUPPORTS_ONE_ONLY)
return 1;
- return SUPPORTS_WEAK;
+ return TARGET_SUPPORTS_WEAK;
}
/* Set up DECL as a public symbol that can be defined in multiple
DECL_COMMON (decl) = 1;
else
{
- gcc_assert (SUPPORTS_WEAK);
+ gcc_assert (TARGET_SUPPORTS_WEAK);
DECL_WEAK (decl) = 1;
}
}
flags = SECTION_CODE;
else if (decl && decl_readonly_section (decl, reloc))
flags = 0;
- else if (current_function_decl
- && cfun
- && crtl->subsections.unlikely_text_section_name
- && strcmp (name, crtl->subsections.unlikely_text_section_name) == 0)
- flags = SECTION_CODE;
- else if (!decl
- && (!current_function_decl || !cfun)
- && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
- flags = SECTION_CODE;
else
flags = SECTION_WRITE;
/* Here the reloc_rw_mask is not testing whether the section should
be read-only or not, but whether the dynamic link will have to
do something. If so, we wish to segregate the data in order to
- minimize cache misses inside the dynamic linker. */
- if (reloc & targetm.asm_out.reloc_rw_mask ())
+ minimize cache misses inside the dynamic linker. If the data
+ has a section attribute, ignore reloc_rw_mask() so that all data
+ in a given named section is catagorized in the same way. */
+ if (reloc & targetm.asm_out.reloc_rw_mask ()
+ && !lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
ret = reloc == 1 ? SECCAT_DATA_REL_LOCAL : SECCAT_DATA_REL;
else
ret = SECCAT_DATA;
}
- else if (reloc & targetm.asm_out.reloc_rw_mask ())
+ else if (reloc & targetm.asm_out.reloc_rw_mask ()
+ && !lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO;
else if (reloc || flag_merge_constants < 2)
/* C and C++ don't allow different variables to share the same
ret = SECCAT_RODATA;
/* There are no read-only thread-local sections. */
- if (TREE_CODE (decl) == VAR_DECL && DECL_TLS_MODEL (decl))
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
{
- if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED)
- {
- if (DECL_EMUTLS_VAR_P (decl))
- {
- if (targetm.emutls.var_section)
- ret = SECCAT_EMUTLS_VAR;
- }
- else
- {
- if (targetm.emutls.tmpl_prefix)
- ret = SECCAT_EMUTLS_TMPL;
- }
- }
/* Note that this would be *just* SECCAT_BSS, except that there's
no concept of a read-only thread-local-data section. */
- else if (ret == SECCAT_BSS
+ if (ret == SECCAT_BSS
|| (flag_zero_initialized_in_bss
&& initializer_zerop (DECL_INITIAL (decl))))
ret = SECCAT_TBSS;
case SECCAT_TBSS:
sname = ".tbss";
break;
- case SECCAT_EMUTLS_VAR:
- sname = targetm.emutls.var_section;
- break;
- case SECCAT_EMUTLS_TMPL:
- sname = targetm.emutls.tmpl_section;
- break;
default:
gcc_unreachable ();
}
case SECCAT_TBSS:
prefix = one_only ? ".tb" : ".tbss";
break;
- case SECCAT_EMUTLS_VAR:
- prefix = targetm.emutls.var_section;
- break;
- case SECCAT_EMUTLS_TMPL:
- prefix = targetm.emutls.tmpl_section;
- break;
default:
gcc_unreachable ();
}
flags |= SYMBOL_FLAG_FUNCTION;
if (targetm.binds_local_p (decl))
flags |= SYMBOL_FLAG_LOCAL;
- if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)
- && DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED)
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT;
else if (targetm.in_small_data_p (decl))
flags |= SYMBOL_FLAG_SMALL;
return true;
}
+/* Return true when RESOLUTION indicate that symbol will be bound to the
+ definition provided by current .o file. */
+
+static bool
+resolution_to_local_definition_p (enum ld_plugin_symbol_resolution resolution)
+{
+ return (resolution == LDPR_PREVAILING_DEF
+ || resolution == LDPR_PREVAILING_DEF_IRONLY);
+}
+
+/* Return true when RESOLUTION indicate that symbol will be bound locally
+ within current executable or DSO. */
+
+static bool
+resolution_local_p (enum ld_plugin_symbol_resolution resolution)
+{
+ return (resolution == LDPR_PREVAILING_DEF
+ || resolution == LDPR_PREVAILING_DEF_IRONLY
+ || resolution == LDPR_PREEMPTED_REG
+ || resolution == LDPR_PREEMPTED_IR
+ || resolution == LDPR_RESOLVED_IR
+ || resolution == LDPR_RESOLVED_EXEC);
+}
+
/* Assume ELF-ish defaults, since that's pretty much the most liberal
wrt cross-module name binding. */
default_binds_local_p_1 (const_tree exp, int shlib)
{
bool local_p;
+ bool resolved_locally = false;
+ 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,
+ because dynamic linking might overwrite symbols
+ in shared libraries. */
+ if (TREE_CODE (exp) == VAR_DECL && TREE_PUBLIC (exp)
+ && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
+ {
+ struct varpool_node *vnode = varpool_get_node (exp);
+ if (vnode && resolution_local_p (vnode->resolution))
+ resolved_locally = true;
+ if (vnode
+ && resolution_to_local_definition_p (vnode->resolution))
+ resolved_to_local_def = true;
+ }
+ else if (TREE_CODE (exp) == FUNCTION_DECL && TREE_PUBLIC (exp))
+ {
+ struct cgraph_node *node = cgraph_get_node_or_alias (exp);
+ if (node
+ && resolution_local_p (node->resolution))
+ resolved_locally = true;
+ if (node
+ && resolution_to_local_definition_p (node->resolution))
+ resolved_to_local_def = true;
+ }
/* A non-decl is an entry in the constant pool. */
if (!DECL_P (exp))
local_p = true;
/* Weakrefs may not bind locally, even though the weakref itself is
- always static and therefore local. */
+ always static and therefore local.
+ FIXME: We can resolve this more curefuly by looking at the weakref
+ alias. */
else if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp)))
local_p = false;
/* Static variables are always local. */
local_p = true;
/* A variable is local if the user has said explicitly that it will
be. */
- else if (DECL_VISIBILITY_SPECIFIED (exp)
+ else if ((DECL_VISIBILITY_SPECIFIED (exp)
+ || resolved_to_local_def)
&& DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
local_p = true;
/* Variables defined outside this object might not be local. */
- else if (DECL_EXTERNAL (exp))
+ else if (DECL_EXTERNAL (exp) && !resolved_locally)
local_p = false;
/* If defined in this object and visibility is not default, must be
local. */
local_p = true;
/* Default visibility weak data can be overridden by a strong symbol
in another module and so are not local. */
- else if (DECL_WEAK (exp))
+ else if (DECL_WEAK (exp)
+ && !resolved_locally)
local_p = false;
/* If PIC, then assume that any global name can be overridden by
- symbols resolved from other modules, unless we are compiling with
- -fwhole-program, which assumes that names are local. */
+ symbols resolved from other modules. */
else if (shlib)
- local_p = flag_whole_program;
+ local_p = false;
/* Uninitialized COMMON variable may be unified with symbols
resolved from other modules. */
else if (DECL_COMMON (exp)
+ && !resolved_locally
&& (DECL_INITIAL (exp) == NULL
|| DECL_INITIAL (exp) == error_mark_node))
local_p = false;
return local_p;
}
+/* Return true when references to DECL must bind to current definition in
+ final executable.
+
+ The condition is usually equivalent to whether the function binds to the
+ current module (shared library or executable), that is to binds_local_p.
+ We use this fact to avoid need for another target hook and implement
+ the logic using binds_local_p and just special cases where
+ decl_binds_to_current_def_p is stronger than binds local_p. In particular
+ the weak definitions (that can be overwritten at linktime by other
+ definition from different object file) and when resolution info is available
+ we simply use the knowledge passed to us by linker plugin. */
+bool
+decl_binds_to_current_def_p (tree decl)
+{
+ gcc_assert (DECL_P (decl));
+ if (!TREE_PUBLIC (decl))
+ return true;
+ if (!targetm.binds_local_p (decl))
+ return false;
+ /* When resolution is available, just use it. */
+ if (TREE_CODE (decl) == VAR_DECL && TREE_PUBLIC (decl)
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ {
+ struct varpool_node *vnode = varpool_get_node (decl);
+ if (vnode
+ && vnode->resolution != LDPR_UNKNOWN)
+ return resolution_to_local_definition_p (vnode->resolution);
+ }
+ else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_PUBLIC (decl))
+ {
+ struct cgraph_node *node = cgraph_get_node_or_alias (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).
+ This rely on fact that binds_local_p behave as decl_replaceable_p
+ for all other declaration types. */
+ return !DECL_WEAK (decl);
+}
+
+/* A replaceable function or variable is one which may be replaced
+ at link-time with an entirely different definition, provided that the
+ replacement has the same type. For example, functions declared
+ with __attribute__((weak)) on most systems are replaceable.
+
+ COMDAT functions are not replaceable, since all definitions of the
+ function must be equivalent. It is important that COMDAT functions
+ not be treated as replaceable so that use of C++ template
+ instantiations is not penalized. */
+
+bool
+decl_replaceable_p (tree decl)
+{
+ gcc_assert (DECL_P (decl));
+ if (!TREE_PUBLIC (decl) || DECL_COMDAT (decl))
+ return false;
+ return !decl_binds_to_current_def_p (decl);
+}
+
/* Default function to output code that will globalize a label. A
target must define GLOBAL_ASM_OP or provide its own function to
globalize a label. */
the class of label and LABELNO is the number within the class. */
void
+default_generate_internal_label (char *buf, const char *prefix,
+ unsigned long labelno)
+{
+ ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
+}
+
+/* This is how to output an internal numbered label where PREFIX is
+ the class of label and LABELNO is the number within the class. */
+
+void
default_internal_label (FILE *stream, const char *prefix,
unsigned long labelno)
{
void
default_file_start (void)
{
- if (targetm.file_start_app_off
+ if (targetm.asm_file_start_app_off
&& !(flag_verbose_asm || flag_debug_asm || flag_dump_rtl_in_asm))
fputs (ASM_APP_OFF, asm_out_file);
- if (targetm.file_start_file_directive)
+ if (targetm.asm_file_start_file_directive)
output_file_directive (asm_out_file, main_input_filename);
}
switch_to_section (get_section (".note.GNU-stack", flags, NULL));
}
+/* Emit a special section directive to indicate that this object file
+ was compiled with -fsplit-stack. This is used to let the linker
+ detect calls between split-stack code and non-split-stack code, so
+ that it can modify the split-stack code to allocate a sufficiently
+ large stack. We emit another special section if there are any
+ functions in this file which have the no_split_stack attribute, to
+ prevent the linker from warning about being unable to convert the
+ functions if they call non-split-stack code. */
+
+void
+file_end_indicate_split_stack (void)
+{
+ if (flag_split_stack)
+ {
+ switch_to_section (get_section (".note.GNU-split-stack", SECTION_DEBUG,
+ NULL));
+ if (saw_no_split_stack)
+ switch_to_section (get_section (".note.GNU-no-split-stack",
+ SECTION_DEBUG, NULL));
+ }
+}
+
/* Output DIRECTIVE (a C string) followed by a newline. This is used as
a get_unnamed_section callback. */
switch (SECTION_STYLE (new_section))
{
case SECTION_NAMED:
- if (cfun
- && !crtl->subsections.unlikely_text_section_name
- && strcmp (new_section->named.name,
- UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
- crtl->subsections.unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME;
-
targetm.asm_out.named_section (new_section->named.name,
new_section->named.common.flags,
new_section->named.decl);
/* Define the values of all anchors relative to the current section
position. */
- for (i = 0; VEC_iterate (rtx, block->anchors, i, symbol); i++)
+ FOR_EACH_VEC_ELT (rtx, block->anchors, i, symbol)
targetm.asm_out.output_anchor (symbol);
/* Output the objects themselves. */
offset = 0;
- for (i = 0; VEC_iterate (rtx, block->objects, i, symbol); i++)
+ FOR_EACH_VEC_ELT (rtx, block->objects, i, symbol)
{
/* Move to the object's offset, padding with zeros if necessary. */
assemble_zeros (SYMBOL_REF_BLOCK_OFFSET (symbol) - offset);
maybe_assemble_visibility (decl);
}
+/* The default hook for TARGET_ASM_OUTPUT_SOURCE_FILENAME. */
+
+void
+default_asm_output_source_filename (FILE *file, const char *name)
+{
+#ifdef ASM_OUTPUT_SOURCE_FILENAME
+ ASM_OUTPUT_SOURCE_FILENAME (file, name);
+#else
+ fprintf (file, "\t.file\t");
+ output_quoted_string (file, name);
+ putc ('\n', file);
+#endif
+}
+
+/* Output a file name in the form wanted by System V. */
+
+void
+output_file_directive (FILE *asm_file, const char *input_name)
+{
+ int len;
+ const char *na;
+
+ if (input_name == NULL)
+ input_name = "<stdin>";
+ else
+ input_name = remap_debug_filename (input_name);
+
+ len = strlen (input_name);
+ na = input_name + len;
+
+ /* NA gets INPUT_NAME sans directory names. */
+ while (na > input_name)
+ {
+ if (IS_DIR_SEPARATOR (na[-1]))
+ break;
+ na--;
+ }
+
+ targetm.asm_out.output_source_filename (asm_file, na);
+}
+
/* Create a DEBUG_EXPR_DECL / DEBUG_EXPR pair from RTL expression
EXP. */
rtx