On Mon, Jan 15, 2024 at 01:28:04PM +0100, Richard Biener wrote:
> On Mon, Jan 15, 2024 at 12:27 PM Andrew Carlotti
> <andrew.carlo...@arm.com> wrote:
> >
> > This allows code to determine why a particular function is
> > multiversioned.  For now, this will primarily be used to preserve
> > existing name mangling quirks when subsequent commits change all
> > function multiversioning name mangling to use explicit target hooks.
> > However, this can also be used in future to allow more of the
> > multiversioning logic to be moved out of target hooks, and to allow
> > targets to simultaneously enable multiversioning with both 'target' and
> > 'target_version' attributes.
> 
> Why does module.cc need to stream the bits?  target_clone runs long
> after the FE finished.  Instead I wonder why LTO doesn't stream the bits
> (tree-streamer-{in,out}.cc)?
>
> You have four states but only mention 'target' and 'target_version', what's 
> the
> states actually?  Can you amend the function_version_source enum
> comment accordingly?

All four states are used, although currently not all within a single target,
and in many places you could also work out whether you're in the
"target_clones" case or the "target"/"target_version" case based upon whether
you're in the frontend code or the target_clone pass.  So perhaps the second
bit can be made redundant in most places, but it's useful in some parts of the
code.

The main benefits of this design are:
- that it allows backend target hooks to distinguish between the different
  causes of function multiversioning without having to create separate hooks,
  or pass an extra argument down the call stack;
- that it allows a backend to choose to support mutltiversioning with both
  "target" and "target_version" attributes (I remember Martin Liška suggested
  supporting "target_version" on x86 as well, and it could provide a way to
  improve how multiversioning works without running into backwards
  compatibility issues for the "target" attribute).

> This looks like stage1 material to me.

I considered it as stage 3 material, because it fixes a bug on aarch64 (where
the existing code didn't comply with the ACLE spec, and would have cause
problems when applied to public symbols).  Admittedly, I did miss the end of
stage 3 by a couple of days; I hadn't realised how early stage 4 began, and
spent the last couple of weeks focussing on Binutils work instead.

However, I've now realised that I can fix this bug entirely within the aarch64
backend (by overwriting the incorrect mangling applied in target-agnostic
code).  I'll send out that patch later today, which should hopefully be more
acceptable at this stage.

Thanks,
Andrew

> Thanks,
> Richard.
> 
> > gcc/ChangeLog:
> >
> >         * multiple_target.cc (expand_target_clones): Use new enum value.
> >         * tree-core.h (enum function_version_source): New enum.
> >         (struct tree_function_decl): Extend versioned_function to two
> >         bits.
> >
> > gcc/cp/ChangeLog:
> >
> >         * decl.cc (maybe_mark_function_versioned): Use new enum value.
> >         (duplicate_decls): Preserve DECL_FUNCTION_VERSIONED enum value.
> >         * module.cc (trees_out::core_bools): Use two bits for
> >         function_decl.versioned_function.
> >         (trees_in::core_bools): Ditto.
> >
> >
> > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > index 
> > b10a72a87bf0a1cabab52c1e4b657bc8a379b91e..527931cd90a0a779a508a096b2623351fd65a2e8
> >  100644
> > --- a/gcc/cp/decl.cc
> > +++ b/gcc/cp/decl.cc
> > @@ -1254,7 +1254,10 @@ maybe_mark_function_versioned (tree decl)
> >  {
> >    if (!DECL_FUNCTION_VERSIONED (decl))
> >      {
> > -      DECL_FUNCTION_VERSIONED (decl) = 1;
> > +      if (TARGET_HAS_FMV_TARGET_ATTRIBUTE)
> > +       DECL_FUNCTION_VERSIONED (decl) = FUNCTION_VERSION_TARGET;
> > +      else
> > +       DECL_FUNCTION_VERSIONED (decl) = FUNCTION_VERSION_TARGET_VERSION;
> >        /* If DECL_ASSEMBLER_NAME has already been set, re-mangle
> >          to include the version marker.  */
> >        if (DECL_ASSEMBLER_NAME_SET_P (decl))
> > @@ -3159,7 +3162,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
> > hiding, bool was_hidden)
> >        && DECL_FUNCTION_VERSIONED (olddecl))
> >      {
> >        /* Set the flag for newdecl so that it gets copied to olddecl.  */
> > -      DECL_FUNCTION_VERSIONED (newdecl) = 1;
> > +      DECL_FUNCTION_VERSIONED (newdecl) = DECL_FUNCTION_VERSIONED 
> > (olddecl);
> >        /* newdecl will be purged after copying to olddecl and is no longer
> >           a version.  */
> >        cgraph_node::delete_function_version_by_decl (newdecl);
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index 
> > aa75e2809d8fdca14443c6b911bf725f6d286d20..ba60d0753f91ef91d45fb5d62f26118be4e34840
> >  100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -5473,7 +5473,11 @@ trees_out::core_bools (tree t)
> >        WB (t->function_decl.looping_const_or_pure_flag);
> >
> >        WB (t->function_decl.has_debug_args_flag);
> > -      WB (t->function_decl.versioned_function);
> > +
> > +      /* versioned_function is a 2 bit enum.  */
> > +      unsigned vf = t->function_decl.versioned_function;
> > +      WB ((vf >> 0) & 1);
> > +      WB ((vf >> 1) & 1);
> >
> >        /* decl_type is a (misnamed) 2 bit discriminator.         */
> >        unsigned kind = t->function_decl.decl_type;
> > @@ -5618,7 +5622,12 @@ trees_in::core_bools (tree t)
> >        RB (t->function_decl.looping_const_or_pure_flag);
> >
> >        RB (t->function_decl.has_debug_args_flag);
> > -      RB (t->function_decl.versioned_function);
> > +
> > +      /* versioned_function is a 2 bit enum.  */
> > +      unsigned vf = 0;
> > +      vf |= unsigned (b ()) << 0;
> > +      vf |= unsigned (b ()) << 1;
> > +      t->function_decl.versioned_function = function_version_source (vf);
> >
> >        /* decl_type is a (misnamed) 2 bit discriminator.         */
> >        unsigned kind = 0;
> > diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc
> > index 
> > 1fdd279da04a7acc5e8c50f528139f19cadcd5ff..56a1934fe820e91b2fa451dcf6989382c906b98c
> >  100644
> > --- a/gcc/multiple_target.cc
> > +++ b/gcc/multiple_target.cc
> > @@ -383,7 +383,7 @@ expand_target_clones (struct cgraph_node *node, bool 
> > definition)
> >    if (decl1_v == NULL)
> >      decl1_v = node->insert_new_function_version ();
> >    before = decl1_v;
> > -  DECL_FUNCTION_VERSIONED (node->decl) = 1;
> > +  DECL_FUNCTION_VERSIONED (node->decl) = FUNCTION_VERSION_TARGET_CLONES;
> >
> >    for (i = 0; i < attrnum; i++)
> >      {
> > @@ -421,7 +421,8 @@ expand_target_clones (struct cgraph_node *node, bool 
> > definition)
> >
> >        before->next = after;
> >        after->prev = before;
> > -      DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
> > +      DECL_FUNCTION_VERSIONED (new_node->decl)
> > +       = FUNCTION_VERSION_TARGET_CLONES;
> >      }
> >
> >    XDELETEVEC (attrs);
> > diff --git a/gcc/tree-core.h b/gcc/tree-core.h
> > index 
> > 8a89462bd7ecac52fcdc11c0b57ccf7c190572b3..e159d53f9d11ba848c49499aa963daa2fbcbc648
> >  100644
> > --- a/gcc/tree-core.h
> > +++ b/gcc/tree-core.h
> > @@ -1955,6 +1955,19 @@ enum function_decl_type
> >    /* 0 values left */
> >  };
> >
> > +/* Enumerate function multiversioning attributes.  This is used to record 
> > which
> > +   attribute enabled multiversioning on a function, and allows targets to
> > +   adjust their behaviour accordingly.  */
> > +
> > +enum function_version_source
> > +{
> > +  FUNCTION_VERSION_NONE = 0,
> > +  FUNCTION_VERSION_TARGET = 1,
> > +  FUNCTION_VERSION_TARGET_CLONES = 2,
> > +  FUNCTION_VERSION_TARGET_VERSION = 3
> > +};
> > +
> > +
> >  /* FUNCTION_DECL inherits from DECL_NON_COMMON because of the use of the
> >     arguments/result/saved_tree fields by front ends.   It was either 
> > inherit
> >     FUNCTION_DECL from non_common, or inherit non_common from FUNCTION_DECL,
> > @@ -2002,10 +2015,10 @@ struct GTY(()) tree_function_decl {
> >    /* Align the bitfield to boundary of a byte.  */
> >    ENUM_BITFIELD(function_decl_type) decl_type: 2;
> >    unsigned has_debug_args_flag : 1;
> > -  unsigned versioned_function : 1;
> > +  ENUM_BITFIELD(function_version_source) versioned_function : 2;
> >    unsigned replaceable_operator : 1;
> >
> > -  /* 11 bits left for future expansion.  */
> > +  /* 10 bits left for future expansion.  */
> >    /* 32 bits on 64-bit HW.  */
> >  };
> >

Reply via email to