When a target_clones function is inlined, the resolver function's
assembler name must be properly registered in the symbol table.
Using SET_DECL_ASSEMBLER_NAME only updates the tree node without
notifying the symbol table, which can lead to an ICE during IPA
inlining when the assembler name hash becomes inconsistent.

Replace SET_DECL_ASSEMBLER_NAME with symtab->change_decl_assembler_name
in make_resolver_func to properly update the symbol table's assembler
name mapping.

This only happens on x86, other targets already uses
symtab->change_decl_assembler_name.

Fixes: b500cd2634 ("x86: fmv: Refactor FMV name mangling.")
Signed-off-by: Yangyu Chen <[email protected]>

gcc/ChangeLog:

        * config/i386/i386-features.cc (make_resolver_func): Use
        symtab->change_decl_assembler_name instead of
        SET_DECL_ASSEMBLER_NAME to properly update the symbol table.

gcc/testsuite/ChangeLog:

        * gcc.target/i386/tct-ipa-inline-ice.c: New test.
---
To reproduce the ICE in the test, we need to allow inlining of
target_clones functions, just apply the following patch to c-attribs.cc:

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 10d9a51418e..8428e303f08 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -6439,9 +6439,6 @@ handle_target_clones_attribute (tree *node, tree name, 
tree ARG_UNUSED (args),
                     "single %<target_clones%> attribute is ignored");
          *no_add_attrs = true;
        }
-      else
-      /* Do not inline functions with multiple clone targets.  */
-       DECL_UNINLINABLE (*node) = 1;
     }
   else
     {

---
 gcc/config/i386/i386-features.cc              |  2 +-
 .../gcc.target/i386/tct-ipa-inline-ice.c      | 48 +++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/tct-ipa-inline-ice.c

diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index 0e4fdcd2853..9200e0c076c 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -5601,7 +5601,7 @@ make_resolver_func (const tree default_decl,
 
   tree id = ix86_mangle_decl_assembler_name
     (decl, node->function_version ()->assembler_name);
-  SET_DECL_ASSEMBLER_NAME (decl, id);
+  symtab->change_decl_assembler_name (decl, id);
 
   DECL_NAME (decl) = DECL_NAME (default_decl);
   TREE_USED (decl) = 1;
diff --git a/gcc/testsuite/gcc.target/i386/tct-ipa-inline-ice.c 
b/gcc/testsuite/gcc.target/i386/tct-ipa-inline-ice.c
new file mode 100644
index 00000000000..b8f77372e00
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/tct-ipa-inline-ice.c
@@ -0,0 +1,48 @@
+/* Test function multiversioning and inlining of a function with a
+   target_clones attribute.  Note, we need to allow inlining of
+   target_clones functions, see
+   "Do not inline functions with multiple clone targets." in c-attribs.cc,
+   otherwise the test would not trigger the ICE.  */
+/* { dg-do assemble } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O3" } */
+
+struct range_state
+{
+  unsigned int n;
+  unsigned int s[58];
+  unsigned int *q[58];
+};
+
+struct coder_state
+{
+  struct range_state r;
+  unsigned int t;
+  unsigned int x[12];
+};
+
+inline void
+bar(struct range_state *r, unsigned int *ptr, unsigned int value)
+{
+  r->s[r->n] = value;
+  r->q[r->n] = ptr;
+  ++r->n;
+}
+
+__attribute__((target_clones("default", "arch=x86-64-v2")))
+inline void
+foo(struct coder_state *c, unsigned int back)
+{
+  if (back == ~0u) {
+    bar(&c->r, &c->x[c->t], 0);
+  }
+}
+
+__attribute__((target_clones("default", "arch=x86-64-v2")))
+int
+ice_trigger(struct coder_state *c, unsigned int back)
+{
+  while (1) {
+    foo(c, back);
+  }
+}
-- 
2.47.3

Reply via email to