diff --git a/gcc/common/config/i386/cpuinfo.h b/gcc/common/config/i386/cpuinfo.h index 1835ac64e67..bbf29bdb116 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 @@ -933,6 +937,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 4e0659fc7b2..dc1a9fa57f8 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 }; @@ -229,6 +233,10 @@ enum processor_features FEATURE_WIDEKL, FEATURE_AVXVNNI, FEATURE_AVX512FP16, + 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 a6783660278..778401032dc 100644 --- a/gcc/common/config/i386/i386-isas.h +++ b/gcc/common/config/i386/i386-isas.h @@ -170,4 +170,9 @@ ISA_NAMES_TABLE_START ISA_NAMES_TABLE_ENTRY("widekl", FEATURE_WIDEKL, P_NONE, "-mwidekl") ISA_NAMES_TABLE_ENTRY("avxvnni", FEATURE_AVXVNNI, P_NONE, "-mavxvnni") ISA_NAMES_TABLE_ENTRY("avx512fp16", FEATURE_AVX512FP16, P_NONE, "-mavx512fp16") + ISA_NAMES_TABLE_ENTRY("x86-64", FEATURE_X86_64_BASELINE, P_X86_64_BASELINE, + NULL) + ISA_NAMES_TABLE_ENTRY("x86-64-v2", FEATURE_X86_64_V2, P_X86_64_V2, NULL) + ISA_NAMES_TABLE_ENTRY("x86-64-v3", FEATURE_X86_64_V3, P_X86_64_V3, NULL) + ISA_NAMES_TABLE_ENTRY("x86-64-v4", FEATURE_X86_64_V4, P_X86_64_V4, NULL) ISA_NAMES_TABLE_END diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c index 17997016207..11ce58b2574 100644 --- a/gcc/config/i386/i386-builtins.c +++ b/gcc/config/i386/i386-builtins.c @@ -1927,8 +1927,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) { @@ -1998,7 +2014,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 8b324a097a4..9501a60f20e 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -21743,6 +21743,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 (); +}