/* Output variables, constants and external declarations, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This file handles generation of all the assembler code
/* We give all constants their own alias set. Perhaps redundant with
MEM_READONLY_P, but pre-dates it. */
-static HOST_WIDE_INT const_alias_set;
+static alias_set_type const_alias_set;
static const char *strip_reg_name (const char *);
static int contains_pointers_p (tree);
static unsigned min_align (unsigned, unsigned);
static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int);
static void globalize_decl (tree);
-static void maybe_assemble_visibility (tree);
#ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_BSS
static void asm_output_bss (FILE *, tree, const char *,
}
else
TREE_STATIC (to) = 1;
-
+
DECL_INITIAL (to) = DECL_INITIAL (decl);
DECL_INITIAL (decl) = NULL;
- cgraph_varpool_finalize_decl (to);
+ varpool_finalize_decl (to);
return build_fold_addr_expr (to);
}
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.from = decl;
+ in.base.from = decl;
loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT);
h = *loc;
if (h != NULL)
h = ggc_alloc (sizeof (struct tree_map));
h->hash = in.hash;
- h->from = decl;
+ h->base.from = decl;
h->to = to;
*(struct tree_map **) loc = h;
tree args, x, *pstmts = (tree *) xstmts;
tree word_type_node;
- if (!DECL_COMMON (h->from))
+ 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);
-
- x = get_emutls_init_templ_addr (h->from);
+
+ /* 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->from));
+ 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->from));
+ 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);
unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT rounded)
{
- targetm.asm_out.globalize_label (file, name);
+ gcc_assert (strcmp (XSTR (XEXP (DECL_RTL (decl), 0), 0), name) == 0);
+ targetm.asm_out.globalize_decl_name (file, decl);
switch_to_section (bss_section);
#ifdef ASM_DECLARE_OBJECT_NAME
last_assemble_variable_decl = decl;
/* Return true if DECL's initializer is suitable for a BSS section. */
static bool
-bss_initializer_p (tree decl)
+bss_initializer_p (const_tree decl)
{
return (DECL_INITIAL (decl) == NULL
|| DECL_INITIAL (decl) == error_mark_node
if (! DECL_USER_ALIGN (decl))
{
#ifdef DATA_ALIGNMENT
- align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
+ unsigned int data_align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
+ /* Don't increase alignment too much for TLS variables - TLS space
+ is too precious. */
+ if (! DECL_THREAD_LOCAL_P (decl) || data_align <= BITS_PER_WORD)
+ align = data_align;
#endif
#ifdef CONSTANT_ALIGNMENT
if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
- align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
+ {
+ unsigned int const_align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl),
+ align);
+ /* Don't increase alignment too much for TLS variables - TLS space
+ is too precious. */
+ if (! DECL_THREAD_LOCAL_P (decl) || const_align <= BITS_PER_WORD)
+ align = const_align;
+ }
#endif
}
if (DECL_INITIAL (decl) == decl)
return false;
+ /* 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 true;
}
if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
mudflap_enqueue_decl (decl);
}
-
-/* Make the rtl for variable VAR be volatile.
- Use this only for static variables. */
-
-void
-make_var_volatile (tree var)
-{
- gcc_assert (MEM_P (DECL_RTL (var)));
-
- MEM_VOLATILE_P (DECL_RTL (var)) = 1;
-}
\f
/* Output a string of literal assembler code
for an `asm' keyword used between functions. */
#endif
}
-void
-default_named_section_asm_out_destructor (rtx symbol, int priority)
+/* Write the address of the entity given by SYMBOL to SEC. */
+void
+assemble_addr_to_section (rtx symbol, section *sec)
+{
+ switch_to_section (sec);
+ assemble_align (POINTER_SIZE);
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+}
+
+/* Return the numbered .ctors.N (if CONSTRUCTOR_P) or .dtors.N (if
+ not) section for PRIORITY. */
+section *
+get_cdtor_priority_section (int priority, bool constructor_p)
{
- const char *section = ".dtors";
char buf[16];
/* ??? This only works reliably with the GNU linker. */
+ sprintf (buf, "%s.%.5u",
+ constructor_p ? ".ctors" : ".dtors",
+ /* Invert the numbering so the linker puts us in the proper
+ order; constructors are run from right to left, and the
+ linker sorts in increasing order. */
+ MAX_INIT_PRIORITY - priority);
+ return get_section (buf, SECTION_WRITE, NULL);
+}
+
+void
+default_named_section_asm_out_destructor (rtx symbol, int priority)
+{
+ section *sec;
+
if (priority != DEFAULT_INIT_PRIORITY)
- {
- sprintf (buf, ".dtors.%.5u",
- /* Invert the numbering so the linker puts us in the proper
- order; constructors are run from right to left, and the
- linker sorts in increasing order. */
- MAX_INIT_PRIORITY - priority);
- section = buf;
- }
+ sec = get_cdtor_priority_section (priority,
+ /*constructor_p=*/false);
+ else
+ sec = get_section (".dtors", SECTION_WRITE, NULL);
- switch_to_section (get_section (section, SECTION_WRITE, NULL));
- assemble_align (POINTER_SIZE);
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ assemble_addr_to_section (symbol, sec);
}
#ifdef DTORS_SECTION_ASM_OP
default_dtor_section_asm_out_destructor (rtx symbol,
int priority ATTRIBUTE_UNUSED)
{
- switch_to_section (dtors_section);
- assemble_align (POINTER_SIZE);
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ assemble_addr_to_section (symbol, dtors_section);
}
#endif
void
default_named_section_asm_out_constructor (rtx symbol, int priority)
{
- const char *section = ".ctors";
- char buf[16];
+ section *sec;
- /* ??? This only works reliably with the GNU linker. */
if (priority != DEFAULT_INIT_PRIORITY)
- {
- sprintf (buf, ".ctors.%.5u",
- /* Invert the numbering so the linker puts us in the proper
- order; constructors are run from right to left, and the
- linker sorts in increasing order. */
- MAX_INIT_PRIORITY - priority);
- section = buf;
- }
+ sec = get_cdtor_priority_section (priority,
+ /*constructor_p=*/true);
+ else
+ sec = get_section (".ctors", SECTION_WRITE, NULL);
- switch_to_section (get_section (section, SECTION_WRITE, NULL));
- assemble_align (POINTER_SIZE);
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ assemble_addr_to_section (symbol, sec);
}
#ifdef CTORS_SECTION_ASM_OP
default_ctor_section_asm_out_constructor (rtx symbol,
int priority ATTRIBUTE_UNUSED)
{
- switch_to_section (ctors_section);
- assemble_align (POINTER_SIZE);
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ assemble_addr_to_section (symbol, ctors_section);
}
#endif
\f
/* We win when global object is found, but it is useful to know about weak
symbol as well so we can produce nicer unique names. */
- if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl))
+ if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl) || flag_shlib)
type = &weak_global_object_name;
if (!*type)
if (flag_reorder_blocks_and_partition)
{
switch_to_section (unlikely_text_section ());
- assemble_align (FUNCTION_BOUNDARY);
+ assemble_align (DECL_ALIGN (decl));
ASM_OUTPUT_LABEL (asm_out_file, cfun->cold_section_label);
/* When the function starts with a cold section, we need to explicitly
&& BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
{
switch_to_section (text_section);
- assemble_align (FUNCTION_BOUNDARY);
+ assemble_align (DECL_ALIGN (decl));
ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
hot_label_written = true;
first_function_block_is_cold = true;
ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_label);
/* Tell assembler to move to target machine's alignment for functions. */
- align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
- if (align < force_align_functions_log)
- align = force_align_functions_log;
+ align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT);
if (align > 0)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
}
/* Handle a user-specified function alignment.
- Note that we still need to align to FUNCTION_BOUNDARY, as above,
+ Note that we still need to align to DECL_ALIGN, as above,
because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all. */
- if (align_functions_log > align
+ if (! DECL_USER_ALIGN (decl)
+ && align_functions_log > align
&& cfun->function_frequency != FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
{
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
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))
+ if (! DECL_EXTERNAL (to)
+ && (! DECL_COMMON (to)
+ || (DECL_INITIAL (decl)
+ && DECL_INITIAL (decl) != error_mark_node)))
{
VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
constructor_elt *elt;
elt->value = get_emutls_init_templ_addr (decl);
DECL_INITIAL (to) = build_constructor (type, v);
+
+ /* 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);
}
decl = to;
}
- if (lang_hooks.decls.prepare_assemble_variable)
- lang_hooks.decls.prepare_assemble_variable (decl);
-
last_assemble_variable_decl = 0;
/* Normally no need to say anything here for external references,
if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
return;
- if (flag_unit_at_a_time)
- pending_assemble_externals = tree_cons (0, decl,
- pending_assemble_externals);
- else
- assemble_external_real (decl);
+ /* We want to output external symbols at very last to check if they
+ are references or not. */
+ pending_assemble_externals = tree_cons (0, decl,
+ pending_assemble_externals);
#endif
}
}
else if (TREE_CODE (decl) == VAR_DECL)
{
- struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
- cgraph_varpool_mark_needed_node (node);
+ struct varpool_node *node = varpool_node (decl);
+ varpool_mark_needed_node (node);
/* C++ frontend use mark_decl_references to force COMDAT variables
to be output that might appear dead otherwise. */
node->force_output = true;
enum machine_mode omode, imode;
unsigned int subalign;
unsigned int subsize, i;
+ unsigned char mclass;
subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1;
subalign = MIN (align, subsize * BITS_PER_UNIT);
- omode = mode_for_size (subsize * BITS_PER_UNIT, MODE_INT, 0);
- imode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+ if (GET_CODE (x) == CONST_FIXED)
+ mclass = GET_MODE_CLASS (GET_MODE (x));
+ else
+ mclass = MODE_INT;
+
+ omode = mode_for_size (subsize * BITS_PER_UNIT, mclass, 0);
+ imode = mode_for_size (size * BITS_PER_UNIT, mclass, 0);
for (i = 0; i < size; i += subsize)
{
break;
case REAL_CST:
+ case FIXED_CST:
case STRING_CST:
case COMPLEX_CST:
case CONSTRUCTOR:
static hashval_t
const_desc_hash (const void *ptr)
{
- return ((struct constant_descriptor_tree *)ptr)->hash;
+ return ((const struct constant_descriptor_tree *)ptr)->hash;
}
static hashval_t
case REAL_CST:
return real_hash (TREE_REAL_CST_PTR (exp));
+ case FIXED_CST:
+ return fixed_hash (TREE_FIXED_CST_PTR (exp));
+
case STRING_CST:
p = TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
return hi;
case PLUS_EXPR:
+ case POINTER_PLUS_EXPR:
case MINUS_EXPR:
return (const_hash_1 (TREE_OPERAND (exp, 0)) * 9
+ const_hash_1 (TREE_OPERAND (exp, 1)));
return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
+ case FIXED_CST:
+ /* Fixed constants are the same only if the same width of type. */
+ if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
+ return 0;
+
+ return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), TREE_FIXED_CST (t2));
+
case STRING_CST:
if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
return 0;
}
case PLUS_EXPR:
+ case POINTER_PLUS_EXPR:
case MINUS_EXPR:
case RANGE_EXPR:
return (compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
return compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
default:
- {
- tree nt1, nt2;
- nt1 = lang_hooks.expand_constant (t1);
- nt2 = lang_hooks.expand_constant (t2);
- if (nt1 != t1 || nt2 != t2)
- return compare_constant (nt1, nt2);
- else
- return 0;
- }
+ return 0;
}
gcc_unreachable ();
case INTEGER_CST:
case REAL_CST:
+ case FIXED_CST:
case STRING_CST:
return copy_node (exp);
copy_constant (TREE_IMAGPART (exp)));
case PLUS_EXPR:
+ case POINTER_PLUS_EXPR:
case MINUS_EXPR:
return build2 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)),
}
default:
- {
- tree t = lang_hooks.expand_constant (exp);
-
- gcc_assert (t != exp);
- return copy_constant (t);
- }
+ gcc_unreachable ();
}
}
\f
h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
break;
+ case CONST_FIXED:
+ h ^= fixed_hash (CONST_FIXED_VALUE (x));
+ break;
+
case CONST_VECTOR:
{
int i;
/* Similar, return the mode. */
enum machine_mode
-get_pool_mode (rtx addr)
+get_pool_mode (const_rtx addr)
{
return SYMBOL_REF_CONSTANT (addr)->mode;
}
case MODE_INT:
case MODE_PARTIAL_INT:
+ case MODE_FRACT:
+ case MODE_UFRACT:
+ case MODE_ACCUM:
+ case MODE_UACCUM:
assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
break;
case MODE_VECTOR_FLOAT:
case MODE_VECTOR_INT:
+ case MODE_VECTOR_FRACT:
+ case MODE_VECTOR_UFRACT:
+ case MODE_VECTOR_ACCUM:
+ case MODE_VECTOR_UACCUM:
{
int i, units;
enum machine_mode submode = GET_MODE_INNER (mode);
tmp = XEXP (x, 0);
gcc_assert (!INSN_DELETED_P (tmp));
gcc_assert (!NOTE_P (tmp)
- || NOTE_LINE_NUMBER (tmp) != NOTE_INSN_DELETED);
+ || NOTE_KIND (tmp) != NOTE_INSN_DELETED);
break;
default:
int reloc = 0, reloc2;
tree tem;
- /* Give the front-end a chance to convert VALUE to something that
- looks more like a constant to the back-end. */
- exp = lang_hooks.expand_constant (exp);
-
switch (TREE_CODE (exp))
{
case ADDR_EXPR:
break;
case PLUS_EXPR:
+ case POINTER_PLUS_EXPR:
reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));
reloc |= compute_reloc_for_constant (TREE_OPERAND (exp, 1));
break;
{
tree tem;
- /* Give the front-end a chance to convert VALUE to something that
- looks more like a constant to the back-end. */
- exp = lang_hooks.expand_constant (exp);
-
switch (TREE_CODE (exp))
{
case ADDR_EXPR:
break;
case PLUS_EXPR:
+ case POINTER_PLUS_EXPR:
case MINUS_EXPR:
output_addressed_constants (TREE_OPERAND (exp, 1));
/* Fall through. */
evaluate the property while walking a constructor for other purposes. */
bool
-constructor_static_from_elts_p (tree ctor)
+constructor_static_from_elts_p (const_tree ctor)
{
return (TREE_CONSTANT (ctor)
&& (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
tree
initializer_constant_valid_p (tree value, tree endtype)
{
- /* Give the front-end a chance to convert VALUE to something that
- looks more like a constant to the back-end. */
- value = lang_hooks.expand_constant (value);
-
switch (TREE_CODE (value))
{
case CONSTRUCTOR:
case INTEGER_CST:
case VECTOR_CST:
case REAL_CST:
+ case FIXED_CST:
case STRING_CST:
case COMPLEX_CST:
return null_pointer_node;
return null_pointer_node;
/* Taking the address of a nested function involves a trampoline. */
if (TREE_CODE (value) == FUNCTION_DECL
- && ((decl_function_context (value)
- && !DECL_NO_STATIC_CHAIN (value))
- || DECL_DLLIMPORT_P (value)))
+ && decl_function_context (value)
+ && !DECL_NO_STATIC_CHAIN (value))
return NULL_TREE;
/* "&{...}" requires a temporary to hold the constructed
object. */
}
break;
+ case POINTER_PLUS_EXPR:
case PLUS_EXPR:
if (! INTEGRAL_TYPE_P (endtype)
|| TYPE_PRECISION (endtype) >= POINTER_SIZE)
endtype);
tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
endtype);
- /* If either term is absolute, use the other terms relocation. */
+ /* If either term is absolute, use the other term's relocation. */
if (valid0 == null_pointer_node)
return valid1;
if (valid1 == null_pointer_node)
enum tree_code code;
unsigned HOST_WIDE_INT thissize;
- /* Some front-ends use constants other than the standard language-independent
- varieties, but which may still be output directly. Give the front-end a
- chance to convert EXP to a language-independent representation. */
- exp = lang_hooks.expand_constant (exp);
-
if (size == 0 || flag_syntax_only)
return;
code = TREE_CODE (TREE_TYPE (exp));
thissize = int_size_in_bytes (TREE_TYPE (exp));
- /* Give the front end another chance to expand constants. */
- exp = lang_hooks.expand_constant (exp);
-
/* Allow a constructor with no elements for any data type.
This means to fill the space with zeros. */
if (TREE_CODE (exp) == CONSTRUCTOR
case POINTER_TYPE:
case REFERENCE_TYPE:
case OFFSET_TYPE:
+ case FIXED_POINT_TYPE:
if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
EXPAND_INITIALIZER),
MIN (size, thissize), align, 0))
- error ("initializer for integer value is too complicated");
+ error ("initializer for integer/fixed-point value is too complicated");
break;
case REAL_TYPE:
/* NEWDECL is weak, but OLDDECL is not. */
/* If we already output the OLDDECL, we're in trouble; we can't
- go back and make it weak. This error cannot caught in
+ go back and make it weak. This error cannot be caught in
declare_weak because the NEWDECL and OLDDECL was not yet
been merged; therefore, TREE_ASM_WRITTEN was not set. */
if (TREE_ASM_WRITTEN (olddecl))
else if (! TREE_SYMBOL_REFERENCED (target))
{
/* Use ASM_WEAKEN_LABEL only if ASM_WEAKEN_DECL is not
- defined, otherwise we and weak_finish_1 would use a
+ defined, otherwise we and weak_finish_1 would use
different macros. */
# if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL
ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target));
static void
globalize_decl (tree decl)
{
- const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
#if defined (ASM_WEAKEN_LABEL) || defined (ASM_WEAKEN_DECL)
if (DECL_WEAK (decl))
{
+ const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
tree *p, t;
#ifdef ASM_WEAKEN_DECL
return;
}
-#elif defined(ASM_MAKE_LABEL_LINKONCE)
- if (DECL_ONE_ONLY (decl))
- ASM_MAKE_LABEL_LINKONCE (asm_out_file, name);
#endif
- targetm.asm_out.globalize_label (asm_out_file, name);
+ targetm.asm_out.globalize_decl_name (asm_out_file, decl);
}
/* We have to be able to tell cgraph about the needed-ness of the target
find_decl_and_mark_needed (tree decl, tree target)
{
struct cgraph_node *fnode = NULL;
- struct cgraph_varpool_node *vnode = NULL;
+ struct varpool_node *vnode = NULL;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
fnode = cgraph_node_for_asm (target);
if (fnode == NULL)
- vnode = cgraph_varpool_node_for_asm (target);
+ vnode = varpool_node_for_asm (target);
}
else
{
- vnode = cgraph_varpool_node_for_asm (target);
+ vnode = varpool_node_for_asm (target);
if (vnode == NULL)
fnode = cgraph_node_for_asm (target);
}
}
else if (vnode)
{
- cgraph_varpool_mark_needed_node (vnode);
+ varpool_mark_needed_node (vnode);
return vnode->decl;
}
else
if (TREE_CODE (decl) == FUNCTION_DECL)
cgraph_node (decl)->alias = true;
else
- cgraph_varpool_node (decl)->alias = true;
+ varpool_node (decl)->alias = true;
/* If the target has already been emitted, we don't have to queue the
- alias. This saves a tad o memory. */
+ alias. This saves a tad of memory. */
target_decl = find_decl_and_mark_needed (decl, target);
if (target_decl && TREE_ASM_WRITTEN (target_decl))
do_assemble_alias (decl, target);
/* A helper function to call assemble_visibility when needed for a decl. */
-static void
+int
maybe_assemble_visibility (tree decl)
{
enum symbol_visibility vis = DECL_VISIBILITY (decl);
if (vis != VISIBILITY_DEFAULT)
- targetm.asm_out.visibility (decl, vis);
+ {
+ targetm.asm_out.visibility (decl, vis);
+ return 1;
+ }
+ else
+ return 0;
}
/* Returns 1 if the target configuration supports defining public symbols
}
enum tls_model
-decl_default_tls_model (tree decl)
+decl_default_tls_model (const_tree decl)
{
enum tls_model kind;
bool is_local;
unsigned int
default_section_type_flags (tree decl, const char *name, int reloc)
{
- return default_section_type_flags_1 (decl, name, reloc, flag_pic);
-}
-
-unsigned int
-default_section_type_flags_1 (tree decl, const char *name, int reloc,
- int shlib)
-{
unsigned int flags;
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
flags = SECTION_CODE;
- else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
+ else if (decl && decl_readonly_section (decl, reloc))
flags = 0;
else if (current_function_decl
&& cfun
}
enum section_category
-categorize_decl_for_section (tree decl, int reloc, int shlib)
+categorize_decl_for_section (const_tree decl, int reloc)
{
enum section_category ret;
|| TREE_SIDE_EFFECTS (decl)
|| ! TREE_CONSTANT (DECL_INITIAL (decl)))
{
- if (shlib && (reloc & 2))
- ret = SECCAT_DATA_REL;
- else if (shlib && reloc)
- ret = SECCAT_DATA_REL_LOCAL;
+ /* 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 ())
+ ret = reloc == 1 ? SECCAT_DATA_REL_LOCAL : SECCAT_DATA_REL;
else
ret = SECCAT_DATA;
}
- else if (shlib && (reloc & 2))
- ret = SECCAT_DATA_REL_RO;
- else if (shlib && reloc)
- ret = SECCAT_DATA_REL_RO_LOCAL;
+ else if (reloc & targetm.asm_out.reloc_rw_mask ())
+ 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
location. -fmerge-all-constants allows even that (at the
}
else if (TREE_CODE (decl) == CONSTRUCTOR)
{
- if ((shlib && reloc)
+ if ((reloc & targetm.asm_out.reloc_rw_mask ())
|| TREE_SIDE_EFFECTS (decl)
|| ! TREE_CONSTANT (decl))
ret = SECCAT_DATA;
}
bool
-decl_readonly_section (tree decl, int reloc)
-{
- return decl_readonly_section_1 (decl, reloc, flag_pic);
-}
-
-bool
-decl_readonly_section_1 (tree decl, int reloc, int shlib)
+decl_readonly_section (const_tree decl, int reloc)
{
- switch (categorize_decl_for_section (decl, reloc, shlib))
+ switch (categorize_decl_for_section (decl, reloc))
{
case SECCAT_RODATA:
case SECCAT_RODATA_MERGE_STR:
default_elf_select_section (tree decl, int reloc,
unsigned HOST_WIDE_INT align)
{
- return default_elf_select_section_1 (decl, reloc, align, flag_pic);
-}
-
-section *
-default_elf_select_section_1 (tree decl, int reloc,
- unsigned HOST_WIDE_INT align, int shlib)
-{
const char *sname;
- switch (categorize_decl_for_section (decl, reloc, shlib))
+ switch (categorize_decl_for_section (decl, reloc))
{
case SECCAT_TEXT:
/* We're not supposed to be called on FUNCTION_DECLs. */
void
default_unique_section (tree decl, int reloc)
{
- default_unique_section_1 (decl, reloc, flag_pic);
-}
-
-void
-default_unique_section_1 (tree decl, int reloc, int shlib)
-{
/* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
const char *prefix, *name;
size_t nlen, plen;
char *string;
- switch (categorize_decl_for_section (decl, reloc, shlib))
+ switch (categorize_decl_for_section (decl, reloc))
{
case SECCAT_TEXT:
prefix = one_only ? ".gnu.linkonce.t." : ".text.";
DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
}
+/* Like compute_reloc_for_constant, except for an RTX. The return value
+ is a mask for which bit 1 indicates a global relocation, and bit 0
+ indicates a local relocation. */
+
+static int
+compute_reloc_for_rtx_1 (rtx *xp, void *data)
+{
+ int *preloc = data;
+ rtx x = *xp;
+
+ switch (GET_CODE (x))
+ {
+ case SYMBOL_REF:
+ *preloc |= SYMBOL_REF_LOCAL_P (x) ? 1 : 2;
+ break;
+ case LABEL_REF:
+ *preloc |= 1;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int
+compute_reloc_for_rtx (rtx x)
+{
+ int reloc;
+
+ switch (GET_CODE (x))
+ {
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ reloc = 0;
+ for_each_rtx (&x, compute_reloc_for_rtx_1, &reloc);
+ return reloc;
+
+ default:
+ return 0;
+ }
+}
+
section *
default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
rtx x,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
- if (flag_pic)
- switch (GET_CODE (x))
- {
- case CONST:
- case SYMBOL_REF:
- case LABEL_REF:
- return data_section;
-
- default:
- break;
- }
-
- return readonly_data_section;
+ if (compute_reloc_for_rtx (x) & targetm.asm_out.reloc_rw_mask ())
+ return data_section;
+ else
+ return readonly_data_section;
}
section *
default_elf_select_rtx_section (enum machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align)
{
- /* ??? Handle small data here somehow. */
+ int reloc = compute_reloc_for_rtx (x);
- if (flag_pic)
- switch (GET_CODE (x))
- {
- case CONST:
- case SYMBOL_REF:
- return get_named_section (NULL, ".data.rel.ro", 3);
+ /* ??? Handle small data here somehow. */
- case LABEL_REF:
+ if (reloc & targetm.asm_out.reloc_rw_mask ())
+ {
+ if (reloc == 1)
return get_named_section (NULL, ".data.rel.ro.local", 1);
-
- default:
- break;
- }
+ else
+ return get_named_section (NULL, ".data.rel.ro", 3);
+ }
return mergeable_constant_section (mode, align, 0);
}
{
char buffer[100];
- sprintf (buffer, ". + " HOST_WIDE_INT_PRINT_DEC,
+ sprintf (buffer, "*. + " HOST_WIDE_INT_PRINT_DEC,
SYMBOL_REF_BLOCK_OFFSET (symbol));
ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer);
}
/* The default implementation of TARGET_USE_ANCHORS_FOR_SYMBOL_P. */
bool
-default_use_anchors_for_symbol_p (rtx symbol)
+default_use_anchors_for_symbol_p (const_rtx symbol)
{
section *sect;
tree decl;
wrt cross-module name binding. */
bool
-default_binds_local_p (tree exp)
+default_binds_local_p (const_tree exp)
{
return default_binds_local_p_1 (exp, flag_shlib);
}
bool
-default_binds_local_p_1 (tree exp, int shlib)
+default_binds_local_p_1 (const_tree exp, int shlib)
{
bool local_p;
else if (DECL_WEAK (exp))
local_p = false;
/* If PIC, then assume that any global name can be overridden by
- symbols resolved from other modules. */
+ symbols resolved from other modules, unless we are compiling with
+ -fwhole-program, which assumes that names are local. */
else if (shlib)
- local_p = false;
+ local_p = flag_whole_program;
/* Uninitialized COMMON variable may be unified with symbols
resolved from other modules. */
else if (DECL_COMMON (exp)
}
#endif /* GLOBAL_ASM_OP */
+/* Default function to output code that will globalize a declaration. */
+void
+default_globalize_decl_name (FILE * stream, tree decl)
+{
+ const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+ targetm.asm_out.globalize_label (stream, name);
+}
+
/* Default function to output a label for unwind information. The
default is to do nothing. A target that needs nonlocal labels for
unwind information must provide its own function to do this. */
htab_traverse (object_block_htab, output_object_block_htab, NULL);
}
+/* This function provides a possible implementation of the
+ TARGET_ASM_RECORD_GCC_SWITCHES target hook for ELF targets. When triggered
+ by -frecord-gcc-switches it creates a new mergeable, string section in the
+ assembler output file called TARGET_ASM_RECORD_GCC_SWITCHES_SECTION which
+ contains the switches in ASCII format.
+
+ FIXME: This code does not correctly handle double quote characters
+ that appear inside strings, (it strips them rather than preserving them).
+ FIXME: ASM_OUTPUT_ASCII, as defined in config/elfos.h will not emit NUL
+ characters - instead it treats them as sub-string separators. Since
+ we want to emit NUL strings terminators into the object file we have to use
+ ASM_OUTPUT_SKIP. */
+
+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;
+ }
+ break;
+
+ case SWITCH_TYPE_DESCRIPTIVE:
+ if (name == NULL)
+ {
+ /* 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
+ {
+ section * sec;
+
+ sec = get_section (targetm.asm_out.record_gcc_switches_section,
+ SECTION_DEBUG
+ | SECTION_MERGE
+ | SECTION_STRINGS
+ | (SECTION_ENTSIZE & 1),
+ NULL);
+ switch_to_section (sec);
+ started = true;
+ }
+ }
+
+ default:
+ break;
+ }
+
+ /* The return value is currently ignored by the caller, but must be 0.
+ For -fverbose-asm the return value would be the number of characters
+ emitted into the assembler file. */
+ return 0;
+}
+
+/* Emit text to declare externally defined symbols. It is needed to
+ properly support non-default visibility. */
+void
+default_elf_asm_output_external (FILE *file ATTRIBUTE_UNUSED,
+ tree decl,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ /* We output the name if and only if TREE_SYMBOL_REFERENCED is
+ set in order to avoid putting out names that are never really
+ used. */
+ if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
+ && targetm.binds_local_p (decl))
+ maybe_assemble_visibility (decl);
+}
+
#include "gt-varasm.h"