/* 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, 2007
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
{
unsigned plen = strlen (prefix);
unsigned nlen = strlen (IDENTIFIER_POINTER (name));
- char *toname = alloca (plen + nlen + 1);
+ char *toname = (char *) alloca (plen + nlen + 1);
memcpy (toname, prefix, plen);
memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
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 = *loc;
+ h = (struct tree_map *) *loc;
if (h != NULL)
to = h->to;
else
to = build_decl (VAR_DECL, get_emutls_object_name (name),
get_emutls_object_type ());
- h = ggc_alloc (sizeof (struct tree_map));
+ h = GGC_NEW (struct tree_map);
h->hash = in.hash;
h->base.from = decl;
h->to = to;
void
emutls_finish (void)
{
- if (!targetm.emutls.register_common)
+ if (targetm.emutls.register_common)
{
tree body = NULL_TREE;
static int
section_entry_eq (const void *p1, const void *p2)
{
- const section *old = p1;
- const char *new = p2;
+ const section *old = (const section *) p1;
+ const char *new_name = (const char *) p2;
- return strcmp (old->named.name, new) == 0;
+ return strcmp (old->named.name, new_name) == 0;
}
static hashval_t
section_entry_hash (const void *p)
{
- const section *old = p;
+ const section *old = (const section *) p;
return htab_hash_string (old->named.name);
}
static int
object_block_entry_eq (const void *p1, const void *p2)
{
- const struct object_block *old = p1;
- const section *new = p2;
+ const struct object_block *old = (const struct object_block *) p1;
+ const section *new_section = (const section *) p2;
- return old->sect == new;
+ return old->sect == new_section;
}
static hashval_t
object_block_entry_hash (const void *p)
{
- const struct object_block *old = p;
+ const struct object_block *old = (const struct object_block *) p;
return hash_section (old->sect);
}
{
section *sect;
- sect = ggc_alloc (sizeof (struct unnamed_section));
+ sect = GGC_NEW (section);
sect->unnamed.common.flags = flags | SECTION_UNNAMED;
sect->unnamed.callback = callback;
sect->unnamed.data = data;
{
section *sect;
- sect = ggc_alloc (sizeof (struct unnamed_section));
+ sect = GGC_NEW (section);
sect->noswitch.common.flags = flags | SECTION_NOSWITCH;
sect->noswitch.callback = callback;
flags |= SECTION_NAMED;
if (*slot == NULL)
{
- sect = ggc_alloc (sizeof (struct named_section));
+ sect = GGC_NEW (section);
sect->named.common.flags = flags;
sect->named.name = ggc_strdup (name);
sect->named.decl = decl;
/* Create the extended SYMBOL_REF. */
size = RTX_HDR_SIZE + sizeof (struct block_symbol);
- symbol = ggc_alloc_zone (size, &rtl_zone);
+ symbol = (rtx) ggc_alloc_zone (size, &rtl_zone);
/* Initialize the normal SYMBOL_REF fields. */
memset (symbol, 0, size);
dsn = DECL_SECTION_NAME (current_function_decl);
if (flag_function_sections && dsn)
{
- name = alloca (TREE_STRING_LENGTH (dsn) + 1);
+ 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);
if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP)
{
- size_t len = strlen (name) + 3;
- char* rname = alloca (len);
+ const char *dot;
+ size_t len;
+ char* rname;
+
+ dot = strchr (name + 1, '.');
+ if (!dot)
+ dot = name;
+ len = strlen (dot) + 8;
+ rname = (char *) alloca (len);
strcpy (rname, ".rodata");
- strcat (rname, name + 5);
+ strcat (rname, dot);
return get_section (rname, SECTION_LINKONCE, decl);
}
/* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo. */
&& strncmp (name, ".gnu.linkonce.t.", 16) == 0)
{
size_t len = strlen (name) + 1;
- char *rname = alloca (len);
+ char *rname = (char *) alloca (len);
memcpy (rname, name, len);
rname[14] = 'r';
&& strncmp (name, ".text.", 6) == 0)
{
size_t len = strlen (name) + 1;
- char *rname = alloca (len + 2);
+ char *rname = (char *) alloca (len + 2);
memcpy (rname, ".rodata", 7);
memcpy (rname + 7, name + 5, len - 5);
void
set_user_assembler_name (tree decl, const char *name)
{
- char *starred = alloca (strlen (name) + 2);
+ char *starred = (char *) alloca (strlen (name) + 2);
starred[0] = '*';
strcpy (starred + 1, name);
change_decl_assembler_name (decl, get_identifier (starred));
/* When the function starts with a cold section, we need to explicitly
align the hot section and write out the hot section label.
But if the current function is a thunk, we do not have a CFG. */
- if (!crtl->is_thunk
+ if (!cfun->is_thunk
&& BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
{
switch_to_section (text_section);
because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all. */
if (! DECL_USER_ALIGN (decl)
&& align_functions_log > align
- && cfun->function_frequency != FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
+ && optimize_function_for_speed_p (cfun))
{
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file,
/* First make the assembler name(s) global if appropriate. */
sect = get_variable_section (decl, false);
if (TREE_PUBLIC (decl)
- && DECL_NAME (decl)
&& (sect->common.flags & SECTION_COMMON) == 0)
globalize_decl (decl);
}
}
-/* In unit-at-a-time mode, we delay assemble_external processing until
+/* We delay assemble_external processing until
the compilation unit is finalized. This is the best we can do for
right now (i.e. stage 3 of GCC 4.0) - the right thing is to delay
it all the way to final. See PR 17982 for further discussion. */
return true;
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0)
+ if (is_builtin_name (name))
return true;
}
return false;
#endif
}
-/* Output something to declare an external symbol to the assembler.
- (Most assemblers don't need this, so we normally output nothing.)
- Do nothing if DECL is not external. */
+/* This TREE_LIST contains any weak symbol declarations waiting
+ to be emitted. */
+static GTY(()) tree weak_decls;
+
+/* Output something to declare an external symbol to the assembler,
+ and qualifiers such as weakness. (Most assemblers don't need
+ extern declaration, so we normally output nothing.) Do nothing if
+ DECL is not external. */
void
assemble_external (tree decl ATTRIBUTE_UNUSED)
open. If it's not, we should not be calling this function. */
gcc_assert (asm_out_file);
-#ifdef ASM_OUTPUT_EXTERNAL
if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
return;
- /* 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);
+ /* We want to output annotation for weak and external symbols at
+ very last to check if they are references or not. */
+
+ if (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
+ locally emitted, inlined or otherwise not-really-extern, but
+ for declarations that can be weak, it happens to be
+ match. */
+ && !TREE_STATIC (decl)
+ && tree_find_value (weak_decls, decl) == NULL_TREE)
+ weak_decls = tree_cons (NULL, decl, weak_decls);
+
+#ifdef ASM_OUTPUT_EXTERNAL
+ if (tree_find_value (pending_assemble_externals, decl) == NULL_TREE)
+ pending_assemble_externals = tree_cons (NULL, decl,
+ pending_assemble_externals);
#endif
}
enum machine_mode omode, imode;
unsigned int subalign;
unsigned int subsize, i;
- unsigned char mclass;
+ enum mode_class mclass;
subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1;
subalign = MIN (align, subsize * BITS_PER_UNIT);
Store them both in the structure *VALUE.
EXP must be reducible. */
-struct addr_const GTY(())
-{
+struct GTY(()) addr_const {
rtx base;
HOST_WIDE_INT offset;
};
Each constant in memory thus far output is recorded
in `const_desc_table'. */
-struct constant_descriptor_tree GTY(())
-{
+struct GTY(()) constant_descriptor_tree {
/* A MEM for the constant. */
rtx rtl;
static int
const_desc_eq (const void *p1, const void *p2)
{
- const struct constant_descriptor_tree *c1 = p1;
- const struct constant_descriptor_tree *c2 = p2;
+ const struct constant_descriptor_tree *const c1
+ = (const struct constant_descriptor_tree *) p1;
+ const struct constant_descriptor_tree *const c2
+ = (const struct constant_descriptor_tree *) p2;
if (c1->hash != c2->hash)
return 0;
return compare_constant (c1->value, c2->value);
int labelno;
struct constant_descriptor_tree *desc;
- desc = ggc_alloc (sizeof (*desc));
+ desc = GGC_NEW (struct constant_descriptor_tree);
desc->value = copy_constant (exp);
/* Propagate marked-ness to copied constant. */
key.hash = const_hash_1 (exp);
loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
- desc = *loc;
+ desc = (struct constant_descriptor_tree *) *loc;
if (desc == 0)
{
desc = build_constant_desc (exp);
key.value = exp;
key.hash = const_hash_1 (exp);
- desc = htab_find_with_hash (const_desc_htab, &key, key.hash);
+ desc = (struct constant_descriptor_tree *)
+ htab_find_with_hash (const_desc_htab, &key, key.hash);
return (desc ? desc->rtl : NULL_RTX);
}
can use one per-file pool. Should add a targetm bit to tell the
difference. */
-struct rtx_constant_pool GTY(())
-{
+struct GTY(()) rtx_constant_pool {
/* Pointers to first and last constant in pool, as ordered by offset. */
struct constant_descriptor_rtx *first;
struct constant_descriptor_rtx *last;
HOST_WIDE_INT offset;
};
-struct constant_descriptor_rtx GTY((chain_next ("%h.next")))
-{
+struct GTY((chain_next ("%h.next"))) constant_descriptor_rtx {
struct constant_descriptor_rtx *next;
rtx mem;
rtx sym;
static hashval_t
const_desc_rtx_hash (const void *ptr)
{
- const struct constant_descriptor_rtx *desc = ptr;
+ const struct constant_descriptor_rtx *const desc
+ = (const struct constant_descriptor_rtx *) ptr;
return desc->hash;
}
static int
const_desc_rtx_eq (const void *a, const void *b)
{
- const struct constant_descriptor_rtx *x = a;
- const struct constant_descriptor_rtx *y = b;
+ const struct constant_descriptor_rtx *const x
+ = (const struct constant_descriptor_rtx *) a;
+ const struct constant_descriptor_rtx *const y
+ = (const struct constant_descriptor_rtx *) b;
if (x->mode != y->mode)
return 0;
break;
}
- hp = data;
+ hp = (hashval_t *) data;
*hp = *hp * 509 + h;
return 0;
}
{
struct rtx_constant_pool *pool;
- pool = ggc_alloc (sizeof (struct rtx_constant_pool));
+ pool = GGC_NEW (struct rtx_constant_pool);
pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
const_desc_rtx_eq, NULL);
pool->first = NULL;
tmp.mode = mode;
hash = const_rtx_hash (x);
slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
- desc = *slot;
+ desc = (struct constant_descriptor_rtx *) *slot;
/* If the constant was already present, return its memory. */
if (desc)
return copy_rtx (desc->mem);
/* Otherwise, create a new descriptor. */
- desc = ggc_alloc (sizeof (*desc));
+ desc = GGC_NEW (struct constant_descriptor_rtx);
*slot = desc;
/* Align the location counter as required by EXP's data type. */
&& !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
}
+/* A subroutine of initializer_constant_valid_p. VALUE is a MINUS_EXPR,
+ PLUS_EXPR or POINTER_PLUS_EXPR. This looks for cases of VALUE
+ which are valid when ENDTYPE is an integer of any size; in
+ particular, this does not accept a pointer minus a constant. This
+ returns null_pointer_node if the VALUE is an absolute constant
+ which can be used to initialize a static variable. Otherwise it
+ returns NULL. */
+
+static tree
+narrowing_initializer_constant_valid_p (tree value, tree endtype)
+{
+ tree op0, op1;
+
+ if (!INTEGRAL_TYPE_P (endtype))
+ return NULL_TREE;
+
+ op0 = TREE_OPERAND (value, 0);
+ op1 = TREE_OPERAND (value, 1);
+
+ /* Like STRIP_NOPS except allow the operand mode to widen. This
+ works around a feature of fold that simplifies (int)(p1 - p2) to
+ ((int)p1 - (int)p2) under the theory that the narrower operation
+ is cheaper. */
+
+ while (CONVERT_EXPR_P (op0)
+ || TREE_CODE (op0) == NON_LVALUE_EXPR)
+ {
+ tree inner = TREE_OPERAND (op0, 0);
+ if (inner == error_mark_node
+ || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+ || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
+ > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+ break;
+ op0 = inner;
+ }
+
+ while (CONVERT_EXPR_P (op1)
+ || TREE_CODE (op1) == NON_LVALUE_EXPR)
+ {
+ tree inner = TREE_OPERAND (op1, 0);
+ if (inner == error_mark_node
+ || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+ || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
+ > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+ break;
+ op1 = inner;
+ }
+
+ op0 = initializer_constant_valid_p (op0, endtype);
+ op1 = initializer_constant_valid_p (op1, endtype);
+
+ /* Both initializers must be known. */
+ if (op0 && op1)
+ {
+ if (op0 == op1
+ && (op0 == null_pointer_node
+ || TREE_CODE (value) == MINUS_EXPR))
+ return null_pointer_node;
+
+ /* Support differences between labels. */
+ if (TREE_CODE (op0) == LABEL_DECL
+ && TREE_CODE (op1) == LABEL_DECL)
+ return null_pointer_node;
+
+ if (TREE_CODE (op0) == STRING_CST
+ && TREE_CODE (op1) == STRING_CST
+ && operand_equal_p (op0, op1, 1))
+ return null_pointer_node;
+ }
+
+ return NULL_TREE;
+}
+
/* Return nonzero if VALUE is a valid constant-valued expression
for use in initializing a static variable; one that can be an
element of a "constant" initializer.
tree
initializer_constant_valid_p (tree value, tree endtype)
{
+ tree ret;
+
switch (TREE_CODE (value))
{
case CONSTRUCTOR:
case ADDR_EXPR:
case FDESC_EXPR:
- value = staticp (TREE_OPERAND (value, 0));
- if (value)
- {
- /* "&(*a).f" is like unto pointer arithmetic. If "a" turns out to
- be a constant, this is old-skool offsetof-like nonsense. */
- if (TREE_CODE (value) == INDIRECT_REF
- && TREE_CONSTANT (TREE_OPERAND (value, 0)))
- 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))
- return NULL_TREE;
- /* "&{...}" requires a temporary to hold the constructed
- object. */
- if (TREE_CODE (value) == CONSTRUCTOR)
- return NULL_TREE;
- }
- return value;
+ {
+ tree op0 = staticp (TREE_OPERAND (value, 0));
+ if (op0)
+ {
+ /* "&(*a).f" is like unto pointer arithmetic. If "a" turns out
+ to be a constant, this is old-skool offsetof-like nonsense. */
+ if (TREE_CODE (op0) == INDIRECT_REF
+ && TREE_CONSTANT (TREE_OPERAND (op0, 0)))
+ return null_pointer_node;
+ /* Taking the address of a nested function involves a trampoline,
+ unless we don't need or want one. */
+ if (TREE_CODE (op0) == FUNCTION_DECL
+ && decl_function_context (op0)
+ && !DECL_NO_STATIC_CHAIN (op0)
+ && !TREE_NO_TRAMPOLINE (value))
+ return NULL_TREE;
+ /* "&{...}" requires a temporary to hold the constructed
+ object. */
+ if (TREE_CODE (op0) == CONSTRUCTOR)
+ return NULL_TREE;
+ }
+ return op0;
+ }
- case VIEW_CONVERT_EXPR:
case NON_LVALUE_EXPR:
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
- CASE_CONVERT:
+ case VIEW_CONVERT_EXPR:
{
- tree src;
- tree src_type;
- tree dest_type;
+ tree src = TREE_OPERAND (value, 0);
+ tree src_type = TREE_TYPE (src);
+ tree dest_type = TREE_TYPE (value);
+
+ /* Allow view-conversions from aggregate to non-aggregate type only
+ if the bit pattern is fully preserved afterwards; otherwise, the
+ RTL expander won't be able to apply a subsequent transformation
+ to the underlying constructor. */
+ if (AGGREGATE_TYPE_P (src_type) && !AGGREGATE_TYPE_P (dest_type))
+ {
+ if (TYPE_MODE (endtype) == TYPE_MODE (dest_type))
+ return initializer_constant_valid_p (src, endtype);
+ else
+ return NULL_TREE;
+ }
- src = TREE_OPERAND (value, 0);
- src_type = TREE_TYPE (src);
- dest_type = TREE_TYPE (value);
+ /* Allow all other kinds of view-conversion. */
+ return initializer_constant_valid_p (src, endtype);
+ }
+
+ CASE_CONVERT:
+ {
+ tree src = TREE_OPERAND (value, 0);
+ tree src_type = TREE_TYPE (src);
+ tree dest_type = TREE_TYPE (value);
/* Allow conversions between pointer types, floating-point
types, and offset types. */
if (valid1 == null_pointer_node)
return valid0;
}
+
+ /* Support narrowing pointer differences. */
+ ret = narrowing_initializer_constant_valid_p (value, endtype);
+ if (ret != NULL_TREE)
+ return ret;
+
break;
case MINUS_EXPR:
}
/* Support narrowing differences. */
- if (INTEGRAL_TYPE_P (endtype))
- {
- tree op0, op1;
-
- op0 = TREE_OPERAND (value, 0);
- op1 = TREE_OPERAND (value, 1);
-
- /* Like STRIP_NOPS except allow the operand mode to widen.
- This works around a feature of fold that simplifies
- (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
- that the narrower operation is cheaper. */
-
- while (CONVERT_EXPR_P (op0)
- || TREE_CODE (op0) == NON_LVALUE_EXPR)
- {
- tree inner = TREE_OPERAND (op0, 0);
- if (inner == error_mark_node
- || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
- || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
- > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
- break;
- op0 = inner;
- }
-
- while (CONVERT_EXPR_P (op1)
- || TREE_CODE (op1) == NON_LVALUE_EXPR)
- {
- tree inner = TREE_OPERAND (op1, 0);
- if (inner == error_mark_node
- || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
- || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
- > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
- break;
- op1 = inner;
- }
-
- op0 = initializer_constant_valid_p (op0, endtype);
- op1 = initializer_constant_valid_p (op1, endtype);
+ ret = narrowing_initializer_constant_valid_p (value, endtype);
+ if (ret != NULL_TREE)
+ return ret;
- /* Both initializers must be known. */
- if (op0 && op1)
- {
- if (op0 == op1)
- return null_pointer_node;
-
- /* Support differences between labels. */
- if (TREE_CODE (op0) == LABEL_DECL
- && TREE_CODE (op1) == LABEL_DECL)
- return null_pointer_node;
-
- if (TREE_CODE (op0) == STRING_CST
- && TREE_CODE (op1) == STRING_CST
- && operand_equal_p (op0, op1, 1))
- return null_pointer_node;
- }
- }
break;
default:
assemble_zeros (size - total_bytes);
}
-/* This TREE_LIST contains any weak symbol declarations waiting
- to be emitted. */
-static GTY(()) tree weak_decls;
-
/* Mark DECL as weak. */
static void
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)
- {
- if (! DECL_WEAK (decl))
- weak_decls = tree_cons (NULL, decl, weak_decls);
- }
- else
+ else if (!SUPPORTS_WEAK)
warning (0, "weak declaration of %q+D not supported", decl);
mark_weak (decl);
of an alias. This requires that the decl have been defined. Aliases
that precede their definition have to be queued for later processing. */
-typedef struct alias_pair GTY(())
-{
+typedef struct GTY(()) alias_pair {
tree decl;
tree target;
} alias_pair;
/* If the target has already been emitted, we don't have to queue the
alias. This saves a tad of memory. */
- target_decl = find_decl_and_mark_needed (decl, target);
+ if (cgraph_global_info_ready)
+ target_decl = find_decl_and_mark_needed (decl, target);
+ else
+ target_decl= NULL;
if (target_decl && TREE_ASM_WRITTEN (target_decl))
do_assemble_alias (decl, target);
else
static int
compute_reloc_for_rtx_1 (rtx *xp, void *data)
{
- int *preloc = data;
+ int *preloc = (int *) data;
rtx x = *xp;
switch (GET_CODE (x))
default_internal_label (FILE *stream, const char *prefix,
unsigned long labelno)
{
- char *const buf = alloca (40 + strlen (prefix));
+ char *const buf = (char *) alloca (40 + strlen (prefix));
ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
ASM_OUTPUT_INTERNAL_LABEL (stream, buf);
}
void
default_file_start (void)
{
- if (targetm.file_start_app_off && !flag_verbose_asm)
+ if (targetm.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)