On Mar 20, 2012, at 3:19 PM, Richard Guenther wrote: […] > > I'd rather get away from using a global main_identifier_node, instead > make that frontend specific, and introduce targetm.main_assembler_name > which the assembler-name creating langhook would make sure to use > when mangling what the FE thinks main is. main_identifier_node should > not serve any purpose outside of Frontends. > > But I see both as a possible cleanup opportunity, not a necessary change.
Something along these lines ? Tristan. diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 89f5438..c575e97 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -622,8 +622,6 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name ATTRIBUTE_UNUSED, integer_type_node, NULL_TREE, true, false, true, false, NULL, Empty); - main_identifier_node = get_identifier ("main"); - /* Install the builtins we might need, either internally or as user available facilities for Intrinsic imports. */ gnat_install_builtins (); diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 7383358..b0fa085d 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -1902,14 +1902,12 @@ create_subprog_decl (tree subprog_name, tree asm_name, tree subprog_type, { SET_DECL_ASSEMBLER_NAME (subprog_decl, asm_name); - /* The expand_main_function circuitry expects "main_identifier_node" to - designate the DECL_NAME of the 'main' entry point, in turn expected - to be declared as the "main" function literally by default. Ada - program entry points are typically declared with a different name + /* Ada program entry points are typically declared with a different name within the binder generated file, exported as 'main' to satisfy the - system expectations. Force main_identifier_node in this case. */ - if (asm_name == main_identifier_node) - DECL_NAME (subprog_decl) = main_identifier_node; + system expectations. Force main_assembler_node in this case. */ + if (IDENTIFIER_LENGTH (asm_name) == 4 + && memcmp (IDENTIFIER_POINTER (asm_name), "main", 4) == 0) + DECL_NAME (subprog_decl) = main_assembler_name; } /* Add this decl to the current binding level. */ diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 835b13b..fea5181 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -291,6 +291,8 @@ enum c_tree_index CTI_DEFAULT_FUNCTION_TYPE, + CTI_MAIN_IDENTIFIER, + /* These are not types, but we have to look them up all the time. */ CTI_FUNCTION_NAME_DECL, CTI_PRETTY_FUNCTION_NAME_DECL, @@ -426,6 +428,10 @@ extern const unsigned int num_c_common_reswords; #define default_function_type c_global_trees[CTI_DEFAULT_FUNCTION_TYPE] +#define main_identifier_node c_global_trees[CTI_MAIN_IDENTIFIER] +#define MAIN_NAME_P(NODE) \ + (IDENTIFIER_NODE_CHECK (NODE) == main_identifier_node) + #define function_name_decl_node c_global_trees[CTI_FUNCTION_NAME_DECL] #define pretty_function_name_decl_node c_global_trees[CTI_PRETTY_FUNCTION_NAME_DECL] #define c99_function_name_decl_node c_global_trees[CTI_C99_FUNCTION_NAME_DECL] diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index bd21169..db53309 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -4513,9 +4513,7 @@ gimple_expand_cfg (void) /* If this function is `main', emit a call to `__main' to run global initializers, etc. */ - if (DECL_NAME (current_function_decl) - && MAIN_NAME_P (DECL_NAME (current_function_decl)) - && DECL_FILE_SCOPE_P (current_function_decl)) + if (cgraph_main_function_p (cgraph_get_node (current_function_decl))) expand_main_function (); /* Initialize the stack_protect_guard field. This must happen after the diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 9cc3690..528fd19 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2766,7 +2766,7 @@ cgraph_propagate_frequency_1 (struct cgraph_node *node, void *data) /* It makes sense to put main() together with the static constructors. It will be executed for sure, but rest of functions called from main are definitely not at startup only. */ - if (MAIN_NAME_P (DECL_NAME (edge->caller->decl))) + if (cgraph_main_function_p (edge->caller)) d->only_called_at_startup = 0; d->only_called_at_exit &= edge->caller->only_called_at_exit; } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 191364c..089d851 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -101,6 +101,9 @@ struct GTY(()) cgraph_local_info { /* True if the function may enter serial irrevocable mode. */ unsigned tm_may_enter_irr : 1; + + /* True if the function is the program entry point (main in C). */ + unsigned main_function : 1; }; /* Information about the function that needs to be computed globally @@ -790,6 +793,13 @@ cgraph_next_function_with_gimple_body (struct cgraph_node *node) return NULL; } +/* Return true iff NODE is the main function (main in C). */ +static inline bool +cgraph_main_function_p (struct cgraph_node *node) +{ + return node && node->local.main_function; +} + /* Walk all functions with body defined. */ #define FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) \ for ((node) = cgraph_first_function_with_gimple_body (); (node); \ diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 516f187..556f21c 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -346,6 +346,9 @@ cgraph_finalize_function (tree decl, bool nested) notice_global_symbol (decl); node->local.finalized = true; node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL; + node->local.main_function = + DECL_FILE_SCOPE_P (decl) + && decl_assembler_name_equal (decl, main_assembler_name); if (cgraph_decide_is_function_needed (node, decl)) cgraph_mark_needed_node (node); diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h index 2eccda9..e0f6234 100644 --- a/gcc/config/i386/cygming.h +++ b/gcc/config/i386/cygming.h @@ -360,7 +360,7 @@ do { \ #undef PROFILE_HOOK #define PROFILE_HOOK(LABEL) \ - if (MAIN_NAME_P (DECL_NAME (current_function_decl))) \ + if (cgraph_main_function_p (cgraph_get_node (current_function_decl))) \ { \ emit_call_insn (gen_rtx_CALL (VOIDmode, \ gen_rtx_MEM (FUNCTION_MODE, \ diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 78a366e..c4a78b1 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -9509,9 +9509,7 @@ ix86_minimum_incoming_stack_boundary (bool sibcall) /* Stack at entrance of main is aligned by runtime. We use the smallest incoming stack boundary. */ if (incoming_stack_boundary > MAIN_STACK_BOUNDARY - && DECL_NAME (current_function_decl) - && MAIN_NAME_P (DECL_NAME (current_function_decl)) - && DECL_FILE_SCOPE_P (current_function_decl)) + && cgraph_main_function_p (cgraph_get_node (current_function_decl))) incoming_stack_boundary = MAIN_STACK_BOUNDARY; return incoming_stack_boundary; diff --git a/gcc/config/pdp11/pdp11.c b/gcc/config/pdp11/pdp11.c index 42e3af0..d1df127 100644 --- a/gcc/config/pdp11/pdp11.c +++ b/gcc/config/pdp11/pdp11.c @@ -240,7 +240,8 @@ pdp11_expand_prologue (void) /* If we are outputting code for main, the switch FPU to the right mode if TARGET_FPU. */ - if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU) + if (TARGET_FPU + && cgraph_main_function_p (cgraph_get_node (current_function_decl))) { emit_insn (gen_setd ()); emit_insn (gen_seti ()); diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 2891bb6..654f8ec 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -8102,6 +8102,11 @@ systems. This macro is used in @code{assemble_name}. Given a symbol @var{name}, perform same mangling as @code{varasm.c}'s @code{assemble_name}, but in memory rather than to a file stream, returning result as an @code{IDENTIFIER_NODE}. Required for correct LTO symtabs. The default implementation calls the @code{TARGET_STRIP_NAME_ENCODING} hook and then prepends the @code{USER_LABEL_PREFIX}, if any. @end deftypefn +@deftypefn {Target Hook} tree TARGET_MAIN_ASSEMBLER_NAME (void) +It returns the assembler name for the 'main' function. +The default is to return 'main', which will be prefixed by USER_LABEL_PREFIX. +@end deftypefn + @defmac ASM_OUTPUT_SYMBOL_REF (@var{stream}, @var{sym}) A C statement (sans semicolon) to output a reference to @code{SYMBOL_REF} @var{sym}. If not defined, @code{assemble_name} diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index a222654..6765344 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -8007,6 +8007,8 @@ systems. This macro is used in @code{assemble_name}. @hook TARGET_MANGLE_ASSEMBLER_NAME +@hook TARGET_MAIN_ASSEMBLER_NAME + @defmac ASM_OUTPUT_SYMBOL_REF (@var{stream}, @var{sym}) A C statement (sans semicolon) to output a reference to @code{SYMBOL_REF} @var{sym}. If not defined, @code{assemble_name} diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index 8a1dd2e..a51b0ac 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -4922,9 +4922,8 @@ create_main_function (tree fndecl) tmp = build_function_type_list (integer_type_node, integer_type_node, build_pointer_type (pchar_type_node), NULL_TREE); - main_identifier_node = get_identifier ("main"); ftn_main = build_decl (input_location, FUNCTION_DECL, - main_identifier_node, tmp); + get_identifier ("main"), tmp); DECL_EXTERNAL (ftn_main) = 0; TREE_PUBLIC (ftn_main) = 1; TREE_STATIC (ftn_main) = 1; diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index 9dddf39..595330e 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -1409,7 +1409,7 @@ execute_split_functions (void) fprintf (dump_file, "Not splitting: noreturn/malloc function.\n"); return 0; } - if (MAIN_NAME_P (DECL_NAME (current_function_decl))) + if (cgraph_main_function_p (node)) { if (dump_file) fprintf (dump_file, "Not splitting: main function.\n"); diff --git a/gcc/ipa.c b/gcc/ipa.c index 388291a..f9dc42d 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -639,7 +639,7 @@ cgraph_externally_visible_p (struct cgraph_node *node, else if (!whole_program) return true; - if (MAIN_NAME_P (DECL_NAME (node->decl))) + if (cgraph_main_function_p (node)) return true; return false; diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 5e899bc..34bcc55 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -502,6 +502,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, bp_pack_value (&bp, node->local.versionable, 1); bp_pack_value (&bp, node->local.can_change_signature, 1); bp_pack_value (&bp, node->local.redefined_extern_inline, 1); + bp_pack_value (&bp, node->local.main_function, 1); bp_pack_value (&bp, node->needed, 1); bp_pack_value (&bp, node->address_taken, 1); bp_pack_value (&bp, node->abstract_and_needed, 1); @@ -904,6 +905,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, node->local.versionable = bp_unpack_value (bp, 1); node->local.can_change_signature = bp_unpack_value (bp, 1); node->local.redefined_extern_inline = bp_unpack_value (bp, 1); + node->local.main_function = bp_unpack_value (bp, 1); node->needed = bp_unpack_value (bp, 1); node->address_taken = bp_unpack_value (bp, 1); node->abstract_and_needed = bp_unpack_value (bp, 1); diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 999db8b..a44a35f 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -1137,13 +1137,6 @@ lto_init (void) /* Create the basic integer types. */ build_common_tree_nodes (flag_signed_char, /*short_double=*/false); - /* The global tree for the main identifier is filled in by - language-specific front-end initialization that is not run in the - LTO back-end. It appears that all languages that perform such - initialization currently do so in the same way, so we do it here. */ - if (main_identifier_node == NULL_TREE) - main_identifier_node = get_identifier ("main"); - /* In the C++ front-end, fileptr_type_node is defined as a variant copy of of ptr_type_node, rather than ptr_node itself. The distinction should only be relevant to the front-end, so we diff --git a/gcc/predict.c b/gcc/predict.c index c12b45f..819e64c 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -2275,7 +2275,7 @@ compute_function_frequency (void) basic_block bb; struct cgraph_node *node = cgraph_get_node (current_function_decl); if (DECL_STATIC_CONSTRUCTOR (current_function_decl) - || MAIN_NAME_P (DECL_NAME (current_function_decl))) + || cgraph_main_function_p (node)) node->only_called_at_startup = true; if (DECL_STATIC_DESTRUCTOR (current_function_decl)) node->only_called_at_exit = true; @@ -2291,7 +2291,7 @@ compute_function_frequency (void) node->frequency = NODE_FREQUENCY_HOT; else if (flags & ECF_NORETURN) node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; - else if (MAIN_NAME_P (DECL_NAME (current_function_decl))) + else if (cgraph_main_function_p (node)) node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; else if (DECL_STATIC_CONSTRUCTOR (current_function_decl) || DECL_STATIC_DESTRUCTOR (current_function_decl)) diff --git a/gcc/target.def b/gcc/target.def index d658b11..2c91620 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -1473,6 +1473,17 @@ DEFHOOK tree, (tree decl, tree id), default_mangle_decl_assembler_name) +/* Return the assembler name for the 'main' function. It should return the + same identifier as mandle_decl_assembler_name will for the C 'main' + function. + The default is to return 'main'. */ +DEFHOOK +(main_assembler_name, + "It returns the assembler name for the 'main' function.\n\ +The default is to return 'main', which will be prefixed by USER_LABEL_PREFIX.", + tree, (void), + default_main_assembler_name) + /* Do something target-specific to record properties of the DECL into the associated SYMBOL_REF. */ DEFHOOK diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 8e3d74e..08535b4 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -371,6 +371,13 @@ default_mangle_assembler_name (const char *name ATTRIBUTE_UNUSED) return get_identifier (stripped); } +/* The default implementation of TARGET_MAIN_ASSEMBLER_NAME. */ +tree +default_main_assembler_name (void) +{ + return get_identifier ("main"); +} + /* True if MODE is valid for the target. By "valid", we mean able to be manipulated in non-trivial ways. In particular, this means all the arithmetic is supported. diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 8618115..3016f04 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -66,6 +66,7 @@ extern void default_print_operand (FILE *, rtx, int); extern void default_print_operand_address (FILE *, rtx); extern bool default_print_operand_punct_valid_p (unsigned char); extern tree default_mangle_assembler_name (const char *); +extern tree default_main_assembler_name (void); extern bool default_scalar_mode_supported_p (enum machine_mode); extern bool targhook_words_big_endian (void); diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index b65f5aa..9cb7a16 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -6933,7 +6933,7 @@ ipa_pta_execute (void) /* We also need to make function return values escape. Nothing escapes by returning from main though. */ - if (!MAIN_NAME_P (DECL_NAME (node->decl))) + if (!cgraph_main_function_p (node->decl)) { varinfo_t fi, rvi; fi = lookup_vi_for_tree (node->decl); diff --git a/gcc/tree.c b/gcc/tree.c index cfea9f7..6a0d380 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -9477,6 +9477,8 @@ build_common_tree_nodes (bool signed_char, bool short_double) va_list_type_node = t; } + + main_assembler_name = targetm.main_assembler_name (); } /* A subroutine of build_common_builtin_nodes. Define a builtin function. */ diff --git a/gcc/tree.h b/gcc/tree.h index 62ee454..45c750f 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3805,7 +3805,7 @@ enum tree_index TI_VOID_LIST_NODE, - TI_MAIN_IDENTIFIER, + TI_MAIN_ASSEMBLER_NAME, TI_SAT_SFRACT_TYPE, TI_SAT_FRACT_TYPE, @@ -4048,9 +4048,7 @@ extern GTY(()) tree global_trees[TI_MAX]; anything else about this node. */ #define void_list_node global_trees[TI_VOID_LIST_NODE] -#define main_identifier_node global_trees[TI_MAIN_IDENTIFIER] -#define MAIN_NAME_P(NODE) \ - (IDENTIFIER_NODE_CHECK (NODE) == main_identifier_node) +#define main_assembler_name global_trees[TI_MAIN_ASSEMBLER_NAME] /* Optimization options (OPTIMIZATION_NODE) to use for default and current functions. */