/* 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, 2008, 2009,
- 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+ Copyright (C) 1987-2014 Free Software Foundation, Inc.
This file is part of GCC.
#include "tm.h"
#include "rtl.h"
#include "tree.h"
+#include "stor-layout.h"
+#include "stringpool.h"
+#include "varasm.h"
#include "flags.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "vec.h"
+#include "machmode.h"
+#include "hard-reg-set.h"
+#include "input.h"
#include "function.h"
#include "expr.h"
-#include "hard-reg-set.h"
#include "regs.h"
#include "output.h"
#include "diagnostic-core.h"
-#include "hashtab.h"
#include "ggc.h"
#include "langhooks.h"
#include "tm_p.h"
#include "target.h"
#include "common/common-target.h"
#include "targhooks.h"
-#include "tree-mudflap.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "hash-map.h"
+#include "is-a.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
#include "cgraph.h"
-#include "pointer-set.h"
#include "asan.h"
+#include "rtl-iter.h"
+#include "tree-chkp.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data
bool first_function_block_is_cold;
-/* We give all constants their own alias set. Perhaps redundant with
- MEM_READONLY_P, but pre-dates it. */
-
-static alias_set_type const_alias_set;
-
/* Whether we saw any functions with no_split_stack. */
static bool saw_no_split_stack;
static bool incorporeal_function_p (tree);
#endif
static void decode_addr_const (tree, struct addr_const *);
-static hashval_t const_desc_hash (const void *);
-static int const_desc_eq (const void *, const void *);
static hashval_t const_hash_1 (const tree);
static int compare_constant (const tree, const tree);
-static tree copy_constant (tree);
static void output_constant_def_contents (rtx);
static void output_addressed_constants (tree);
-static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
-static unsigned min_align (unsigned, unsigned);
+static unsigned HOST_WIDE_INT output_constant (tree, unsigned HOST_WIDE_INT,
+ unsigned int);
static void globalize_decl (tree);
static bool decl_readonly_section_1 (enum section_category);
#ifdef BSS_SECTION_ASM_OP
/* Return a nonzero value if DECL has a section attribute. */
#define IN_NAMED_SECTION(DECL) \
((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
- && DECL_SECTION_NAME (DECL) != NULL_TREE)
+ && DECL_SECTION_NAME (DECL) != NULL)
+
+struct section_hasher : ggc_hasher<section *>
+{
+ typedef const char *compare_type;
+
+ static hashval_t hash (section *);
+ static bool equal (section *, const char *);
+};
/* Hash table of named sections. */
-static GTY((param_is (section))) htab_t section_htab;
+static GTY(()) hash_table<section_hasher> *section_htab;
+
+struct object_block_hasher : ggc_hasher<object_block *>
+{
+ typedef const section *compare_type;
+
+ static hashval_t hash (object_block *);
+ static bool equal (object_block *, const section *);
+};
/* A table of object_blocks, indexed by section. */
-static GTY((param_is (struct object_block))) htab_t object_block_htab;
+static GTY(()) hash_table<object_block_hasher> *object_block_htab;
/* The next number to use for internal anchor labels. */
static GTY(()) int anchor_labelno;
/* Helper routines for maintaining section_htab. */
-static int
-section_entry_eq (const void *p1, const void *p2)
+bool
+section_hasher::equal (section *old, const char *new_name)
{
- const section *old = (const section *) p1;
- const char *new_name = (const char *) p2;
-
return strcmp (old->named.name, new_name) == 0;
}
-static hashval_t
-section_entry_hash (const void *p)
+hashval_t
+section_hasher::hash (section *old)
{
- const section *old = (const section *) p;
return htab_hash_string (old->named.name);
}
/* Helper routines for maintaining object_block_htab. */
-static int
-object_block_entry_eq (const void *p1, const void *p2)
+inline bool
+object_block_hasher::equal (object_block *old, const section *new_section)
{
- const struct object_block *old = (const struct object_block *) p1;
- const section *new_section = (const section *) p2;
-
return old->sect == new_section;
}
-static hashval_t
-object_block_entry_hash (const void *p)
+hashval_t
+object_block_hasher::hash (object_block *old)
{
- const struct object_block *old = (const struct object_block *) p;
return hash_section (old->sect);
}
{
section *sect;
- sect = ggc_alloc_section ();
+ sect = ggc_alloc<section> ();
sect->unnamed.common.flags = flags | SECTION_UNNAMED;
sect->unnamed.callback = callback;
sect->unnamed.data = data;
{
section *sect;
- sect = ggc_alloc_section ();
+ sect = ggc_alloc<section> ();
sect->noswitch.common.flags = flags | SECTION_NOSWITCH;
sect->noswitch.callback = callback;
{
section *sect, **slot;
- slot = (section **)
- htab_find_slot_with_hash (section_htab, name,
- htab_hash_string (name), INSERT);
+ slot = section_htab->find_slot_with_hash (name, htab_hash_string (name),
+ INSERT);
flags |= SECTION_NAMED;
if (*slot == NULL)
{
- sect = ggc_alloc_section ();
+ sect = ggc_alloc<section> ();
sect->named.common.flags = flags;
sect->named.name = ggc_strdup (name);
sect->named.decl = decl;
return sect;
}
/* Sanity check user variables for flag changes. */
- if (decl == 0)
- decl = sect->named.decl;
- gcc_assert (decl);
- if (sect->named.decl == NULL)
- error ("%+D causes a section type conflict", decl);
- else
+ if (sect->named.decl != NULL
+ && DECL_P (sect->named.decl)
+ && decl != sect->named.decl)
{
- error ("%+D causes a section type conflict with %D",
- decl, sect->named.decl);
- if (decl != sect->named.decl)
- inform (DECL_SOURCE_LOCATION (sect->named.decl),
- "%qD was declared here", sect->named.decl);
+ if (decl != NULL && DECL_P (decl))
+ error ("%+D causes a section type conflict with %D",
+ decl, sect->named.decl);
+ else
+ error ("section type conflict with %D", sect->named.decl);
+ inform (DECL_SOURCE_LOCATION (sect->named.decl),
+ "%qD was declared here", sect->named.decl);
}
+ else if (decl != NULL && DECL_P (decl))
+ error ("%+D causes a section type conflict", decl);
+ else
+ error ("section type conflict");
/* Make sure we don't error about one section multiple times. */
sect->common.flags |= SECTION_OVERRIDE;
}
get_block_for_section (section *sect)
{
struct object_block *block;
- void **slot;
if (sect == NULL)
return NULL;
- slot = htab_find_slot_with_hash (object_block_htab, sect,
- hash_section (sect), INSERT);
- block = (struct object_block *) *slot;
+ object_block **slot
+ = object_block_htab->find_slot_with_hash (sect, hash_section (sect),
+ INSERT);
+ block = *slot;
if (block == NULL)
{
- block = ggc_alloc_cleared_object_block ();
+ block = ggc_cleared_alloc<object_block> ();
block->sect = sect;
*slot = block;
}
/* Create the extended SYMBOL_REF. */
size = RTX_HDR_SIZE + sizeof (struct block_symbol);
- symbol = ggc_alloc_zone_rtx_def (size, &rtl_zone);
+ symbol = (rtx) ggc_internal_alloc (size);
/* Initialize the normal SYMBOL_REF fields. */
memset (symbol, 0, size);
{
unsigned int flags;
- gcc_assert (!decl || DECL_P (decl));
if (name == NULL)
- name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ {
+ gcc_assert (decl && DECL_P (decl) && DECL_SECTION_NAME (decl));
+ name = DECL_SECTION_NAME (decl);
+ }
flags = targetm.section_type_flags (decl, name, reloc);
-
return get_section (name, flags, decl);
}
+/* Worker for resolve_unique_section. */
+
+static bool
+set_implicit_section (struct symtab_node *n, void *data ATTRIBUTE_UNUSED)
+{
+ n->implicit_section = true;
+ return false;
+}
+
/* If required, set DECL_SECTION_NAME to a unique name. */
void
resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED,
int flag_function_or_data_sections)
{
- if (DECL_SECTION_NAME (decl) == NULL_TREE
+ if (DECL_SECTION_NAME (decl) == NULL
&& targetm_common.have_named_sections
&& (flag_function_or_data_sections
- || DECL_ONE_ONLY (decl)))
+ || DECL_COMDAT_GROUP (decl)))
{
targetm.asm_out.unique_section (decl, reloc);
- DECL_HAS_IMPLICIT_SECTION_NAME_P (decl) = true;
+ if (DECL_SECTION_NAME (decl))
+ symtab_node::get (decl)->call_for_symbol_and_aliases
+ (set_implicit_section, NULL, true);
}
}
hot_function_section (tree decl)
{
if (decl != NULL_TREE
- && DECL_SECTION_NAME (decl) != NULL_TREE
+ && DECL_SECTION_NAME (decl) != NULL
&& targetm_common.have_named_sections)
return get_named_section (decl, NULL, 0);
else
{
if (named_section_suffix)
{
- tree dsn = DECL_SECTION_NAME (decl);
+ const char *dsn = DECL_SECTION_NAME (decl);
const char *stripped_name;
char *name, *buffer;
- name = (char *) alloca (TREE_STRING_LENGTH (dsn) + 1);
- memcpy (name, TREE_STRING_POINTER (dsn),
- TREE_STRING_LENGTH (dsn) + 1);
+ name = (char *) alloca (strlen (dsn) + 1);
+ memcpy (name, dsn,
+ strlen (dsn) + 1);
stripped_name = targetm.strip_name_encoding (name);
buffer = ACONCAT ((stripped_name, named_section_suffix, NULL));
return get_named_section (decl, buffer, 0);
}
- else if (DECL_HAS_IMPLICIT_SECTION_NAME_P (decl))
+ else if (symtab_node::get (decl)->implicit_section)
{
const char *name;
/* Do not try to split gnu_linkonce functions. This gets somewhat
slipperly. */
- if (DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP)
+ if (DECL_COMDAT_GROUP (decl) && !HAVE_COMDAT_GROUP)
return NULL;
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
name = targetm.strip_name_encoding (name);
/* Old GNU linkers have buggy --gc-section support, which sometimes
results in .gcc_except_table* sections being garbage collected. */
if (decl
- && DECL_SECTION_NAME (decl)
- && DECL_HAS_IMPLICIT_SECTION_NAME_P (decl))
+ && symtab_node::get (decl)->implicit_section)
return NULL;
#endif
unlikely executed (this happens especially with function splitting
where we can split away unnecessary parts of static constructors. */
if (startup && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED)
- return get_named_text_section (decl, ".text.startup", NULL);
+ {
+ /* If we do have a profile or(and) LTO phase is executed, we do not need
+ these ELF section. */
+ if (!in_lto_p || !flag_profile_values)
+ return get_named_text_section (decl, ".text.startup", NULL);
+ else
+ return NULL;
+ }
/* Similarly for exit. */
if (exit && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED)
case NODE_FREQUENCY_UNLIKELY_EXECUTED:
return get_named_text_section (decl, ".text.unlikely", NULL);
case NODE_FREQUENCY_HOT:
- return get_named_text_section (decl, ".text.hot", NULL);
+ /* If we do have a profile or(and) LTO phase is executed, we do not need
+ these ELF section. */
+ if (!in_lto_p || !flag_profile_values)
+ return get_named_text_section (decl, ".text.hot", NULL);
default:
return NULL;
}
if (decl)
{
- struct cgraph_node *node = cgraph_get_node (decl);
+ struct cgraph_node *node = cgraph_node::get (decl);
if (node)
{
#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
if (decl != NULL_TREE
- && DECL_SECTION_NAME (decl) != NULL_TREE)
+ && DECL_SECTION_NAME (decl) != NULL)
{
if (targetm.asm_out.function_section)
section = targetm.asm_out.function_section (decl, freq,
{
if (decl != NULL_TREE && DECL_SECTION_NAME (decl))
{
- const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ const char *name = DECL_SECTION_NAME (decl);
- if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP)
+ if (DECL_COMDAT_GROUP (decl) && HAVE_COMDAT_GROUP)
{
const char *dot;
size_t len;
return get_section (rname, SECTION_LINKONCE, decl);
}
/* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo. */
- else if (DECL_ONE_ONLY (decl)
+ else if (DECL_COMDAT_GROUP (decl)
&& strncmp (name, ".gnu.linkonce.t.", 16) == 0)
{
size_t len = strlen (name) + 1;
&& (len = int_size_in_bytes (TREE_TYPE (decl))) > 0
&& TREE_STRING_LENGTH (decl) >= len)
{
- enum machine_mode mode;
+ machine_mode mode;
unsigned int modesize;
const char *str;
HOST_WIDE_INT i;
/* Return the section to use for constant merging. */
section *
-mergeable_constant_section (enum machine_mode mode ATTRIBUTE_UNUSED,
+mergeable_constant_section (machine_mode mode ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED,
unsigned int flags ATTRIBUTE_UNUSED)
{
char *starred = (char *) alloca (strlen (name) + 2);
starred[0] = '*';
strcpy (starred + 1, name);
- change_decl_assembler_name (decl, get_identifier (starred));
+ symtab->change_decl_assembler_name (decl, get_identifier (starred));
SET_DECL_RTL (decl, NULL_RTX);
}
\f
if (asmspec[0] != 0 && i < 0)
{
i = atoi (asmspec);
- if (i < FIRST_PSEUDO_REGISTER && i >= 0)
+ if (i < FIRST_PSEUDO_REGISTER && i >= 0 && reg_names[i][0])
return i;
else
return -2;
for (i = 0; i < (int) ARRAY_SIZE (table); i++)
if (table[i].name[0]
- && ! strcmp (asmspec, table[i].name))
+ && ! strcmp (asmspec, table[i].name)
+ && reg_names[table[i].number][0])
return table[i].number;
}
#endif /* ADDITIONAL_REGISTER_NAMES */
bss_initializer_p (const_tree decl)
{
return (DECL_INITIAL (decl) == NULL
- || DECL_INITIAL (decl) == error_mark_node
+ /* In LTO we have no errors in program; error_mark_node is used
+ to mark offlined constructors. */
+ || (DECL_INITIAL (decl) == error_mark_node
+ && !in_lto_p)
|| (flag_zero_initialized_in_bss
/* Leave constant zeroes in .rodata so they
can be shared. */
In particular, a.out format supports a maximum alignment of 4. */
if (align > MAX_OFILE_ALIGNMENT)
{
- warning (0, "alignment of %q+D is greater than maximum object "
- "file alignment. Using %d", decl,
- MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
+ error ("alignment of %q+D is greater than maximum object "
+ "file alignment %d", decl,
+ MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
align = MAX_OFILE_ALIGNMENT;
}
- /* On some machines, it is good to increase alignment sometimes. */
if (! DECL_USER_ALIGN (decl))
{
+#ifdef DATA_ABI_ALIGNMENT
+ unsigned int data_abi_align
+ = DATA_ABI_ALIGNMENT (TREE_TYPE (decl), align);
+ /* For backwards compatibility, don't assume the ABI alignment for
+ TLS variables. */
+ if (! DECL_THREAD_LOCAL_P (decl) || data_abi_align <= BITS_PER_WORD)
+ align = data_abi_align;
+#endif
+
+ /* On some machines, it is good to increase alignment sometimes.
+ But as DECL_ALIGN is used both for actually emitting the variable
+ and for code accessing the variable as guaranteed alignment, we
+ can only increase the alignment if it is a performance optimization
+ if the references to it must bind to the current definition. */
+ if (decl_binds_to_current_def_p (decl)
+ && !DECL_VIRTUAL_P (decl))
+ {
+#ifdef DATA_ALIGNMENT
+ 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
+ /* In LTO we have no errors in program; error_mark_node is used
+ to mark offlined constructors. */
+ && (in_lto_p || DECL_INITIAL (decl) != error_mark_node))
+ {
+ 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
+ }
+ }
+
+ /* Reset the alignment in case we have made it tighter, so we can benefit
+ from it in get_pointer_alignment. */
+ DECL_ALIGN (decl) = align;
+}
+
+/* Return DECL_ALIGN (decl), possibly increased for optimization purposes
+ beyond what align_variable returned. */
+
+static unsigned int
+get_variable_align (tree decl)
+{
+ unsigned int align = DECL_ALIGN (decl);
+
+ /* For user aligned vars or static vars align_variable already did
+ everything. */
+ if (DECL_USER_ALIGN (decl) || !TREE_PUBLIC (decl))
+ return align;
+
+#ifdef DATA_ABI_ALIGNMENT
+ if (DECL_THREAD_LOCAL_P (decl))
+ align = DATA_ABI_ALIGNMENT (TREE_TYPE (decl), align);
+#endif
+
+ /* For decls that bind to the current definition, align_variable
+ did also everything, except for not assuming ABI required alignment
+ of TLS variables. For other vars, increase the alignment here
+ as an optimization. */
+ if (!decl_binds_to_current_def_p (decl))
+ {
+ /* On some machines, it is good to increase alignment sometimes. */
#ifdef DATA_ALIGNMENT
unsigned int data_align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
/* Don't increase alignment too much for TLS variables - TLS space
- is too precious. */
+ 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)
+ if (DECL_INITIAL (decl) != 0
+ /* In LTO we have no errors in program; error_mark_node is used
+ to mark offlined constructors. */
+ && (in_lto_p || DECL_INITIAL (decl) != error_mark_node))
{
unsigned int const_align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl),
align);
#endif
}
- /* Reset the alignment in case we have made it tighter, so we can benefit
- from it in get_pointer_alignment. */
- DECL_ALIGN (decl) = align;
+ return align;
}
/* Return the section into which the given VAR_DECL or CONST_DECL
{
addr_space_t as = ADDR_SPACE_GENERIC;
int reloc;
+ varpool_node *vnode = varpool_node::get (decl);
+ if (vnode)
+ {
+ vnode = vnode->ultimate_alias_target ();
+ decl = vnode->decl;
+ }
if (TREE_TYPE (decl) != error_mark_node)
as = TYPE_ADDR_SPACE (TREE_TYPE (decl));
+ /* We need the constructor to figure out reloc flag. */
+ if (vnode)
+ vnode->get_constructor ();
+
if (DECL_COMMON (decl))
{
/* If the decl has been given an explicit section name, or it resides
&& bss_initializer_p (decl))
{
if (!TREE_PUBLIC (decl)
- && !(flag_asan && asan_protect_global (decl)))
+ && !((flag_sanitize & SANITIZE_ADDRESS)
+ && asan_protect_global (decl)))
return lcomm_section;
if (bss_noswitch_section)
return bss_noswitch_section;
}
- return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
+ return targetm.asm_out.select_section (decl, reloc,
+ get_variable_align (decl));
}
/* Return the block into which object_block DECL should be placed. */
/* There's no point using object blocks for something that is
isolated by definition. */
- if (DECL_ONE_ONLY (decl))
+ if (DECL_COMDAT_GROUP (decl))
return NULL;
}
constant size. */
if (DECL_SIZE_UNIT (decl) == NULL)
return NULL;
- if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
+ if (!tree_fits_uhwi_p (DECL_SIZE_UNIT (decl)))
return NULL;
/* Find out which section should contain DECL. We cannot put it into
static bool
use_blocks_for_decl_p (tree decl)
{
+ struct symtab_node *snode;
+
/* Only data DECLs can be placed into object blocks. */
if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_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)))
+ if (TREE_CODE (decl) == VAR_DECL
+ && (snode = symtab_node::get (decl)) != NULL
+ && snode->alias)
return false;
return targetm.use_blocks_for_decl_p (decl);
}
+/* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at *ALIAS
+ until we find an identifier that is not itself a transparent alias.
+ Modify the alias passed to it by reference (and all aliases on the
+ way to the ultimate target), such that they do not have to be
+ followed again, and return the ultimate target of the alias
+ chain. */
+
+static inline tree
+ultimate_transparent_alias_target (tree *alias)
+{
+ tree target = *alias;
+
+ if (IDENTIFIER_TRANSPARENT_ALIAS (target))
+ {
+ gcc_assert (TREE_CHAIN (target));
+ target = ultimate_transparent_alias_target (&TREE_CHAIN (target));
+ gcc_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target)
+ && ! TREE_CHAIN (target));
+ *alias = target;
+ }
+
+ return target;
+}
+
/* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL. DECL should
have static storage duration. In other words, it should not be an
automatic variable, including PARM_DECLs.
{
const char *name = 0;
int reg_number;
+ tree id;
rtx x;
/* Check that we are not being given an automatic variable. */
&& SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (x, 0)))
change_symbol_block (XEXP (x, 0), get_block_for_decl (decl));
- /* Make this function static known to the mudflap runtime. */
- if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
- mudflap_enqueue_decl (decl);
-
return;
}
return;
}
- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ id = DECL_ASSEMBLER_NAME (decl);
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && cgraph_node::get (decl)
+ && cgraph_node::get (decl)->instrumentation_clone)
+ ultimate_transparent_alias_target (&id);
+ name = IDENTIFIER_POINTER (id);
if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL
&& DECL_REGISTER (decl))
else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
{
const char *asmspec = name+1;
- enum machine_mode mode = DECL_MODE (decl);
+ machine_mode mode = DECL_MODE (decl);
reg_number = decode_reg_name (asmspec);
/* First detect errors in declaring global registers. */
if (reg_number == -1)
/* As a register variable, it has no section. */
return;
}
+ /* Avoid internal errors from invalid register
+ specifications. */
+ SET_DECL_ASSEMBLER_NAME (decl, NULL_TREE);
+ DECL_HARD_REGISTER (decl) = 0;
+ return;
}
/* Now handle ordinary static variables and functions (in memory).
Also handle vars declared register invalidly. */
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
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+ && DECL_SECTION_NAME (decl) != NULL
&& DECL_INITIAL (decl) == NULL_TREE
&& DECL_COMMON (decl))
DECL_COMMON (decl) = 0;
x = create_block_symbol (name, get_block_for_decl (decl), -1);
else
{
- enum machine_mode address_mode = Pmode;
+ machine_mode address_mode = Pmode;
if (TREE_TYPE (decl) != error_mark_node)
{
addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl));
If the name is changed, the macro ASM_OUTPUT_LABELREF
will have to know how to strip this information. */
targetm.encode_section_info (decl, DECL_RTL (decl), true);
-
- /* Make this function static known to the mudflap runtime. */
- if (flag_mudflap && TREE_CODE (decl) == VAR_DECL)
- mudflap_enqueue_decl (decl);
}
/* Like make_decl_rtl, but inhibit creation of new alias sets when
rtx
make_decl_rtl_for_debug (tree decl)
{
- unsigned int save_aliasing_flag, save_mudflap_flag;
+ unsigned int save_aliasing_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. It is undesirable to register decl with mudflap
- in this case as well. */
+ new set. */
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;
}
\f
{
switch_to_section (sec);
assemble_align (POINTER_SIZE);
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ assemble_integer (symbol, POINTER_SIZE_UNITS, POINTER_SIZE, 1);
}
/* Return the numbered .ctors.N (if CONSTRUCTOR_P) or .dtors.N (if
if (DECL_SECTION_NAME (decl))
{
- struct cgraph_node *node = cgraph_get_node (current_function_decl);
+ struct cgraph_node *node = cgraph_node::get (current_function_decl);
/* Calls to function_section rely on first_function_block_is_cold
being accurate. */
first_function_block_is_cold = (node
in_cold_section_p = first_function_block_is_cold;
}
+/* Get the function's name, as described by its RTL. This may be
+ different from the DECL_NAME name used in the source file. */
+const char *
+get_fnname_from_decl (tree decl)
+{
+ rtx x = DECL_RTL (decl);
+ gcc_assert (MEM_P (x));
+ x = XEXP (x, 0);
+ gcc_assert (GET_CODE (x) == SYMBOL_REF);
+ return XSTR (x, 0);
+}
+
/* Output assembler code for the constant pool of a function and associated
with defining the name of the function. DECL describes the function.
NAME is the function's name. For the constant pool, we use the current
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 (!cfun->is_thunk
- && BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
+ && BB_PARTITION (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb) == BB_COLD_PARTITION)
{
switch_to_section (text_section);
assemble_align (DECL_ALIGN (decl));
/* Make function name accessible from other files, if appropriate. */
- if (TREE_PUBLIC (decl))
+ if (TREE_PUBLIC (decl)
+ || (cgraph_node::get (decl)->instrumentation_clone
+ && cgraph_node::get (decl)->instrumented_version
+ && TREE_PUBLIC (cgraph_node::get (decl)->instrumented_version->decl)))
{
notice_global_symbol (decl);
unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
{
#if defined ASM_OUTPUT_ALIGNED_BSS
- ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl));
+ ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size,
+ get_variable_align (decl));
return true;
#endif
}
{
#if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name,
- size, DECL_ALIGN (decl));
+ size, get_variable_align (decl));
return true;
#elif defined ASM_OUTPUT_ALIGNED_COMMON
- ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl));
+ ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
+ get_variable_align (decl));
return true;
#else
ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
NAME is the name of DECL's SYMBOL_REF. */
static void
-assemble_noswitch_variable (tree decl, const char *name, section *sect)
+assemble_noswitch_variable (tree decl, const char *name, section *sect,
+ unsigned int align)
{
unsigned HOST_WIDE_INT size, rounded;
- size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
rounded = size;
- if (flag_asan && asan_protect_global (decl))
+ if ((flag_sanitize & SANITIZE_ADDRESS) && asan_protect_global (decl))
size += asan_red_zone_size (size);
/* Don't allocate zero bytes of common,
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
if (!sect->noswitch.callback (decl, name, size, rounded)
- && (unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
- warning (0, "requested alignment for %q+D is greater than "
- "implemented alignment of %wu", decl, rounded);
+ && (unsigned HOST_WIDE_INT) (align / BITS_PER_UNIT) > rounded)
+ error ("requested alignment for %q+D is greater than "
+ "implemented alignment of %wu", decl, rounded);
}
/* A subroutine of assemble_variable. Output the label and contents of
if (!dont_output_data)
{
+ /* Caller is supposed to use varpool_get_constructor when it wants
+ to output the body. */
+ gcc_assert (!in_lto_p || DECL_INITIAL (decl) != error_mark_node);
if (DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node
&& !initializer_zerop (DECL_INITIAL (decl)))
/* Output the actual data. */
output_constant (DECL_INITIAL (decl),
- tree_low_cst (DECL_SIZE_UNIT (decl), 1),
- DECL_ALIGN (decl));
+ tree_to_uhwi (DECL_SIZE_UNIT (decl)),
+ get_variable_align (decl));
else
/* Leave space for it. */
- assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
+ assemble_zeros (tree_to_uhwi (DECL_SIZE_UNIT (decl)));
+ targetm.asm_out.decl_end ();
}
}
+/* Write out assembly for the variable DECL, which is not defined in
+ the current translation unit. */
+void
+assemble_undefined_decl (tree decl)
+{
+ const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+ targetm.asm_out.assemble_undefined_decl (asm_out_file, name, decl);
+}
+
/* 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.
const char *name;
rtx decl_rtl, symbol;
section *sect;
+ unsigned int align;
bool asan_protected = false;
/* This function is supposed to handle VARIABLES. Ensure we have one. */
align_variable (decl, dont_output_data);
- if (flag_asan
+ if ((flag_sanitize & SANITIZE_ADDRESS)
&& asan_protect_global (decl))
{
asan_protected = true;
set_mem_align (decl_rtl, DECL_ALIGN (decl));
+ align = get_variable_align (decl);
+
if (TREE_PUBLIC (decl))
maybe_assemble_visibility (decl);
place_block_symbol (symbol);
}
else if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
- assemble_noswitch_variable (decl, name, sect);
+ assemble_noswitch_variable (decl, name, sect, align);
else
{
- switch_to_section (sect);
- if (DECL_ALIGN (decl) > BITS_PER_UNIT)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
+ /* The following bit of code ensures that vtable_map
+ variables are not only in the comdat section, but that
+ each variable has its own unique comdat name. If this
+ code is removed, the variables end up in the same section
+ with a single comdat name.
+
+ FIXME: resolve_unique_section needs to deal better with
+ decls with both DECL_SECTION_NAME and DECL_ONE_ONLY. Once
+ that is fixed, this if-else statement can be replaced with
+ a single call to "switch_to_section (sect)". */
+ if (sect->named.name
+ && (strcmp (sect->named.name, ".vtable_map_vars") == 0))
+ {
+#if defined (OBJECT_FORMAT_ELF)
+ targetm.asm_out.named_section (sect->named.name,
+ sect->named.common.flags
+ | SECTION_LINKONCE,
+ DECL_NAME (decl));
+ in_section = sect;
+#else
+ switch_to_section (sect);
+#endif
+ }
+ else
+ switch_to_section (sect);
+ if (align > BITS_PER_UNIT)
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
assemble_variable_contents (decl, name, dont_output_data);
if (asan_protected)
{
unsigned HOST_WIDE_INT int size
- = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ = tree_to_uhwi (DECL_SIZE_UNIT (decl));
assemble_zeros (asan_red_zone_size (size));
}
}
}
+
+/* Given a function declaration (FN_DECL), this function assembles the
+ function into the .preinit_array section. */
+
+void
+assemble_vtv_preinit_initializer (tree fn_decl)
+{
+ section *sect;
+ unsigned flags = SECTION_WRITE;
+ rtx symbol = XEXP (DECL_RTL (fn_decl), 0);
+
+ flags |= SECTION_NOTYPE;
+ sect = get_section (".preinit_array", flags, fn_decl);
+ switch_to_section (sect);
+ assemble_addr_to_section (symbol, sect);
+}
+
/* Return 1 if type TYPE contains any pointers. */
static int
/* Avoid O(external_decls**2) lookups in the pending_assemble_externals
TREE_LIST in assemble_external. */
-static struct pointer_set_t *pending_assemble_externals_set;
+static hash_set<tree> *pending_assemble_externals_set;
/* True if DECL is a function decl for which no out-of-line copy exists.
It is assumed that DECL's assembler name has been set. */
pending_assemble_externals = 0;
pending_assemble_externals_processed = true;
- pointer_set_destroy (pending_assemble_externals_set);
+ delete pending_assemble_externals_set;
#endif
}
Ideally, only final.c would be calling this function, but it is
not clear whether that would break things somehow. See PR 17982
for further discussion. */
- gcc_assert (cgraph_state == CGRAPH_STATE_EXPANSION
- || cgraph_state == CGRAPH_STATE_FINISHED);
+ gcc_assert (state == EXPANSION
+ || state == FINISHED);
#endif
if (!DECL_P (decl) || !DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
return;
}
- if (! pointer_set_insert (pending_assemble_externals_set, decl))
+ if (! pending_assemble_externals_set->add (decl))
pending_assemble_externals = tree_cons (NULL, decl,
pending_assemble_externals);
#endif
If we know a method will be emitted in other TU and no new
functions can be marked reachable, just use the external
definition. */
- struct cgraph_node *node = cgraph_get_create_node (decl);
+ struct cgraph_node *node = cgraph_node::get_create (decl);
if (!DECL_EXTERNAL (decl)
- && !node->local.finalized)
- cgraph_mark_force_output_node (node);
+ && !node->definition)
+ node->mark_force_output ();
}
else if (TREE_CODE (decl) == VAR_DECL)
{
- struct varpool_node *node = varpool_node_for_decl (decl);
+ varpool_node *node = varpool_node::get_create (decl);
/* C++ frontend use mark_decl_references to force COMDAT variables
to be output that might appear dead otherwise. */
- node->symbol.force_output = true;
+ node->force_output = true;
}
/* else do nothing - we can get various sorts of CST nodes here,
which do not need to be marked. */
}
-/* Follow the IDENTIFIER_TRANSPARENT_ALIAS chain starting at *ALIAS
- until we find an identifier that is not itself a transparent alias.
- Modify the alias passed to it by reference (and all aliases on the
- way to the ultimate target), such that they do not have to be
- followed again, and return the ultimate target of the alias
- chain. */
-
-static inline tree
-ultimate_transparent_alias_target (tree *alias)
-{
- tree target = *alias;
-
- if (IDENTIFIER_TRANSPARENT_ALIAS (target))
- {
- gcc_assert (TREE_CHAIN (target));
- target = ultimate_transparent_alias_target (&TREE_CHAIN (target));
- gcc_assert (! IDENTIFIER_TRANSPARENT_ALIAS (target)
- && ! TREE_CHAIN (target));
- *alias = target;
- }
-
- return target;
-}
-
/* Output to FILE (an assembly file) a reference to NAME. If NAME
starts with a *, the rest of NAME is output verbatim. Otherwise
NAME is transformed in a target-specific way (usually by the
const char *op = integer_asm_op (size, aligned_p);
/* Avoid GAS bugs for large values. Specifically negative values whose
absolute value fits in a bfd_vma, but not in a bfd_signed_vma. */
- if (size > UNITS_PER_WORD && size > POINTER_SIZE / BITS_PER_UNIT)
+ if (size > UNITS_PER_WORD && size > POINTER_SIZE_UNITS)
return false;
return op && (assemble_integer_with_op (op, x), true);
}
it into words it if is multi-word, otherwise split it into bytes. */
if (size > 1)
{
- enum machine_mode omode, imode;
+ machine_mode omode, imode;
unsigned int subalign;
unsigned int subsize, i;
enum mode_class mclass;
}
\f
void
-assemble_real (REAL_VALUE_TYPE d, enum machine_mode mode, unsigned int align)
+assemble_real (REAL_VALUE_TYPE d, machine_mode mode, unsigned int align)
{
long data[4] = {0, 0, 0, 0};
int i;
while (1)
{
if (TREE_CODE (target) == COMPONENT_REF
- && host_integerp (byte_position (TREE_OPERAND (target, 1)), 0))
+ && tree_fits_shwi_p (byte_position (TREE_OPERAND (target, 1))))
{
offset += int_byte_position (TREE_OPERAND (target, 1));
target = TREE_OPERAND (target, 0);
else if (TREE_CODE (target) == ARRAY_REF
|| TREE_CODE (target) == ARRAY_RANGE_REF)
{
- offset += (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (target)), 1)
- * tree_low_cst (TREE_OPERAND (target, 1), 0));
+ offset += (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (target)))
+ * tree_to_shwi (TREE_OPERAND (target, 1)));
target = TREE_OPERAND (target, 0);
}
else if (TREE_CODE (target) == MEM_REF
&& TREE_CODE (TREE_OPERAND (target, 0)) == ADDR_EXPR)
{
- offset += mem_ref_offset (target).low;
+ offset += mem_ref_offset (target).to_short_addr ();
target = TREE_OPERAND (TREE_OPERAND (target, 0), 0);
}
else if (TREE_CODE (target) == INDIRECT_REF
value->offset = offset;
}
\f
-
-static GTY((param_is (struct constant_descriptor_tree)))
- htab_t const_desc_htab;
+static GTY(()) hash_table<tree_descriptor_hasher> *const_desc_htab;
static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int);
/* Constant pool accessor function. */
-htab_t
+hash_table<tree_descriptor_hasher> *
constant_pool_htab (void)
{
return const_desc_htab;
/* Compute a hash code for a constant expression. */
-static hashval_t
-const_desc_hash (const void *ptr)
+hashval_t
+tree_descriptor_hasher::hash (constant_descriptor_tree *ptr)
{
- return ((const struct constant_descriptor_tree *)ptr)->hash;
+ return ptr->hash;
}
static hashval_t
switch (code)
{
case INTEGER_CST:
- p = (char *) &TREE_INT_CST (exp);
- len = sizeof TREE_INT_CST (exp);
+ p = (char *) &TREE_INT_CST_ELT (exp, 0);
+ len = TREE_INT_CST_NUNITS (exp) * sizeof (HOST_WIDE_INT);
break;
case REAL_CST:
break;
case LABEL_REF:
- hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+ hi = (value.offset
+ + CODE_LABEL_NUMBER (LABEL_REF_LABEL (value.base)) * 13);
break;
default:
}
/* Wrapper of compare_constant, for the htab interface. */
-static int
-const_desc_eq (const void *p1, const void *p2)
+bool
+tree_descriptor_hasher::equal (constant_descriptor_tree *c1,
+ constant_descriptor_tree *c2)
{
- 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);
break;
case LABEL_REF:
- ret = (CODE_LABEL_NUMBER (XEXP (value1.base, 0))
- == CODE_LABEL_NUMBER (XEXP (value2.base, 0)));
+ ret = (CODE_LABEL_NUMBER (LABEL_REF_LABEL (value1.base))
+ == CODE_LABEL_NUMBER (LABEL_REF_LABEL (value2.base)));
break;
default:
case MINUS_EXPR:
case RANGE_EXPR:
return (compare_constant (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
- && compare_constant(TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
+ && compare_constant (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
CASE_CONVERT:
case VIEW_CONVERT_EXPR:
gcc_unreachable ();
}
\f
-/* Make a copy of the whole tree structure for a constant. This
- handles the same types of nodes that compare_constant handles. */
-
-static tree
-copy_constant (tree exp)
-{
- switch (TREE_CODE (exp))
- {
- case ADDR_EXPR:
- /* For ADDR_EXPR, we do not want to copy the decl whose address
- is requested. We do want to copy constants though. */
- if (CONSTANT_CLASS_P (TREE_OPERAND (exp, 0)))
- return build1 (TREE_CODE (exp), TREE_TYPE (exp),
- copy_constant (TREE_OPERAND (exp, 0)));
- else
- return copy_node (exp);
-
- case INTEGER_CST:
- case REAL_CST:
- case FIXED_CST:
- case STRING_CST:
- return copy_node (exp);
-
- case COMPLEX_CST:
- return build_complex (TREE_TYPE (exp),
- copy_constant (TREE_REALPART (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)),
- copy_constant (TREE_OPERAND (exp, 1)));
-
- CASE_CONVERT:
- case VIEW_CONVERT_EXPR:
- return build1 (TREE_CODE (exp), TREE_TYPE (exp),
- copy_constant (TREE_OPERAND (exp, 0)));
-
- case VECTOR_CST:
- return build_vector (TREE_TYPE (exp), VECTOR_CST_ELTS (exp));
-
- case CONSTRUCTOR:
- {
- tree copy = copy_node (exp);
- vec<constructor_elt, va_gc> *v;
- unsigned HOST_WIDE_INT idx;
- tree purpose, value;
-
- vec_alloc (v, vec_safe_length (CONSTRUCTOR_ELTS (exp)));
- FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, purpose, value)
- {
- constructor_elt ce = {purpose, copy_constant (value)};
- v->quick_push (ce);
- }
- CONSTRUCTOR_ELTS (copy) = v;
- return copy;
- }
-
- default:
- gcc_unreachable ();
- }
-}
-\f
/* Return the section into which constant EXP should be placed. */
static section *
int labelno;
tree decl;
- desc = ggc_alloc_constant_descriptor_tree ();
- desc->value = copy_constant (exp);
-
- /* Propagate marked-ness to copied constant. */
- if (flag_mudflap && mf_marked_p (exp))
- mf_mark (desc->value);
+ desc = ggc_alloc<constant_descriptor_tree> ();
+ desc->value = exp;
/* Create a string containing the label name, in LABEL. */
labelno = const_labelno++;
rtl = gen_const_mem (TYPE_MODE (TREE_TYPE (exp)), symbol);
set_mem_attributes (rtl, exp, 1);
set_mem_alias_set (rtl, 0);
- set_mem_alias_set (rtl, const_alias_set);
/* We cannot share RTX'es in pool entries.
Mark this piece of RTL as required for unsharing. */
{
struct constant_descriptor_tree *desc;
struct constant_descriptor_tree key;
- void **loc;
/* 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);
+ constant_descriptor_tree **loc
+ = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT);
- desc = (struct constant_descriptor_tree *) *loc;
+ desc = *loc;
if (desc == 0)
{
desc = build_constant_desc (exp);
/* Output the value of EXP. */
output_constant (exp, size, align);
+
+ targetm.asm_out.decl_end ();
}
/* We must output the constant data referred to by SYMBOL; do so. */
/* We are no longer deferring this constant. */
TREE_ASM_WRITTEN (decl) = TREE_ASM_WRITTEN (exp) = 1;
- if (flag_asan && TREE_CODE (exp) == STRING_CST
+ if ((flag_sanitize & SANITIZE_ADDRESS)
+ && TREE_CODE (exp) == STRING_CST
&& asan_protect_global (exp))
{
asan_protected = true;
assemble_zeros (asan_red_zone_size (size));
}
}
- if (flag_mudflap)
- mudflap_enqueue_constant (exp);
}
/* Look up EXP in the table of constant descriptors. Return the rtl
rtx
lookup_constant_def (tree exp)
{
- struct constant_descriptor_tree *desc;
struct constant_descriptor_tree key;
key.value = exp;
key.hash = const_hash_1 (exp);
- desc = (struct constant_descriptor_tree *)
- htab_find_with_hash (const_desc_htab, &key, key.hash);
+ constant_descriptor_tree *desc
+ = const_desc_htab->find_with_hash (&key, key.hash);
return (desc ? desc->rtl : NULL_RTX);
}
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);
+ constant_descriptor_tree **loc
+ = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT);
- desc = (struct constant_descriptor_tree *) *loc;
+ desc = *loc;
if (desc == 0)
{
desc = build_constant_desc (exp);
}
decl = SYMBOL_REF_DECL (XEXP (desc->rtl, 0));
- varpool_finalize_decl (decl);
+ varpool_node::finalize_decl (decl);
return decl;
}
\f
+struct GTY((chain_next ("%h.next"), for_user)) constant_descriptor_rtx {
+ struct constant_descriptor_rtx *next;
+ rtx mem;
+ rtx sym;
+ rtx constant;
+ HOST_WIDE_INT offset;
+ hashval_t hash;
+ machine_mode mode;
+ unsigned int align;
+ int labelno;
+ int mark;
+};
+
+struct const_rtx_desc_hasher : ggc_hasher<constant_descriptor_rtx *>
+{
+ static hashval_t hash (constant_descriptor_rtx *);
+ static bool equal (constant_descriptor_rtx *, constant_descriptor_rtx *);
+};
+
/* Used in the hash tables to avoid outputting the same constant
twice. Unlike 'struct constant_descriptor_tree', RTX constants
are output once per function, not once per file. */
It is used on RISC machines where immediate integer arguments and
constant addresses are restricted so that such constants must be stored
in memory. */
- htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_htab;
+ hash_table<const_rtx_desc_hasher> *const_rtx_htab;
/* Current offset in constant pool (does not include any
machine-specific header). */
HOST_WIDE_INT offset;
};
-struct GTY((chain_next ("%h.next"))) constant_descriptor_rtx {
- struct constant_descriptor_rtx *next;
- rtx mem;
- rtx sym;
- rtx constant;
- HOST_WIDE_INT offset;
- hashval_t hash;
- enum machine_mode mode;
- unsigned int align;
- int labelno;
- int mark;
-};
-
/* Hash and compare functions for const_rtx_htab. */
-static hashval_t
-const_desc_rtx_hash (const void *ptr)
+hashval_t
+const_rtx_desc_hasher::hash (constant_descriptor_rtx *desc)
{
- 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)
+bool
+const_rtx_desc_hasher::equal (constant_descriptor_rtx *x,
+ constant_descriptor_rtx *y)
{
- 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;
return rtx_equal_p (x->constant, y->constant);
}
-/* This is the worker function for const_rtx_hash, called via for_each_rtx. */
+/* Hash one component of a constant. */
-static int
-const_rtx_hash_1 (rtx *xp, void *data)
+static hashval_t
+const_rtx_hash_1 (const_rtx x)
{
unsigned HOST_WIDE_INT hwi;
- enum machine_mode mode;
+ machine_mode mode;
enum rtx_code code;
- hashval_t h, *hp;
- rtx x;
+ hashval_t h;
+ int i;
- x = *xp;
code = GET_CODE (x);
mode = GET_MODE (x);
h = (hashval_t) code * 1048573 + mode;
{
case CONST_INT:
hwi = INTVAL (x);
+
fold_hwi:
{
int shift = sizeof (hashval_t) * CHAR_BIT;
const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
- int i;
h ^= (hashval_t) hwi;
for (i = 1; i < n; ++i)
}
break;
+ case CONST_WIDE_INT:
+ hwi = GET_MODE_PRECISION (mode);
+ {
+ for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+ hwi ^= CONST_WIDE_INT_ELT (x, i);
+ goto fold_hwi;
+ }
+
case CONST_DOUBLE:
- if (mode == VOIDmode)
+ if (TARGET_SUPPORTS_WIDE_INT == 0 && mode == VOIDmode)
{
hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
goto fold_hwi;
h ^= fixed_hash (CONST_FIXED_VALUE (x));
break;
- case CONST_VECTOR:
- {
- int i;
- for (i = XVECLEN (x, 0); i-- > 0; )
- h = h * 251 + const_rtx_hash_1 (&XVECEXP (x, 0, i), data);
- }
- break;
-
case SYMBOL_REF:
h ^= htab_hash_string (XSTR (x, 0));
break;
case LABEL_REF:
- h = h * 251 + CODE_LABEL_NUMBER (XEXP (x, 0));
+ h = h * 251 + CODE_LABEL_NUMBER (LABEL_REF_LABEL (x));
break;
case UNSPEC:
break;
}
- hp = (hashval_t *) data;
- *hp = *hp * 509 + h;
- return 0;
+ return h;
}
/* Compute a hash value for X, which should be a constant. */
const_rtx_hash (rtx x)
{
hashval_t h = 0;
- for_each_rtx (&x, const_rtx_hash_1, &h);
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, ALL)
+ h = h * 509 + const_rtx_hash_1 (*iter);
return h;
}
{
struct rtx_constant_pool *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 = ggc_alloc<rtx_constant_pool> ();
+ pool->const_rtx_htab = hash_table<const_rtx_desc_hasher>::create_ggc (31);
pool->first = NULL;
pool->last = NULL;
pool->offset = 0;
and return a MEM rtx to refer to it in memory. */
rtx
-force_const_mem (enum machine_mode mode, rtx x)
+force_const_mem (machine_mode mode, rtx x)
{
struct constant_descriptor_rtx *desc, tmp;
struct rtx_constant_pool *pool;
rtx def, symbol;
hashval_t hash;
unsigned int align;
- void **slot;
+ constant_descriptor_rtx **slot;
/* If we're not allowed to drop X into the constant pool, don't. */
if (targetm.cannot_force_const_mem (mode, x))
tmp.constant = x;
tmp.mode = mode;
hash = const_rtx_hash (x);
- slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
- desc = (struct constant_descriptor_rtx *) *slot;
+ slot = pool->const_rtx_htab->find_slot_with_hash (&tmp, hash, INSERT);
+ desc = *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_constant_descriptor_rtx ();
+ desc = ggc_alloc<constant_descriptor_rtx> ();
*slot = desc;
/* Align the location counter as required by EXP's data type. */
/* Given a constant pool SYMBOL_REF, return the corresponding constant. */
rtx
-get_pool_constant (rtx addr)
+get_pool_constant (const_rtx addr)
{
return SYMBOL_REF_CONSTANT (addr)->constant;
}
/* Similar, return the mode. */
-enum machine_mode
+machine_mode
get_pool_mode (const_rtx addr)
{
return SYMBOL_REF_CONSTANT (addr)->mode;
in MODE with known alignment ALIGN. */
static void
-output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
+output_constant_pool_2 (machine_mode mode, rtx x, unsigned int align)
{
switch (GET_MODE_CLASS (mode))
{
case MODE_UFRACT:
case MODE_ACCUM:
case MODE_UACCUM:
+ case MODE_POINTER_BOUNDS:
assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
break;
case MODE_VECTOR_UACCUM:
{
int i, units;
- enum machine_mode submode = GET_MODE_INNER (mode);
+ machine_mode submode = GET_MODE_INNER (mode);
unsigned int subalign = MIN (align, GET_MODE_BITSIZE (submode));
gcc_assert (GET_CODE (x) == CONST_VECTOR);
CODE_LABEL into a NOTE. */
/* ??? This seems completely and utterly wrong. Certainly it's
not true for NOTE_INSN_DELETED_LABEL, but I disbelieve proper
- functioning even with INSN_DELETED_P and friends. */
+ functioning even with rtx_insn::deleted and friends. */
tmp = x;
switch (GET_CODE (tmp))
/* FALLTHRU */
case LABEL_REF:
- tmp = XEXP (tmp, 0);
- gcc_assert (!INSN_DELETED_P (tmp));
+ tmp = LABEL_REF_LABEL (tmp);
+ gcc_assert (!as_a<rtx_insn *> (tmp)->deleted ());
gcc_assert (!NOTE_P (tmp)
|| NOTE_KIND (tmp) != NOTE_INSN_DELETED);
break;
return;
}
-/* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
- to as used. Emit referenced deferred strings. This function can
- be used with for_each_rtx to mark all SYMBOL_REFs in an rtx. */
+/* Mark all constants that are referenced by SYMBOL_REFs in X.
+ Emit referenced deferred strings. */
-static int
-mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED)
+static void
+mark_constants_in_pattern (rtx insn)
{
- rtx x = *current_rtx;
-
- if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
- return 0;
-
- if (CONSTANT_POOL_ADDRESS_P (x))
- {
- struct constant_descriptor_rtx *desc = SYMBOL_REF_CONSTANT (x);
- if (desc->mark == 0)
- {
- desc->mark = 1;
- for_each_rtx (&desc->constant, mark_constant, NULL);
- }
- }
- else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
{
- tree decl = SYMBOL_REF_DECL (x);
- if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl)))
+ const_rtx x = *iter;
+ if (GET_CODE (x) == SYMBOL_REF)
{
- n_deferred_constants--;
- output_constant_def_contents (x);
+ if (CONSTANT_POOL_ADDRESS_P (x))
+ {
+ struct constant_descriptor_rtx *desc = SYMBOL_REF_CONSTANT (x);
+ if (desc->mark == 0)
+ {
+ desc->mark = 1;
+ iter.substitute (desc->constant);
+ }
+ }
+ else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
+ {
+ tree decl = SYMBOL_REF_DECL (x);
+ if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl)))
+ {
+ n_deferred_constants--;
+ output_constant_def_contents (CONST_CAST_RTX (x));
+ }
+ }
}
}
-
- return -1;
}
/* Look through appropriate parts of INSN, marking all entries in the
deferred strings that are used. */
static void
-mark_constants (rtx insn)
+mark_constants (rtx_insn *insn)
{
if (!INSN_P (insn))
return;
/* Insns may appear inside a SEQUENCE. Only check the patterns of
insns, not any notes that may be attached. We don't want to mark
a constant just because it happens to appear in a REG_EQUIV note. */
- if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+ if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (PATTERN (insn)))
{
- rtx seq = PATTERN (insn);
- int i, n = XVECLEN (seq, 0);
+ int i, n = seq->len ();
for (i = 0; i < n; ++i)
{
- rtx subinsn = XVECEXP (seq, 0, i);
+ rtx subinsn = seq->element (i);
if (INSN_P (subinsn))
- for_each_rtx (&PATTERN (subinsn), mark_constant, NULL);
+ mark_constants_in_pattern (subinsn);
}
}
else
- for_each_rtx (&PATTERN (insn), mark_constant, NULL);
+ mark_constants_in_pattern (insn);
}
/* Look through the instructions for this function, and mark all the
static void
mark_constant_pool (void)
{
- rtx insn;
+ rtx_insn *insn;
if (!crtl->uses_const_pool && n_deferred_constants == 0)
return;
break;
}
- if (TREE_PUBLIC (tem))
+ if (!targetm.binds_local_p (tem))
reloc |= 2;
else
reloc |= 1;
output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int,
oc_outer_state *);
-/* Output assembler code for constant EXP to FILE, with no label.
+/* Output assembler code for constant EXP, with no label.
This includes the pseudo-op such as ".int" or ".byte", and a newline.
Assumes output_addressed_constants has been done on EXP already.
- Generate exactly SIZE bytes of assembler data, padding at the end
- with zeros if necessary. SIZE must always be specified.
+ Generate at least SIZE bytes of assembler data, padding at the end
+ with zeros if necessary. SIZE must always be specified. The returned
+ value is the actual number of bytes of assembler data generated, which
+ may be bigger than SIZE if the object contains a variable length field.
SIZE is important for structure constructors,
since trailing members may have been omitted from the constructor.
ALIGN is the alignment of the data in bits. */
-void
+static unsigned HOST_WIDE_INT
output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align)
{
enum tree_code code;
unsigned HOST_WIDE_INT thissize;
if (size == 0 || flag_syntax_only)
- return;
+ return size;
/* See if we're trying to initialize a pointer in a non-default mode
to the address of some declaration somewhere. If the target says
exp = build1 (ADDR_EXPR, saved_type, TREE_OPERAND (exp, 0));
/* Likewise for constant ints. */
else if (TREE_CODE (exp) == INTEGER_CST)
- exp = build_int_cst_wide (saved_type, TREE_INT_CST_LOW (exp),
- TREE_INT_CST_HIGH (exp));
+ exp = wide_int_to_tree (saved_type, exp);
}
&& vec_safe_is_empty (CONSTRUCTOR_ELTS (exp)))
{
assemble_zeros (size);
- return;
+ return size;
}
if (TREE_CODE (exp) == FDESC_EXPR)
{
#ifdef ASM_OUTPUT_FDESC
- HOST_WIDE_INT part = tree_low_cst (TREE_OPERAND (exp, 1), 0);
+ HOST_WIDE_INT part = tree_to_shwi (TREE_OPERAND (exp, 1));
tree decl = TREE_OPERAND (exp, 0);
ASM_OUTPUT_FDESC (asm_out_file, decl, part);
#else
gcc_unreachable ();
#endif
- return;
+ return size;
}
/* Now output the underlying data. If we've handling the padding, return.
case REFERENCE_TYPE:
case OFFSET_TYPE:
case FIXED_POINT_TYPE:
+ case POINTER_BOUNDS_TYPE:
+ case NULLPTR_TYPE:
if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
EXPAND_INITIALIZER),
MIN (size, thissize), align, 0))
switch (TREE_CODE (exp))
{
case CONSTRUCTOR:
- output_constructor (exp, size, align, NULL);
- return;
+ return output_constructor (exp, size, align, NULL);
case STRING_CST:
- thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
- size);
+ thissize
+ = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp), size);
assemble_string (TREE_STRING_POINTER (exp), thissize);
break;
-
case VECTOR_CST:
{
- int elt_size;
- unsigned int i, nalign;
- enum machine_mode inner;
-
- inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
- nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
-
- elt_size = GET_MODE_SIZE (inner);
-
+ machine_mode inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+ unsigned int nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
+ int elt_size = GET_MODE_SIZE (inner);
output_constant (VECTOR_CST_ELT (exp, 0), elt_size, align);
thissize = elt_size;
- for (i = 1; i < VECTOR_CST_NELTS (exp); ++i)
+ for (unsigned int i = 1; i < VECTOR_CST_NELTS (exp); i++)
{
output_constant (VECTOR_CST_ELT (exp, i), elt_size, nalign);
thissize += elt_size;
case RECORD_TYPE:
case UNION_TYPE:
gcc_assert (TREE_CODE (exp) == CONSTRUCTOR);
- output_constructor (exp, size, align, NULL);
- return;
+ return output_constructor (exp, size, align, NULL);
case ERROR_MARK:
- return;
+ return 0;
default:
gcc_unreachable ();
if (size > thissize)
assemble_zeros (size - thissize);
+
+ return size;
}
\f
tree max_index;
unsigned HOST_WIDE_INT cnt;
tree index, value, tmp;
- double_int i;
+ offset_int i;
/* This code used to attempt to handle string constants that are not
arrays of single-bytes, but nothing else does, so there's no point in
/* Compute the total number of array elements. */
tmp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)));
- i = tree_to_double_int (max_index) - tree_to_double_int (tmp);
- i += double_int_one;
+ i = wi::to_offset (max_index) - wi::to_offset (tmp) + 1;
/* Multiply by the array element unit size to find number of bytes. */
- i *= tree_to_double_int (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
+ i *= wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
- gcc_assert (i.fits_uhwi ());
- return i.low;
+ gcc_assert (wi::fits_uhwi_p (i));
+ return i.to_uhwi ();
}
/* Other datastructures + helpers for output_constructor. */
/* Received arguments. */
tree exp; /* Constructor expression. */
+ tree type; /* Type of constructor expression. */
unsigned HOST_WIDE_INT size; /* # bytes to output - pad if necessary. */
unsigned int align; /* Known initial alignment. */
-
- /* Constructor expression data. */
- tree type; /* Expression type. */
- tree field; /* Current field decl in a record. */
- tree min_index; /* Lower bound if specified for an array. */
+ tree min_index; /* Lower bound if specified for an array. */
/* Output processing state. */
HOST_WIDE_INT total_bytes; /* # bytes output so far / current position. */
- bool byte_buffer_in_use; /* Whether byte ... */
- int byte; /* ... contains part of a bitfield byte yet to
- be output. */
-
+ int byte; /* Part of a bitfield byte yet to be output. */
int last_relative_index; /* Implicit or explicit index of the last
array element output within a bitfield. */
+ bool byte_buffer_in_use; /* Whether BYTE is in use. */
+
/* Current element. */
- tree val; /* Current element value. */
- tree index; /* Current element index. */
+ tree field; /* Current field decl in a record. */
+ tree val; /* Current element value. */
+ tree index; /* Current element index. */
} oc_local_state;
= int_size_in_bytes (TREE_TYPE (local->type));
HOST_WIDE_INT lo_index
- = tree_low_cst (TREE_OPERAND (local->index, 0), 0);
+ = tree_to_shwi (TREE_OPERAND (local->index, 0));
HOST_WIDE_INT hi_index
- = tree_low_cst (TREE_OPERAND (local->index, 1), 0);
+ = tree_to_shwi (TREE_OPERAND (local->index, 1));
HOST_WIDE_INT index;
unsigned int align2
if (local->val == NULL_TREE)
assemble_zeros (fieldsize);
else
- output_constant (local->val, fieldsize, align2);
+ fieldsize = output_constant (local->val, fieldsize, align2);
/* Count its size. */
local->total_bytes += fieldsize;
sign-extend the result because Ada has negative DECL_FIELD_OFFSETs
but we are using an unsigned sizetype. */
unsigned prec = TYPE_PRECISION (sizetype);
- double_int idx = tree_to_double_int (local->index)
- - tree_to_double_int (local->min_index);
- idx = idx.sext (prec);
- fieldpos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (local->val)), 1)
- * idx.low);
+ offset_int idx = wi::sext (wi::to_offset (local->index)
+ - wi::to_offset (local->min_index), prec);
+ fieldpos = (idx * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (local->val))))
+ .to_short_addr ();
}
else if (local->field != NULL_TREE)
fieldpos = int_byte_position (local->field);
Note no alignment needed in an array, since that is guaranteed
if each element has the proper size. */
if ((local->field != NULL_TREE || local->index != NULL_TREE)
- && fieldpos != local->total_bytes)
+ && fieldpos > local->total_bytes)
{
- gcc_assert (fieldpos >= local->total_bytes);
assemble_zeros (fieldpos - local->total_bytes);
local->total_bytes = fieldpos;
}
gcc_assert (!fieldsize || !DECL_CHAIN (local->field));
}
else
- fieldsize = tree_low_cst (DECL_SIZE_UNIT (local->field), 1);
+ fieldsize = tree_to_uhwi (DECL_SIZE_UNIT (local->field));
}
else
fieldsize = int_size_in_bytes (TREE_TYPE (local->type));
if (local->val == NULL_TREE)
assemble_zeros (fieldsize);
else
- output_constant (local->val, fieldsize, align2);
+ fieldsize = output_constant (local->val, fieldsize, align2);
/* Count its size. */
local->total_bytes += fieldsize;
}
-/* Helper for output_constructor. From the current LOCAL and OUTER states,
- output an element that is a true bitfield or part of an outer one. */
+/* Helper for output_constructor. From the LOCAL state, output an element
+ that is a true bitfield or part of an outer one. BIT_OFFSET is the offset
+ from the start of a possibly ongoing outer byte buffer. */
static void
-output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer)
+output_constructor_bitfield (oc_local_state *local, unsigned int bit_offset)
{
/* Bit size of this element. */
HOST_WIDE_INT ebitsize
= (local->field
- ? tree_low_cst (DECL_SIZE (local->field), 1)
- : tree_low_cst (TYPE_SIZE (TREE_TYPE (local->type)), 1));
+ ? tree_to_uhwi (DECL_SIZE (local->field))
+ : tree_to_uhwi (TYPE_SIZE (TREE_TYPE (local->type))));
/* Relative index of this element if this is an array component. */
HOST_WIDE_INT relative_index
= (!local->field
? (local->index
- ? (tree_low_cst (local->index, 0)
- - tree_low_cst (local->min_index, 0))
+ ? (tree_to_shwi (local->index)
+ - tree_to_shwi (local->min_index))
: local->last_relative_index + 1)
: 0);
/* Bit position of this element from the start of a possibly ongoing
outer byte buffer. */
HOST_WIDE_INT byte_relative_ebitpos
- = ((outer ? outer->bit_offset : 0) + constructor_relative_ebitpos);
+ = bit_offset + constructor_relative_ebitpos;
/* From the start of a possibly ongoing outer byte buffer, offsets to
the first bit of this element and to the first bit past the end of
return;
}
- /* If this field does not start in this (or, next) byte,
- skip some bytes. */
+ /* If this field does not start in this (or next) byte, skip some bytes. */
if (next_offset / BITS_PER_UNIT != local->total_bytes)
{
/* Output remnant of any bit field in previous bytes. */
pending data, then retrieve the new pending data afterwards. */
if (TREE_CODE (local->val) == CONSTRUCTOR)
{
- oc_outer_state output_state;
-
- output_state.bit_offset = next_offset % BITS_PER_UNIT;
- output_state.byte = local->byte;
+ oc_outer_state temp_state;
+ temp_state.bit_offset = next_offset % BITS_PER_UNIT;
+ temp_state.byte = local->byte;
local->total_bytes
- += output_constructor (local->val, 0, 0, &output_state);
- local->byte = output_state.byte;
+ += output_constructor (local->val, 0, 0, &temp_state);
+ local->byte = temp_state.byte;
return;
}
HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
- /* Advance from byte to byte
- within this element when necessary. */
+ /* Advance from byte to byte within this element when necessary. */
while (next_byte != local->total_bytes)
{
assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
local->byte = 0;
}
- /* Number of bits we can process at once
- (all part of the same byte). */
- this_time = MIN (end_offset - next_offset,
- BITS_PER_UNIT - next_bit);
+ /* Number of bits we can process at once (all part of the same byte). */
+ this_time = MIN (end_offset - next_offset, BITS_PER_UNIT - next_bit);
if (BYTES_BIG_ENDIAN)
{
- /* On big-endian machine, take the most significant bits
- first (of the bits that are significant)
- and put them into bytes from the most significant end. */
+ /* On big-endian machine, take the most significant bits (of the
+ bits that are significant) first and put them into bytes from
+ the most significant end. */
shift = end_offset - next_offset - this_time;
/* Don't try to take a bunch of bits that cross
- the word boundary in the INTEGER_CST. We can
- only select bits from the LOW or HIGH part
- not from both. */
- if (shift < HOST_BITS_PER_WIDE_INT
- && shift + this_time > HOST_BITS_PER_WIDE_INT)
+ the word boundary in the INTEGER_CST. We can
+ only select bits from one element. */
+ if ((shift / HOST_BITS_PER_WIDE_INT)
+ != ((shift + this_time - 1) / HOST_BITS_PER_WIDE_INT))
{
- this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
- shift = HOST_BITS_PER_WIDE_INT;
+ const int end = shift + this_time - 1;
+ shift = end & -HOST_BITS_PER_WIDE_INT;
+ this_time = end - shift + 1;
}
/* Now get the bits from the appropriate constant word. */
- if (shift < HOST_BITS_PER_WIDE_INT)
- value = TREE_INT_CST_LOW (local->val);
- else
- {
- gcc_assert (shift < HOST_BITS_PER_DOUBLE_INT);
- value = TREE_INT_CST_HIGH (local->val);
- shift -= HOST_BITS_PER_WIDE_INT;
- }
+ value = TREE_INT_CST_ELT (local->val, shift / HOST_BITS_PER_WIDE_INT);
+ shift = shift & (HOST_BITS_PER_WIDE_INT - 1);
- /* Get the result. This works only when:
+ /* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
local->byte |= (((value >> shift)
& (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
}
else
{
- /* On little-endian machines,
- take first the least significant bits of the value
- and pack them starting at the least significant
+ /* On little-endian machines, take the least significant bits of
+ the value first and pack them starting at the least significant
bits of the bytes. */
shift = next_offset - byte_relative_ebitpos;
/* Don't try to take a bunch of bits that cross
- the word boundary in the INTEGER_CST. We can
- only select bits from the LOW or HIGH part
- not from both. */
- if (shift < HOST_BITS_PER_WIDE_INT
- && shift + this_time > HOST_BITS_PER_WIDE_INT)
- this_time = (HOST_BITS_PER_WIDE_INT - shift);
+ the word boundary in the INTEGER_CST. We can
+ only select bits from one element. */
+ if ((shift / HOST_BITS_PER_WIDE_INT)
+ != ((shift + this_time - 1) / HOST_BITS_PER_WIDE_INT))
+ this_time
+ = HOST_BITS_PER_WIDE_INT - (shift & (HOST_BITS_PER_WIDE_INT - 1));
/* Now get the bits from the appropriate constant word. */
- if (shift < HOST_BITS_PER_WIDE_INT)
- value = TREE_INT_CST_LOW (local->val);
- else
- {
- gcc_assert (shift < HOST_BITS_PER_DOUBLE_INT);
- value = TREE_INT_CST_HIGH (local->val);
- shift -= HOST_BITS_PER_WIDE_INT;
- }
+ value = TREE_INT_CST_ELT (local->val, shift / HOST_BITS_PER_WIDE_INT);
+ shift = shift & (HOST_BITS_PER_WIDE_INT - 1);
- /* Get the result. This works only when:
+ /* Get the result. This works only when:
1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
local->byte |= (((value >> shift)
& (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
static unsigned HOST_WIDE_INT
output_constructor (tree exp, unsigned HOST_WIDE_INT size,
- unsigned int align, oc_outer_state * outer)
+ unsigned int align, oc_outer_state *outer)
{
unsigned HOST_WIDE_INT cnt;
constructor_elt *ce;
/* Setup our local state to communicate with helpers. */
local.exp = exp;
+ local.type = TREE_TYPE (exp);
local.size = size;
local.align = align;
+ if (TREE_CODE (local.type) == ARRAY_TYPE && TYPE_DOMAIN (local.type))
+ local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
+ else
+ local.min_index = NULL_TREE;
local.total_bytes = 0;
local.byte_buffer_in_use = outer != NULL;
local.byte = outer ? outer->byte : 0;
-
- local.type = TREE_TYPE (exp);
-
local.last_relative_index = -1;
- local.min_index = NULL_TREE;
- if (TREE_CODE (local.type) == ARRAY_TYPE
- && TYPE_DOMAIN (local.type) != NULL_TREE)
- local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
-
gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
/* As CE goes through the elements of the constant, FIELD goes through the
(even if the initializer in a source program incorrectly contains
more one). */
- local.field = NULL_TREE;
if (TREE_CODE (local.type) == RECORD_TYPE)
local.field = TYPE_FIELDS (local.type);
+ else
+ local.field = NULL_TREE;
for (cnt = 0;
vec_safe_iterate (CONSTRUCTOR_ELTS (exp), cnt, &ce);
build_nonstandard_integer_type
(TYPE_PRECISION (TREE_TYPE (local.val)), 0),
local.val);
- output_constructor_bitfield (&local, outer);
+ output_constructor_bitfield (&local, outer ? outer->bit_offset : 0);
}
}
static void
mark_weak (tree decl)
{
+ if (DECL_WEAK (decl))
+ return;
+
+ struct symtab_node *n = symtab_node::get (decl);
+ if (n && n->refuse_visibility_changes)
+ error ("%+D declared weak after being used", decl);
DECL_WEAK (decl) = 1;
if (DECL_RTL_SET_P (decl)
static tree
find_decl (tree target)
{
- symtab_node node = symtab_node_for_asm (target);
+ symtab_node *node = symtab_node::get_for_asmname (target);
if (node)
- return node->symbol.decl;
+ return node->decl;
return NULL_TREE;
}
void
do_assemble_alias (tree decl, tree target)
{
+ tree id;
+
/* Emulated TLS had better not get this var. */
- gcc_assert(!(!targetm.have_tls
- && TREE_CODE (decl) == VAR_DECL
- && DECL_THREAD_LOCAL_P (decl)));
+ gcc_assert (!(!targetm.have_tls
+ && TREE_CODE (decl) == VAR_DECL
+ && DECL_THREAD_LOCAL_P (decl)));
if (TREE_ASM_WRITTEN (decl))
return;
+ id = DECL_ASSEMBLER_NAME (decl);
+ ultimate_transparent_alias_target (&id);
+
/* We must force creation of DECL_RTL for debug info generation, even though
we don't use it here. */
make_decl_rtl (decl);
TREE_ASM_WRITTEN (decl) = 1;
TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
+ TREE_ASM_WRITTEN (id) = 1;
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
{
#ifdef ASM_OUTPUT_WEAKREF
ASM_OUTPUT_WEAKREF (asm_out_file, decl,
- IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ IDENTIFIER_POINTER (id),
IDENTIFIER_POINTER (target));
#else
if (!TARGET_SUPPORTS_WEAK)
}
#ifdef ASM_OUTPUT_DEF
+ tree orig_decl = decl;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && cgraph_node::get (decl)->instrumentation_clone
+ && cgraph_node::get (decl)->instrumented_version)
+ orig_decl = cgraph_node::get (decl)->instrumented_version->decl;
+
/* Make name accessible from other files, if appropriate. */
- if (TREE_PUBLIC (decl))
+ if (TREE_PUBLIC (decl) || TREE_PUBLIC (orig_decl))
{
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");
+#if defined (ASM_OUTPUT_TYPE_DIRECTIVE)
+ if (targetm.has_ifunc_p ())
+ ASM_OUTPUT_TYPE_DIRECTIVE
+ (asm_out_file, IDENTIFIER_POINTER (id),
+ IFUNC_ASM_TYPE);
+ else
#endif
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "ifunc is not supported on this target");
}
# ifdef ASM_OUTPUT_DEF_FROM_DECLS
ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
# else
ASM_OUTPUT_DEF (asm_out_file,
- IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ IDENTIFIER_POINTER (id),
IDENTIFIER_POINTER (target));
# endif
#elif defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
const char *name;
tree *p, t;
- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ name = IDENTIFIER_POINTER (id);
# ifdef ASM_WEAKEN_DECL
ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
# else
/* Remove this function from the pending weak list so that
we do not emit multiple .weak directives for it. */
for (p = &weak_decls; (t = *p) ; )
- if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
+ if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t))
+ || id == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
*p = TREE_CHAIN (t);
else
p = &TREE_CHAIN (t);
list, for the same reason. */
for (p = &weakref_targets; (t = *p) ; )
{
- if (DECL_ASSEMBLER_NAME (decl)
- == ultimate_transparent_alias_target (&TREE_VALUE (t)))
+ if (id == ultimate_transparent_alias_target (&TREE_VALUE (t)))
*p = TREE_CHAIN (t);
else
p = &TREE_CHAIN (t);
if (alias == target)
error ("weakref %q+D ultimately targets itself", decl);
- else
- {
-#ifndef ASM_OUTPUT_WEAKREF
- IDENTIFIER_TRANSPARENT_ALIAS (alias) = 1;
- TREE_CHAIN (alias) = target;
-#endif
- }
if (TREE_PUBLIC (decl))
error ("weakref %q+D must have static linkage", decl);
}
# if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
error_at (DECL_SOURCE_LOCATION (decl),
"alias definitions not supported in this configuration");
+ TREE_ASM_WRITTEN (decl) = 1;
return;
# else
if (!DECL_WEAK (decl))
else
error_at (DECL_SOURCE_LOCATION (decl),
"only weak aliases are supported in this configuration");
+ TREE_ASM_WRITTEN (decl) = 1;
return;
}
# endif
/* Allow aliases to aliases. */
if (TREE_CODE (decl) == FUNCTION_DECL)
- cgraph_get_create_node (decl)->alias = true;
+ cgraph_node::get_create (decl)->alias = true;
else
- varpool_node_for_decl (decl)->alias = true;
+ varpool_node::get_create (decl)->alias = true;
/* If the target has already been emitted, we don't have to queue the
alias. This saves a tad of memory. */
- if (cgraph_global_info_ready)
+ if (symtab->global_info_ready)
target_decl = find_decl (target);
else
target_decl= NULL;
if ((target_decl && TREE_ASM_WRITTEN (target_decl))
- || cgraph_state >= CGRAPH_STATE_EXPANSION)
+ || symtab->state >= EXPANSION)
do_assemble_alias (decl, target);
else
{
if (tm_clone_hash == NULL)
tm_clone_hash = htab_create_ggc (32, tree_map_hash, tree_map_eq, 0);
- h = ggc_alloc_tree_map ();
+ h = ggc_alloc<tree_map> ();
h->hash = htab_hash_pointer (o);
h->base.from = o;
h->to = n;
{
tree src = p->from;
tree dst = p->to;
- struct cgraph_node *src_n = cgraph_get_node (src);
- struct cgraph_node *dst_n = cgraph_get_node (dst);
+ struct cgraph_node *src_n = cgraph_node::get (src);
+ struct cgraph_node *dst_n = cgraph_node::get (dst);
/* The function ipa_tm_create_version() marks the clone as needed if
the original function was needed. But we also mark the clone as
TM_GETTMCLONE. If neither of these are true, we didn't generate
a clone, and we didn't call it indirectly... no sense keeping it
in the clone table. */
- if (!dst_n || !dst_n->analyzed)
+ if (!dst_n || !dst_n->definition)
continue;
/* This covers the case where we have optimized the original
function away, and only access the transactional clone. */
- if (!src_n || !src_n->analyzed)
+ if (!src_n || !src_n->definition)
continue;
if (!switched)
}
assemble_integer (XEXP (DECL_RTL (src), 0),
- POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ POINTER_SIZE_UNITS, POINTER_SIZE, 1);
assemble_integer (XEXP (DECL_RTL (dst), 0),
- POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ POINTER_SIZE_UNITS, POINTER_SIZE, 1);
}
}
assemble_name (asm_out_file, name);
fprintf (asm_out_file, "\n");
#else
- warning (OPT_Wattributes, "visibility attribute not supported "
- "in this configuration; ignored");
+ if (!DECL_ARTIFICIAL (decl))
+ warning (OPT_Wattributes, "visibility attribute not supported "
+ "in this configuration; ignored");
#endif
}
{
enum symbol_visibility vis = DECL_VISIBILITY (decl);
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && cgraph_node::get (decl)
+ && cgraph_node::get (decl)->instrumentation_clone
+ && cgraph_node::get (decl)->instrumented_version)
+ vis = DECL_VISIBILITY (cgraph_node::get (decl)->instrumented_version->decl);
+
if (vis != VISIBILITY_DEFAULT)
{
targetm.asm_out.assemble_visibility (decl, vis);
void
make_decl_one_only (tree decl, tree comdat_group)
{
+ struct symtab_node *symbol;
gcc_assert (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FUNCTION_DECL);
TREE_PUBLIC (decl) = 1;
+ if (TREE_CODE (decl) == VAR_DECL)
+ symbol = varpool_node::get_create (decl);
+ else
+ symbol = cgraph_node::get_create (decl);
+
if (SUPPORTS_ONE_ONLY)
{
#ifdef MAKE_DECL_ONE_ONLY
MAKE_DECL_ONE_ONLY (decl);
#endif
- DECL_COMDAT_GROUP (decl) = comdat_group;
+ symbol->set_comdat_group (comdat_group);
}
else if (TREE_CODE (decl) == VAR_DECL
- && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
+ && (DECL_INITIAL (decl) == 0
+ || (!in_lto_p && DECL_INITIAL (decl) == error_mark_node)))
DECL_COMMON (decl) = 1;
else
{
void
init_varasm_once (void)
{
- section_htab = htab_create_ggc (31, section_entry_hash,
- section_entry_eq, NULL);
- object_block_htab = htab_create_ggc (31, object_block_entry_hash,
- object_block_entry_eq, NULL);
- const_desc_htab = htab_create_ggc (1009, const_desc_hash,
- const_desc_eq, NULL);
+ section_htab = hash_table<section_hasher>::create_ggc (31);
+ object_block_htab = hash_table<object_block_hasher>::create_ggc (31);
+ const_desc_htab = hash_table<tree_descriptor_hasher>::create_ggc (1009);
- const_alias_set = new_alias_set ();
shared_constant_pool = create_constant_pool ();
#ifdef TEXT_SECTION_ASM_OP
readonly_data_section = text_section;
#ifdef ASM_OUTPUT_EXTERNAL
- pending_assemble_externals_set = pointer_set_create ();
+ pending_assemble_externals_set = new hash_set<tree>;
#endif
}
flags |= SECTION_RELRO;
}
- if (decl && DECL_ONE_ONLY (decl))
+ if (decl && DECL_P (decl) && DECL_COMDAT_GROUP (decl))
+ flags |= SECTION_LINKONCE;
+
+ if (strcmp (name, ".vtable_map_vars") == 0)
flags |= SECTION_LINKONCE;
if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
if (strcmp (name, ".bss") == 0
|| strncmp (name, ".bss.", 5) == 0
|| strncmp (name, ".gnu.linkonce.b.", 16) == 0
+ || strcmp (name, ".persistent.bss") == 0
|| strcmp (name, ".sbss") == 0
|| strncmp (name, ".sbss.", 6) == 0
|| strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
if (!(flags & SECTION_DEBUG))
*f++ = 'a';
+#if defined (HAVE_GAS_SECTION_EXCLUDE) && HAVE_GAS_SECTION_EXCLUDE == 1
if (flags & SECTION_EXCLUDE)
*f++ = 'e';
+#endif
if (flags & SECTION_WRITE)
*f++ = 'w';
if (flags & SECTION_CODE)
return SECCAT_TEXT;
else if (TREE_CODE (decl) == STRING_CST)
{
- if (flag_mudflap
- || (flag_asan && asan_protect_global (CONST_CAST_TREE (decl))))
+ if ((flag_sanitize & SANITIZE_ADDRESS)
+ && asan_protect_global (CONST_CAST_TREE (decl)))
/* or !flag_merge_constants */
return SECCAT_RODATA;
else
}
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 || flag_mudflap
- || (flag_asan && asan_protect_global (CONST_CAST_TREE (decl))))
+ else if (reloc || flag_merge_constants < 2
+ || ((flag_sanitize & SANITIZE_ADDRESS)
+ && asan_protect_global (CONST_CAST_TREE (decl))))
/* C and C++ don't allow different variables to share the same
location. -fmerge-all-constants allows even that (at the
expense of not conforming). */
gcc_unreachable ();
}
- if (!DECL_P (decl))
- decl = NULL_TREE;
return get_named_section (decl, sname, reloc);
}
bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
const char *prefix, *name, *linkonce;
char *string;
+ tree id;
switch (categorize_decl_for_section (decl, reloc))
{
gcc_unreachable ();
}
- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ id = DECL_ASSEMBLER_NAME (decl);
+ ultimate_transparent_alias_target (&id);
+ name = IDENTIFIER_POINTER (id);
name = targetm.strip_name_encoding (name);
/* If we're using one_only, then there needs to be a .gnu.linkonce
string = ACONCAT ((linkonce, prefix, ".", name, NULL));
- DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
+ set_decl_section_name (decl, 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. */
+/* Subroutine of compute_reloc_for_rtx for leaf rtxes. */
static int
-compute_reloc_for_rtx_1 (rtx *xp, void *data)
+compute_reloc_for_rtx_1 (const_rtx x)
{
- int *preloc = (int *) data;
- rtx x = *xp;
-
switch (GET_CODE (x))
{
case SYMBOL_REF:
- *preloc |= SYMBOL_REF_LOCAL_P (x) ? 1 : 2;
- break;
+ return SYMBOL_REF_LOCAL_P (x) ? 1 : 2;
case LABEL_REF:
- *preloc |= 1;
- break;
+ return 1;
default:
- break;
+ return 0;
}
-
- return 0;
}
+/* 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 (rtx x)
+compute_reloc_for_rtx (const_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;
+ return compute_reloc_for_rtx_1 (x);
+
+ case CONST:
+ {
+ int reloc = 0;
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, ALL)
+ reloc |= compute_reloc_for_rtx_1 (*iter);
+ return reloc;
+ }
default:
return 0;
}
section *
-default_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
+default_select_rtx_section (machine_mode mode ATTRIBUTE_UNUSED,
rtx x,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
}
section *
-default_elf_select_rtx_section (enum machine_mode mode, rtx x,
+default_elf_select_rtx_section (machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align)
{
int reloc = compute_reloc_for_rtx (x);
decl = SYMBOL_REF_DECL (symbol);
if (decl && DECL_P (decl))
{
- /* Don't use section anchors for decls that might be defined by
- other modules. */
- if (!targetm.binds_local_p (decl))
+ /* Don't use section anchors for decls that might be defined or
+ usurped by other modules. */
+ if (TREE_PUBLIC (decl) && !decl_binds_to_current_def_p (decl))
return false;
/* Don't use section anchors for decls that will be placed in a
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->symbol.resolution))
+ varpool_node *vnode = varpool_node::get (exp);
+ if (vnode && (resolution_local_p (vnode->resolution) || vnode->in_other_partition))
resolved_locally = true;
if (vnode
- && resolution_to_local_definition_p (vnode->symbol.resolution))
+ && 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 (exp);
+ struct cgraph_node *node = cgraph_node::get (exp);
if (node
- && resolution_local_p (node->symbol.resolution))
+ && (resolution_local_p (node->resolution) || node->in_other_partition))
resolved_locally = true;
if (node
- && resolution_to_local_definition_p (node->symbol.resolution))
+ && resolution_to_local_definition_p (node->resolution))
resolved_to_local_def = true;
}
else if (DECL_COMMON (exp)
&& !resolved_locally
&& (DECL_INITIAL (exp) == NULL
- || DECL_INITIAL (exp) == error_mark_node))
+ || (!in_lto_p && DECL_INITIAL (exp) == error_mark_node)))
local_p = false;
/* Otherwise we're left with initialized (or non-common) global data
which is of necessity defined locally. */
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)
+decl_binds_to_current_def_p (const_tree decl)
{
gcc_assert (DECL_P (decl));
- if (!TREE_PUBLIC (decl))
- return true;
if (!targetm.binds_local_p (decl))
return false;
+ if (!TREE_PUBLIC (decl))
+ return true;
/* When resolution is available, just use it. */
if (TREE_CODE (decl) == VAR_DECL
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
{
- struct varpool_node *vnode = varpool_get_node (decl);
+ varpool_node *vnode = varpool_node::get (decl);
if (vnode
- && vnode->symbol.resolution != LDPR_UNKNOWN)
- return resolution_to_local_definition_p (vnode->symbol.resolution);
+ && vnode->resolution != LDPR_UNKNOWN)
+ return resolution_to_local_definition_p (vnode->resolution);
}
else if (TREE_CODE (decl) == FUNCTION_DECL)
{
- struct cgraph_node *node = cgraph_get_node (decl);
+ struct cgraph_node *node = cgraph_node::get (decl);
if (node
- && node->symbol.resolution != LDPR_UNKNOWN)
- return resolution_to_local_definition_p (node->symbol.resolution);
+ && 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 locally but still can be overwritten).
+ binds locally but still can be overwritten), DECL_COMMON (can be merged
+ with a non-common definition somewhere in the same module) or
+ DECL_EXTERNAL.
This rely on fact that binds_local_p behave as decl_replaceable_p
for all other declaration types. */
- return !DECL_WEAK (decl);
+ if (DECL_WEAK (decl))
+ return false;
+ if (DECL_COMMON (decl)
+ && (DECL_INITIAL (decl) == NULL
+ || (!in_lto_p && DECL_INITIAL (decl) == error_mark_node)))
+ return false;
+ if (DECL_EXTERNAL (decl))
+ return false;
+ return true;
}
/* A replaceable function or variable is one which may be replaced
gcc_assert (DECL_P (decl));
if (!TREE_PUBLIC (decl) || DECL_COMDAT (decl))
return false;
+ if (!flag_semantic_interposition
+ && !DECL_WEAK (decl))
+ return false;
return !decl_binds_to_current_def_p (decl);
}
decl = SYMBOL_REF_DECL (symbol);
alignment = DECL_ALIGN (decl);
size = get_constant_size (DECL_INITIAL (decl));
- if (flag_asan
+ if ((flag_sanitize & SANITIZE_ADDRESS)
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
&& asan_protect_global (DECL_INITIAL (decl)))
size += asan_red_zone_size (size);
}
else
{
+ struct symtab_node *snode;
decl = SYMBOL_REF_DECL (symbol);
- alignment = DECL_ALIGN (decl);
- size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
- if (flag_asan && asan_protect_global (decl))
+
+ snode = symtab_node::get (decl);
+ if (snode->alias)
+ {
+ rtx target = DECL_RTL (snode->ultimate_alias_target ()->decl);
+
+ place_block_symbol (target);
+ SYMBOL_REF_BLOCK_OFFSET (symbol) = SYMBOL_REF_BLOCK_OFFSET (target);
+ return;
+ }
+ alignment = get_variable_align (decl);
+ size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
+ if ((flag_sanitize & SANITIZE_ADDRESS)
+ && asan_protect_global (decl))
{
size += asan_red_zone_size (size);
alignment = MAX (alignment,
DECL_ALIGN (decl));
size = get_constant_size (DECL_INITIAL (decl));
offset += size;
- if (flag_asan
+ if ((flag_sanitize & SANITIZE_ADDRESS)
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
&& asan_protect_global (DECL_INITIAL (decl)))
{
HOST_WIDE_INT size;
decl = SYMBOL_REF_DECL (symbol);
assemble_variable_contents (decl, XSTR (symbol, 0), false);
- size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
offset += size;
- if (flag_asan && asan_protect_global (decl))
+ if ((flag_sanitize & SANITIZE_ADDRESS)
+ && asan_protect_global (decl))
{
size = asan_red_zone_size (size);
assemble_zeros (size);
/* A htab_traverse callback used to call output_object_block for
each member of object_block_htab. */
-static int
-output_object_block_htab (void **slot, void *data ATTRIBUTE_UNUSED)
+int
+output_object_block_htab (object_block **slot, void *)
{
- output_object_block ((struct object_block *) (*slot));
+ output_object_block (*slot);
return 1;
}
void
output_object_blocks (void)
{
- htab_traverse (object_block_htab, output_object_block_htab, NULL);
+ object_block_htab->traverse<void *, output_object_block_htab> (NULL);
}
/* This function provides a possible implementation of the
make_debug_expr_from_rtl (const_rtx exp)
{
tree ddecl = make_node (DEBUG_EXPR_DECL), type;
- enum machine_mode mode = GET_MODE (exp);
+ machine_mode mode = GET_MODE (exp);
rtx dval;
DECL_ARTIFICIAL (ddecl) = 1;
to asm_out_file. Instead, add a fake top-level asm statement.
This allows the front ends to use this hook without actually
writing to asm_out_file, to handle #ident or Pragma Ident. */
- if (cgraph_state == CGRAPH_STATE_PARSING)
+ if (symtab->state == PARSING)
{
char *buf = ACONCAT ((ident_asm_op, "\"", ident_str, "\"\n", NULL));
- add_asm_node (build_string (strlen (buf), buf));
+ symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
}
else
fprintf (asm_out_file, "%s\"%s\"\n", ident_asm_op, ident_str);