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.

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