#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "double-int.h"
-#include "input.h"
#include "alias.h"
#include "symtab.h"
-#include "wide-int.h"
-#include "inchash.h"
#include "tree.h"
#include "fold-const.h"
#include "stor-layout.h"
#include "flags.h"
#include "hard-reg-set.h"
#include "function.h"
-#include "hashtab.h"
-#include "statistics.h"
-#include "real.h"
-#include "fixed-value.h"
#include "insn-config.h"
#include "expmed.h"
#include "dojump.h"
#include "regs.h"
#include "output.h"
#include "diagnostic-core.h"
-#include "ggc.h"
#include "langhooks.h"
#include "tm_p.h"
#include "debug.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 "asan.h"
#include "rtl-iter.h"
at the cold section. */
bool in_cold_section_p;
+/* The following global holds the "function name" for the code in the
+ cold section of a function, if hot/cold function splitting is enabled
+ and there was actually code that went into the cold section. A
+ pseudo function name is needed for the cold section of code for some
+ debugging tools that perform symbolization. */
+tree cold_function_name = NULL_TREE;
+
/* A linked list of all the unnamed sections. */
static GTY(()) section *unnamed_sections;
((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
&& DECL_SECTION_NAME (DECL) != NULL)
-struct section_hasher : ggc_hasher<section *>
+struct section_hasher : ggc_ptr_hash<section>
{
typedef const char *compare_type;
/* Hash table of named sections. */
static GTY(()) hash_table<section_hasher> *section_htab;
-struct object_block_hasher : ggc_hasher<object_block *>
+struct object_block_hasher : ggc_ptr_hash<object_block>
{
typedef const section *compare_type;
else
return targetm.asm_out.select_section
(decl, freq == NODE_FREQUENCY_UNLIKELY_EXECUTED,
- DECL_ALIGN (decl));
+ symtab_node::get (decl)->definition_alignment ());
#else
if (targetm.asm_out.function_section)
section = targetm.asm_out.function_section (decl, freq, startup, exit);
return readonly_data_section;
}
+/* A subroutine of mergeable_string_section and mergeable_constant_section. */
+
+static const char *
+function_mergeable_rodata_prefix (void)
+{
+ section *s = targetm.asm_out.function_rodata_section (current_function_decl);
+ if (SECTION_STYLE (s) == SECTION_NAMED)
+ return s->named.name;
+ else
+ return targetm.asm_out.mergeable_rodata_prefix;
+}
+
/* Return the section to use for string merging. */
static section *
const char *str;
HOST_WIDE_INT i;
int j, unit;
- const char *prefix = targetm.asm_out.mergeable_rodata_prefix;
+ const char *prefix = function_mergeable_rodata_prefix ();
char *name = (char *) alloca (strlen (prefix) + 30);
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl)));
&& align <= 256
&& (align & (align - 1)) == 0)
{
- const char *prefix = targetm.asm_out.mergeable_rodata_prefix;
+ const char *prefix = function_mergeable_rodata_prefix ();
char *name = (char *) alloca (strlen (prefix) + 30);
sprintf (name, "%s.cst%d", prefix, (int) (align / 8));
confused with that register and be eliminated. This usage is
somewhat suspect... */
- SET_DECL_RTL (decl, gen_rtx_raw_REG (mode, reg_number));
+ SET_DECL_RTL (decl, gen_raw_REG (mode, reg_number));
ORIGINAL_REGNO (DECL_RTL (decl)) = reg_number;
REG_USERVAR_P (DECL_RTL (decl)) = 1;
void
notice_global_symbol (tree decl)
{
- const char **type = &first_global_object_name;
+ const char **t = &first_global_object_name;
if (first_global_object_name
|| !TREE_PUBLIC (decl)
|| DECL_EXTERNAL (decl)
|| !DECL_NAME (decl)
+ || (TREE_CODE (decl) == VAR_DECL && DECL_HARD_REGISTER (decl))
|| (TREE_CODE (decl) != FUNCTION_DECL
&& (TREE_CODE (decl) != VAR_DECL
|| (DECL_COMMON (decl)
&& (DECL_INITIAL (decl) == 0
- || DECL_INITIAL (decl) == error_mark_node))))
- || !MEM_P (DECL_RTL (decl)))
+ || DECL_INITIAL (decl) == error_mark_node)))))
return;
/* We win when global object is found, but it is useful to know about weak
symbol as well so we can produce nicer unique names. */
if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl) || flag_shlib)
- type = &weak_global_object_name;
+ t = &weak_global_object_name;
- if (!*type)
+ if (!*t)
{
- const char *p;
- const char *name;
- rtx decl_rtl = DECL_RTL (decl);
-
- p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
- name = ggc_strdup (p);
-
- *type = name;
+ tree id = DECL_ASSEMBLER_NAME (decl);
+ ultimate_transparent_alias_target (&id);
+ *t = ggc_strdup (targetm.strip_name_encoding (IDENTIFIER_POINTER (id)));
}
}
ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LCOLDE", const_labelno);
crtl->subsections.cold_section_end_label = ggc_strdup (tmp_label);
const_labelno++;
+ cold_function_name = NULL_TREE;
}
else
{
if (CONSTANT_POOL_BEFORE_FUNCTION)
output_constant_pool (fnname, decl);
+ align = symtab_node::get (decl)->definition_alignment ();
+
/* Make sure the not and cold text (code) sections are properly
aligned. This is necessary here in the case where the function
has both hot and cold sections, because we don't want to re-set
first_function_block_is_cold = false;
switch_to_section (unlikely_text_section ());
- assemble_align (DECL_ALIGN (decl));
+ assemble_align (align);
ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.cold_section_label);
/* When the function starts with a cold section, we need to explicitly
&& BB_PARTITION (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb) == BB_COLD_PARTITION)
{
switch_to_section (text_section);
- assemble_align (DECL_ALIGN (decl));
+ assemble_align (align);
ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label);
hot_label_written = true;
first_function_block_is_cold = true;
ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label);
/* Tell assembler to move to target machine's alignment for functions. */
- align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT);
+ align = floor_log2 (align / BITS_PER_UNIT);
if (align > 0)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
save_text_section = in_section;
switch_to_section (unlikely_text_section ());
+#ifdef ASM_DECLARE_COLD_FUNCTION_SIZE
+ if (cold_function_name != NULL_TREE)
+ ASM_DECLARE_COLD_FUNCTION_SIZE (asm_out_file,
+ IDENTIFIER_POINTER (cold_function_name),
+ decl);
+#endif
ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.cold_section_end_label);
if (first_function_block_is_cold)
switch_to_section (text_section);
unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
{
#if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
+ unsigned int align = symtab_node::get (decl)->definition_alignment ();
ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name,
- size, DECL_ALIGN (decl));
+ size, align);
return true;
#elif defined ASM_OUTPUT_ALIGNED_LOCAL
- ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl));
+ unsigned int align = symtab_node::get (decl)->definition_alignment ();
+ ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, align);
return true;
#else
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)
{
-#if defined ASM_OUTPUT_ALIGNED_BSS
ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size,
get_variable_align (decl));
return true;
-#endif
}
#endif
/* Now construct the SYMBOL_REF and the MEM. */
if (use_object_blocks_p ())
{
- section *sect = get_constant_section (exp, DECL_ALIGN (decl));
+ int align = (TREE_CODE (decl) == CONST_DECL
+ || (TREE_CODE (decl) == VAR_DECL
+ && DECL_IN_CONSTANT_POOL (decl))
+ ? DECL_ALIGN (decl)
+ : symtab_node::get (decl)->definition_alignment ());
+ section *sect = get_constant_section (exp, align);
symbol = create_block_symbol (ggc_strdup (label),
get_block_for_section (sect), -1);
}
{
tree decl = SYMBOL_REF_DECL (symbol);
tree exp = DECL_INITIAL (decl);
- unsigned int align;
bool asan_protected = false;
/* Make sure any other constants whose addresses appear in EXP
place_block_symbol (symbol);
else
{
- align = DECL_ALIGN (decl);
+ int align = (TREE_CODE (decl) == CONST_DECL
+ || (TREE_CODE (decl) == VAR_DECL
+ && DECL_IN_CONSTANT_POOL (decl))
+ ? DECL_ALIGN (decl)
+ : symtab_node::get (decl)->definition_alignment ());
switch_to_section (get_constant_section (exp, align));
if (align > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
int mark;
};
-struct const_rtx_desc_hasher : ggc_hasher<constant_descriptor_rtx *>
+struct const_rtx_desc_hasher : ggc_ptr_hash<constant_descriptor_rtx>
{
static hashval_t hash (constant_descriptor_rtx *);
static bool equal (constant_descriptor_rtx *, constant_descriptor_rtx *);
/* Output the label. */
targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno);
- /* Output the data. */
- output_constant_pool_2 (desc->mode, x, align);
+ /* Output the data.
+ Pass actual alignment value while emitting string constant to asm code
+ as function 'output_constant_pool_1' explicitly passes the alignment as 1
+ assuming that the data is already aligned which prevents the generation
+ of fix-up table entries. */
+ output_constant_pool_2 (desc->mode, x, desc->align);
/* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
sections have proper size. */
to its transaction aware clone. Note that tm_pure functions are
considered to be their own clone. */
-struct tm_clone_hasher : ggc_cache_hasher<tree_map *>
+struct tm_clone_hasher : ggc_cache_ptr_hash<tree_map>
{
static hashval_t hash (tree_map *m) { return tree_map_hash (m); }
static bool equal (tree_map *a, tree_map *b) { return tree_map_eq (a, b); }
- static void handle_cache_entry (tree_map *&e)
+ static int
+ keep_cache_entry (tree_map *&e)
{
- if (e != HTAB_EMPTY_ENTRY || e != HTAB_DELETED_ENTRY)
- {
- extern void gt_ggc_mx (tree_map *&);
- if (ggc_marked_p (e->base.from))
- gt_ggc_mx (e);
- else
- e = static_cast<tree_map *> (HTAB_DELETED_ENTRY);
- }
+ return ggc_marked_p (e->base.from);
}
};
-static GTY((cache))
- hash_table<tm_clone_hasher> *tm_clone_hash;
+static GTY((cache)) hash_table<tm_clone_hasher> *tm_clone_hash;
void
record_tm_clone_pair (tree o, tree n)
|| resolution == LDPR_RESOLVED_EXEC);
}
-static bool
-default_binds_local_p_2 (const_tree exp, bool shlib, bool weak_dominate)
+/* COMMON_LOCAL_P is true means that the linker can guarantee that an
+ uninitialized common symbol in the executable will still be defined
+ (through COPY relocation) in the executable. */
+
+bool
+default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate,
+ bool extern_protected_data, bool common_local_p)
{
/* A non-decl is an entry in the constant pool. */
if (!DECL_P (exp))
because dynamic linking might overwrite symbols
in shared libraries. */
bool resolved_locally = false;
- bool defined_locally = false;
+
+ bool uninited_common = (DECL_COMMON (exp)
+ && (DECL_INITIAL (exp) == NULL
+ || (!in_lto_p
+ && DECL_INITIAL (exp) == error_mark_node)));
+
+ /* A non-external variable is defined locally only if it isn't
+ uninitialized COMMON variable or common_local_p is true. */
+ bool defined_locally = (!DECL_EXTERNAL (exp)
+ && (!uninited_common || common_local_p));
if (symtab_node *node = symtab_node::get (exp))
{
- if (node->definition || node->in_other_partition)
- {
- defined_locally = true;
- resolved_locally = (weak_dominate && !shlib);
- }
+ if (node->in_other_partition)
+ defined_locally = true;
if (resolution_to_local_definition_p (node->resolution))
defined_locally = resolved_locally = true;
else if (resolution_local_p (node->resolution))
resolved_locally = true;
}
+ if (defined_locally && weak_dominate && !shlib)
+ resolved_locally = true;
/* Undefined weak symbols are never defined locally. */
if (DECL_WEAK (exp) && !defined_locally)
or if we have a definition for the symbol. We cannot infer visibility
for undefined symbols. */
if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT
+ && (TREE_CODE (exp) == FUNCTION_DECL
+ || !extern_protected_data
+ || DECL_VISIBILITY (exp) != VISIBILITY_PROTECTED)
&& (DECL_VISIBILITY_SPECIFIED (exp) || defined_locally))
return true;
/* Uninitialized COMMON variable may be unified with symbols
resolved from other modules. */
- if (DECL_COMMON (exp)
- && !resolved_locally
- && (DECL_INITIAL (exp) == NULL
- || (!in_lto_p && DECL_INITIAL (exp) == error_mark_node)))
+ if (uninited_common && !resolved_locally)
return false;
/* Otherwise we're left with initialized (or non-common) global data
bool
default_binds_local_p (const_tree exp)
{
- return default_binds_local_p_2 (exp, flag_shlib != 0, true);
+ return default_binds_local_p_3 (exp, flag_shlib != 0, true, false, false);
+}
+
+/* Similar to default_binds_local_p, but common symbol may be local. */
+
+bool
+default_binds_local_p_2 (const_tree exp)
+{
+ return default_binds_local_p_3 (exp, flag_shlib != 0, true, false,
+ !flag_pic);
}
bool
default_binds_local_p_1 (const_tree exp, int shlib)
{
- return default_binds_local_p_2 (exp, shlib != 0, false);
+ return default_binds_local_p_3 (exp, shlib != 0, false, false, false);
}
/* Return true when references to DECL must bind to current definition in
fputs (ASM_APP_OFF, asm_out_file);
if (targetm.asm_file_start_file_directive)
- output_file_directive (asm_out_file, main_input_filename);
+ {
+ /* LTO produced units have no meaningful main_input_filename. */
+ if (in_lto_p)
+ output_file_directive (asm_out_file, "<artificial>");
+ else
+ output_file_directive (asm_out_file, main_input_filename);
+ }
}
/* This is a generic routine suitable for use as TARGET_ASM_FILE_END
else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol))
{
decl = SYMBOL_REF_DECL (symbol);
+ gcc_checking_assert (DECL_IN_CONSTANT_POOL (decl));
alignment = DECL_ALIGN (decl);
size = get_constant_size (DECL_INITIAL (decl));
if ((flag_sanitize & SANITIZE_ADDRESS)
if (CONSTANT_POOL_ADDRESS_P (symbol))
{
desc = SYMBOL_REF_CONSTANT (symbol);
+ /* Pass 1 for align as we have already laid out everything in the block.
+ So aligning shouldn't be necessary. */
output_constant_pool_1 (desc, 1);
offset += GET_MODE_SIZE (desc->mode);
}
{
HOST_WIDE_INT size;
decl = SYMBOL_REF_DECL (symbol);
- assemble_constant_contents (DECL_INITIAL (decl), XSTR (symbol, 0),
- DECL_ALIGN (decl));
+ assemble_constant_contents
+ (DECL_INITIAL (decl), XSTR (symbol, 0), DECL_ALIGN (decl));
+
size = get_constant_size (DECL_INITIAL (decl));
offset += size;
if ((flag_sanitize & SANITIZE_ADDRESS)
}
}
-/* A htab_traverse callback used to call output_object_block for
- each member of object_block_htab. */
+/* A callback for qsort to compare object_blocks. */
-int
-output_object_block_htab (object_block **slot, void *)
+static int
+output_object_block_compare (const void *x, const void *y)
{
- output_object_block (*slot);
- return 1;
+ object_block *p1 = *(object_block * const*)x;
+ object_block *p2 = *(object_block * const*)y;
+
+ if (p1->sect->common.flags & SECTION_NAMED
+ && !(p2->sect->common.flags & SECTION_NAMED))
+ return 1;
+
+ if (!(p1->sect->common.flags & SECTION_NAMED)
+ && p2->sect->common.flags & SECTION_NAMED)
+ return -1;
+
+ if (p1->sect->common.flags & SECTION_NAMED
+ && p2->sect->common.flags & SECTION_NAMED)
+ return strcmp (p1->sect->named.name, p2->sect->named.name);
+
+ unsigned f1 = p1->sect->common.flags;
+ unsigned f2 = p2->sect->common.flags;
+ if (f1 == f2)
+ return 0;
+ return f1 < f2 ? -1 : 1;
}
/* Output the definitions of all object_blocks. */
void
output_object_blocks (void)
{
- object_block_htab->traverse<void *, output_object_block_htab> (NULL);
+ vec<object_block *, va_heap> v;
+ v.create (object_block_htab->elements ());
+ object_block *obj;
+ hash_table<object_block_hasher>::iterator hi;
+
+ FOR_EACH_HASH_TABLE_ELEMENT (*object_block_htab, obj, object_block *, hi)
+ v.quick_push (obj);
+
+ /* Sort them in order to output them in a deterministic manner,
+ otherwise we may get .rodata sections in different orders with
+ and without -g. */
+ v.qsort (output_object_block_compare);
+ unsigned i;
+ FOR_EACH_VEC_ELT (v, i, obj)
+ output_object_block (obj);
+
+ v.release ();
}
/* This function provides a possible implementation of the