#include "expr.h"
#include "hard-reg-set.h"
#include "regs.h"
-#include "real.h"
#include "output.h"
+#include "diagnostic-core.h"
#include "toplev.h"
#include "hashtab.h"
#include "ggc.h"
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
static GTY(()) section *unnamed_sections;
/* Return a nonzero value if DECL has a section attribute. */
-#ifndef IN_NAMED_SECTION
#define IN_NAMED_SECTION(DECL) \
((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
&& DECL_SECTION_NAME (DECL) != NULL_TREE)
-#endif
/* Hash table of named sections. */
static GTY((param_is (section))) htab_t section_htab;
/* 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_TLS_MODEL (to) = TLS_MODEL_EMULATED;
- 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_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_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 = htab_hash_string (IDENTIFIER_POINTER (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_NEW (struct 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;
- 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. */
-
- 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);
-
- 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;
-}
-
-void
-emutls_finish (void)
-{
- if (targetm.emutls.register_common)
- {
- tree body = NULL_TREE;
-
- if (emutls_htab == NULL)
- return;
-
- 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
{
section *sect;
- sect = GGC_NEW (section);
+ sect = ggc_alloc_section ();
sect->unnamed.common.flags = flags | SECTION_UNNAMED;
sect->unnamed.callback = callback;
sect->unnamed.data = data;
{
section *sect;
- sect = GGC_NEW (section);
+ sect = ggc_alloc_section ();
sect->noswitch.common.flags = flags | SECTION_NOSWITCH;
sect->noswitch.callback = callback;
flags |= SECTION_NAMED;
if (*slot == NULL)
{
- sect = GGC_NEW (section);
+ sect = ggc_alloc_section ();
sect->named.common.flags = flags;
sect->named.name = ggc_strdup (name);
sect->named.decl = decl;
block = (struct object_block *) *slot;
if (block == NULL)
{
- block = (struct object_block *)
- ggc_alloc_cleared (sizeof (struct object_block));
+ block = ggc_alloc_cleared_object_block ();
block->sect = sect;
*slot = block;
}
/* Create the extended SYMBOL_REF. */
size = RTX_HDR_SIZE + sizeof (struct block_symbol);
- symbol = (rtx) ggc_alloc_zone (size, &rtl_zone);
+ symbol = ggc_alloc_zone_rtx_def (size, &rtl_zone);
/* Initialize the normal SYMBOL_REF fields. */
memset (symbol, 0, size);
&& 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;
return;
}
+ /* If this variable belongs to the global constant pool, retrieve the
+ pre-computed RTL or recompute it in LTO mode. */
+ if (TREE_CODE (decl) == VAR_DECL && DECL_IN_CONSTANT_POOL (decl))
+ {
+ SET_DECL_RTL (decl, output_constant_def (DECL_INITIAL (decl), 1));
+ return;
+ }
+
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
/* Specifying a section attribute on a variable forces it into a
non-.bss section, and thus it cannot be common. */
- gcc_assert (!(TREE_CODE (decl) == VAR_DECL
- && DECL_SECTION_NAME (decl) != NULL_TREE
- && DECL_INITIAL (decl) == NULL_TREE
- && DECL_COMMON (decl))
- || !DECL_COMMON (decl));
+ /* FIXME: In general this code should not be necessary because
+ visibility pass is doing the same work. But notice_global_symbol
+ is called early and it needs to make DECL_RTL to get the name.
+ we take care of recomputing the DECL_RTL after visibility is changed. */
+ if (TREE_CODE (decl) == VAR_DECL
+ && DECL_SECTION_NAME (decl) != NULL_TREE
+ && DECL_INITIAL (decl) == NULL_TREE
+ && DECL_COMMON (decl))
+ DECL_COMMON (decl) = 0;
/* Variables can't be both common and weak. */
- gcc_assert (TREE_CODE (decl) != VAR_DECL
- || !DECL_WEAK (decl)
- || !DECL_COMMON (decl));
+ if (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl))
+ DECL_COMMON (decl) = 0;
if (use_object_blocks_p () && use_blocks_for_decl_p (decl))
x = create_block_symbol (name, get_block_for_decl (decl), -1);
rtx
make_decl_rtl_for_debug (tree decl)
{
- unsigned int save_aliasing_flag;
+ unsigned int save_aliasing_flag, save_mudflap_flag;
rtx rtl;
if (DECL_RTL_SET_P (decl))
we do not want to create alias sets that will throw the alias
numbers off in the comparison dumps. So... clearing
flag_strict_aliasing will keep new_alias_set() from creating a
- new set. */
+ new set. It is undesirable to register decl with mudflap
+ in this case as well. */
save_aliasing_flag = flag_strict_aliasing;
flag_strict_aliasing = 0;
+ save_mudflap_flag = flag_mudflap;
+ flag_mudflap = 0;
rtl = DECL_RTL (decl);
/* Reset DECL_RTL back, as various parts of the compiler expects
SET_DECL_RTL (decl, NULL);
flag_strict_aliasing = save_aliasing_flag;
+ flag_mudflap = save_mudflap_flag;
return rtl;
}
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)))
{
if (flag_syntax_only)
return;
- app_disable ();
-
if (! dont_output_data
&& ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
gcc_assert (MEM_P (decl_rtl));
gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF);
symbol = XEXP (decl_rtl, 0);
+
+ /* If this symbol belongs to the tree constant pool, output the constant
+ if it hasn't already been written. */
+ if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+ {
+ tree decl = SYMBOL_REF_DECL (symbol);
+ if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl)))
+ output_constant_def_contents (symbol);
+ return;
+ }
+
+ app_disable ();
+
name = XSTR (symbol, 0);
if (TREE_PUBLIC (decl) && DECL_NAME (decl))
notice_global_symbol (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;
/* Assemble a label named NAME. */
void
-assemble_label (const char *name)
+assemble_label (FILE *file, const char *name)
{
- ASM_OUTPUT_LABEL (asm_out_file, name);
+ ASM_OUTPUT_LABEL (file, name);
}
/* Set the symbol_referenced flag for ID. */
{
if (TREE_CODE (target) == COMPONENT_REF
&& host_integerp (byte_position (TREE_OPERAND (target, 1)), 0))
-
{
offset += int_byte_position (TREE_OPERAND (target, 1));
target = TREE_OPERAND (target, 0);
* tree_low_cst (TREE_OPERAND (target, 1), 0));
target = TREE_OPERAND (target, 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))
+ == ADDR_EXPR)
+ target = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (target, 0), 0), 0);
else
break;
}
static GTY((param_is (struct constant_descriptor_tree)))
htab_t const_desc_htab;
-static struct constant_descriptor_tree * build_constant_desc (tree);
static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int);
/* Constant pool accessor function. */
return (const_hash_1 (TREE_REALPART (exp)) * 5
+ const_hash_1 (TREE_IMAGPART (exp)));
+ case VECTOR_CST:
+ {
+ tree link;
+
+ hi = 7 + TYPE_VECTOR_SUBPARTS (TREE_TYPE (exp));
+
+ for (link = TREE_VECTOR_CST_ELTS (exp); link; link = TREE_CHAIN (link))
+ hi = hi * 563 + const_hash_1 (TREE_VALUE (link));
+
+ return hi;
+ }
+
case CONSTRUCTOR:
{
unsigned HOST_WIDE_INT idx;
return (compare_constant (TREE_REALPART (t1), TREE_REALPART (t2))
&& compare_constant (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
+ case VECTOR_CST:
+ {
+ tree link1, link2;
+
+ if (TYPE_VECTOR_SUBPARTS (TREE_TYPE (t1))
+ != TYPE_VECTOR_SUBPARTS (TREE_TYPE (t2)))
+ return 0;
+
+ link2 = TREE_VECTOR_CST_ELTS (t2);
+ for (link1 = TREE_VECTOR_CST_ELTS (t1);
+ link1;
+ link1 = TREE_CHAIN (link1))
+ {
+ if (!compare_constant (TREE_VALUE (link1), TREE_VALUE (link2)))
+ return 0;
+ link2 = TREE_CHAIN (link2);
+ }
+
+ return 1;
+ }
+
case CONSTRUCTOR:
{
VEC(constructor_elt, gc) *v1, *v2;
case FDESC_EXPR:
{
struct addr_const value1, value2;
+ enum rtx_code code;
+ int ret;
decode_addr_const (t1, &value1);
decode_addr_const (t2, &value2);
- return (value1.offset == value2.offset
- && strcmp (XSTR (value1.base, 0), XSTR (value2.base, 0)) == 0);
+
+ if (value1.offset != value2.offset)
+ return 0;
+
+ code = GET_CODE (value1.base);
+ if (code != GET_CODE (value2.base))
+ return 0;
+
+ switch (code)
+ {
+ case SYMBOL_REF:
+ ret = (strcmp (XSTR (value1.base, 0), XSTR (value2.base, 0)) == 0);
+ break;
+
+ case LABEL_REF:
+ ret = (CODE_LABEL_NUMBER (XEXP (value1.base, 0))
+ == CODE_LABEL_NUMBER (XEXP (value2.base, 0)));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ return ret;
}
case PLUS_EXPR:
return build1 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)));
+ case VECTOR_CST:
+ return build_vector (TREE_TYPE (exp),
+ copy_list (TREE_VECTOR_CST_ELTS (exp)));
+
case CONSTRUCTOR:
{
tree copy = copy_node (exp);
}
}
\f
-/* Return the alignment of constant EXP in bits. */
-
-static unsigned int
-get_constant_alignment (tree exp)
-{
- unsigned int align;
-
- align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
- align = CONSTANT_ALIGNMENT (exp, align);
-#endif
- return align;
-}
-
/* Return the section into which constant EXP should be placed. */
static section *
-get_constant_section (tree exp)
+get_constant_section (tree exp, unsigned int align)
{
- if (IN_NAMED_SECTION (exp))
- return get_named_section (exp, NULL, compute_reloc_for_constant (exp));
- else
- return targetm.asm_out.select_section (exp,
- compute_reloc_for_constant (exp),
- get_constant_alignment (exp));
+ return targetm.asm_out.select_section (exp,
+ compute_reloc_for_constant (exp),
+ align);
}
/* Return the size of constant EXP in bytes. */
static struct constant_descriptor_tree *
build_constant_desc (tree exp)
{
- rtx symbol;
- rtx rtl;
+ struct constant_descriptor_tree *desc;
+ rtx symbol, rtl;
char label[256];
int labelno;
- struct constant_descriptor_tree *desc;
+ tree decl;
- desc = GGC_NEW (struct constant_descriptor_tree);
+ desc = ggc_alloc_constant_descriptor_tree ();
desc->value = copy_constant (exp);
/* Propagate marked-ness to copied constant. */
labelno = const_labelno++;
ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
- /* We have a symbol name; construct the SYMBOL_REF and the MEM. */
+ /* Construct the VAR_DECL associated with the constant. */
+ decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (label),
+ TREE_TYPE (exp));
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ TREE_ADDRESSABLE (decl) = 1;
+ /* We don't set the RTL yet as this would cause varpool to assume that the
+ variable is referenced. Moreover, it would just be dropped in LTO mode.
+ Instead we set the flag that will be recognized in make_decl_rtl. */
+ DECL_IN_CONSTANT_POOL (decl) = 1;
+ DECL_INITIAL (decl) = desc->value;
+ /* ??? CONSTANT_ALIGNMENT hasn't been updated for vector types on most
+ architectures so use DATA_ALIGNMENT as well, except for strings. */
+ if (TREE_CODE (exp) == STRING_CST)
+ {
+#ifdef CONSTANT_ALIGNMENT
+ DECL_ALIGN (decl) = CONSTANT_ALIGNMENT (exp, DECL_ALIGN (decl));
+#endif
+ }
+ else
+ align_variable (decl, 0);
+
+ /* Now construct the SYMBOL_REF and the MEM. */
if (use_object_blocks_p ())
{
- section *sect = get_constant_section (exp);
+ section *sect = get_constant_section (exp, DECL_ALIGN (decl));
symbol = create_block_symbol (ggc_strdup (label),
get_block_for_section (sect), -1);
}
else
symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL;
- SET_SYMBOL_REF_DECL (symbol, desc->value);
+ SET_SYMBOL_REF_DECL (symbol, decl);
TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;
rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);
ASM_OUTPUT_LABELREF will have to know how to strip this
information. This call might invalidate our local variable
SYMBOL; we can't use it afterward. */
-
targetm.encode_section_info (exp, rtl, true);
desc->rtl = rtl;
size = get_constant_size (exp);
/* Do any machine/system dependent processing of the constant. */
-#ifdef ASM_DECLARE_CONSTANT_NAME
- ASM_DECLARE_CONSTANT_NAME (asm_out_file, label, exp, size);
-#else
- /* Standard thing is just output label for the constant. */
- ASM_OUTPUT_LABEL (asm_out_file, label);
-#endif /* ASM_DECLARE_CONSTANT_NAME */
+ targetm.asm_out.declare_constant_name (asm_out_file, label, exp, size);
/* Output the value of EXP. */
output_constant (exp, size, align);
static void
output_constant_def_contents (rtx symbol)
{
- tree exp = SYMBOL_REF_DECL (symbol);
+ tree decl = SYMBOL_REF_DECL (symbol);
+ tree exp = DECL_INITIAL (decl);
unsigned int align;
/* Make sure any other constants whose addresses appear in EXP
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
place_block_symbol (symbol);
else
{
- switch_to_section (get_constant_section (exp));
- align = get_constant_alignment (exp);
+ align = DECL_ALIGN (decl);
+ switch_to_section (get_constant_section (exp, align));
if (align > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
assemble_constant_contents (exp, XSTR (symbol, 0), align);
return (desc ? desc->rtl : NULL_RTX);
}
+
+/* Return a tree representing a reference to constant data in memory
+ for the constant expression EXP.
+
+ This is the counterpart of output_constant_def at the Tree level. */
+
+tree
+tree_output_constant_def (tree exp)
+{
+ struct constant_descriptor_tree *desc, key;
+ void **loc;
+ tree decl;
+
+ /* Look up EXP in the table of constant descriptors. If we didn't find
+ it, create a new one. */
+ key.value = exp;
+ key.hash = const_hash_1 (exp);
+ loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
+
+ desc = (struct constant_descriptor_tree *) *loc;
+ if (desc == 0)
+ {
+ desc = build_constant_desc (exp);
+ desc->hash = key.hash;
+ *loc = desc;
+ }
+
+ decl = SYMBOL_REF_DECL (XEXP (desc->rtl, 0));
+ varpool_finalize_decl (decl);
+ return decl;
+}
\f
/* Used in the hash tables to avoid outputting the same constant
twice. Unlike 'struct constant_descriptor_tree', RTX constants
{
struct rtx_constant_pool *pool;
- pool = GGC_NEW (struct rtx_constant_pool);
+ pool = ggc_alloc_rtx_constant_pool ();
pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
const_desc_rtx_eq, NULL);
pool->first = NULL;
return copy_rtx (desc->mem);
/* Otherwise, create a new descriptor. */
- desc = GGC_NEW (struct constant_descriptor_rtx);
+ desc = ggc_alloc_constant_descriptor_rtx ();
*slot = desc;
/* Align the location counter as required by EXP's data type. */
}
else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
{
- tree exp = SYMBOL_REF_DECL (x);
- if (!TREE_ASM_WRITTEN (exp))
+ tree decl = SYMBOL_REF_DECL (x);
+ if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl)))
{
n_deferred_constants--;
output_constant_def_contents (x);
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;
else if (vnode)
{
varpool_mark_needed_node (vnode);
+ vnode->force_output = 1;
return vnode->decl;
}
else
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);
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);
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)
{
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 (! (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;
+ }
}
}
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);
alias_pair *p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
p->decl = decl;
p->target = target;
+ p->emitted_diags = ALIAS_DIAG_NONE;
}
}
the visibility type VIS, which must not be VISIBILITY_DEFAULT. */
void
-default_assemble_visibility (tree decl, int vis)
+default_assemble_visibility (tree decl ATTRIBUTE_UNUSED,
+ int vis ATTRIBUTE_UNUSED)
{
+#ifdef HAVE_GAS_HIDDEN
static const char * const visibility_types[] = {
NULL, "protected", "hidden", "internal"
};
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
type = visibility_types[vis];
-#ifdef HAVE_GAS_HIDDEN
fprintf (asm_out_file, "\t.%s\t", type);
assemble_name (asm_out_file, name);
fprintf (asm_out_file, "\n");
if (vis != VISIBILITY_DEFAULT)
{
- targetm.asm_out.visibility (decl, vis);
+ targetm.asm_out.assemble_visibility (decl, vis);
return 1;
}
else
gcc_unreachable ();
}
+#ifndef TLS_SECTION_ASM_FLAG
+#define TLS_SECTION_ASM_FLAG 'T'
+#endif
+
void
default_elf_asm_named_section (const char *name, unsigned int flags,
tree decl ATTRIBUTE_UNUSED)
if (flags & SECTION_STRINGS)
*f++ = 'S';
if (flags & SECTION_TLS)
- *f++ = 'T';
+ *f++ = TLS_SECTION_ASM_FLAG;
if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
*f++ = 'G';
*f = '\0';
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. */
ASM_OUTPUT_INTERNAL_LABEL (stream, buf);
}
+
+/* The default implementation of ASM_DECLARE_CONSTANT_NAME. */
+
+void
+default_asm_declare_constant_name (FILE *file, const char *name,
+ const_tree exp ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+ assemble_label (file, name);
+}
+
/* This is the default behavior at the beginning of a file. It's
controlled by two other target-hook toggles. */
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. */
else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
{
decl = SYMBOL_REF_DECL (symbol);
- alignment = get_constant_alignment (decl);
- size = get_constant_size (decl);
+ alignment = DECL_ALIGN (decl);
+ size = get_constant_size (DECL_INITIAL (decl));
}
else
{
/* 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);
else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
{
decl = SYMBOL_REF_DECL (symbol);
- assemble_constant_contents (decl, XSTR (symbol, 0),
- get_constant_alignment (decl));
- offset += get_constant_size (decl);
+ assemble_constant_contents (DECL_INITIAL (decl), XSTR (symbol, 0),
+ DECL_ALIGN (decl));
+ offset += get_constant_size (DECL_INITIAL (decl));
}
else
{
int
elf_record_gcc_switches (print_switch_type type, const char * name)
{
- static char buffer[1024];
-
- /* This variable is used as part of a simplistic heuristic to detect
- command line switches which take an argument:
-
- "If a command line option does not start with a dash then
- it is an argument for the previous command line option."
-
- This fails in the case of the command line option which is the name
- of the file to compile, but otherwise it is pretty reasonable. */
- static bool previous_name_held_back = FALSE;
-
switch (type)
{
case SWITCH_TYPE_PASSED:
- if (* name != '-')
- {
- if (previous_name_held_back)
- {
- unsigned int len = strlen (buffer);
-
- snprintf (buffer + len, sizeof buffer - len, " %s", name);
- ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
- ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
- previous_name_held_back = FALSE;
- }
- else
- {
- strncpy (buffer, name, sizeof buffer);
- ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
- ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
- }
- }
- else
- {
- if (previous_name_held_back)
- {
- ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
- ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
- }
-
- strncpy (buffer, name, sizeof buffer);
- previous_name_held_back = TRUE;
- }
+ ASM_OUTPUT_ASCII (asm_out_file, name, strlen (name));
+ ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
break;
case SWITCH_TYPE_DESCRIPTIVE:
/* Distinguish between invocations where name is NULL. */
static bool started = false;
- if (started)
- {
- if (previous_name_held_back)
- {
- ASM_OUTPUT_ASCII (asm_out_file, buffer, strlen (buffer));
- ASM_OUTPUT_SKIP (asm_out_file, (unsigned HOST_WIDE_INT) 1);
- }
- }
- else
+ if (!started)
{
section * sec;
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
+make_debug_expr_from_rtl (const_rtx exp)
+{
+ tree ddecl = make_node (DEBUG_EXPR_DECL), type;
+ enum machine_mode mode = GET_MODE (exp);
+ rtx dval;
+
+ DECL_ARTIFICIAL (ddecl) = 1;
+ if (REG_P (exp) && REG_EXPR (exp))
+ type = TREE_TYPE (REG_EXPR (exp));
+ else if (MEM_P (exp) && MEM_EXPR (exp))
+ type = TREE_TYPE (MEM_EXPR (exp));
+ else
+ type = NULL_TREE;
+ if (type && TYPE_MODE (type) == mode)
+ TREE_TYPE (ddecl) = type;
+ else
+ TREE_TYPE (ddecl) = lang_hooks.types.type_for_mode (mode, 1);
+ DECL_MODE (ddecl) = mode;
+ dval = gen_rtx_DEBUG_EXPR (mode);
+ DEBUG_EXPR_TREE_DECL (dval) = ddecl;
+ SET_DECL_RTL (ddecl, dval);
+ return dval;
+}
+
#include "gt-varasm.h"