Bug 101696 - Function multiversioning not usable with new x86-64-v*
Summary: Function multiversioning not usable with new x86-64-v*
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 11.2.0
: P3 normal
Target Milestone: 12.0
Assignee: Martin Liška
URL:
Keywords: patch
Depends on:
Blocks:
 
Reported: 2021-07-30 15:26 UTC by Hannes Hauswedell
Modified: 2025-10-23 23:39 UTC (History)
3 users (show)

See Also:
Host:
Target: x86_64-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-08-03 00:00:00


Attachments
A patch (1.00 KB, patch)
2021-08-11 15:07 UTC, H.J. Lu
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Hannes Hauswedell 2021-07-30 15:26:26 UTC
I really like the new feature levels, so I have created the respective binaries for an application. I now want to dispatch to the correct one, so I thought the easiest thing would be to have a small "arch_detect" program that gives me the feature level as return value:

__attribute__ ((target ("default")))
int foo ()
{
    // The default version of foo.
    return 0;
}

__attribute__ ((target ("arch=x86-64")))
int foo ()
{
    return 1;
}

__attribute__ ((target ("arch=x86-64-v2")))
int foo ()
{
    return 2;
}
__attribute__ ((target ("arch=x86-64-v3")))
int foo ()
{
    return 3;
}

__attribute__ ((target ("arch=x86-64-v4")))
int foo ()
{
    return 4;
}

int main ()
{
    return foo();
}


This builds fine but always returns 0 -- independent of whether I build the binary without -march or with -march=x86-64-v4.

Curiously, if I add the following overload:

__attribute__ ((target ("sse4.2")))
int foo ()
{
    // The default version of foo.
    return 7;
}

it will no longer build without -march=x86-64-v4, complaining that "no dispatcher was found for the versioning attributes". If I add -march=x86-64-v4, it will build without errors but always return 7 and not the feature level.

What am I missing?
Comment 1 Richard Biener 2021-08-02 08:26:26 UTC
It doesn't work this way, see the target_clones and ifunc attribute documentation.  You could eventually use __builtin_cpu_is or __builtin_cpu_supports.
Comment 2 Hannes Hauswedell 2021-08-03 09:38:55 UTC
What do you mean with "It doesn't work this way"?

Maybe I wasn't clear in my original post; I am not interested in a dispatching mechanism for the application, I just want to have an mini-application that returns 0, 1, 2, 3 or 4 depending on which feature level is available on the current computer.

How is my example different from https://gcc.gnu.org/onlinedocs/gcc/Function-Multiversioning.html (other than using the new feature levels)?

Thanks
Comment 3 Richard Biener 2021-08-03 11:00:10 UTC
Ah, this only works with the C++ frontend.  I can confirm your observation, it looks like the arch=x86-64-vN handling is incomplete.
Comment 4 Martin Liška 2021-08-03 11:30:43 UTC
I can handle this issue.
Comment 5 Martin Liška 2021-08-11 12:10:59 UTC
Right now, the x86-64* are defined as aliases to k8:

  {"x86-64", PROCESSOR_K8, CPU_K8, PTA_X86_64_BASELINE, 0, P_NONE},
  {"x86-64-v2", PROCESSOR_K8, CPU_GENERIC, PTA_X86_64_V2 | PTA_NO_TUNE,
   0, P_NONE},
  {"x86-64-v3", PROCESSOR_K8, CPU_GENERIC, PTA_X86_64_V3 | PTA_NO_TUNE,
   0, P_NONE},
  {"x86-64-v4", PROCESSOR_K8, CPU_GENERIC, PTA_X86_64_V4 | PTA_NO_TUNE,
   0, P_NONE},

and it has the corresponding pta info:

(gdb) p *arch_info
$10 = {
  name = 0x1f96cdc "x86-64",
  processor = PROCESSOR_K8,
  schedule = CPU_K8,
  flags = {
    low = 0,
    high = 137445326852
  },
  model = 0,
  priority = P_NONE
}

thus we end up with:
pr101696.c:16:5: error: no dispatcher found for the versioning attributes
   16 | int foo ()
      |     ^~~

So first step that needs to be done is adding support for the march names in:
__builtin_cpu_is.
@H.J. Can you please add that?
Comment 6 H.J. Lu 2021-08-11 14:30:31 UTC
(In reply to Martin Liška from comment #5)
> Right now, the x86-64* are defined as aliases to k8:
> 
>   {"x86-64", PROCESSOR_K8, CPU_K8, PTA_X86_64_BASELINE, 0, P_NONE},
>   {"x86-64-v2", PROCESSOR_K8, CPU_GENERIC, PTA_X86_64_V2 | PTA_NO_TUNE,
>    0, P_NONE},
>   {"x86-64-v3", PROCESSOR_K8, CPU_GENERIC, PTA_X86_64_V3 | PTA_NO_TUNE,
>    0, P_NONE},
>   {"x86-64-v4", PROCESSOR_K8, CPU_GENERIC, PTA_X86_64_V4 | PTA_NO_TUNE,
>    0, P_NONE},
> 
> and it has the corresponding pta info:
> 
> (gdb) p *arch_info
> $10 = {
>   name = 0x1f96cdc "x86-64",
>   processor = PROCESSOR_K8,
>   schedule = CPU_K8,
>   flags = {
>     low = 0,
>     high = 137445326852
>   },
>   model = 0,
>   priority = P_NONE
> }
> 
> thus we end up with:
> pr101696.c:16:5: error: no dispatcher found for the versioning attributes
>    16 | int foo ()
>       |     ^~~
> 
> So first step that needs to be done is adding support for the march names in:
> __builtin_cpu_is.
> @H.J. Can you please add that?

It is very difficult to add them to __builtin_cpu_is since there are no
such processors.  However, add them to __builtin_cpu_supports is possible.
Comment 7 Martin Liška 2021-08-11 14:34:55 UTC
> It is very difficult to add them to __builtin_cpu_is since there are no
> such processors.

I see!

> However, add them to __builtin_cpu_supports is possible.

Please do so we can then leverage that in the target attribute.
Comment 8 H.J. Lu 2021-08-11 15:07:27 UTC
Created attachment 51290 [details]
A patch

Try this.
Comment 9 Martin Liška 2021-08-12 14:23:07 UTC
I've just sent patch to ML:
https://gcc.gnu.org/pipermail/gcc-patches/2021-August/577275.html
Comment 10 GCC Commits 2021-09-13 15:26:43 UTC
The master branch has been updated by Martin Liska <marxin@gcc.gnu.org>:

https://gcc.gnu.org/g:8ea292591e42aa4d52b4b7a00b86335bfd2e2e85

commit r12-3494-g8ea292591e42aa4d52b4b7a00b86335bfd2e2e85
Author: Martin Liska <mliska@suse.cz>
Date:   Thu Aug 12 15:20:43 2021 +0200

    i386: support micro-levels in target{,_clone} attrs [PR101696]
    
    As mentioned in the PR, we do miss supports target micro-architectures
    in target and target_clone attribute. While the levels
    x86-64 x86-64-v2 x86-64-v3 x86-64-v4 are supported values by -march
    option, they are actually only aliases for k8 CPU. That said, they are more
    closer to __builtin_cpu_supports function and we decided to implement
    it there.
    
            PR target/101696
    
    gcc/ChangeLog:
    
            * common/config/i386/cpuinfo.h (cpu_indicator_init): Add support
            for x86-64 micro levels for __builtin_cpu_supports.
            * common/config/i386/i386-cpuinfo.h (enum feature_priority):
            Add priorities for the micro-arch levels.
            (enum processor_features): Add new features.
            * common/config/i386/i386-isas.h: Add micro-arch features.
            * config/i386/i386-builtins.c (get_builtin_code_for_version):
            Support the micro-arch levels by callsing
            __builtin_cpu_supports.
            * doc/extend.texi: Document that the levels are support by
              __builtin_cpu_supports.
    
    gcc/testsuite/ChangeLog:
    
            * g++.target/i386/mv30.C: New test.
            * gcc.target/i386/mvc16.c: New test.
            * gcc.target/i386/builtin_target.c (CHECK___builtin_cpu_supports):
            New.
    
    Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>
Comment 11 Martin Liška 2021-09-13 15:27:54 UTC
Implemented on master.