On Mon, Mar 2, 2026 at 8:09 AM Yangyu Chen <[email protected]> wrote:
>
> 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.
OK.
Thanks,
Uros.
> ---
> 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
>