Patchwork [Patch/cfgexpand] : also consider assembler_name to call expand_main_function

login
register
mail settings
Submitter Tristan Gingold
Date March 20, 2012, 4 p.m.
Message ID <D999EBA8-A0F5-49E6-9BC3-90A44A8BE9DD@adacore.com>
Download mbox | patch
Permalink /patch/147812/
State New
Headers show

Comments

Tristan Gingold - March 20, 2012, 4 p.m.
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.
Richard Guenther - March 20, 2012, 4:01 p.m.
On Tue, 20 Mar 2012, Tristan Gingold wrote:

> 
> 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 ?

Yes, but I'd simply call the hook at the places you now use
main_assembler_name and not create a global tree node for it.

Richard.

> 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.  */
> 
>
Tristan Gingold - March 20, 2012, 4:06 p.m.
On Mar 20, 2012, at 5:01 PM, Richard Guenther wrote:

> On Tue, 20 Mar 2012, Tristan Gingold wrote:
> 
>> 
>> 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 ?
> 
> Yes, but I'd simply call the hook at the places you now use
> main_assembler_name and not create a global tree node for it.

But we use it at the beginning of graph_finalize_function, so caching it
makes sense, doesn't it ?

Tristan.
Richard Guenther - March 21, 2012, 7:44 a.m.
On Tue, 20 Mar 2012, Tristan Gingold wrote:

> 
> On Mar 20, 2012, at 5:01 PM, Richard Guenther wrote:
> 
> > On Tue, 20 Mar 2012, Tristan Gingold wrote:
> > 
> >> 
> >> 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 ?
> > 
> > Yes, but I'd simply call the hook at the places you now use
> > main_assembler_name and not create a global tree node for it.
> 
> But we use it at the beginning of graph_finalize_function, so caching it
> makes sense, doesn't it ?

Well, maybe ;)  I have no strong opinion here.

Richard.

Patch

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.  */