From 22ab27eab643d99addd00c11f62eca891e11ac08 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 12 Aug 2021 15:20:43 +0200 Subject: [PATCH] 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 --- gcc/common/config/i386/cpuinfo.h | 48 ++++++++++++++++++ gcc/common/config/i386/i386-cpuinfo.h | 8 +++ gcc/common/config/i386/i386-isas.h | 4 ++ gcc/config/i386/i386-builtins.c | 22 ++++++-- gcc/doc/extend.texi | 12 +++++ gcc/testsuite/g++.target/i386/mv30.C | 50 +++++++++++++++++++ .../gcc.target/i386/builtin_target.c | 2 + gcc/testsuite/gcc.target/i386/mvc16.c | 15 ++++++ 8 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.target/i386/mv30.C create mode 100644 gcc/testsuite/gcc.target/i386/mvc16.c diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h index 458f41de776..89158597c1f 100644 --- a/gcc/common/config/i386/cpuinfo.h +++ b/gcc/common/config/i386/cpuinfo.h @@ -46,6 +46,10 @@ struct __processor_model2 # define CHECK___builtin_cpu_is(cpu) #endif +#ifndef CHECK___builtin_cpu_supports +# define CHECK___builtin_cpu_supports(isa) +#endif + /* Return non-zero if the processor has feature F. */ static inline int @@ -931,6 +935,50 @@ cpu_indicator_init (struct __processor_model *cpu_model, else cpu_model->__cpu_vendor = VENDOR_OTHER; + if (has_cpu_feature (cpu_model, cpu_features2, FEATURE_LM) + && has_cpu_feature (cpu_model, cpu_features2, FEATURE_SSE2)) + { + CHECK___builtin_cpu_supports ("x86-64"); + set_cpu_feature (cpu_model, cpu_features2, + FEATURE_X86_64_BASELINE); + if (has_cpu_feature (cpu_model, cpu_features2, FEATURE_CMPXCHG16B) + && has_cpu_feature (cpu_model, cpu_features2, FEATURE_POPCNT) + && has_cpu_feature (cpu_model, cpu_features2, FEATURE_LAHF_LM) + && has_cpu_feature (cpu_model, cpu_features2, FEATURE_SSE4_2)) + { + CHECK___builtin_cpu_supports ("x86-64-v2"); + set_cpu_feature (cpu_model, cpu_features2, + FEATURE_X86_64_V2); + if (has_cpu_feature (cpu_model, cpu_features2, FEATURE_AVX2) + && has_cpu_feature (cpu_model, cpu_features2, FEATURE_BMI) + && has_cpu_feature (cpu_model, cpu_features2, FEATURE_BMI2) + && has_cpu_feature (cpu_model, cpu_features2, FEATURE_F16C) + && has_cpu_feature (cpu_model, cpu_features2, FEATURE_FMA) + && has_cpu_feature (cpu_model, cpu_features2, + FEATURE_LZCNT) + && has_cpu_feature (cpu_model, cpu_features2, + FEATURE_MOVBE)) + { + CHECK___builtin_cpu_supports ("x86-64-v3"); + set_cpu_feature (cpu_model, cpu_features2, + FEATURE_X86_64_V3); + if (has_cpu_feature (cpu_model, cpu_features2, + FEATURE_AVX512BW) + && has_cpu_feature (cpu_model, cpu_features2, + FEATURE_AVX512CD) + && has_cpu_feature (cpu_model, cpu_features2, + FEATURE_AVX512DQ) + && has_cpu_feature (cpu_model, cpu_features2, + FEATURE_AVX512VL)) + { + CHECK___builtin_cpu_supports ("x86-64-v4"); + set_cpu_feature (cpu_model, cpu_features2, + FEATURE_X86_64_V4); + } + } + } + } + gcc_assert (cpu_model->__cpu_vendor < VENDOR_MAX); gcc_assert (cpu_model->__cpu_type < CPU_TYPE_MAX); gcc_assert (cpu_model->__cpu_subtype < CPU_SUBTYPE_MAX); diff --git a/gcc/common/config/i386/i386-cpuinfo.h b/gcc/common/config/i386/i386-cpuinfo.h index e68dd656046..1b1846d59b8 100644 --- a/gcc/common/config/i386/i386-cpuinfo.h +++ b/gcc/common/config/i386/i386-cpuinfo.h @@ -102,6 +102,7 @@ enum feature_priority P_MMX, P_SSE, P_SSE2, + P_X86_64_BASELINE, P_SSE3, P_SSSE3, P_PROC_SSSE3, @@ -111,6 +112,7 @@ enum feature_priority P_SSE4_2, P_PROC_SSE4_2, P_POPCNT, + P_X86_64_V2, P_AES, P_PCLMUL, P_AVX, @@ -125,8 +127,10 @@ enum feature_priority P_BMI2, P_AVX2, P_PROC_AVX2, + P_X86_64_V3, P_AVX512F, P_PROC_AVX512F, + P_X86_64_V4, P_PROC_DYNAMIC }; @@ -228,6 +232,10 @@ enum processor_features FEATURE_AESKLE, FEATURE_WIDEKL, FEATURE_AVXVNNI, + FEATURE_X86_64_BASELINE, + FEATURE_X86_64_V2, + FEATURE_X86_64_V3, + FEATURE_X86_64_V4, CPU_FEATURE_MAX }; diff --git a/gcc/common/config/i386/i386-isas.h b/gcc/common/config/i386/i386-isas.h index 898c18f3dda..cd9523b8fbc 100644 --- a/gcc/common/config/i386/i386-isas.h +++ b/gcc/common/config/i386/i386-isas.h @@ -169,4 +169,8 @@ ISA_NAMES_TABLE_START ISA_NAMES_TABLE_ENTRY("aeskle", FEATURE_AESKLE, P_NONE, NULL) ISA_NAMES_TABLE_ENTRY("widekl", FEATURE_WIDEKL, P_NONE, "-mwidekl") ISA_NAMES_TABLE_ENTRY("avxvnni", FEATURE_AVXVNNI, P_NONE, "-mavxvnni") + ISA_NAMES_TABLE_ENTRY("x86-64", FEATURE_X86_64_BASELINE, P_NONE, NULL) + ISA_NAMES_TABLE_ENTRY("x86-64-v2", FEATURE_X86_64_V2, P_NONE, NULL) + ISA_NAMES_TABLE_ENTRY("x86-64-v3", FEATURE_X86_64_V3, P_NONE, NULL) + ISA_NAMES_TABLE_ENTRY("x86-64-v4", FEATURE_X86_64_V4, P_NONE, NULL) ISA_NAMES_TABLE_END diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c index 204e2903126..492873bb076 100644 --- a/gcc/config/i386/i386-builtins.c +++ b/gcc/config/i386/i386-builtins.c @@ -1904,8 +1904,24 @@ get_builtin_code_for_version (tree decl, tree *predicate_list) return 0; new_target = TREE_TARGET_OPTION (target_node); gcc_assert (new_target); - - if (new_target->arch_specified && new_target->arch > 0) + enum ix86_builtins builtin_fn = IX86_BUILTIN_CPU_IS; + + /* Special case x86-64 micro-level architectures. */ + const char *arch_name = attrs_str + strlen ("arch="); + if (startswith (arch_name, "x86-64")) + { + arg_str = arch_name; + builtin_fn = IX86_BUILTIN_CPU_SUPPORTS; + if (strcmp (arch_name, "x86-64") == 0) + priority = P_X86_64_BASELINE; + else if (strcmp (arch_name, "x86-64-v2") == 0) + priority = P_X86_64_V2; + else if (strcmp (arch_name, "x86-64-v3") == 0) + priority = P_X86_64_V3; + else if (strcmp (arch_name, "x86-64-v4") == 0) + priority = P_X86_64_V4; + } + else if (new_target->arch_specified && new_target->arch > 0) for (i = 0; i < pta_size; i++) if (processor_alias_table[i].processor == new_target->arch) { @@ -1975,7 +1991,7 @@ get_builtin_code_for_version (tree decl, tree *predicate_list) if (predicate_list) { - predicate_decl = ix86_builtins [(int) IX86_BUILTIN_CPU_IS]; + predicate_decl = ix86_builtins [(int) builtin_fn]; /* For a C string literal the length includes the trailing NULL. */ predicate_arg = build_string_literal (strlen (arg_str) + 1, arg_str); predicate_chain = tree_cons (predicate_decl, predicate_arg, diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 49df8e6dc38..d2c695f8dab 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -21644,6 +21644,18 @@ AMD Family 19h CPU. @item znver3 AMD Family 19h Zen version 3. + +@item x86-64 +Baseline x86-64 microarchitecture level (as defined in x86-64 psABI). + +@item x86-64-v2 +x86-64-v2 microarchitecture level. + +@item x86-64-v3 +x86-64-v3 microarchitecture level. + +@item x86-64-v4 +x86-64-v4 microarchitecture level. @end table Here is an example: diff --git a/gcc/testsuite/g++.target/i386/mv30.C b/gcc/testsuite/g++.target/i386/mv30.C new file mode 100644 index 00000000000..b4947f0b481 --- /dev/null +++ b/gcc/testsuite/g++.target/i386/mv30.C @@ -0,0 +1,50 @@ +// PR target/101696 +// Test that dispatching can choose the right multiversion +// for x86-64 microarchitecture levels. + +// { dg-do run } +// { dg-require-ifunc "" } +// { dg-options "-O2" } + +#include + +int __attribute__ ((target("default"))) +foo () +{ + return 0; +} + +int __attribute__ ((target("arch=x86-64"))) foo () { + return 1; +} + +int __attribute__ ((target("arch=x86-64-v2"))) foo () { + return 2; +} + +int __attribute__ ((target("arch=x86-64-v3"))) foo () { + return 3; +} + +int __attribute__ ((target("arch=x86-64-v4"))) foo () { + return 4; +} + + +int main () +{ + int val = foo (); + + if (__builtin_cpu_supports ("x86-64-v4")) + assert (val == 4); + else if (__builtin_cpu_supports ("x86-64-v3")) + assert (val == 3); + else if (__builtin_cpu_supports ("x86-64-v2")) + assert (val == 2); + else if (__builtin_cpu_supports ("x86-64")) + assert (val == 1); + else + assert (val == 0); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/builtin_target.c b/gcc/testsuite/gcc.target/i386/builtin_target.c index aa9680544d8..3e7505a8c3a 100644 --- a/gcc/testsuite/gcc.target/i386/builtin_target.c +++ b/gcc/testsuite/gcc.target/i386/builtin_target.c @@ -10,6 +10,8 @@ #include #include "cpuid.h" #define CHECK___builtin_cpu_is(cpu) assert (__builtin_cpu_is (cpu)) +#define CHECK___builtin_cpu_supports(isa) \ + assert (__builtin_cpu_supports (isa)) #define gcc_assert(a) assert (a) #define gcc_unreachable() abort () #define inline diff --git a/gcc/testsuite/gcc.target/i386/mvc16.c b/gcc/testsuite/gcc.target/i386/mvc16.c new file mode 100644 index 00000000000..def6581f7e7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/mvc16.c @@ -0,0 +1,15 @@ +/* { dg-do run } */ +/* { dg-require-ifunc "" } */ + +__attribute__((target_clones("arch=x86-64", "arch=x86-64-v2", "arch=x86-64-v3", "arch=x86-64-v4", "default"))) +int +foo () +{ + return 0; +} + +int +main () +{ + return foo (); +} -- 2.32.0