From 3b73548b5998cfb9594fb3d8901ea4d9ae6a87a9 Mon Sep 17 00:00:00 2001 From: hubicka Date: Tue, 23 Nov 2010 16:06:37 +0000 Subject: [PATCH] * tree.h (DECL_HAS_IMPLICIT_SECTION_NAME_P): New macro. (tree_decl_with_vis): Add implicit_section_name_p. * targhooks.h (default_function_section): Declare. * target.def (function_section): New hook. * defaults.h (HOT_TEXT_SECTION_NAME, UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Remove. * predict.c (choose_function_section): Remove. (estimate_bb_frequencies): Do not use choose_function_section. * coretypes.h (enum node_frequency): Move here from cgraph.h * cgraph.h (enum node_frequency): Remove. * varasm.c (initialize_cold_section_name, unlikely_text_section, unlikely_text_section_p): Remove. (named_subsection_entry): New structure. (get_text_section): New function. (default_function_section): New function. (function_section_1): Break out from ...; handle profile info. (function_section): ... here. (unlikely_text_section): Remove. (unlikely_text_section_p): Use function_section_1. (assemble_start_function): Do not initialize cold section. (default_section_type_flags): Do not special case cold subsection. (switch_to_section): Likewise. * output.h (get_text_section): Define. * config/i386/winnt.c: Do not special case cold section. * config/darwin-protos.h (darwin_function_section): Declare. * config/microblaze/microblaze.h (HOT_TEXT_SECTION_NAME, UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Remove. * config/ia64/hpux.h (HOT_TEXT_SECTION_NAME, UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Remove. (TARGET_ASM_FUNCTION_SECTION): Define to ia64_hpux_function_section. * config/ia64/ia64.c (ia64_hpux_function_section): New function. * config/darwin.c (machopic_select_section): Use darwin_function_section. (darwin_function_section): New function. * config/darwin.h (HOT_TEXT_SECTION_NAME, UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Remove. (TARGET_ASM_FUNCTION_SECTION): Define. * system.h (HOT_TEXT_SECTION_NAME, UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Poison. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167085 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 42 ++++++ gcc/cgraph.h | 14 -- gcc/config.in | 4 + gcc/config/darwin-protos.h | 1 + gcc/config/darwin.c | 48 ++++++- gcc/config/darwin.h | 7 +- gcc/config/i386/winnt.c | 9 -- gcc/config/ia64/hpux.h | 6 +- gcc/config/ia64/ia64.c | 13 ++ gcc/config/microblaze/microblaze.h | 4 - gcc/configure.ac | 22 +++ gcc/coretypes.h | 16 +++ gcc/defaults.h | 8 -- gcc/doc/tm.texi | 10 ++ gcc/doc/tm.texi.in | 10 ++ gcc/function.h | 5 - gcc/output.h | 4 + gcc/predict.c | 32 ----- gcc/system.h | 5 +- gcc/target.def | 13 ++ gcc/targhooks.h | 3 +- gcc/tree.h | 9 +- gcc/varasm.c | 276 +++++++++++++++++++++---------------- 23 files changed, 357 insertions(+), 204 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8f6f36887fb..67c3dfa0bfe 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,45 @@ +2010-11-23 Jan Hubicka + + * tree.h (DECL_HAS_IMPLICIT_SECTION_NAME_P): New macro. + (tree_decl_with_vis): Add implicit_section_name_p. + * targhooks.h (default_function_section): Declare. + * target.def (function_section): New hook. + * defaults.h (HOT_TEXT_SECTION_NAME, + UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Remove. + * predict.c (choose_function_section): Remove. + (estimate_bb_frequencies): Do not use choose_function_section. + * coretypes.h (enum node_frequency): Move here from cgraph.h + * cgraph.h (enum node_frequency): Remove. + * varasm.c (initialize_cold_section_name, unlikely_text_section, + unlikely_text_section_p): Remove. + (named_subsection_entry): New structure. + (get_text_section): New function. + (default_function_section): New function. + (function_section_1): Break out from ...; handle profile info. + (function_section): ... here. + (unlikely_text_section): Remove. + (unlikely_text_section_p): Use function_section_1. + (assemble_start_function): Do not initialize cold section. + (default_section_type_flags): Do not special case cold subsection. + (switch_to_section): Likewise. + * output.h (get_text_section): Define. + * config/i386/winnt.c: Do not special case cold section. + * config/darwin-protos.h (darwin_function_section): Declare. + * config/microblaze/microblaze.h (HOT_TEXT_SECTION_NAME, + UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Remove. + * config/ia64/hpux.h (HOT_TEXT_SECTION_NAME, + UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Remove. + (TARGET_ASM_FUNCTION_SECTION): Define to ia64_hpux_function_section. + * config/ia64/ia64.c (ia64_hpux_function_section): New function. + * config/darwin.c (machopic_select_section): Use + darwin_function_section. + (darwin_function_section): New function. + * config/darwin.h (HOT_TEXT_SECTION_NAME, + UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Remove. + (TARGET_ASM_FUNCTION_SECTION): Define. + * system.h (HOT_TEXT_SECTION_NAME, + UNLIKELY_EXECUTED_TEXT_SECTION_NAME): Poison. + 2010-11-23 Iain Sandoe * config/darwin.h (LINK_COMMAND_SPEC_A): Use %(link_gcc_c_sequence). diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 99e4ee3eac6..99d549c328a 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -180,20 +180,6 @@ struct GTY(()) cgraph_clone_info bitmap combined_args_to_skip; }; -enum node_frequency { - /* This function most likely won't be executed at all. - (set only when profile feedback is available or via function attribute). */ - NODE_FREQUENCY_UNLIKELY_EXECUTED, - /* For functions that are known to be executed once (i.e. constructors, destructors - and main function. */ - NODE_FREQUENCY_EXECUTED_ONCE, - /* The default value. */ - NODE_FREQUENCY_NORMAL, - /* Optimize this function hard - (set only when profile feedback is available or via function attribute). */ - NODE_FREQUENCY_HOT -}; - /* The cgraph data structure. Each function decl has assigned cgraph_node listing callees and callers. */ diff --git a/gcc/config.in b/gcc/config.in index b6a95b53e19..a31fc59d566 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1142,6 +1142,10 @@ #undef HAVE_LD_DEMANGLE #endif +/* Define if your linker supports plugin. */ +#ifndef USED_FOR_TARGET +#undef HAVE_LD_PLUGIN +#endif /* Define if your linker supports --eh-frame-hdr option. */ #undef HAVE_LD_EH_FRAME_HDR diff --git a/gcc/config/darwin-protos.h b/gcc/config/darwin-protos.h index e70de1bee80..08cacc14234 100644 --- a/gcc/config/darwin-protos.h +++ b/gcc/config/darwin-protos.h @@ -57,6 +57,7 @@ extern section *machopic_select_section (tree, int, unsigned HOST_WIDE_INT); extern section *machopic_select_rtx_section (enum machine_mode, rtx, unsigned HOST_WIDE_INT); +extern section *darwin_function_section (tree, enum node_frequency, bool, bool); extern void darwin_unique_section (tree decl, int reloc); extern void darwin_asm_named_section (const char *, unsigned int, tree); extern void darwin_non_lazy_pcrel (FILE *, rtx); diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index 79b42725f48..e8da4f1e699 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -1233,12 +1233,22 @@ machopic_select_section (tree decl, && DECL_WEAK (decl) && !lookup_attribute ("weak_import", DECL_ATTRIBUTES (decl))); - section *base_section; + section *base_section = NULL; switch (categorize_decl_for_section (decl, reloc)) { case SECCAT_TEXT: - base_section = darwin_text_section (reloc, weak); + { + struct cgraph_node *node; + if (decl && TREE_CODE (decl) == FUNCTION_DECL + && (node = cgraph_get_node (decl)) != NULL) + base_section = darwin_function_section (decl, + node->frequency, + node->only_called_at_startup, + node->only_called_at_exit); + if (!base_section) + base_section = darwin_text_section (reloc, weak); + } break; case SECCAT_RODATA: @@ -2362,4 +2372,38 @@ darwin_enter_string_into_cfstring_table (tree str) } } +/* Choose named function section based on its frequency. */ + +section * +darwin_function_section (tree decl, enum node_frequency freq, + bool startup, bool exit) +{ + /* Startup code should go to startup subsection unless it is + unlikely executed (this happens especially with function splitting + where we can split away unnecesary parts of static constructors. */ + if (startup && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED) + return get_named_text_section + (decl, "__TEXT,__startup,regular,pure_instructions", "_startup"); + + /* Similarly for exit. */ + if (exit && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED) + return get_named_text_section (decl, + "__TEXT,__exit,regular,pure_instructions", + "_exit"); + + /* Group cold functions together, similarly for hot code. */ + switch (freq) + { + case NODE_FREQUENCY_UNLIKELY_EXECUTED: + return get_named_text_section + (decl, + "__TEXT,__unlikely,regular,pure_instructions", "_unlikely"); + case NODE_FREQUENCY_HOT: + return get_named_text_section + (decl, "__TEXT,__hot,regular,pure_instructions", "_hot"); + default: + return NULL; + } +} + #include "gt-darwin.h" diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index b93f5884ac5..854cb95b407 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -664,11 +664,6 @@ int darwin_label_is_anonymous_local_objc_name (const char *name); /* The generic version, archs should over-ride where required. */ #define MACHOPIC_NL_SYMBOL_PTR_SECTION ".non_lazy_symbol_pointer" -/* These are used by -fbranch-probabilities */ -#define HOT_TEXT_SECTION_NAME "__TEXT,__text,regular,pure_instructions" -#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME \ - "__TEXT,__unlikely,regular,pure_instructions" - /* Declare the section variables. */ #ifndef USED_FOR_TARGET enum darwin_section_enum { @@ -683,6 +678,8 @@ extern GTY(()) section * darwin_sections[NUM_DARWIN_SECTIONS]; #undef TARGET_ASM_SELECT_SECTION #define TARGET_ASM_SELECT_SECTION machopic_select_section #define USE_SELECT_SECTION_FOR_FUNCTIONS +#undef TARGET_ASM_FUNCTION_SECTION +#define TARGET_ASM_FUNCTION_SECTION darwin_function_section #undef TARGET_ASM_SELECT_RTX_SECTION #define TARGET_ASM_SELECT_RTX_SECTION machopic_select_rtx_section diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c index b8d2979c465..b8d6d69f559 100644 --- a/gcc/config/i386/winnt.c +++ b/gcc/config/i386/winnt.c @@ -414,15 +414,6 @@ i386_pe_section_type_flags (tree decl, const char *name, int reloc) flags = SECTION_CODE; else if (decl && decl_readonly_section (decl, reloc)) flags = 0; - else if (current_function_decl - && cfun - && crtl->subsections.unlikely_text_section_name - && strcmp (name, crtl->subsections.unlikely_text_section_name) == 0) - flags = SECTION_CODE; - else if (!decl - && (!current_function_decl || !cfun) - && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0) - flags = SECTION_CODE; else { flags = SECTION_WRITE; diff --git a/gcc/config/ia64/hpux.h b/gcc/config/ia64/hpux.h index b422441d343..38a005b0626 100644 --- a/gcc/config/ia64/hpux.h +++ b/gcc/config/ia64/hpux.h @@ -218,8 +218,4 @@ do { \ it is fixed, prevent code from being put into .text.unlikely or .text.hot. */ -#undef UNLIKELY_EXECUTED_TEXT_SECTION_NAME -#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME ".text" - -#undef HOT_TEXT_SECTION_NAME -#define HOT_TEXT_SECTION_NAME ".text" +#define TARGET_ASM_FUNCTION_SECTION ia64_hpux_function_section diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 06258cb9136..a007743e2e5 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -336,6 +336,8 @@ static tree ia64_builtin_decl (unsigned, bool); static reg_class_t ia64_preferred_reload_class (rtx, reg_class_t); static enum machine_mode ia64_get_reg_raw_mode (int regno); +static section * ia64_hpux_function_section (tree, enum node_frequency, + bool, bool); /* Table of valid machine attributes. */ static const struct attribute_spec ia64_attribute_table[] = @@ -11022,4 +11024,15 @@ ia64_get_reg_raw_mode (int regno) return default_get_reg_raw_mode(regno); } +/* Always default to .text section until HP-UX linker is fixed. */ + +ATTRIBUTE_UNUSED static section * +ia64_hpux_function_section (tree decl ATTRIBUTE_UNUSED, + enum node_frequency freq ATTRIBUTE_UNUSED, + bool startup ATTRIBUTE_UNUSED, + bool exit ATTRIBUTE_UNUSED) +{ + return NULL; +} + #include "gt-ia64.h" diff --git a/gcc/config/microblaze/microblaze.h b/gcc/config/microblaze/microblaze.h index 63fd4f6aaf8..2fb438de30f 100644 --- a/gcc/config/microblaze/microblaze.h +++ b/gcc/config/microblaze/microblaze.h @@ -880,10 +880,6 @@ do { \ #define SBSS_SECTION_ASM_OP "\t.sbss" /* Small RW uninitialized data */ #define SBSS2_SECTION_ASM_OP "\t.sbss2" /* Small RO uninitialized data */ -#define HOT_TEXT_SECTION_NAME ".text.hot" -#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME \ - ".text.unlikely" - /* We do this to save a few 10s of code space that would be taken up by the call_FUNC () wrappers, used by the generic CRT_CALL_STATIC_FUNCTION definition in crtstuff.c. */ diff --git a/gcc/configure.ac b/gcc/configure.ac index 0eb2d8bddee..8d6d1649fa4 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -3127,6 +3127,28 @@ if test x"$demangler_in_ld" = xyes; then AC_MSG_RESULT($gcc_cv_ld_demangle) fi +if test x"$linker_plugin_in_ld" = xyes; then + AC_MSG_CHECKING(linker support) + gcc_cv_ld_plugin=no + if test x"$ld_is_gold" = xyes; then + gcc_cv_ld_plugin=yes + else if test $in_tree_ld = yes; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 21 -o "$gcc_cv_gld_major_version" -gt 2; then \ + gcc_cv_ld_plugin=yes + fi + elif test x$PLUGIN_LD != x -a x"$gnu_ld" = xyes; then + # Check if the GNU linker supports --plugin-opt option + if $gcc_cv_ld --help 2>/dev/null | grep no-demangle > /dev/null; then + gcc_cv_ld_plugin=yes + fi + fi + if test x"$gcc_cv_ld_plugin" = xyes; then + AC_DEFINE(HAVE_LD_PLUGIN, 1, +[Define if your linker supports plugin.]) + fi + AC_MSG_RESULT($gcc_cv_ld_plugin) +fi + case "$target" in # All TARGET_ABI_OSF targets. alpha*-*-osf* | alpha*-*-linux* | alpha*-*-*bsd*) diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 3c6368419e4..20932b8d9f3 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -121,6 +121,22 @@ enum unwind_info_type UI_TARGET }; +/* Callgraph node profile representation. */ +enum node_frequency { + /* This function most likely won't be executed at all. + (set only when profile feedback is available or via function attribute). */ + NODE_FREQUENCY_UNLIKELY_EXECUTED, + /* For functions that are known to be executed once (i.e. constructors, destructors + and main function. */ + NODE_FREQUENCY_EXECUTED_ONCE, + /* The default value. */ + NODE_FREQUENCY_NORMAL, + /* Optimize this function hard + (set only when profile feedback is available or via function attribute). */ + NODE_FREQUENCY_HOT +}; + + struct edge_def; typedef struct edge_def *edge; typedef const struct edge_def *const_edge; diff --git a/gcc/defaults.h b/gcc/defaults.h index cfbc04d6c92..fb4a8284422 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -897,14 +897,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define TARGET_DEC_EVAL_METHOD 2 #endif -#ifndef HOT_TEXT_SECTION_NAME -#define HOT_TEXT_SECTION_NAME ".text.hot" -#endif - -#ifndef UNLIKELY_EXECUTED_TEXT_SECTION_NAME -#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME ".text.unlikely" -#endif - #ifndef HAS_LONG_COND_BRANCH #define HAS_LONG_COND_BRANCH 0 #endif diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index fd3f426e106..b58ee7b3117 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -7328,6 +7328,16 @@ is non-NULL, it is the @code{VAR_DECL} or @code{FUNCTION_DECL} with which this section is associated. @end deftypefn +@deftypefn {Target Hook} {section *} TARGET_ASM_FUNCTION_SECTION (tree @var{decl}, enum node_frequency @var{freq}, bool @var{startup}, bool @var{exit}) +Return preferred text (sub)section for function @var{decl}. +Main purpose of this function is to separate cold, normal and hot +functions. @var{startup} is true when function is known to be used only +at startup (from static constructors or it is @code{main()}). +@var{exit} is true when function is known to be used only at exit +(from static destructors). +Return NULL if function should go to default text section. +@end deftypefn + @deftypevr {Target Hook} bool TARGET_HAVE_NAMED_SECTIONS This flag is true if the target supports @code{TARGET_ASM_NAMED_SECTION}. @end deftypevr diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index ea4c8430a19..f230307cdad 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -7303,6 +7303,16 @@ is non-NULL, it is the @code{VAR_DECL} or @code{FUNCTION_DECL} with which this section is associated. @end deftypefn +@hook TARGET_ASM_FUNCTION_SECTION +Return preferred text (sub)section for function @var{decl}. +Main purpose of this function is to separate cold, normal and hot +functions. @var{startup} is true when function is known to be used only +at startup (from static constructors or it is @code{main()}). +@var{exit} is true when function is known to be used only at exit +(from static destructors). +Return NULL if function should go to default text section. +@end deftypefn + @hook TARGET_HAVE_NAMED_SECTIONS This flag is true if the target supports @code{TARGET_ASM_NAMED_SECTION}. @end deftypevr diff --git a/gcc/function.h b/gcc/function.h index 93a9b82601b..fcfa825e0a9 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -226,11 +226,6 @@ struct GTY(()) function_subsections { const char *cold_section_label; const char *hot_section_end_label; const char *cold_section_end_label; - - /* String to be used for name of cold text sections, via - targetm.asm_out.named_section. */ - - const char *unlikely_text_section_name; }; /* Describe an empty area of space in the stack frame. These can be chained diff --git a/gcc/output.h b/gcc/output.h index 07372a388a1..928aa1f580f 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -269,6 +269,10 @@ extern bool default_assemble_integer (rtx, unsigned int, int); be outputable. */ extern bool assemble_integer (rtx, unsigned, unsigned, int); +/* Return section for TEXT_SECITON_NAME if DECL or DECL_SECTION_NAME (DECL) + is NULL. */ +extern section *get_named_text_section (tree, const char *, const char *); + /* An interface to assemble_integer for the common case in which a value is fully aligned and must be printed. VALUE is the value of the integer object and SIZE is the number of bytes it contains. */ diff --git a/gcc/predict.c b/gcc/predict.c index 5fcfc1ea432..cb4edcd185f 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -78,7 +78,6 @@ static sreal real_zero, real_one, real_almost_one, real_br_prob_base, static void combine_predictions_for_insn (rtx, basic_block); static void dump_prediction (FILE *, enum br_predictor, int, basic_block, int); static void predict_paths_leading_to (basic_block, enum br_predictor, enum prediction); -static void choose_function_section (void); static bool can_predict_insn_p (const_rtx); /* Information we hold about each branch predictor. @@ -2185,8 +2184,6 @@ estimate_bb_frequencies (void) free_aux_for_edges (); } compute_function_frequency (); - if (flag_reorder_functions) - choose_function_section (); } /* Decide whether function is hot, cold or unlikely executed. */ @@ -2232,35 +2229,6 @@ compute_function_frequency (void) } } -/* Choose appropriate section for the function. */ -static void -choose_function_section (void) -{ - struct cgraph_node *node = cgraph_node (current_function_decl); - if (DECL_SECTION_NAME (current_function_decl) - || !targetm.have_named_sections - /* Theoretically we can split the gnu.linkonce text section too, - but this requires more work as the frequency needs to match - for all generated objects so we need to merge the frequency - of all instances. For now just never set frequency for these. */ - || DECL_ONE_ONLY (current_function_decl)) - return; - - /* If we are doing the partitioning optimization, let the optimization - choose the correct section into which to put things. */ - - if (flag_reorder_blocks_and_partition) - return; - - if (node->frequency == NODE_FREQUENCY_HOT) - DECL_SECTION_NAME (current_function_decl) = - build_string (strlen (HOT_TEXT_SECTION_NAME), HOT_TEXT_SECTION_NAME); - if (node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) - DECL_SECTION_NAME (current_function_decl) = - build_string (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME), - UNLIKELY_EXECUTED_TEXT_SECTION_NAME); -} - static bool gate_estimate_probability (void) { diff --git a/gcc/system.h b/gcc/system.h index 73e513933f5..4de117ec35f 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -725,8 +725,9 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; OPTIMIZATION_OPTIONS CLASS_LIKELY_SPILLED_P \ USING_SJLJ_EXCEPTIONS TARGET_UNWIND_INFO \ LABEL_ALIGN_MAX_SKIP LOOP_ALIGN_MAX_SKIP \ - LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP JUMP_ALIGN_MAX_SKIP \ - CAN_DEBUG_WITHOUT_FP + LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP JUMP_ALIGN_MAX_SKIP \ + CAN_DEBUG_WITHOUT_FP UNLIKELY_EXECUTED_TEXT_SECTION_NAME \ + HOT_TEXT_SECTION_NAME /* Other obsolete target macros, or macros that used to be in target headers and were not used, and may be obsolete or may never have diff --git a/gcc/target.def b/gcc/target.def index 199b58cfc13..22d5660b13d 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -281,6 +281,19 @@ DEFHOOK void, (const char *name, unsigned int flags, tree decl), default_no_named_section) +/* Return preferred text (sub)section for function DECL. + Main purpose of this function is to separate cold, normal and hot + functions. STARTUP is true when function is known to be used only + at startup (from static constructors or it is main()). + EXIT is true when function is known to be used only at exit + (from static destructors). + Return NULL if function should go to default text section. */ +DEFHOOK +(function_section, + "", + section *, (tree decl, enum node_frequency freq, bool startup, bool exit), + default_function_section) + /* Return a mask describing how relocations should be treated when selecting sections. Bit 1 should be set if global relocations should be placed in a read-write section; bit 0 should be set if diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 71b612fa0a8..aff1b2745ed 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -171,7 +171,8 @@ extern int default_label_align_after_barrier_max_skip (rtx); extern int default_loop_align_max_skip (rtx); extern int default_label_align_max_skip (rtx); extern int default_jump_align_max_skip (rtx); - +extern section * default_function_section(tree decl, enum node_frequency freq, + bool startup, bool exit); extern enum machine_mode default_get_reg_raw_mode(int); extern const struct default_options empty_optimization_table[]; diff --git a/gcc/tree.h b/gcc/tree.h index 90170e78d07..8bc52ec87e2 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3107,6 +3107,11 @@ struct GTY(()) tree_parm_decl { #define DECL_HAS_INIT_PRIORITY_P(NODE) \ (VAR_DECL_CHECK (NODE)->decl_with_vis.init_priority_p) +/* Specify whether the section name was set by user or by + compiler via -ffunction-sections. */ +#define DECL_HAS_IMPLICIT_SECTION_NAME_P(NODE) \ + (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.implicit_section_name_p) + struct GTY(()) tree_decl_with_vis { struct tree_decl_with_rtl common; tree assembler_name; @@ -3135,7 +3140,9 @@ struct GTY(()) tree_decl_with_vis { unsigned init_priority_p : 1; /* Used by C++ only. Might become a generic decl flag. */ unsigned shadowed_for_var_p : 1; - /* 14 unused bits. */ + /* When SECTION_NAME is implied by -ffunsection-section. */ + unsigned implicit_section_name_p : 1; + /* 13 unused bits. */ }; extern tree decl_debug_expr_lookup (tree); diff --git a/gcc/varasm.c b/gcc/varasm.c index 6171e30799a..fc996f1f8cd 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -368,69 +368,6 @@ create_block_symbol (const char *label, struct object_block *block, return symbol; } -static void -initialize_cold_section_name (void) -{ - const char *stripped_name; - char *name, *buffer; - tree dsn; - - gcc_assert (cfun && current_function_decl); - if (crtl->subsections.unlikely_text_section_name) - return; - - dsn = DECL_SECTION_NAME (current_function_decl); - if (flag_function_sections && dsn) - { - name = (char *) alloca (TREE_STRING_LENGTH (dsn) + 1); - memcpy (name, TREE_STRING_POINTER (dsn), TREE_STRING_LENGTH (dsn) + 1); - - stripped_name = targetm.strip_name_encoding (name); - - buffer = ACONCAT ((stripped_name, "_unlikely", NULL)); - crtl->subsections.unlikely_text_section_name = ggc_strdup (buffer); - } - else - crtl->subsections.unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME; -} - -/* Tell assembler to switch to unlikely-to-be-executed text section. */ - -section * -unlikely_text_section (void) -{ - if (cfun) - { - if (!crtl->subsections.unlikely_text_section_name) - initialize_cold_section_name (); - - return get_named_section (NULL, crtl->subsections.unlikely_text_section_name, 0); - } - else - return get_named_section (NULL, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0); -} - -/* When called within a function context, return true if the function - has been assigned a cold text section and if SECT is that section. - When called outside a function context, return true if SECT is the - default cold section. */ - -bool -unlikely_text_section_p (section *sect) -{ - const char *name; - - if (cfun) - name = crtl->subsections.unlikely_text_section_name; - else - name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME; - - return (name - && sect - && SECTION_STYLE (sect) == SECTION_NAMED - && strcmp (name, sect->named.name) == 0); -} - /* Return a section with a particular name and with whatever SECTION_* flags section_type_flags deems appropriate. The name of the section is taken from NAME if nonnull, otherwise it is taken from DECL's @@ -462,7 +399,10 @@ resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED, && targetm.have_named_sections && (flag_function_or_data_sections || DECL_ONE_ONLY (decl))) - targetm.asm_out.unique_section (decl, reloc); + { + targetm.asm_out.unique_section (decl, reloc); + DECL_HAS_IMPLICIT_SECTION_NAME_P (decl) = true; + } } #ifdef BSS_SECTION_ASM_OP @@ -539,49 +479,176 @@ hot_function_section (tree decl) } #endif +/* Return section for TEXT_SECTION_NAME if DECL or DECL_SECTION_NAME (DECL) + is NULL. + + When DECL_SECTION_NAME is non-NULL and it is implicit section and + NAMED_SECTION_SUFFIX is non-NULL, then produce section called + concatenate the name with NAMED_SECTION_SUFFIX. + Otherwise produce "TEXT_SECTION_NAME.IMPLICIT_NAME". */ + +section * +get_named_text_section (tree decl, + const char *text_section_name, + const char *named_section_suffix) +{ + if (decl && DECL_SECTION_NAME (decl)) + { + if (named_section_suffix) + { + tree 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); + + 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)) + { + const char *name; + + /* Do not try to split gnu_linkonce functions. This gets somewhat + slipperly. */ + if (DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP) + return NULL; + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + name = targetm.strip_name_encoding (name); + return get_named_section (decl, ACONCAT ((text_section_name, ".", + name, NULL)), 0); + } + else + return NULL; + } + return get_named_section (decl, text_section_name, 0); +} + +/* Choose named function section based on its frequency. */ + +section * +default_function_section (tree decl, enum node_frequency freq, + bool startup, bool exit) +{ + /* Startup code should go to startup subsection unless it is + unlikely executed (this happens especially with function splitting + where we can split away unnecesary parts of static constructors. */ + if (startup && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED) + return get_named_text_section (decl, ".text.startup", NULL); + + /* Similarly for exit. */ + if (exit && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED) + return get_named_text_section (decl, ".text.exit", NULL); + + /* Group cold functions together, similarly for hot code. */ + switch (freq) + { + 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); + default: + return NULL; + } +} + /* Return the section for function DECL. If DECL is NULL_TREE, return the text section. We can be passed - NULL_TREE under some circumstances by dbxout.c at least. */ + NULL_TREE under some circumstances by dbxout.c at least. -section * -function_section (tree decl) + If FORCE_COLD is true, return cold function section ignoring + the frequency info of cgraph_node. */ + +static section * +function_section_1 (tree decl, bool force_cold) { - int reloc = 0; + section *section = NULL; + enum node_frequency freq = NODE_FREQUENCY_NORMAL; + bool startup = false, exit = false; + + if (decl) + { + struct cgraph_node *node = cgraph_node (decl); - if (first_function_block_is_cold) - reloc = 1; + freq = node->frequency; + startup = node->only_called_at_startup; + exit = node->only_called_at_exit; + } + if (force_cold) + freq = NODE_FREQUENCY_UNLIKELY_EXECUTED; #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS if (decl != NULL_TREE && DECL_SECTION_NAME (decl) != NULL_TREE) - return reloc ? unlikely_text_section () - : get_named_section (decl, NULL, 0); + { + if (targetm.asm_out.function_section) + section = targetm.asm_out.function_section (decl, freq, + startup, exit); + if (section) + return section; + return get_named_section (decl, NULL, 0); + } else - return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl)); + return targetm.asm_out.select_section + (decl, freq == NODE_FREQUENCY_UNLIKELY_EXECUTED, + DECL_ALIGN (decl)); #else - return reloc ? unlikely_text_section () : hot_function_section (decl); + if (targetm.asm_out.function_section) + section = targetm.asm_out.function_section (decl, freq, startup, exit); + if (section) + return section; + return hot_function_section (decl); #endif } +/* Return the section for function DECL. + + If DECL is NULL_TREE, return the text section. We can be passed + NULL_TREE under some circumstances by dbxout.c at least. */ + +section * +function_section (tree decl) +{ + /* Handle cases where function splitting code decides + to put function entry point into unlikely executed section + despite the fact that the function itself is not cold + (i.e. it is called rarely but contains a hot loop that is + better to live in hot subsection for the code locality). */ + return function_section_1 (decl, + first_function_block_is_cold); +} + +/* Return the section for the current function, take IN_COLD_SECTION_P + into account. */ + section * current_function_section (void) { -#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS - if (current_function_decl != NULL_TREE - && DECL_SECTION_NAME (current_function_decl) != NULL_TREE) - return in_cold_section_p ? unlikely_text_section () - : get_named_section (current_function_decl, - NULL, 0); - else - return targetm.asm_out.select_section (current_function_decl, - in_cold_section_p, - DECL_ALIGN (current_function_decl)); -#else - return (in_cold_section_p - ? unlikely_text_section () - : hot_function_section (current_function_decl)); -#endif + return function_section_1 (current_function_decl, in_cold_section_p); +} + +/* Tell assembler to switch to unlikely-to-be-executed text section. */ + +section * +unlikely_text_section (void) +{ + return function_section_1 (current_function_decl, true); +} + +/* When called within a function context, return true if the function + has been assigned a cold text section and if SECT is that section. + When called outside a function context, return true if SECT is the + default cold section. */ + +bool +unlikely_text_section_p (section *sect) +{ + return sect == function_section_1 (current_function_decl, true); } /* Return the read-only data section associated with function DECL. */ @@ -1454,8 +1521,6 @@ assemble_start_function (tree decl, const char *fnname) char tmp_label[100]; bool hot_label_written = false; - crtl->subsections.unlikely_text_section_name = NULL; - first_function_block_is_cold = false; if (flag_reorder_blocks_and_partition) { @@ -1513,16 +1578,10 @@ assemble_start_function (tree decl, const char *fnname) else if (DECL_SECTION_NAME (decl)) { /* Calls to function_section rely on first_function_block_is_cold - being accurate. The first block may be cold even if we aren't - doing partitioning, if the entire function was decided by - choose_function_section (predict.c) to be cold. */ - - initialize_cold_section_name (); - - if (crtl->subsections.unlikely_text_section_name - && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), - crtl->subsections.unlikely_text_section_name) == 0) - first_function_block_is_cold = true; + being accurate. */ + first_function_block_is_cold + = (cgraph_node (current_function_decl)->frequency + == NODE_FREQUENCY_UNLIKELY_EXECUTED); } in_cold_section_p = first_function_block_is_cold; @@ -5871,15 +5930,6 @@ default_section_type_flags (tree decl, const char *name, int reloc) flags = SECTION_CODE; else if (decl && decl_readonly_section (decl, reloc)) flags = 0; - else if (current_function_decl - && cfun - && crtl->subsections.unlikely_text_section_name - && strcmp (name, crtl->subsections.unlikely_text_section_name) == 0) - flags = SECTION_CODE; - else if (!decl - && (!current_function_decl || !cfun) - && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0) - flags = SECTION_CODE; else flags = SECTION_WRITE; @@ -6810,12 +6860,6 @@ switch_to_section (section *new_section) switch (SECTION_STYLE (new_section)) { case SECTION_NAMED: - if (cfun - && !crtl->subsections.unlikely_text_section_name - && strcmp (new_section->named.name, - UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0) - crtl->subsections.unlikely_text_section_name = UNLIKELY_EXECUTED_TEXT_SECTION_NAME; - targetm.asm_out.named_section (new_section->named.name, new_section->named.common.flags, new_section->named.decl); -- 2.11.0