/* Output variables, constants and external declarations, for GNU compiler.
- Copyright (C) 1987-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 "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 "basic-block.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;
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_rtx_def (size);
+ symbol = (rtx) ggc_internal_alloc (size);
/* Initialize the normal SYMBOL_REF fields. */
memset (symbol, 0, size);
if (name == NULL)
{
gcc_assert (decl && DECL_P (decl) && DECL_SECTION_NAME (decl));
- name = TREE_STRING_POINTER (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;
}
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))
+ 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);
#endif
#ifdef CONSTANT_ALIGNMENT
if (DECL_INITIAL (decl) != 0
- && DECL_INITIAL (decl) != error_mark_node)
+ /* 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);
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);
{
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
/* 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. */
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));
{
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 size, rounded;
- size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
rounded = size;
if ((flag_sanitize & SANITIZE_ADDRESS) && asan_protect_global (decl))
if (!sect->noswitch.callback (decl, name, size, rounded)
&& (unsigned HOST_WIDE_INT) (align / BITS_PER_UNIT) > rounded)
- warning (0, "requested alignment for %q+D is greater than "
- "implemented alignment of %wu", decl, 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),
+ 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.
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));
}
}
/* 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->symbol.definition)
- 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:
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);
+ 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. */
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))
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
{
- struct constant_descriptor_rtx *desc = SYMBOL_REF_CONSTANT (x);
- if (desc->mark == 0)
+ const_rtx x = *iter;
+ if (GET_CODE (x) == SYMBOL_REF)
{
- desc->mark = 1;
- for_each_rtx (&desc->constant, mark_constant, NULL);
- }
- }
- 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 (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;
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 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);
break;
case VECTOR_CST:
{
- enum machine_mode inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+ 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);
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. */
= 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;
/* 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);
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 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
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 defined (ASM_OUTPUT_TYPE_DIRECTIVE)
if (targetm.has_ifunc_p ())
ASM_OUTPUT_TYPE_DIRECTIVE
- (asm_out_file, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ (asm_out_file, IDENTIFIER_POINTER (id),
IFUNC_ASM_TYPE);
else
#endif
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 !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)->symbol.alias = true;
+ cgraph_node::get_create (decl)->alias = true;
else
- varpool_node_for_decl (decl)->symbol.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->symbol.definition)
+ 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->symbol.definition)
+ 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);
}
}
{
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_P (decl) && DECL_ONE_ONLY (decl))
+ if (decl && DECL_P (decl) && DECL_COMDAT_GROUP (decl))
flags |= SECTION_LINKONCE;
if (strcmp (name, ".vtable_map_vars") == 0)
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)
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);
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 (!targetm.binds_local_p (decl))
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), DECL_COMMON (can be merged
return false;
if (DECL_COMMON (decl)
&& (DECL_INITIAL (decl) == NULL
- || DECL_INITIAL (decl) == error_mark_node))
+ || (!in_lto_p && DECL_INITIAL (decl) == error_mark_node)))
return false;
if (DECL_EXTERNAL (decl))
return false;
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);
}
}
else
{
+ struct symtab_node *snode;
decl = SYMBOL_REF_DECL (symbol);
+
+ 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_low_cst (DECL_SIZE_UNIT (decl), 1);
+ size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
if ((flag_sanitize & SANITIZE_ADDRESS)
&& asan_protect_global (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_sanitize & SANITIZE_ADDRESS)
&& asan_protect_global (decl))
/* 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);