diff options
author | Martin Liska <mliska@suse.cz> | 2022-10-04 12:04:54 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-10-04 12:04:54 +0200 |
commit | da0970e441345f8349522ff1abac5c223044ebb1 (patch) | |
tree | 17c2091a83c584a1eae4f8e219a460f85c5d3fd8 /gcc/common | |
parent | 54f3cfaf3a6f50958c71d79c85206a6c722e1a22 (diff) | |
parent | e886ebd17965d78f609b62479f4f48085108389c (diff) | |
download | gcc-da0970e441345f8349522ff1abac5c223044ebb1.zip gcc-da0970e441345f8349522ff1abac5c223044ebb1.tar.gz gcc-da0970e441345f8349522ff1abac5c223044ebb1.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/common')
-rw-r--r-- | gcc/common/config/aarch64/aarch64-common.cc | 305 |
1 files changed, 87 insertions, 218 deletions
diff --git a/gcc/common/config/aarch64/aarch64-common.cc b/gcc/common/config/aarch64/aarch64-common.cc index 7fac90d..6100783 100644 --- a/gcc/common/config/aarch64/aarch64-common.cc +++ b/gcc/common/config/aarch64/aarch64-common.cc @@ -30,6 +30,7 @@ #include "opts.h" #include "flags.h" #include "diagnostic.h" +#include "config/aarch64/aarch64-feature-deps.h" #ifdef TARGET_BIG_ENDIAN_DEFAULT #undef TARGET_DEFAULT_TARGET_FLAGS @@ -41,8 +42,6 @@ #undef TARGET_OPTION_OPTIMIZATION_TABLE #define TARGET_OPTION_OPTIMIZATION_TABLE aarch_option_optimization_table -#undef TARGET_OPTION_INIT_STRUCT -#define TARGET_OPTION_INIT_STRUCT aarch64_option_init_struct /* Set default optimization options. */ static const struct default_options aarch_option_optimization_table[] = @@ -65,6 +64,17 @@ static const struct default_options aarch_option_optimization_table[] = { OPT_LEVELS_NONE, 0, NULL, 0 } }; +/* Set OPTS->x_aarch64_asm_isa_flags to FLAGS and update + OPTS->x_aarch64_isa_flags accordingly. */ +void +aarch64_set_asm_isa_flags (gcc_options *opts, aarch64_feature_flags flags) +{ + opts->x_aarch64_asm_isa_flags = flags; + opts->x_aarch64_isa_flags = flags; + if (opts->x_target_flags & MASK_GENERAL_REGS_ONLY) + opts->x_aarch64_isa_flags &= ~feature_deps::get_flags_off (AARCH64_FL_FP); +} + /* Implement TARGET_HANDLE_OPTION. This function handles the target specific options for CPU/target selection. @@ -99,6 +109,7 @@ aarch64_handle_option (struct gcc_options *opts, case OPT_mgeneral_regs_only: opts->x_target_flags |= MASK_GENERAL_REGS_ONLY; + aarch64_set_asm_isa_flags (opts, opts->x_aarch64_asm_isa_flags); return true; case OPT_mfix_cortex_a53_835769: @@ -128,64 +139,52 @@ aarch64_handle_option (struct gcc_options *opts, /* An ISA extension in the co-processor and main instruction set space. */ struct aarch64_option_extension { - const char *const name; - const uint64_t flag_canonical; - const uint64_t flags_on; - const uint64_t flags_off; - const bool is_synthetic; + const char *name; + aarch64_feature_flags flag_canonical; + aarch64_feature_flags flags_on; + aarch64_feature_flags flags_off; }; /* ISA extensions in AArch64. */ -static const struct aarch64_option_extension all_extensions[] = -{ -#define AARCH64_OPT_EXTENSION(NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, \ - SYNTHETIC, Z) \ - {NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, SYNTHETIC}, -#include "config/aarch64/aarch64-option-extensions.def" - {NULL, 0, 0, 0, false} -}; - -/* A copy of the ISA extensions list for AArch64 sorted by the popcount of - bits and extension turned on. Cached for efficiency. */ -static struct aarch64_option_extension all_extensions_by_on[] = +static constexpr aarch64_option_extension all_extensions[] = { -#define AARCH64_OPT_EXTENSION(NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, \ - SYNTHETIC, Z) \ - {NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, SYNTHETIC}, +#define AARCH64_OPT_EXTENSION(NAME, IDENT, C, D, E, F) \ + {NAME, AARCH64_FL_##IDENT, feature_deps::IDENT ().explicit_on, \ + feature_deps::get_flags_off (feature_deps::root_off_##IDENT)}, #include "config/aarch64/aarch64-option-extensions.def" - {NULL, 0, 0, 0, false} + {NULL, 0, 0, 0} }; struct processor_name_to_arch { - const std::string processor_name; - const enum aarch64_arch arch; - const uint64_t flags; + const char *processor_name; + aarch64_arch arch; + aarch64_feature_flags flags; }; struct arch_to_arch_name { - const enum aarch64_arch arch; - const std::string arch_name; - const uint64_t flags; + aarch64_arch arch; + const char *arch_name; + aarch64_feature_flags flags; }; /* Map processor names to the architecture revision they implement and the default set of architectural feature flags they support. */ -static const struct processor_name_to_arch all_cores[] = +static constexpr processor_name_to_arch all_cores[] = { -#define AARCH64_CORE(NAME, X, IDENT, ARCH_IDENT, FLAGS, COSTS, IMP, PART, VARIANT) \ - {NAME, AARCH64_ARCH_##ARCH_IDENT, FLAGS}, +#define AARCH64_CORE(NAME, CORE_IDENT, C, ARCH_IDENT, E, F, G, H, I) \ + {NAME, AARCH64_ARCH_##ARCH_IDENT, feature_deps::cpu_##CORE_IDENT}, #include "config/aarch64/aarch64-cores.def" - {"generic", AARCH64_ARCH_8A, AARCH64_FL_FOR_ARCH8}, + {"generic", AARCH64_ARCH_V8A, feature_deps::V8A ().enable}, {"", aarch64_no_arch, 0} }; /* Map architecture revisions to their string representation. */ -static const struct arch_to_arch_name all_architectures[] = +static constexpr arch_to_arch_name all_architectures[] = { -#define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH, FLAGS) \ - {AARCH64_ARCH_##ARCH_IDENT, NAME, FLAGS}, +#define AARCH64_ARCH(NAME, B, ARCH_IDENT, D, E) \ + {AARCH64_ARCH_##ARCH_IDENT, NAME, feature_deps::ARCH_IDENT ().enable}, #include "config/aarch64/aarch64-arches.def" {aarch64_no_arch, "", 0} }; @@ -197,7 +196,7 @@ static const struct arch_to_arch_name all_architectures[] = a copy of the string is created and stored to INVALID_EXTENSION. */ enum aarch64_parse_opt_result -aarch64_parse_extension (const char *str, uint64_t *isa_flags, +aarch64_parse_extension (const char *str, aarch64_feature_flags *isa_flags, std::string *invalid_extension) { /* The extension string is parsed left to right. */ @@ -239,9 +238,9 @@ aarch64_parse_extension (const char *str, uint64_t *isa_flags, { /* Add or remove the extension. */ if (adding_ext) - *isa_flags |= (opt->flags_on | opt->flag_canonical); + *isa_flags |= opt->flags_on; else - *isa_flags &= ~(opt->flags_off | opt->flag_canonical); + *isa_flags &= ~opt->flags_off; break; } } @@ -270,78 +269,6 @@ aarch64_get_all_extension_candidates (auto_vec<const char *> *candidates) candidates->safe_push (opt->name); } -/* Comparer to sort aarch64's feature extensions by population count. Largest - first. */ - -typedef const struct aarch64_option_extension opt_ext; - -int opt_ext_cmp (const void* a, const void* b) -{ - opt_ext *opt_a = (opt_ext *)a; - opt_ext *opt_b = (opt_ext *)b; - - /* We consider the total set of bits an options turns on to be the union of - the singleton set containing the option itself and the set of options it - turns on as a dependency. As an example +dotprod turns on FL_DOTPROD and - FL_SIMD. As such the set of bits represented by this option is - {FL_DOTPROD, FL_SIMD}. */ - uint64_t total_flags_a = opt_a->flag_canonical & opt_a->flags_on; - uint64_t total_flags_b = opt_b->flag_canonical & opt_b->flags_on; - int popcnt_a = popcount_hwi ((HOST_WIDE_INT)total_flags_a); - int popcnt_b = popcount_hwi ((HOST_WIDE_INT)total_flags_b); - int order = popcnt_b - popcnt_a; - - /* If they have the same amount of bits set, give it a more - deterministic ordering by using the value of the bits themselves. */ - if (order != 0) - return order; - - if (total_flags_a != total_flags_b) - return total_flags_a < total_flags_b ? 1 : -1; - - return 0; -} - -/* Implement TARGET_OPTION_INIT_STRUCT. */ - -static void -aarch64_option_init_struct (struct gcc_options *opts ATTRIBUTE_UNUSED) -{ - /* Sort the extensions based on how many bits they set, order the larger - counts first. We sort the list because this makes processing the - feature bits O(n) instead of O(n^2). While n is small, the function - to calculate the feature strings is called on every options push, - pop and attribute change (arm_neon headers, lto etc all cause this to - happen quite frequently). It is a trade-off between time and space and - so time won. */ - int n_extensions = ARRAY_SIZE (all_extensions); - qsort (&all_extensions_by_on, n_extensions, - sizeof (struct aarch64_option_extension), opt_ext_cmp); -} - -/* Checks to see if enough bits from the option OPT are enabled in - ISA_FLAG_BITS to be able to replace the individual options with the - canonicalized version of the option. This is done based on two rules: - - 1) Synthetic groups, such as +crypto we only care about the bits that are - turned on. e.g. +aes+sha2 can be replaced with +crypto. - - 2) Options that themselves have a bit, such as +rdma, in this case, all the - feature bits they turn on must be available and the bit for the option - itself must be. In this case it's effectively a reduction rather than a - grouping. e.g. +fp+simd is not enough to turn on +rdma, for that you would - need +rdma+fp+simd which is reduced down to +rdma. -*/ - -static bool -aarch64_contains_opt (uint64_t isa_flag_bits, opt_ext *opt) -{ - uint64_t flags_check - = opt->is_synthetic ? opt->flags_on : opt->flag_canonical; - - return (isa_flag_bits & flags_check) == flags_check; -} - /* Return a string representation of ISA_FLAGS. DEFAULT_ARCH_FLAGS gives the default set of flags which are implied by whatever -march we'd put out. Our job is to figure out the minimal set of "+" and @@ -349,121 +276,63 @@ aarch64_contains_opt (uint64_t isa_flag_bits, opt_ext *opt) that all the "+" flags come before the "+no" flags. */ std::string -aarch64_get_extension_string_for_isa_flags (uint64_t isa_flags, - uint64_t default_arch_flags) +aarch64_get_extension_string_for_isa_flags + (aarch64_feature_flags isa_flags, + aarch64_feature_flags default_arch_flags) { - const struct aarch64_option_extension *opt = NULL; std::string outstr = ""; - uint64_t isa_flag_bits = isa_flags; - - /* Pass one: Minimize the search space by reducing the set of options - to the smallest set that still turns on the same features as before in - conjunction with the bits that are turned on by default for the selected - architecture. */ - for (opt = all_extensions_by_on; opt->name != NULL; opt++) + aarch64_feature_flags current_flags = default_arch_flags; + + /* As a special case, do not assume that the assembler will enable CRC + even if it is the default for the architecture. This is required + because some CPUs had an incorrect specification in older assemblers: + even though CRC should be the default for these cases the -mcpu + values would not turn it on. + + However, assemblers with Armv8-R AArch64 support should not have this + issue, so we don't need this fix when targeting Armv8-R. */ + auto explicit_flags = (!(current_flags & AARCH64_FL_V8R) + ? AARCH64_FL_CRC : 0); + + /* Add the features in isa_flags & ~current_flags using the smallest + possible number of extensions. We can do this by iterating over the + array in reverse order, since the array is sorted topologically. + But in order to make the output more readable, it seems better + to add the strings in definition order. */ + aarch64_feature_flags added = 0; + for (unsigned int i = ARRAY_SIZE (all_extensions); i-- > 0; ) { - /* If the bit is on by default, then all the options it turns on are also - on by default due to the transitive dependencies. - - If the option is enabled explicitly in the set then we need to emit - an option for it. Since this list is sorted by extensions setting the - largest number of featers first, we can be sure that nothing else will - ever need to set the bits we already set. Consider the following - situation: - - Feat1 = A + B + C - Feat2 = A + B - Feat3 = A + D - Feat4 = B + C - Feat5 = C - - The following results are expected: - - A + C = A + Feat5 - B + C = Feat4 - Feat4 + A = Feat1 - Feat2 + Feat5 = Feat1 - Feat1 + C = Feat1 - Feat3 + Feat4 = Feat1 + D - - This search assumes that all invidual feature bits are use visible, - in other words the user must be able to do +A, +B, +C and +D. */ - if (aarch64_contains_opt (isa_flag_bits | default_arch_flags, opt)) - { - /* We remove all the dependent bits, to prevent them from being turned - on twice. This only works because we assume that all there are - individual options to set all bits standalone. */ - - /* PR target/94396. - - For flags which would already imply a bit that's on by default (e.g - fp16fml which implies +fp,+fp16) we must emit the flags that are not - on by default. i.e. in Armv8.4-a +fp16fml is default if +fp16. So - if a user passes armv8.4-a+fp16 (or +fp16fml) then we need to emit - +fp16. But if +fp16fml is used in an architecture where it is - completely optional we only have to emit the canonical flag. */ - uint64_t toggle_bits = opt->flags_on & default_arch_flags; - /* Now check to see if the canonical flag is on by default. If it - is not then enabling it will enable all bits in flags_on. */ - if ((opt->flag_canonical & default_arch_flags) == 0) - toggle_bits = opt->flags_on; - - isa_flag_bits &= ~toggle_bits; - isa_flag_bits |= opt->flag_canonical; - } - } + auto &opt = all_extensions[i]; - /* By toggling bits on and off, we may have set bits on that are already - enabled by default. So we mask the default set out so we don't emit an - option for them. Instead of checking for this each time during Pass One - we just mask all default bits away at the end. */ - isa_flag_bits &= ~default_arch_flags; - - /* We now have the smallest set of features we need to process. A subsequent - linear scan of the bits in isa_flag_bits will allow us to print the ext - names. However as a special case if CRC was enabled before, always print - it. This is required because some CPUs have an incorrect specification - in older assemblers. Even though CRC should be the default for these - cases the -mcpu values won't turn it on. - - Note that assemblers with Armv8-R AArch64 support should not have this - issue, so we don't need this fix when targeting Armv8-R. */ - if ((isa_flags & AARCH64_ISA_CRC) && !AARCH64_ISA_V8_R) - isa_flag_bits |= AARCH64_ISA_CRC; - - /* Pass Two: - Print the option names that we're sure we must turn on. These are only - optional extension names. Mandatory ones have already been removed and - ones we explicitly want off have been too. */ - for (opt = all_extensions_by_on; opt->name != NULL; opt++) - { - if (isa_flag_bits & opt->flag_canonical) - { - outstr += "+"; - outstr += opt->name; - } - } + /* As a special case, emit +crypto rather than +aes+sha2, + in order to support assemblers that predate the separate + per-feature crypto flags. */ + auto flags = opt.flag_canonical; + if (flags == AARCH64_FL_CRYPTO) + flags = AARCH64_FL_AES | AARCH64_FL_SHA2; - /* Pass Three: - Print out a +no for any mandatory extension that we are - turning off. By this point aarch64_parse_extension would have ensured - that any optional extensions are turned off. The only things left are - things that can't be turned off usually, e.g. something that is on by - default because it's mandatory and we want it off. For turning off bits - we don't guarantee the smallest set of flags, but instead just emit all - options the user has specified. - - The assembler requires all +<opts> to be printed before +no<opts>. */ - for (opt = all_extensions_by_on; opt->name != NULL; opt++) - { - if ((~isa_flags) & opt->flag_canonical - && !((~default_arch_flags) & opt->flag_canonical)) + if ((flags & isa_flags & (explicit_flags | ~current_flags)) == flags) { - outstr += "+no"; - outstr += opt->name; + current_flags |= opt.flags_on; + added |= opt.flag_canonical; } } + for (auto &opt : all_extensions) + if (added & opt.flag_canonical) + { + outstr += "+"; + outstr += opt.name; + } + + /* Remove the features in current_flags & ~isa_flags. */ + for (auto &opt : all_extensions) + if (opt.flag_canonical & current_flags & ~isa_flags) + { + current_flags &= ~opt.flags_off; + outstr += "+no"; + outstr += opt.name; + } return outstr; } @@ -517,7 +386,7 @@ aarch64_rewrite_selected_cpu (const char *name) || a_to_an->arch == aarch64_no_arch) fatal_error (input_location, "unknown value %qs for %<-mcpu%>", name); - uint64_t extensions = p_to_a->flags; + aarch64_feature_flags extensions = p_to_a->flags; aarch64_parse_extension (extension_str.c_str (), &extensions, NULL); std::string outstr = a_to_an->arch_name |