Alfie Richards <alfie.richa...@arm.com> writes:
> This adds the assembler_name member to cgraph_function_version_info
> to store the base assembler name for the function to be mangled. This is
> used in later patches for refactoring FMV mangling.
>
> gcc/c/ChangeLog:
>
>       * c-decl.cc (start_decl): Record assembler_name.
>       (start_function): Record assembler_name.
>
> gcc/ChangeLog:
>
>       * cgraph.cc (cgraph_node::record_function_versions): Record
>       assembler_name.
>       * cgraph.h (struct cgraph_function_version_info): Add assembler_name.
>
> gcc/cp/ChangeLog:
>
>       * decl.cc (maybe_mark_function_versioned): Record assember_name.
>       (start_decl): Record assembler_name.
>       (start_preparsed_function): Record assembler_name.

I'm not really qualified to review this part, but FWIW, my main question
would be: is it safe to cache the DECL_ASSEMBLER_NAME so early?  E.g. wrt
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117987 , it looks like the
C frontend applies the asm in finish_decl rather than start_decl.
I don't know whether the name could change even later, or whether
it is supposed to be final after finish_decl.

Also:

> ---
>  gcc/c/c-decl.cc | 20 ++++++++++++++++++++
>  gcc/cgraph.cc   | 10 ++++++++--
>  gcc/cgraph.h    |  3 +++
>  gcc/cp/decl.cc  | 34 ++++++++++++++++++++++++++++++++++
>  4 files changed, 65 insertions(+), 2 deletions(-)
>
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index 0dcbae9b26f..daa19f360e6 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -5762,6 +5762,16 @@ start_decl (struct c_declarator *declarator, struct 
> c_declspecs *declspecs,
>        && VAR_OR_FUNCTION_DECL_P (decl))
>        objc_check_global_decl (decl);
>  
> +  /* Store the base assembler name for mangling later.  */
> +  if (TREE_CODE (decl) == FUNCTION_DECL
> +      && lookup_attribute ("target_clones", DECL_ATTRIBUTES (decl)))
> +    {
> +      cgraph_node *node = cgraph_node::get_create (decl);
> +      if (!node->function_version ())
> +     node->insert_new_function_version ();
> +      node->function_version ()->assembler_name = DECL_ASSEMBLER_NAME (decl);
> +    }
> +
>    /* Add this decl to the current scope.
>       TEM may equal DECL or it may be a previous decl of the same name.  */
>    if (do_push)
> @@ -10863,6 +10873,16 @@ start_function (struct c_declspecs *declspecs, 
> struct c_declarator *declarator,
>  
>    current_function_decl = pushdecl (decl1);
>  
> +  /* Store the base assembler name for mangling later.  */
> +  if (TREE_CODE (decl1) == FUNCTION_DECL
> +      && lookup_attribute ("target_clones", DECL_ATTRIBUTES (decl1)))
> +    {
> +      cgraph_node *node = cgraph_node::get_create (decl1);
> +      if (!node->function_version ())
> +     node->insert_new_function_version ();
> +      node->function_version ()->assembler_name = DECL_ASSEMBLER_NAME 
> (decl1);
> +    }
> +
>    if (tree access = build_attr_access_from_parms (parms, false))
>      decl_attributes (&current_function_decl, access, ATTR_FLAG_INTERNAL,
>                    old_decl);
> diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
> index 1ea38d16e56..c2038be4671 100644
> --- a/gcc/cgraph.cc
> +++ b/gcc/cgraph.cc
> @@ -252,10 +252,16 @@ cgraph_node::record_function_versions (tree decl1, tree 
> decl2)
>    decl2_v = decl2_node->function_version ();
>  
>    if (decl1_v == NULL)
> -    decl1_v = decl1_node->insert_new_function_version ();
> +    {
> +      decl1_v = decl1_node->insert_new_function_version ();
> +      decl1_v->assembler_name = DECL_ASSEMBLER_NAME (decl1);
> +    }
>  
>    if (decl2_v == NULL)
> -    decl2_v = decl2_node->insert_new_function_version ();
> +    {
> +      decl2_v = decl2_node->insert_new_function_version ();
> +      decl2_v->assembler_name = DECL_ASSEMBLER_NAME (decl2);
> +    }
>  
>    gcc_assert (decl1_v);
>    gcc_assert (decl2_v);
> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
> index 065fcc742e8..d9177364b7a 100644
> --- a/gcc/cgraph.h
> +++ b/gcc/cgraph.h
> @@ -856,6 +856,9 @@ struct GTY((for_user)) cgraph_function_version_info {
>       dispatcher. The dispatcher decl is an alias to the resolver
>       function decl.  */
>    tree dispatcher_resolver;
> +
> +  /* The assmbly name of the function set before version mangling.  */
> +  tree assembler_name;
>  };
>  
>  #define DEFCIFCODE(code, type, string)       CIF_ ## code,
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 3b3b4481964..fdef98f8062 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -1273,6 +1273,12 @@ maybe_mark_function_versioned (tree decl)
>  {
>    if (!DECL_FUNCTION_VERSIONED (decl))
>      {
> +      cgraph_node *node = cgraph_node::get_create (decl);
> +      if (!node->function_version ())
> +     node->insert_new_function_version ();
> +      if (!node->function_version ()->assembler_name)
> +     node->function_version ()->assembler_name = DECL_ASSEMBLER_NAME (decl);
> +
>        DECL_FUNCTION_VERSIONED (decl) = 1;
>        /* If DECL_ASSEMBLER_NAME has already been set, re-mangle
>        to include the version marker.  */
> @@ -6155,6 +6161,20 @@ start_decl (const cp_declarator *declarator,
>  
>    was_public = TREE_PUBLIC (decl);
>  
> +  /* Set the assembler string for any versioned function.  */
> +  if (TREE_CODE (decl) == FUNCTION_DECL
> +      && (lookup_attribute (TARGET_HAS_FMV_TARGET_ATTRIBUTE ? "target"
> +                                                         : "target_version",
> +                         DECL_ATTRIBUTES (decl))
> +       || lookup_attribute ("target_clones", DECL_ATTRIBUTES (decl))))
> +    {
> +      cgraph_node *node = cgraph_node::get_create (decl);
> +      if (!node->function_version ())
> +     node->insert_new_function_version ();
> +      if (!node->function_version ()->assembler_name)
> +     node->function_version ()->assembler_name = DECL_ASSEMBLER_NAME (decl);
> +    }

function_version () is a hash lookup, so I think we should try to minimise
the number of calls.  E.g.:

    auto *decl_version = node->function_version ();
    if (!decl_version)
      decl_version = node->insert_new_function_version ();

It'd also be good avoid the cut-&-paste, in the sense that the C frontend
has two copies of the same code, and similarly the C++ frontend.

Thanks,
Richard

> +
>    if ((DECL_EXTERNAL (decl) || TREE_CODE (decl) == FUNCTION_DECL)
>        && current_function_decl)
>      {
> @@ -18743,6 +18763,20 @@ start_preparsed_function (tree decl1, tree attrs, 
> int flags)
>    if (!DECL_OMP_DECLARE_REDUCTION_P (decl1))
>      start_lambda_scope (decl1);
>  
> +  /* Set the assembler string for any versioned function.  */
> +  if (TREE_CODE (decl1) == FUNCTION_DECL
> +      && (lookup_attribute (TARGET_HAS_FMV_TARGET_ATTRIBUTE ? "target"
> +                                                         : "target_version",
> +                         DECL_ATTRIBUTES (decl1))
> +       || lookup_attribute ("target_clones", DECL_ATTRIBUTES (decl1))))
> +    {
> +      cgraph_node *node = cgraph_node::get_create (decl1);
> +      if (!node->function_version ())
> +     node->insert_new_function_version ();
> +      if (!node->function_version ()->assembler_name)
> +     node->function_version ()->assembler_name = DECL_ASSEMBLER_NAME (decl1);
> +    }
> +
>    return true;
>  }
>  

Reply via email to