X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gcc%2Fvarasm.c;h=84df52013d7096253da5cfe206f51b1fd07c63a5;hb=eada42206385b31baa5bb62d78115b2ac2730e7b;hp=1e7c2b523c107e37a55f0542ea65cfe30aca4bf1;hpb=6f8bb7637206ba0ea0b736dc3528bbb76d074c47;p=platform%2Fupstream%2Fgcc.git diff --git a/gcc/varasm.c b/gcc/varasm.c index 1e7c2b5..84df520 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -1,5 +1,5 @@ /* Output variables, constants and external declarations, for GNU compiler. - Copyright (C) 1987-2016 Free Software Foundation, Inc. + Copyright (C) 1987-2020 Free Software Foundation, Inc. This file is part of GCC. @@ -47,12 +47,16 @@ along with GCC; see the file COPYING3. If not see #include "stmt.h" #include "expr.h" #include "expmed.h" +#include "optabs.h" #include "output.h" #include "langhooks.h" #include "debug.h" #include "common/common-target.h" +#include "stringpool.h" +#include "attribs.h" #include "asan.h" #include "rtl-iter.h" +#include "file-prefix-map.h" /* remap_debug_filename() */ #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data declarations. */ @@ -65,8 +69,8 @@ extern GTY(()) const char *weak_global_object_name; const char *first_global_object_name; const char *weak_global_object_name; -struct addr_const; -struct constant_descriptor_rtx; +class addr_const; +class constant_descriptor_rtx; struct rtx_constant_pool; #define n_deferred_constants (crtl->varasm.deferred_constants) @@ -102,13 +106,13 @@ static int contains_pointers_p (tree); #ifdef ASM_OUTPUT_EXTERNAL static bool incorporeal_function_p (tree); #endif -static void decode_addr_const (tree, struct addr_const *); +static void decode_addr_const (tree, class addr_const *); static hashval_t const_hash_1 (const tree); static int compare_constant (const tree, const tree); static void output_constant_def_contents (rtx); -static void output_addressed_constants (tree); +static void output_addressed_constants (tree, int); static unsigned HOST_WIDE_INT output_constant (tree, unsigned HOST_WIDE_INT, - unsigned int, bool); + unsigned int, bool, bool); static void globalize_decl (tree); static bool decl_readonly_section_1 (enum section_category); #ifdef BSS_SECTION_ASM_OP @@ -222,7 +226,7 @@ hash_section (section *sect) { if (sect->common.flags & SECTION_NAMED) return htab_hash_string (sect->named.name); - return sect->common.flags; + return sect->common.flags & ~SECTION_DECLARED; } /* Helper routines for maintaining object_block_htab. */ @@ -293,6 +297,17 @@ get_section (const char *name, unsigned int flags, tree decl) else { sect = *slot; + /* It is fine if one of the sections has SECTION_NOTYPE as long as + the other has none of the contrary flags (see the logic at the end + of default_section_type_flags, below). */ + if (((sect->common.flags ^ flags) & SECTION_NOTYPE) + && !((sect->common.flags | flags) + & (SECTION_CODE | SECTION_BSS | SECTION_TLS | SECTION_ENTSIZE + | (HAVE_COMDAT_GROUP ? SECTION_LINKONCE : 0)))) + { + sect->common.flags |= SECTION_NOTYPE; + flags |= SECTION_NOTYPE; + } if ((sect->common.flags & ~SECTION_DECLARED) != flags && ((sect->common.flags | flags) & SECTION_OVERRIDE) == 0) { @@ -320,15 +335,15 @@ get_section (const char *name, unsigned int flags, tree decl) && decl != sect->named.decl) { if (decl != NULL && DECL_P (decl)) - error ("%+D causes a section type conflict with %D", + error ("%+qD causes a section type conflict with %qD", decl, sect->named.decl); else - error ("section type conflict with %D", sect->named.decl); + error ("section type conflict with %qD", 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); + error ("%+qD causes a section type conflict", decl); else error ("section type conflict"); /* Make sure we don't error about one section multiple times. */ @@ -349,7 +364,11 @@ use_object_blocks_p (void) /* Return the object_block structure for section SECT. Create a new structure if we haven't created one already. Return null if SECT - itself is null. */ + itself is null. Return also null for mergeable sections since + section anchors can't be used in mergeable sections anyway, + because the linker might move objects around, and using the + object blocks infrastructure in that case is both a waste and a + maintenance burden. */ static struct object_block * get_block_for_section (section *sect) @@ -359,6 +378,9 @@ get_block_for_section (section *sect) if (sect == NULL) return NULL; + if (sect->common.flags & SECTION_MERGE) + return NULL; + object_block **slot = object_block_htab->find_slot_with_hash (sect, hash_section (sect), INSERT); @@ -567,9 +589,13 @@ default_function_section (tree decl, enum node_frequency freq, where we can split away unnecessary parts of static constructors. */ if (startup && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED) { - /* 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) + /* During LTO the tp_first_run profiling will naturally place all + initialization code first. Using separate section is counter-productive + because startup only code may call functions which are no longer + startup only. */ + if (!in_lto_p + || !cgraph_node::get (decl)->tp_first_run + || !opt_for_fn (decl, flag_profile_reorder_functions)) return get_named_text_section (decl, ".text.startup", NULL); else return NULL; @@ -585,10 +611,7 @@ default_function_section (tree decl, enum node_frequency freq, case NODE_FREQUENCY_UNLIKELY_EXECUTED: return get_named_text_section (decl, ".text.unlikely", NULL); case NODE_FREQUENCY_HOT: - /* 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); + return get_named_text_section (decl, ".text.hot", NULL); /* FALLTHRU */ default: return NULL; @@ -693,6 +716,16 @@ unlikely_text_section_p (section *sect) return sect == function_section_1 (current_function_decl, true); } +/* Switch to the other function partition (if inside of hot section + into cold section, otherwise into the hot section). */ + +void +switch_to_other_text_partition (void) +{ + in_cold_section_p = !in_cold_section_p; + switch_to_section (current_function_section ()); +} + /* Return the read-only data section associated with function DECL. */ section * @@ -781,9 +814,9 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED, && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE && align <= 256 && (len = int_size_in_bytes (TREE_TYPE (decl))) > 0 - && TREE_STRING_LENGTH (decl) >= len) + && TREE_STRING_LENGTH (decl) == len) { - machine_mode mode; + scalar_int_mode mode; unsigned int modesize; const char *str; HOST_WIDE_INT i; @@ -791,7 +824,7 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED, const char *prefix = function_mergeable_rodata_prefix (); char *name = (char *) alloca (strlen (prefix) + 30); - mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl))); + mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (TREE_TYPE (decl))); modesize = GET_MODE_BITSIZE (mode); if (modesize >= 8 && modesize <= 256 && (modesize & (modesize - 1)) == 0) @@ -799,6 +832,9 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED, if (align < modesize) align = modesize; + if (!HAVE_LD_ALIGNED_SHF_MERGE && align > 8) + return readonly_data_section; + str = TREE_STRING_POINTER (decl); unit = GET_MODE_SIZE (mode); @@ -811,7 +847,7 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED, if (j == unit) break; } - if (i == len - unit) + if (i == len - unit || (unit == 1 && i == len)) { sprintf (name, "%s.str%d.%d", prefix, modesize / 8, (int) (align / 8)); @@ -831,15 +867,14 @@ mergeable_constant_section (machine_mode mode ATTRIBUTE_UNUSED, unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) { - unsigned int modesize = GET_MODE_BITSIZE (mode); - if (HAVE_GAS_SHF_MERGE && flag_merge_constants && mode != VOIDmode && mode != BLKmode - && modesize <= align + && known_le (GET_MODE_BITSIZE (mode), align) && align >= 8 && align <= 256 - && (align & (align - 1)) == 0) + && (align & (align - 1)) == 0 + && (HAVE_LD_ALIGNED_SHF_MERGE ? 1 : align == 8)) { const char *prefix = function_mergeable_rodata_prefix (); char *name = (char *) alloca (strlen (prefix) + 30); @@ -972,18 +1007,18 @@ decode_reg_name (const char *name) /* Return true if DECL's initializer is suitable for a BSS section. */ bool -bss_initializer_p (const_tree decl) +bss_initializer_p (const_tree decl, bool named) { - return (DECL_INITIAL (decl) == NULL - /* 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. */ - && !TREE_READONLY (decl) - && initializer_zerop (DECL_INITIAL (decl)))); + /* Do not put non-common constants into the .bss section, they belong in + a readonly section, except when NAMED is true. */ + return ((!TREE_READONLY (decl) || DECL_COMMON (decl) || named) + && (DECL_INITIAL (decl) == NULL + /* 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 + && initializer_zerop (DECL_INITIAL (decl))))); } /* Compute the alignment of variable specified by DECL. @@ -1043,7 +1078,7 @@ align_variable (tree decl, bool dont_output_data) && (in_lto_p || DECL_INITIAL (decl) != error_mark_node)) { unsigned int const_align - = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align); + = targetm.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) @@ -1094,8 +1129,8 @@ get_variable_align (tree decl) to mark offlined constructors. */ && (in_lto_p || DECL_INITIAL (decl) != error_mark_node)) { - unsigned int const_align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), - align); + unsigned int const_align + = targetm.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) @@ -1154,7 +1189,8 @@ get_variable_section (tree decl, bool prefer_noswitch_p) { section *sect = get_named_section (decl, NULL, reloc); - if ((sect->common.flags & SECTION_BSS) && !bss_initializer_p (decl)) + if ((sect->common.flags & SECTION_BSS) + && !bss_initializer_p (decl, true)) { error_at (DECL_SOURCE_LOCATION (decl), "only zero initializers are allowed in section %qs", @@ -1241,10 +1277,9 @@ use_blocks_for_decl_p (tree decl) if (!VAR_P (decl) && TREE_CODE (decl) != CONST_DECL) return false; - /* Detect decls created by dw2_force_const_mem. Such decls are - special because DECL_INITIAL doesn't specify the decl's true value. - dw2_output_indirect_constants will instead call assemble_variable - with dont_output_data set to 1 and then print the contents itself. */ + /* DECL_INITIAL (decl) set to decl is a hack used for some decls that + are never used from code directly and we never want object block handling + for those. */ if (DECL_INITIAL (decl) == decl) return false; @@ -1355,10 +1390,6 @@ make_decl_rtl (tree 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 @@ -1385,7 +1416,7 @@ make_decl_rtl (tree decl) else if (!in_hard_reg_set_p (operand_reg_set, mode, reg_number)) error ("the register specified for %q+D is not general enough" " to be used as a register variable", decl); - else if (!HARD_REGNO_MODE_OK (reg_number, mode)) + else if (!targetm.hard_regno_mode_ok (reg_number, mode)) error ("register specified for %q+D isn%'t suitable for data type", decl); /* Now handle properly declared static register variables. */ @@ -1420,7 +1451,7 @@ make_decl_rtl (tree decl) name = IDENTIFIER_POINTER (DECL_NAME (decl)); ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name); #endif - nregs = hard_regno_nregs[reg_number][mode]; + nregs = hard_regno_nregs (reg_number, mode); while (nregs > 0) globalize_reg (decl, reg_number + --nregs); } @@ -1670,10 +1701,6 @@ decide_function_section (tree decl) { first_function_block_is_cold = false; - if (flag_reorder_blocks_and_partition) - /* We will decide in assemble_start_function. */ - return; - if (DECL_SECTION_NAME (decl)) { struct cgraph_node *node = cgraph_node::get (current_function_decl); @@ -1711,7 +1738,7 @@ assemble_start_function (tree decl, const char *fnname) char tmp_label[100]; bool hot_label_written = false; - if (flag_reorder_blocks_and_partition) + if (crtl->has_bb_partition) { ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LHOTB", const_labelno); crtl->subsections.hot_section_label = ggc_strdup (tmp_label); @@ -1746,7 +1773,7 @@ assemble_start_function (tree decl, const char *fnname) has both hot and cold sections, because we don't want to re-set the alignment when the section switch happens mid-function. */ - if (flag_reorder_blocks_and_partition) + if (crtl->has_bb_partition) { first_function_block_is_cold = false; @@ -1773,8 +1800,7 @@ assemble_start_function (tree decl, const char *fnname) /* Switch to the correct text section for the start of the function. */ switch_to_section (function_section (decl)); - if (flag_reorder_blocks_and_partition - && !hot_label_written) + if (crtl->has_bb_partition && !hot_label_written) ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label); /* Tell assembler to move to target machine's alignment for functions. */ @@ -1788,21 +1814,25 @@ assemble_start_function (tree decl, const char *fnname) Note that we still need to align to DECL_ALIGN, as above, because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all. */ if (! DECL_USER_ALIGN (decl) - && align_functions_log > align + && align_functions.levels[0].log > align && optimize_function_for_speed_p (cfun)) { #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN - int align_log = align_functions_log; + int align_log = align_functions.levels[0].log; #endif - int max_skip = align_functions - 1; + int max_skip = align_functions.levels[0].maxskip; if (flag_limit_function_alignment && crtl->max_insn_address > 0 && max_skip >= crtl->max_insn_address) max_skip = crtl->max_insn_address - 1; #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file, align_log, max_skip); + if (max_skip == align_functions.levels[0].maxskip) + ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file, + align_functions.levels[1].log, + align_functions.levels[1].maxskip); #else - ASM_OUTPUT_ALIGN (asm_out_file, align_functions_log); + ASM_OUTPUT_ALIGN (asm_out_file, align_functions.levels[0].log); #endif } @@ -1815,10 +1845,7 @@ assemble_start_function (tree decl, const char *fnname) /* Make function name accessible from other files, if appropriate. */ - 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))) + if (TREE_PUBLIC (decl)) { notice_global_symbol (decl); @@ -1830,6 +1857,14 @@ assemble_start_function (tree decl, const char *fnname) if (DECL_PRESERVE_P (decl)) targetm.asm_out.mark_decl_preserved (fnname); + unsigned short patch_area_size = crtl->patch_area_size; + unsigned short patch_area_entry = crtl->patch_area_entry; + + /* Emit the patching area before the entry label, if any. */ + if (patch_area_entry > 0) + targetm.asm_out.print_patchable_function_entry (asm_out_file, + patch_area_entry, true); + /* Do any machine/system dependent processing of the function name. */ #ifdef ASM_DECLARE_FUNCTION_NAME ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl); @@ -1838,6 +1873,13 @@ assemble_start_function (tree decl, const char *fnname) ASM_OUTPUT_FUNCTION_LABEL (asm_out_file, fnname, current_function_decl); #endif /* ASM_DECLARE_FUNCTION_NAME */ + /* And the area after the label. Record it if we haven't done so yet. */ + if (patch_area_size > patch_area_entry) + targetm.asm_out.print_patchable_function_entry (asm_out_file, + patch_area_size + - patch_area_entry, + patch_area_entry == 0); + if (lookup_attribute ("no_split_stack", DECL_ATTRIBUTES (decl))) saw_no_split_stack = true; } @@ -1850,7 +1892,7 @@ assemble_end_function (tree decl, const char *fnname ATTRIBUTE_UNUSED) { #ifdef ASM_DECLARE_FUNCTION_SIZE /* We could have switched section in the middle of the function. */ - if (flag_reorder_blocks_and_partition) + if (crtl->has_bb_partition) switch_to_section (function_section (decl)); ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl); #endif @@ -1861,7 +1903,7 @@ assemble_end_function (tree decl, const char *fnname ATTRIBUTE_UNUSED) } /* Output labels for end of hot/cold text sections (to be used by debug info.) */ - if (flag_reorder_blocks_and_partition) + if (crtl->has_bb_partition) { section *save_text_section; @@ -1910,7 +1952,7 @@ assemble_zeros (unsigned HOST_WIDE_INT size) /* Assemble an alignment pseudo op for an ALIGN-bit boundary. */ void -assemble_align (int align) +assemble_align (unsigned int align) { if (align > BITS_PER_UNIT) { @@ -2057,7 +2099,7 @@ assemble_noswitch_variable (tree decl, const char *name, section *sect, static void assemble_variable_contents (tree decl, const char *name, - bool dont_output_data) + bool dont_output_data, bool merge_strings) { /* Do any machine/system dependent processing of the object. */ #ifdef ASM_DECLARE_OBJECT_NAME @@ -2080,7 +2122,7 @@ assemble_variable_contents (tree decl, const char *name, output_constant (DECL_INITIAL (decl), tree_to_uhwi (DECL_SIZE_UNIT (decl)), get_variable_align (decl), - false); + false, merge_strings); else /* Leave space for it. */ assemble_zeros (tree_to_uhwi (DECL_SIZE_UNIT (decl))); @@ -2230,7 +2272,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, /* Output any data that we will need to use the address of. */ if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node) - output_addressed_constants (DECL_INITIAL (decl)); + output_addressed_constants (DECL_INITIAL (decl), 0); /* dbxout.c needs to know this. */ if (sect && (sect->common.flags & SECTION_CODE) != 0) @@ -2256,7 +2298,9 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, 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); + assemble_variable_contents (decl, name, dont_output_data, + (sect->common.flags & SECTION_MERGE) + && (sect->common.flags & SECTION_STRINGS)); if (asan_protected) { unsigned HOST_WIDE_INT int size @@ -2341,13 +2385,12 @@ static hash_set *pending_assemble_externals_set; static bool incorporeal_function_p (tree decl) { - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)) + if (TREE_CODE (decl) == FUNCTION_DECL && fndecl_built_in_p (decl)) { const char *name; if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL - && (DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA - || DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA_WITH_ALIGN)) + && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (decl))) return true; name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); @@ -2408,7 +2451,7 @@ assemble_external (tree decl ATTRIBUTE_UNUSED) gcc_assert (asm_out_file); /* In a perfect world, the following condition would be true. - Sadly, the Java and Go front ends emit assembly *from the front end*, + Sadly, the Go front end emit assembly *from the front end*, bypassing the call graph. See PR52739. Fix before GCC 4.8. */ #if 0 /* This function should only be called if we are expanding, or have @@ -2520,20 +2563,16 @@ assemble_name_raw (FILE *file, const char *name) ASM_OUTPUT_LABELREF (file, name); } -/* Like assemble_name_raw, but should be used when NAME might refer to - an entity that is also represented as a tree (like a function or - variable). If NAME does refer to such an entity, that entity will - be marked as referenced. */ - -void -assemble_name (FILE *file, const char *name) +/* Return NAME that should actually be emitted, looking through + transparent aliases. If NAME refers to an entity that is also + represented as a tree (like a function or variable), mark the entity + as referenced. */ +const char * +assemble_name_resolve (const char *name) { - const char *real_name; - tree id; + const char *real_name = targetm.strip_name_encoding (name); + tree id = maybe_get_identifier (real_name); - real_name = targetm.strip_name_encoding (name); - - id = maybe_get_identifier (real_name); if (id) { tree id_orig = id; @@ -2545,7 +2584,18 @@ assemble_name (FILE *file, const char *name) gcc_assert (! TREE_CHAIN (id)); } - assemble_name_raw (file, name); + return name; +} + +/* Like assemble_name_raw, but should be used when NAME might refer to + an entity that is also represented as a tree (like a function or + variable). If NAME does refer to such an entity, that entity will + be marked as referenced. */ + +void +assemble_name (FILE *file, const char *name) +{ + assemble_name_raw (file, assemble_name_resolve (name)); } /* Allocate SIZE bytes writable static space with a gensym name @@ -2668,10 +2718,24 @@ integer_asm_op (int size, int aligned_p) return targetm.asm_out.byte_op; case 2: return ops->hi; + case 3: + return ops->psi; case 4: return ops->si; + case 5: + case 6: + case 7: + return ops->pdi; case 8: return ops->di; + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + return ops->pti; case 16: return ops->ti; default: @@ -2737,8 +2801,8 @@ assemble_integer (rtx x, unsigned int size, unsigned int align, int force) else mclass = MODE_INT; - omode = mode_for_size (subsize * BITS_PER_UNIT, mclass, 0); - imode = mode_for_size (size * BITS_PER_UNIT, mclass, 0); + omode = mode_for_size (subsize * BITS_PER_UNIT, mclass, 0).require (); + imode = mode_for_size (size * BITS_PER_UNIT, mclass, 0).require (); for (i = 0; i < size; i += subsize) { @@ -2764,7 +2828,7 @@ assemble_integer (rtx x, unsigned int size, unsigned int align, int force) in reverse storage order. */ void -assemble_real (REAL_VALUE_TYPE d, machine_mode mode, unsigned int align, +assemble_real (REAL_VALUE_TYPE d, scalar_float_mode mode, unsigned int align, bool reverse) { long data[4] = {0, 0, 0, 0}; @@ -2791,25 +2855,27 @@ assemble_real (REAL_VALUE_TYPE d, machine_mode mode, unsigned int align, real_to_target (data, &d, mode); /* Put out the first word with the specified alignment. */ + unsigned int chunk_nunits = MIN (nunits, units_per); if (reverse) elt = flip_storage_order (SImode, gen_int_mode (data[nelts - 1], SImode)); else - elt = GEN_INT (data[0]); - assemble_integer (elt, MIN (nunits, units_per), align, 1); - nunits -= units_per; + elt = GEN_INT (sext_hwi (data[0], chunk_nunits * BITS_PER_UNIT)); + assemble_integer (elt, chunk_nunits, align, 1); + nunits -= chunk_nunits; /* Subsequent words need only 32-bit alignment. */ align = min_align (align, 32); for (int i = 1; i < nelts; i++) { + chunk_nunits = MIN (nunits, units_per); if (reverse) elt = flip_storage_order (SImode, gen_int_mode (data[nelts - 1 - i], SImode)); else - elt = GEN_INT (data[i]); - assemble_integer (elt, MIN (nunits, units_per), align, 1); - nunits -= units_per; + elt = GEN_INT (sext_hwi (data[i], chunk_nunits * BITS_PER_UNIT)); + assemble_integer (elt, chunk_nunits, align, 1); + nunits -= chunk_nunits; } } @@ -2818,37 +2884,42 @@ assemble_real (REAL_VALUE_TYPE d, machine_mode mode, unsigned int align, Store them both in the structure *VALUE. EXP must be reducible. */ -struct addr_const { +class addr_const { +public: rtx base; - HOST_WIDE_INT offset; + poly_int64 offset; }; static void -decode_addr_const (tree exp, struct addr_const *value) +decode_addr_const (tree exp, class addr_const *value) { tree target = TREE_OPERAND (exp, 0); - int offset = 0; + poly_int64 offset = 0; rtx x; while (1) { + poly_int64 bytepos; if (TREE_CODE (target) == COMPONENT_REF - && tree_fits_shwi_p (byte_position (TREE_OPERAND (target, 1)))) + && poly_int_tree_p (byte_position (TREE_OPERAND (target, 1)), + &bytepos)) { - offset += int_byte_position (TREE_OPERAND (target, 1)); + offset += bytepos; target = TREE_OPERAND (target, 0); } else if (TREE_CODE (target) == ARRAY_REF || TREE_CODE (target) == ARRAY_RANGE_REF) { - offset += (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (target))) - * tree_to_shwi (TREE_OPERAND (target, 1))); + /* Truncate big offset. */ + offset + += (TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (target))) + * wi::to_poly_widest (TREE_OPERAND (target, 1)).force_shwi ()); 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).to_short_addr (); + offset += mem_ref_offset (target).force_shwi (); target = TREE_OPERAND (TREE_OPERAND (target, 0), 0); } else if (TREE_CODE (target) == INDIRECT_REF @@ -2878,7 +2949,21 @@ decode_addr_const (tree exp, struct addr_const *value) case COMPLEX_CST: case CONSTRUCTOR: case INTEGER_CST: - x = output_constant_def (target, 1); + x = lookup_constant_def (target); + /* Should have been added by output_addressed_constants. */ + gcc_assert (x); + break; + + case INDIRECT_REF: + /* This deals with absolute addresses. */ + offset += tree_to_shwi (TREE_OPERAND (target, 0)); + x = gen_rtx_MEM (QImode, + gen_rtx_SYMBOL_REF (Pmode, "origin of addresses")); + break; + + case COMPOUND_LITERAL_EXPR: + gcc_assert (COMPOUND_LITERAL_EXPR_DECL (target)); + x = DECL_RTL (COMPOUND_LITERAL_EXPR_DECL (target)); break; default: @@ -2947,13 +3032,11 @@ const_hash_1 (const tree exp) case VECTOR_CST: { - unsigned i; - - hi = 7 + VECTOR_CST_NELTS (exp); - - for (i = 0; i < VECTOR_CST_NELTS (exp); ++i) - hi = hi * 563 + const_hash_1 (VECTOR_CST_ELT (exp, i)); - + hi = 7 + VECTOR_CST_NPATTERNS (exp); + hi = hi * 563 + VECTOR_CST_NELTS_PER_PATTERN (exp); + unsigned int count = vector_cst_encoded_nelts (exp); + for (unsigned int i = 0; i < count; ++i) + hi = hi * 563 + const_hash_1 (VECTOR_CST_ENCODED_ELT (exp, i)); return hi; } @@ -2972,9 +3055,13 @@ const_hash_1 (const tree exp) } case ADDR_EXPR: + if (CONSTANT_CLASS_P (TREE_OPERAND (exp, 0))) + return const_hash_1 (TREE_OPERAND (exp, 0)); + + /* Fallthru. */ case FDESC_EXPR: { - struct addr_const value; + class addr_const value; decode_addr_const (exp, &value); switch (GET_CODE (value.base)) @@ -2982,14 +3069,14 @@ const_hash_1 (const tree exp) case SYMBOL_REF: /* Don't hash the address of the SYMBOL_REF; only use the offset and the symbol name. */ - hi = value.offset; + hi = value.offset.coeffs[0]; p = XSTR (value.base, 0); for (i = 0; p[i] != 0; i++) hi = ((hi * 613) + (unsigned) (p[i])); break; case LABEL_REF: - hi = (value.offset + hi = (value.offset.coeffs[0] + CODE_LABEL_NUMBER (label_ref_label (value.base)) * 13); break; @@ -3058,10 +3145,16 @@ compare_constant (const tree t1, const tree t2) return tree_int_cst_equal (t1, t2); case REAL_CST: - /* Real constants are the same only if the same width of type. */ + /* Real constants are the same only if the same width of type. In + addition to the same width, we need to check whether the modes are the + same. There might be two floating point modes that are the same size + but have different representations, such as the PowerPC that has 2 + different 128-bit floating point types (IBM extended double and IEEE + 128-bit floating point). */ if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2))) return 0; - + if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))) + return 0; return real_identical (&TREE_REAL_CST (t1), &TREE_REAL_CST (t2)); case FIXED_CST: @@ -3072,7 +3165,9 @@ compare_constant (const tree t1, const tree t2) return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), TREE_FIXED_CST (t2)); case STRING_CST: - if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))) + if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)) + || int_size_in_bytes (TREE_TYPE (t1)) + != int_size_in_bytes (TREE_TYPE (t2))) return 0; return (TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) @@ -3085,14 +3180,18 @@ compare_constant (const tree t1, const tree t2) case VECTOR_CST: { - unsigned i; + if (VECTOR_CST_NPATTERNS (t1) + != VECTOR_CST_NPATTERNS (t2)) + return 0; - if (VECTOR_CST_NELTS (t1) != VECTOR_CST_NELTS (t2)) + if (VECTOR_CST_NELTS_PER_PATTERN (t1) + != VECTOR_CST_NELTS_PER_PATTERN (t2)) return 0; - for (i = 0; i < VECTOR_CST_NELTS (t1); ++i) - if (!compare_constant (VECTOR_CST_ELT (t1, i), - VECTOR_CST_ELT (t2, i))) + unsigned int count = vector_cst_encoded_nelts (t1); + for (unsigned int i = 0; i < count; ++i) + if (!compare_constant (VECTOR_CST_ENCODED_ELT (t1, i), + VECTOR_CST_ENCODED_ELT (t2, i))) return 0; return 1; @@ -3158,14 +3257,14 @@ compare_constant (const tree t1, const tree t2) case ADDR_EXPR: case FDESC_EXPR: { - struct addr_const value1, value2; + class addr_const value1, value2; enum rtx_code code; int ret; decode_addr_const (t1, &value1); decode_addr_const (t2, &value2); - if (value1.offset != value2.offset) + if (maybe_ne (value1.offset, value2.offset)) return 0; code = GET_CODE (value1.base); @@ -3225,8 +3324,9 @@ get_constant_size (tree exp) HOST_WIDE_INT size; size = int_size_in_bytes (TREE_TYPE (exp)); - if (TREE_CODE (exp) == STRING_CST) - size = MAX (TREE_STRING_LENGTH (exp), size); + gcc_checking_assert (size >= 0); + gcc_checking_assert (TREE_CODE (exp) != STRING_CST + || size >= TREE_STRING_LENGTH (exp)); return size; } @@ -3266,14 +3366,20 @@ build_constant_desc (tree exp) Instead we set the flag that will be recognized in make_decl_rtl. */ DECL_IN_CONSTANT_POOL (decl) = 1; DECL_INITIAL (decl) = desc->value; - /* ??? CONSTANT_ALIGNMENT hasn't been updated for vector types on most - architectures so use DATA_ALIGNMENT as well, except for strings. */ + /* ??? targetm.constant_alignment hasn't been updated for vector types on + most architectures so use DATA_ALIGNMENT as well, except for strings. */ if (TREE_CODE (exp) == STRING_CST) + SET_DECL_ALIGN (decl, targetm.constant_alignment (exp, DECL_ALIGN (decl))); + else { - SET_DECL_ALIGN (decl, CONSTANT_ALIGNMENT (exp, DECL_ALIGN (decl))); + align_variable (decl, 0); + if (DECL_ALIGN (decl) < GET_MODE_ALIGNMENT (DECL_MODE (decl)) + && ((optab_handler (movmisalign_optab, DECL_MODE (decl)) + != CODE_FOR_nothing) + || targetm.slow_unaligned_access (DECL_MODE (decl), + DECL_ALIGN (decl)))) + SET_DECL_ALIGN (decl, GET_MODE_ALIGNMENT (DECL_MODE (decl))); } - else - align_variable (decl, 0); /* Now construct the SYMBOL_REF and the MEM. */ if (use_object_blocks_p ()) @@ -3293,9 +3399,12 @@ build_constant_desc (tree exp) TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1; rtl = gen_const_mem (TYPE_MODE (TREE_TYPE (exp)), symbol); - set_mem_attributes (rtl, exp, 1); set_mem_alias_set (rtl, 0); + /* Putting EXP into the literal pool might have imposed a different + alignment which should be visible in the RTX as well. */ + set_mem_align (rtl, DECL_ALIGN (decl)); + /* We cannot share RTX'es in pool entries. Mark this piece of RTL as required for unsharing. */ RTX_FLAG (rtl, used) = 1; @@ -3312,6 +3421,43 @@ build_constant_desc (tree exp) return desc; } +/* Subroutine of output_constant_def and tree_output_constant_def: + Add a constant to the hash table that tracks which constants + already have labels. */ + +static constant_descriptor_tree * +add_constant_to_table (tree exp, int defer) +{ + /* The hash table methods may call output_constant_def for addressed + constants, so handle them first. */ + output_addressed_constants (exp, defer); + + /* Sanity check to catch recursive insertion. */ + static bool inserting; + gcc_assert (!inserting); + inserting = true; + + /* Look up EXP in the table of constant descriptors. If we didn't + find it, create a new one. */ + struct constant_descriptor_tree key; + key.value = exp; + key.hash = const_hash_1 (exp); + constant_descriptor_tree **loc + = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT); + + inserting = false; + + struct constant_descriptor_tree *desc = *loc; + if (!desc) + { + desc = build_constant_desc (exp); + desc->hash = key.hash; + *loc = desc; + } + + return desc; +} + /* Return an rtx representing a reference to constant data in memory for the constant expression EXP. @@ -3328,24 +3474,7 @@ build_constant_desc (tree exp) rtx output_constant_def (tree exp, int defer) { - struct constant_descriptor_tree *desc; - struct constant_descriptor_tree key; - - /* 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); - constant_descriptor_tree **loc - = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT); - - desc = *loc; - if (desc == 0) - { - desc = build_constant_desc (exp); - desc->hash = key.hash; - *loc = desc; - } - + struct constant_descriptor_tree *desc = add_constant_to_table (exp, defer); maybe_output_constant_def_contents (desc, defer); return desc->rtl; } @@ -3388,7 +3517,8 @@ maybe_output_constant_def_contents (struct constant_descriptor_tree *desc, constant's alignment in bits. */ static void -assemble_constant_contents (tree exp, const char *label, unsigned int align) +assemble_constant_contents (tree exp, const char *label, unsigned int align, + bool merge_strings) { HOST_WIDE_INT size; @@ -3398,7 +3528,7 @@ assemble_constant_contents (tree exp, const char *label, unsigned int align) targetm.asm_out.declare_constant_name (asm_out_file, label, exp, size); /* Output the value of EXP. */ - output_constant (exp, size, align, false); + output_constant (exp, size, align, false, merge_strings); targetm.asm_out.decl_end (); } @@ -3414,7 +3544,7 @@ output_constant_def_contents (rtx symbol) /* Make sure any other constants whose addresses appear in EXP are assigned label numbers. */ - output_addressed_constants (exp); + output_addressed_constants (exp, 0); /* We are no longer deferring this constant. */ TREE_ASM_WRITTEN (decl) = TREE_ASM_WRITTEN (exp) = 1; @@ -3439,10 +3569,13 @@ output_constant_def_contents (rtx symbol) || (VAR_P (decl) && DECL_IN_CONSTANT_POOL (decl)) ? DECL_ALIGN (decl) : symtab_node::get (decl)->definition_alignment ()); - switch_to_section (get_constant_section (exp, align)); + section *sect = get_constant_section (exp, align); + switch_to_section (sect); if (align > BITS_PER_UNIT) ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); - assemble_constant_contents (exp, XSTR (symbol, 0), align); + assemble_constant_contents (exp, XSTR (symbol, 0), align, + (sect->common.flags & SECTION_MERGE) + && (sect->common.flags & SECTION_STRINGS)); if (asan_protected) { HOST_WIDE_INT size = get_constant_size (exp); @@ -3475,37 +3608,21 @@ lookup_constant_def (tree exp) tree tree_output_constant_def (tree exp) { - struct constant_descriptor_tree *desc, key; - 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); - constant_descriptor_tree **loc - = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT); - - desc = *loc; - if (desc == 0) - { - desc = build_constant_desc (exp); - desc->hash = key.hash; - *loc = desc; - } - - decl = SYMBOL_REF_DECL (XEXP (desc->rtl, 0)); + struct constant_descriptor_tree *desc = add_constant_to_table (exp, 1); + tree decl = SYMBOL_REF_DECL (XEXP (desc->rtl, 0)); varpool_node::finalize_decl (decl); return decl; } -struct GTY((chain_next ("%h.next"), for_user)) constant_descriptor_rtx { - struct constant_descriptor_rtx *next; +class GTY((chain_next ("%h.next"), for_user)) constant_descriptor_rtx { +public: + class constant_descriptor_rtx *next; rtx mem; rtx sym; rtx constant; HOST_WIDE_INT offset; hashval_t hash; - machine_mode mode; + fixed_size_mode mode; unsigned int align; int labelno; int mark; @@ -3526,8 +3643,8 @@ struct const_rtx_desc_hasher : ggc_ptr_hash struct GTY(()) rtx_constant_pool { /* Pointers to first and last constant in pool, as ordered by offset. */ - struct constant_descriptor_rtx *first; - struct constant_descriptor_rtx *last; + class constant_descriptor_rtx *first; + class constant_descriptor_rtx *last; /* Hash facility for making memory-constants from constant rtl-expressions. It is used on RISC machines where immediate integer arguments and @@ -3592,7 +3709,7 @@ const_rtx_hash_1 (const_rtx x) break; case CONST_WIDE_INT: - hwi = GET_MODE_PRECISION (mode); + hwi = 0; { for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++) hwi ^= CONST_WIDE_INT_ELT (x, i); @@ -3681,18 +3798,24 @@ simplify_subtraction (rtx x) } /* Given a constant rtx X, make (or find) a memory constant for its value - and return a MEM rtx to refer to it in memory. */ + and return a MEM rtx to refer to it in memory. IN_MODE is the mode + of X. */ rtx -force_const_mem (machine_mode mode, rtx x) +force_const_mem (machine_mode in_mode, rtx x) { - struct constant_descriptor_rtx *desc, tmp; + class constant_descriptor_rtx *desc, tmp; struct rtx_constant_pool *pool; char label[256]; rtx def, symbol; hashval_t hash; unsigned int align; constant_descriptor_rtx **slot; + fixed_size_mode mode; + + /* We can't force variable-sized objects to memory. */ + if (!is_a (in_mode, &mode)) + return NULL_RTX; /* If we're not allowed to drop X into the constant pool, don't. */ if (targetm.cannot_force_const_mem (mode, x)) @@ -3722,11 +3845,8 @@ force_const_mem (machine_mode mode, rtx x) *slot = desc; /* Align the location counter as required by EXP's data type. */ - align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode); - - tree type = lang_hooks.types.type_for_mode (mode, 0); - if (type != NULL_TREE) - align = CONSTANT_ALIGNMENT (make_tree (type, x), align); + machine_mode align_mode = (mode == VOIDmode ? word_mode : mode); + align = targetm.static_rtx_alignment (align_mode); pool->offset += (align / BITS_PER_UNIT) - 1; pool->offset &= ~ ((align / BITS_PER_UNIT) - 1); @@ -3768,7 +3888,6 @@ force_const_mem (machine_mode mode, rtx x) /* Construct the MEM. */ desc->mem = def = gen_const_mem (mode, symbol); - set_mem_attributes (def, lang_hooks.types.type_for_mode (mode, 0), 1); set_mem_align (def, align); /* If we're dropping a label to the constant pool, make sure we @@ -3793,7 +3912,7 @@ get_pool_constant (const_rtx addr) rtx get_pool_constant_mark (rtx addr, bool *pmarked) { - struct constant_descriptor_rtx *desc; + class constant_descriptor_rtx *desc; desc = SYMBOL_REF_CONSTANT (addr); *pmarked = (desc->mark != 0); @@ -3802,25 +3921,27 @@ get_pool_constant_mark (rtx addr, bool *pmarked) /* Similar, return the mode. */ -machine_mode +fixed_size_mode get_pool_mode (const_rtx addr) { return SYMBOL_REF_CONSTANT (addr)->mode; } -/* Return the size of the constant pool. */ +/* Return TRUE if and only if the constant pool has no entries. Note + that even entries we might end up choosing not to emit are counted + here, so there is the potential for missed optimizations. */ -int -get_pool_size (void) +bool +constant_pool_empty_p (void) { - return crtl->varasm.pool->offset; + return crtl->varasm.pool->first == NULL; } /* Worker function for output_constant_pool_1. Emit assembly for X in MODE with known alignment ALIGN. */ static void -output_constant_pool_2 (machine_mode mode, rtx x, unsigned int align) +output_constant_pool_2 (fixed_size_mode mode, rtx x, unsigned int align) { switch (GET_MODE_CLASS (mode)) { @@ -3828,7 +3949,8 @@ output_constant_pool_2 (machine_mode mode, rtx x, unsigned int align) case MODE_DECIMAL_FLOAT: { gcc_assert (CONST_DOUBLE_AS_FLOAT_P (x)); - assemble_real (*CONST_DOUBLE_REAL_VALUE (x), mode, align, false); + assemble_real (*CONST_DOUBLE_REAL_VALUE (x), + as_a (mode), align, false); break; } @@ -3838,10 +3960,35 @@ output_constant_pool_2 (machine_mode mode, rtx x, unsigned int align) 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_BOOL: + { + gcc_assert (GET_CODE (x) == CONST_VECTOR); + + /* Pick the smallest integer mode that contains at least one + whole element. Often this is byte_mode and contains more + than one element. */ + unsigned int nelts = GET_MODE_NUNITS (mode); + unsigned int elt_bits = GET_MODE_BITSIZE (mode) / nelts; + unsigned int int_bits = MAX (elt_bits, BITS_PER_UNIT); + scalar_int_mode int_mode = int_mode_for_size (int_bits, 0).require (); + + /* Build the constant up one integer at a time. */ + unsigned int elts_per_int = int_bits / elt_bits; + for (unsigned int i = 0; i < nelts; i += elts_per_int) + { + unsigned HOST_WIDE_INT value = 0; + unsigned int limit = MIN (nelts - i, elts_per_int); + for (unsigned int j = 0; j < limit; ++j) + if (INTVAL (CONST_VECTOR_ELT (x, i + j)) != 0) + value |= 1 << (j * elt_bits); + output_constant_pool_2 (int_mode, gen_int_mode (value, int_mode), + i != 0 ? MIN (align, int_bits) : align); + } + break; + } case MODE_VECTOR_FLOAT: case MODE_VECTOR_INT: case MODE_VECTOR_FRACT: @@ -3850,11 +3997,11 @@ output_constant_pool_2 (machine_mode mode, rtx x, unsigned int align) case MODE_VECTOR_UACCUM: { int i, units; - machine_mode submode = GET_MODE_INNER (mode); + scalar_mode submode = GET_MODE_INNER (mode); unsigned int subalign = MIN (align, GET_MODE_BITSIZE (submode)); gcc_assert (GET_CODE (x) == CONST_VECTOR); - units = CONST_VECTOR_NUNITS (x); + units = GET_MODE_NUNITS (mode); for (i = 0; i < units; i++) { @@ -3873,7 +4020,7 @@ output_constant_pool_2 (machine_mode mode, rtx x, unsigned int align) giving it ALIGN bits of alignment. */ static void -output_constant_pool_1 (struct constant_descriptor_rtx *desc, +output_constant_pool_1 (class constant_descriptor_rtx *desc, unsigned int align) { rtx x, tmp; @@ -3942,6 +4089,29 @@ output_constant_pool_1 (struct constant_descriptor_rtx *desc, return; } +/* Recompute the offsets of entries in POOL, and the overall size of + POOL. Do this after calling mark_constant_pool to ensure that we + are computing the offset values for the pool which we will actually + emit. */ + +static void +recompute_pool_offsets (struct rtx_constant_pool *pool) +{ + class constant_descriptor_rtx *desc; + pool->offset = 0; + + for (desc = pool->first; desc ; desc = desc->next) + if (desc->mark) + { + /* Recalculate offset. */ + unsigned int align = desc->align; + pool->offset += (align / BITS_PER_UNIT) - 1; + pool->offset &= ~ ((align / BITS_PER_UNIT) - 1); + desc->offset = pool->offset; + pool->offset += GET_MODE_SIZE (desc->mode); + } +} + /* Mark all constants that are referenced by SYMBOL_REFs in X. Emit referenced deferred strings. */ @@ -3956,7 +4126,7 @@ mark_constants_in_pattern (rtx insn) { if (CONSTANT_POOL_ADDRESS_P (x)) { - struct constant_descriptor_rtx *desc = SYMBOL_REF_CONSTANT (x); + class constant_descriptor_rtx *desc = SYMBOL_REF_CONSTANT (x); if (desc->mark == 0) { desc->mark = 1; @@ -4025,7 +4195,7 @@ mark_constant_pool (void) static void output_constant_pool_contents (struct rtx_constant_pool *pool) { - struct constant_descriptor_rtx *desc; + class constant_descriptor_rtx *desc; for (desc = pool->first; desc ; desc = desc->next) if (desc->mark) @@ -4060,6 +4230,11 @@ output_constant_pool (const char *fnname ATTRIBUTE_UNUSED, case we do not need to output the constant. */ mark_constant_pool (); + /* Having marked the constant pool entries we'll actually emit, we + now need to rebuild the offset information, which may have become + stale. */ + recompute_pool_offsets (pool); + #ifdef ASM_OUTPUT_POOL_PROLOGUE ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset); #endif @@ -4152,7 +4327,7 @@ compute_reloc_for_constant (tree exp) Indicate whether an ADDR_EXPR has been encountered. */ static void -output_addressed_constants (tree exp) +output_addressed_constants (tree exp, int defer) { tree tem; @@ -4172,21 +4347,21 @@ output_addressed_constants (tree exp) tem = DECL_INITIAL (tem); if (CONSTANT_CLASS_P (tem) || TREE_CODE (tem) == CONSTRUCTOR) - output_constant_def (tem, 0); + output_constant_def (tem, defer); if (TREE_CODE (tem) == MEM_REF) - output_addressed_constants (TREE_OPERAND (tem, 0)); + output_addressed_constants (TREE_OPERAND (tem, 0), defer); break; case PLUS_EXPR: case POINTER_PLUS_EXPR: case MINUS_EXPR: - output_addressed_constants (TREE_OPERAND (exp, 1)); + output_addressed_constants (TREE_OPERAND (exp, 1), defer); gcc_fallthrough (); CASE_CONVERT: case VIEW_CONVERT_EXPR: - output_addressed_constants (TREE_OPERAND (exp, 0)); + output_addressed_constants (TREE_OPERAND (exp, 0), defer); break; case CONSTRUCTOR: @@ -4194,7 +4369,7 @@ output_addressed_constants (tree exp) unsigned HOST_WIDE_INT idx; FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, tem) if (tem != 0) - output_addressed_constants (tem); + output_addressed_constants (tem, defer); } break; @@ -4250,8 +4425,8 @@ narrowing_initializer_constant_valid_p (tree value, tree endtype, tree *cache) tree inner = TREE_OPERAND (op0, 0); if (inner == error_mark_node || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner))) - || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))) - > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner))))) + || (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (TREE_TYPE (op0))) + > GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (TREE_TYPE (inner))))) break; op0 = inner; } @@ -4262,8 +4437,8 @@ narrowing_initializer_constant_valid_p (tree value, tree endtype, tree *cache) tree inner = TREE_OPERAND (op1, 0); if (inner == error_mark_node || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner))) - || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1))) - > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner))))) + || (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (TREE_TYPE (op1))) + > GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (TREE_TYPE (inner))))) break; op1 = inner; } @@ -4438,8 +4613,15 @@ initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache) return initializer_constant_valid_p_1 (src, endtype, cache); /* Allow conversions between other integer types only if - explicit value. */ - if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type)) + explicit value. Don't allow sign-extension to a type larger + than word and pointer, there aren't relocations that would + allow to sign extend it to a wider type. */ + if (INTEGRAL_TYPE_P (dest_type) + && INTEGRAL_TYPE_P (src_type) + && (TYPE_UNSIGNED (src_type) + || TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type) + || TYPE_PRECISION (dest_type) <= BITS_PER_WORD + || TYPE_PRECISION (dest_type) <= POINTER_SIZE)) { tree inner = initializer_constant_valid_p_1 (src, endtype, cache); if (inner == null_pointer_node) @@ -4513,6 +4695,7 @@ initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache) } return ret; + case POINTER_DIFF_EXPR: case MINUS_EXPR: if (TREE_CODE (endtype) == REAL_TYPE) return NULL_TREE; @@ -4627,6 +4810,30 @@ initializer_constant_valid_for_bitfield_p (tree value) return false; } +/* Check if a STRING_CST fits into the field. + Tolerate only the case when the NUL termination + does not fit into the field. */ + +static bool +check_string_literal (tree string, unsigned HOST_WIDE_INT size) +{ + tree type = TREE_TYPE (string); + tree eltype = TREE_TYPE (type); + unsigned HOST_WIDE_INT elts = tree_to_uhwi (TYPE_SIZE_UNIT (eltype)); + unsigned HOST_WIDE_INT mem_size = tree_to_uhwi (TYPE_SIZE_UNIT (type)); + int len = TREE_STRING_LENGTH (string); + + if (elts != 1 && elts != 2 && elts != 4) + return false; + if (len < 0 || len % elts != 0) + return false; + if (size < (unsigned)len) + return false; + if (mem_size != size) + return false; + return true; +} + /* output_constructor outer state of relevance in recursive calls, typically for nested aggregate bitfields. */ @@ -4665,7 +4872,7 @@ output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int, bool, static unsigned HOST_WIDE_INT output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align, - bool reverse) + bool reverse, bool merge_strings) { enum tree_code code; unsigned HOST_WIDE_INT thissize; @@ -4681,7 +4888,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align, if (TREE_CODE (exp) == NOP_EXPR && POINTER_TYPE_P (TREE_TYPE (exp)) && targetm.addr_space.valid_pointer_mode - (TYPE_MODE (TREE_TYPE (exp)), + (SCALAR_INT_TYPE_MODE (TREE_TYPE (exp)), TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))))) { tree saved_type = TREE_TYPE (exp); @@ -4691,7 +4898,7 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align, while (TREE_CODE (exp) == NOP_EXPR && POINTER_TYPE_P (TREE_TYPE (exp)) && targetm.addr_space.valid_pointer_mode - (TYPE_MODE (TREE_TYPE (exp)), + (SCALAR_INT_TYPE_MODE (TREE_TYPE (exp)), TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))))) exp = TREE_OPERAND (exp, 0); @@ -4762,7 +4969,6 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align, case REFERENCE_TYPE: case OFFSET_TYPE: case FIXED_POINT_TYPE: - case POINTER_BOUNDS_TYPE: case NULLPTR_TYPE: cst = expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); if (reverse) @@ -4775,15 +4981,17 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align, if (TREE_CODE (exp) != REAL_CST) error ("initializer for floating value is not a floating constant"); else - assemble_real (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)), + assemble_real (TREE_REAL_CST (exp), + SCALAR_FLOAT_TYPE_MODE (TREE_TYPE (exp)), align, reverse); break; case COMPLEX_TYPE: - output_constant (TREE_REALPART (exp), thissize / 2, align, reverse); + output_constant (TREE_REALPART (exp), thissize / 2, align, + reverse, false); output_constant (TREE_IMAGPART (exp), thissize / 2, min_align (align, BITS_PER_UNIT * (thissize / 2)), - reverse); + reverse, false); break; case ARRAY_TYPE: @@ -4793,22 +5001,28 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align, case CONSTRUCTOR: return output_constructor (exp, size, align, reverse, NULL); case STRING_CST: - thissize - = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp), size); + thissize = (unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp); + if (merge_strings + && (thissize == 0 + || TREE_STRING_POINTER (exp) [thissize - 1] != '\0')) + thissize++; + gcc_checking_assert (check_string_literal (exp, size)); assemble_string (TREE_STRING_POINTER (exp), thissize); break; case VECTOR_CST: { - machine_mode inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp))); + scalar_mode inner = SCALAR_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, - reverse); + reverse, false); thissize = elt_size; - for (unsigned int i = 1; i < VECTOR_CST_NELTS (exp); i++) + /* Static constants must have a fixed size. */ + unsigned int nunits = VECTOR_CST_NELTS (exp).to_constant (); + for (unsigned int i = 1; i < nunits; i++) { output_constant (VECTOR_CST_ELT (exp, i), elt_size, nalign, - reverse); + reverse, false); thissize += elt_size; } break; @@ -4911,6 +5125,26 @@ struct oc_local_state { static void output_constructor_array_range (oc_local_state *local) { + /* Perform the index calculation in modulo arithmetic but + sign-extend the result because Ada has negative DECL_FIELD_OFFSETs + but we are using an unsigned sizetype. */ + unsigned prec = TYPE_PRECISION (sizetype); + offset_int idx = wi::sext (wi::to_offset (TREE_OPERAND (local->index, 0)) + - wi::to_offset (local->min_index), prec); + tree valtype = TREE_TYPE (local->val); + HOST_WIDE_INT fieldpos + = (idx * wi::to_offset (TYPE_SIZE_UNIT (valtype))).to_short_addr (); + + /* Advance to offset of this element. */ + if (fieldpos > local->total_bytes) + { + assemble_zeros (fieldpos - local->total_bytes); + local->total_bytes = fieldpos; + } + else + /* Must not go backwards. */ + gcc_assert (fieldpos == local->total_bytes); + unsigned HOST_WIDE_INT fieldsize = int_size_in_bytes (TREE_TYPE (local->type)); @@ -4929,8 +5163,8 @@ output_constructor_array_range (oc_local_state *local) if (local->val == NULL_TREE) assemble_zeros (fieldsize); else - fieldsize - = output_constant (local->val, fieldsize, align2, local->reverse); + fieldsize = output_constant (local->val, fieldsize, align2, + local->reverse, false); /* Count its size. */ local->total_bytes += fieldsize; @@ -5012,6 +5246,8 @@ output_constructor_regular_field (oc_local_state *local) on the chain is a TYPE_DECL of the enclosing struct. */ const_tree next = DECL_CHAIN (local->field); gcc_assert (!fieldsize || !next || TREE_CODE (next) != FIELD_DECL); + tree size = TYPE_SIZE_UNIT (TREE_TYPE (local->val)); + gcc_checking_assert (compare_tree_int (size, fieldsize) == 0); } else fieldsize = tree_to_uhwi (DECL_SIZE_UNIT (local->field)); @@ -5023,8 +5259,8 @@ output_constructor_regular_field (oc_local_state *local) if (local->val == NULL_TREE) assemble_zeros (fieldsize); else - fieldsize - = output_constant (local->val, fieldsize, align2, local->reverse); + fieldsize = output_constant (local->val, fieldsize, align2, + local->reverse, false); /* Count its size. */ local->total_bytes += fieldsize; @@ -5134,7 +5370,7 @@ output_constructor_bitfield (oc_local_state *local, unsigned int bit_offset) { int this_time; int shift; - HOST_WIDE_INT value; + unsigned HOST_WIDE_INT value; HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT; HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT; @@ -5166,15 +5402,13 @@ output_constructor_bitfield (oc_local_state *local, unsigned int bit_offset) this_time = end - shift + 1; } - /* Now get the bits from the appropriate constant word. */ - value = TREE_INT_CST_ELT (local->val, shift / HOST_BITS_PER_WIDE_INT); - shift = shift & (HOST_BITS_PER_WIDE_INT - 1); + /* Now get the bits we want to insert. */ + value = wi::extract_uhwi (wi::to_widest (local->val), + shift, this_time); /* 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)) - << (BITS_PER_UNIT - this_time - next_bit)); + local->byte |= value << (BITS_PER_UNIT - this_time - next_bit); } else { @@ -5191,15 +5425,13 @@ output_constructor_bitfield (oc_local_state *local, unsigned int bit_offset) this_time = HOST_BITS_PER_WIDE_INT - (shift & (HOST_BITS_PER_WIDE_INT - 1)); - /* Now get the bits from the appropriate constant word. */ - value = TREE_INT_CST_ELT (local->val, shift / HOST_BITS_PER_WIDE_INT); - shift = shift & (HOST_BITS_PER_WIDE_INT - 1); + /* Now get the bits we want to insert. */ + value = wi::extract_uhwi (wi::to_widest (local->val), + shift, this_time); /* 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)) - << next_bit); + local->byte |= value << next_bit; } next_offset += this_time; @@ -5342,7 +5574,7 @@ mark_weak (tree decl) struct symtab_node *n = symtab_node::get (decl); if (n && n->refuse_visibility_changes) - error ("%+D declared weak after being used", decl); + error ("%+qD declared weak after being used", decl); DECL_WEAK (decl) = 1; if (DECL_RTL_SET_P (decl) @@ -5499,7 +5731,8 @@ weak_finish (void) tree alias_decl = TREE_PURPOSE (t); tree target = ultimate_transparent_alias_target (&TREE_VALUE (t)); - if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias_decl))) + if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias_decl)) + || TREE_SYMBOL_REFERENCED (target)) /* Remove alias_decl from the weak list, but leave entries for the target alone. */ target = NULL_TREE; @@ -5667,11 +5900,6 @@ do_assemble_alias (tree decl, tree target) #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) || TREE_PUBLIC (orig_decl)) @@ -5679,7 +5907,8 @@ do_assemble_alias (tree decl, tree target) globalize_decl (decl); maybe_assemble_visibility (decl); } - if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl))) + if (TREE_CODE (decl) == FUNCTION_DECL + && cgraph_node::get (decl)->ifunc_resolver) { #if defined (ASM_OUTPUT_TYPE_DIRECTIVE) if (targetm.has_ifunc_p ()) @@ -5689,7 +5918,7 @@ do_assemble_alias (tree decl, tree target) else #endif error_at (DECL_SOURCE_LOCATION (decl), - "ifunc is not supported on this target"); + "%qs is not supported on this target", "ifunc"); } # ifdef ASM_OUTPUT_DEF_FROM_DECLS @@ -5732,6 +5961,23 @@ do_assemble_alias (tree decl, tree target) #endif } +/* Output .symver directive. */ + +void +do_assemble_symver (tree decl, tree target) +{ + tree id = DECL_ASSEMBLER_NAME (decl); + ultimate_transparent_alias_target (&id); + ultimate_transparent_alias_target (&target); +#ifdef ASM_OUTPUT_SYMVER_DIRECTIVE + ASM_OUTPUT_SYMVER_DIRECTIVE (asm_out_file, + IDENTIFIER_POINTER (target), + IDENTIFIER_POINTER (id)); +#else + error ("symver is only supported on ELF platforms"); +#endif +} + /* Emit an assembler directive to make the symbol for DECL an alias to the symbol for TARGET. */ @@ -5747,9 +5993,9 @@ assemble_alias (tree decl, tree target) ultimate_transparent_alias_target (&target); if (alias == target) - error ("weakref %q+D ultimately targets itself", decl); + error ("%qs symbol %q+D ultimately targets itself", "weakref", decl); if (TREE_PUBLIC (decl)) - error ("weakref %q+D must have static linkage", decl); + error ("%qs symbol %q+D must have static linkage", "weakref", decl); } else { @@ -5762,9 +6008,11 @@ assemble_alias (tree decl, tree target) # else if (!DECL_WEAK (decl)) { - if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl))) + /* NB: ifunc_resolver isn't set when an error is detected. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl))) error_at (DECL_SOURCE_LOCATION (decl), - "ifunc is not supported in this configuration"); + "%qs is not supported in this configuration", "ifunc"); else error_at (DECL_SOURCE_LOCATION (decl), "only weak aliases are supported in this configuration"); @@ -5993,13 +6241,6 @@ int maybe_assemble_visibility (tree decl) { 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); @@ -6218,15 +6459,26 @@ default_section_type_flags (tree decl, const char *name, int reloc) || strncmp (name, ".gnu.linkonce.tb.", 17) == 0) flags |= SECTION_TLS | SECTION_BSS; - /* These three sections have special ELF types. They are neither - SHT_PROGBITS nor SHT_NOBITS, so when changing sections we don't - want to print a section type (@progbits or @nobits). If someone - is silly enough to emit code or TLS variables to one of these - sections, then don't handle them specially. */ - if (!(flags & (SECTION_CODE | SECTION_BSS | SECTION_TLS)) - && (strcmp (name, ".init_array") == 0 - || strcmp (name, ".fini_array") == 0 - || strcmp (name, ".preinit_array") == 0)) + if (strcmp (name, ".noinit") == 0) + flags |= SECTION_WRITE | SECTION_BSS | SECTION_NOTYPE; + + /* Various sections have special ELF types that the assembler will + assign by default based on the name. They are neither SHT_PROGBITS + nor SHT_NOBITS, so when changing sections we don't want to print a + section type (@progbits or @nobits). Rather than duplicating the + assembler's knowledge of what those special name patterns are, just + let the assembler choose the type if we don't know a specific + reason to set it to something other than the default. SHT_PROGBITS + is the default for sections whose name is not specially known to + the assembler, so it does no harm to leave the choice to the + assembler when @progbits is the best thing we know to use. If + someone is silly enough to emit code or TLS variables to one of + these sections, then don't handle them specially. + + default_elf_asm_named_section (below) handles the BSS, TLS, ENTSIZE, and + LINKONCE cases when NOTYPE is not set, so leave those to its logic. */ + if (!(flags & (SECTION_CODE | SECTION_BSS | SECTION_TLS | SECTION_ENTSIZE)) + && !(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))) flags |= SECTION_NOTYPE; return flags; @@ -6285,7 +6537,7 @@ default_elf_asm_named_section (const char *name, unsigned int flags, { if (!(flags & SECTION_DEBUG)) *f++ = 'a'; -#if defined (HAVE_GAS_SECTION_EXCLUDE) && HAVE_GAS_SECTION_EXCLUDE == 1 +#if HAVE_GAS_SECTION_EXCLUDE if (flags & SECTION_EXCLUDE) *f++ = 'e'; #endif @@ -6312,6 +6564,10 @@ default_elf_asm_named_section (const char *name, unsigned int flags, fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars); + /* default_section_type_flags (above) knows which flags need special + handling here, and sets NOTYPE when none of these apply so that the + assembler's logic for default types can apply to user-chosen + section names. */ if (!(flags & SECTION_NOTYPE)) { const char *type; @@ -6420,11 +6676,13 @@ categorize_decl_for_section (const_tree decl, int reloc) } else if (VAR_P (decl)) { + tree d = CONST_CAST_TREE (decl); if (bss_initializer_p (decl)) ret = SECCAT_BSS; else if (! TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl) - || ! TREE_CONSTANT (DECL_INITIAL (decl))) + || (DECL_INITIAL (decl) + && ! TREE_CONSTANT (DECL_INITIAL (decl)))) { /* Here the reloc_rw_mask is not testing whether the section should be read-only or not, but whether the dynamic link will have to @@ -6439,12 +6697,23 @@ categorize_decl_for_section (const_tree decl, int reloc) ret = reloc == 1 ? SECCAT_DATA_REL_RO_LOCAL : SECCAT_DATA_REL_RO; else if (reloc || flag_merge_constants < 2 || ((flag_sanitize & SANITIZE_ADDRESS) - && asan_protect_global (CONST_CAST_TREE (decl)))) + /* PR 81697: for architectures that use section anchors we + need to ignore DECL_RTL_SET_P (decl) for string constants + inside this asan_protect_global call because otherwise + we'll wrongly put them into SECCAT_RODATA_MERGE_CONST + section, set DECL_RTL (decl) later on and add DECL to + protected globals via successive asan_protect_global + calls. In this scenario we'll end up with wrong + alignment of these strings at runtime and possible ASan + false positives. */ + && asan_protect_global (d, use_object_blocks_p () + && use_blocks_for_decl_p (d)))) /* 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). */ ret = SECCAT_RODATA; - else if (TREE_CODE (DECL_INITIAL (decl)) == STRING_CST) + else if (DECL_INITIAL (decl) + && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST) ret = SECCAT_RODATA_MERGE_STR_INIT; else ret = SECCAT_RODATA_MERGE_CONST; @@ -6467,8 +6736,9 @@ categorize_decl_for_section (const_tree decl, int reloc) /* Note that this would be *just* SECCAT_BSS, except that there's no concept of a read-only thread-local-data section. */ if (ret == SECCAT_BSS - || (flag_zero_initialized_in_bss - && initializer_zerop (DECL_INITIAL (decl)))) + || DECL_INITIAL (decl) == NULL + || (flag_zero_initialized_in_bss + && initializer_zerop (DECL_INITIAL (decl)))) ret = SECCAT_TBSS; else ret = SECCAT_TDATA; @@ -6517,6 +6787,7 @@ default_elf_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) { const char *sname; + switch (categorize_decl_for_section (decl, reloc)) { case SECCAT_TEXT: @@ -6554,6 +6825,13 @@ default_elf_select_section (tree decl, int reloc, sname = ".tdata"; break; case SECCAT_BSS: + if (DECL_P (decl) + && lookup_attribute ("noinit", DECL_ATTRIBUTES (decl)) != NULL_TREE) + { + sname = ".noinit"; + break; + } + if (bss_section) return bss_section; sname = ".bss"; @@ -6780,14 +7058,13 @@ default_asm_output_anchor (rtx symbol) bool default_use_anchors_for_symbol_p (const_rtx symbol) { - section *sect; tree decl; + section *sect = SYMBOL_REF_BLOCK (symbol)->sect; - /* Don't use anchors for mergeable sections. The linker might move - the objects around. */ - sect = SYMBOL_REF_BLOCK (symbol)->sect; - if (sect->common.flags & SECTION_MERGE) - return false; + /* This function should only be called with non-zero SYMBOL_REF_BLOCK, + furthermore get_block_for_section should not create object blocks + for mergeable sections. */ + gcc_checking_assert (sect && !(sect->common.flags & SECTION_MERGE)); /* Don't use anchors for small data sections. The small data register acts as an anchor for such sections. */ @@ -6868,7 +7145,8 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, weakref alias. */ if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp)) || (TREE_CODE (exp) == FUNCTION_DECL - && lookup_attribute ("ifunc", DECL_ATTRIBUTES (exp)))) + && cgraph_node::get (exp) + && cgraph_node::get (exp)->ifunc_resolver)) return false; /* Static variables are always local. */ @@ -7214,7 +7492,7 @@ void place_block_symbol (rtx symbol) { unsigned HOST_WIDE_INT size, mask, offset; - struct constant_descriptor_rtx *desc; + class constant_descriptor_rtx *desc; unsigned int alignment; struct object_block *block; tree decl; @@ -7376,7 +7654,7 @@ get_section_anchor (struct object_block *block, HOST_WIDE_INT offset, static void output_object_block (struct object_block *block) { - struct constant_descriptor_rtx *desc; + class constant_descriptor_rtx *desc; unsigned int i; HOST_WIDE_INT offset; tree decl; @@ -7395,6 +7673,7 @@ output_object_block (struct object_block *block) else switch_to_section (block->sect); + gcc_checking_assert (!(block->sect->common.flags & SECTION_MERGE)); assemble_align (block->alignment); /* Define the values of all anchors relative to the current section @@ -7421,8 +7700,8 @@ output_object_block (struct object_block *block) { 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), false); size = get_constant_size (DECL_INITIAL (decl)); offset += size; @@ -7439,7 +7718,7 @@ output_object_block (struct object_block *block) { HOST_WIDE_INT size; decl = SYMBOL_REF_DECL (symbol); - assemble_variable_contents (decl, XSTR (symbol, 0), false); + assemble_variable_contents (decl, XSTR (symbol, 0), false, false); size = tree_to_uhwi (DECL_SIZE_UNIT (decl)); offset += size; if ((flag_sanitize & SANITIZE_ADDRESS)