diff options
author | Christophe Lyon <christophe.lyon@linaro.org> | 2016-04-11 15:20:14 +0200 |
---|---|---|
committer | Linaro Code Review <review@review.linaro.org> | 2016-04-12 10:59:45 +0000 |
commit | 55d3bceea8eef018564a026e615af58cca5d6273 (patch) | |
tree | cd5fae31de16d725f1b590dfa176a0c5e2b26877 | |
parent | 07017c3304ec630a4d2b63fdf6346be9407f9153 (diff) |
gcc/
Backport from trunk r233342.
2016-02-11 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* config/aarch64/aarch64.c (aarch64_last_printed_arch_string):
New variable.
(aarch64_last_printed_tune_string): Likewise.
(aarch64_declare_function_name): Only output .arch assembler
directive if it will be different from the previously output
directive. Same for .tune comment but only if -dA is set.
(aarch64_start_file): New function.
(TARGET_ASM_FILE_START): Define.
gcc/testsuite/
Backport from trunk r233342.
2016-02-11 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* gcc.target/aarch64/target_attr_15.c: Scan assembly for
.arch armv8-a\n. Add -dA to dg-options.
* gcc.target/aarch64/assembler_arch_1.c: New test.
* gcc.target/aarch64/target_attr_7.c: Add -dA to dg-options.
gcc/testsuite/
Backport from trunk r233559.
2016-02-19 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* lib/target-supports.exp: Define aarch64_asm_FUNC_ok checks
for fp, simd, crypto, crc, lse.
* doc/sourcebuild.texi (AArch64-specific attributes): Document the
above.
* gcc.target/aarch64/assembler_arch_1.c: Add aarch64_asm_lse_ok
effective target check.
gcc/
Backport from trunk r234875.
2016-04-11 James Greenhalgh <james.greenhalgh@arm.com>
* config/aarch64/aarch64.h (AARCH64_FL_FOR_ARCH8_1): Also add
AARCH64_FL_CRC.
gcc/
Backport from trunk r234876.
2016-04-11 James Greenhalgh <james.greenhalgh@arm.com>
PR target/70133
* config/aarch64/aarch64-common.c (aarch64_option_extension): Keep
track of a canonical flag name.
(all_extensions): Likewise.
(arch_to_arch_name): Also track extension flags enabled by the arch.
(all_architectures): Likewise.
(aarch64_parse_extension): Move to here.
(aarch64_get_extension_string_for_isa_flags): Take a new argument,
rework.
(aarch64_rewrite_selected_cpu): Update for above change.
* config/aarch64/aarch64-option-extensions.def: Rework the way flags
are handled, such that the single explicit value enabled by an
extension is kept seperate from the implicit values it also enables.
* config/aarch64/aarch64-protos.h (aarch64_parse_opt_result): Move
to here.
(aarch64_parse_extension): New.
* config/aarch64/aarch64.c (aarch64_parse_opt_result): Move from
here to config/aarch64/aarch64-protos.h.
(aarch64_parse_extension): Move from here to
common/config/aarch64/aarch64-common.c.
(aarch64_option_print): Update.
(aarch64_declare_function_name): Likewise.
(aarch64_start_file): Likewise.
* config/aarch64/driver-aarch64.c (arch_extension): Keep track of
the canonical flag for extensions.
* config.gcc (aarch64*-*-*): Extend regex for capturing extension
flags.
gcc/testsuite/
Backport from trunk r234876.
2016-04-11 James Greenhalgh <james.greenhalgh@arm.com>
PR target/70133
* gcc.target/aarch64/mgeneral-regs_4.c: Fix expected output.
* gcc.target/aarch64/target_attr_15.c: Likewise.
gcc/
Backport from trunk r234877.
2016-04-11 James Greenhalgh <james.greenhalgh@arm.com>
PR target/70133
* config/aarch64/driver-aarch64.c
(aarch64_get_extension_string_for_isa_flags): New.
(arch_extension): Rename to...
(aarch64_arch_extension): ...This.
(ext_to_feat_string): Rename to...
(aarch64_extensions): ...This.
(aarch64_core_data): Keep track of architecture extension flags.
(cpu_data): Rename to...
(aarch64_cpu_data): ...This.
(aarch64_arch_driver_info): Keep track of architecture extension
flags.
(get_arch_name_from_id): Rename to...
(get_arch_from_id): ...This, change return type.
(host_detect_local_cpu): Update and reformat for renames, handle
extensions through common infrastructure.
Change-Id: I30437869d04438f2efc2946e6bdfc5a621578cce
-rw-r--r-- | gcc/common/config/aarch64/aarch64-common.c | 116 | ||||
-rw-r--r-- | gcc/config.gcc | 14 | ||||
-rw-r--r-- | gcc/config/aarch64/aarch64-option-extensions.def | 36 | ||||
-rw-r--r-- | gcc/config/aarch64/aarch64-protos.h | 26 | ||||
-rw-r--r-- | gcc/config/aarch64/aarch64.c | 136 | ||||
-rw-r--r-- | gcc/config/aarch64/aarch64.h | 2 | ||||
-rw-r--r-- | gcc/config/aarch64/driver-aarch64.c | 192 | ||||
-rw-r--r-- | gcc/doc/sourcebuild.texi | 3 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/assembler_arch_1.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/mgeneral-regs_4.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/target_attr_1.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/target_attr_15.c | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/target_attr_7.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/lib/target-supports.exp | 17 |
14 files changed, 369 insertions, 204 deletions
diff --git a/gcc/common/config/aarch64/aarch64-common.c b/gcc/common/config/aarch64/aarch64-common.c index 07c6bba4519..ae34dfa95a1 100644 --- a/gcc/common/config/aarch64/aarch64-common.c +++ b/gcc/common/config/aarch64/aarch64-common.c @@ -111,6 +111,7 @@ struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER; struct aarch64_option_extension { const char *const name; + const unsigned long flag_canonical; const unsigned long flags_on; const unsigned long flags_off; }; @@ -118,11 +119,11 @@ struct aarch64_option_extension /* ISA extensions in AArch64. */ static const struct aarch64_option_extension all_extensions[] = { -#define AARCH64_OPT_EXTENSION(NAME, FLAGS_ON, FLAGS_OFF, FEATURE_STRING) \ - {NAME, FLAGS_ON, FLAGS_OFF}, +#define AARCH64_OPT_EXTENSION(NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, Z) \ + {NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF}, #include "config/aarch64/aarch64-option-extensions.def" #undef AARCH64_OPT_EXTENSION - {NULL, 0, 0} + {NULL, 0, 0, 0} }; struct processor_name_to_arch @@ -136,6 +137,7 @@ struct arch_to_arch_name { const enum aarch64_arch arch; const std::string arch_name; + const unsigned long flags; }; /* Map processor names to the architecture revision they implement and @@ -154,26 +156,111 @@ static const struct processor_name_to_arch all_cores[] = static const struct arch_to_arch_name all_architectures[] = { #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH, FLAGS) \ - {AARCH64_ARCH_##ARCH_IDENT, NAME}, + {AARCH64_ARCH_##ARCH_IDENT, NAME, FLAGS}, #include "config/aarch64/aarch64-arches.def" #undef AARCH64_ARCH - {aarch64_no_arch, ""} + {aarch64_no_arch, "", 0} }; -/* Return a string representation of ISA_FLAGS. */ +/* Parse the architecture extension string STR and update ISA_FLAGS + with the architecture features turned on or off. Return a + aarch64_parse_opt_result describing the result. */ + +enum aarch64_parse_opt_result +aarch64_parse_extension (const char *str, unsigned long *isa_flags) +{ + /* The extension string is parsed left to right. */ + const struct aarch64_option_extension *opt = NULL; + + /* Flag to say whether we are adding or removing an extension. */ + int adding_ext = -1; + + while (str != NULL && *str != 0) + { + const char *ext; + size_t len; + + str++; + ext = strchr (str, '+'); + + if (ext != NULL) + len = ext - str; + else + len = strlen (str); + + if (len >= 2 && strncmp (str, "no", 2) == 0) + { + adding_ext = 0; + len -= 2; + str += 2; + } + else if (len > 0) + adding_ext = 1; + + if (len == 0) + return AARCH64_PARSE_MISSING_ARG; + + + /* Scan over the extensions table trying to find an exact match. */ + for (opt = all_extensions; opt->name != NULL; opt++) + { + if (strlen (opt->name) == len && strncmp (opt->name, str, len) == 0) + { + /* Add or remove the extension. */ + if (adding_ext) + *isa_flags |= (opt->flags_on | opt->flag_canonical); + else + *isa_flags &= ~(opt->flags_off | opt->flag_canonical); + break; + } + } + + if (opt->name == NULL) + { + /* Extension not found in list. */ + return AARCH64_PARSE_INVALID_FEATURE; + } + + str = ext; + }; + + return AARCH64_PARSE_OK; +} + +/* 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 + "+no" feature flags to put out, and to put them out grouped such + that all the "+" flags come before the "+no" flags. */ std::string -aarch64_get_extension_string_for_isa_flags (unsigned long isa_flags) +aarch64_get_extension_string_for_isa_flags (unsigned long isa_flags, + unsigned long default_arch_flags) { const struct aarch64_option_extension *opt = NULL; std::string outstr = ""; + /* Pass one: Find all the things we need to turn on. As a special case, + we always want to put out +crc if it is enabled. */ for (opt = all_extensions; opt->name != NULL; opt++) - if ((isa_flags & opt->flags_on) == opt->flags_on) + if ((isa_flags & opt->flag_canonical + && !(default_arch_flags & opt->flag_canonical)) + || (default_arch_flags & opt->flag_canonical + && opt->flag_canonical == AARCH64_ISA_CRC)) { outstr += "+"; outstr += opt->name; } + + /* Pass two: Find all the things we need to turn off. */ + for (opt = all_extensions; opt->name != NULL; opt++) + if ((~isa_flags) & opt->flag_canonical + && !((~default_arch_flags) & opt->flag_canonical)) + { + outstr += "+no"; + outstr += opt->name; + } + return outstr; } @@ -185,7 +272,7 @@ const char * aarch64_rewrite_selected_cpu (const char *name) { std::string original_string (name); - std::string extensions; + std::string extension_str; std::string processor; size_t extension_pos = original_string.find_first_of ('+'); @@ -193,8 +280,8 @@ aarch64_rewrite_selected_cpu (const char *name) if (extension_pos != std::string::npos) { processor = original_string.substr (0, extension_pos); - extensions = original_string.substr (extension_pos, - std::string::npos); + extension_str = original_string.substr (extension_pos, + std::string::npos); } else { @@ -226,9 +313,12 @@ aarch64_rewrite_selected_cpu (const char *name) || a_to_an->arch == aarch64_no_arch) fatal_error (input_location, "unknown value %qs for -mcpu", name); + unsigned long extensions = p_to_a->flags; + aarch64_parse_extension (extension_str.c_str (), &extensions); + std::string outstr = a_to_an->arch_name - + aarch64_get_extension_string_for_isa_flags (p_to_a->flags) - + extensions; + + aarch64_get_extension_string_for_isa_flags (extensions, + a_to_an->flags); /* We are going to memory leak here, nobody elsewhere in the callchain is going to clean up after us. The alternative is diff --git a/gcc/config.gcc b/gcc/config.gcc index 1c547a02035..9c24db2bf43 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -3536,22 +3536,28 @@ case "${target}" in ${srcdir}/config/aarch64/aarch64-option-extensions.def \ > /dev/null; then - ext_on=`grep "^AARCH64_OPT_EXTENSION(\"$base_ext\"," \ + ext_canon=`grep "^AARCH64_OPT_EXTENSION(\"$base_ext\"," \ ${srcdir}/config/aarch64/aarch64-option-extensions.def | \ sed -e 's/^[^,]*,[ ]*//' | \ sed -e 's/,.*$//'` - ext_off=`grep "^AARCH64_OPT_EXTENSION(\"$base_ext\"," \ + ext_on=`grep "^AARCH64_OPT_EXTENSION(\"$base_ext\"," \ ${srcdir}/config/aarch64/aarch64-option-extensions.def | \ sed -e 's/^[^,]*,[ ]*[^,]*,[ ]*//' | \ sed -e 's/,.*$//' | \ sed -e 's/).*$//'` + ext_off=`grep "^AARCH64_OPT_EXTENSION(\"$base_ext\"," \ + ${srcdir}/config/aarch64/aarch64-option-extensions.def | \ + sed -e 's/^[^,]*,[ ]*[^,]*,[ ]*[^,]*,[ ]*//' | \ + sed -e 's/,.*$//' | \ + sed -e 's/).*$//'` + if [ $ext = $base_ext ]; then # Adding extension - ext_mask="("$ext_mask") | ("$ext_on")" + ext_mask="("$ext_mask") | ("$ext_on" | "$ext_canon")" else # Removing extension - ext_mask="("$ext_mask") & ~("$ext_off")" + ext_mask="("$ext_mask") & ~("$ext_off" | "$ext_canon")" fi true diff --git a/gcc/config/aarch64/aarch64-option-extensions.def b/gcc/config/aarch64/aarch64-option-extensions.def index 3e94c313690..520f2952eb5 100644 --- a/gcc/config/aarch64/aarch64-option-extensions.def +++ b/gcc/config/aarch64/aarch64-option-extensions.def @@ -21,23 +21,37 @@ Before using #include to read this file, define a macro: - AARCH64_OPT_EXTENSION(EXT_NAME, FLAGS_ON, FLAGS_OFF, FEATURE_STRING) + AARCH64_OPT_EXTENSION(EXT_NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, FEATURE_STRING) EXT_NAME is the name of the extension, represented as a string constant. - FLAGS_ON are the bitwise-or of the features that the extension adds. - FLAGS_OFF are the bitwise-or of the features that the extension removes. + FLAGS_CANONICAL is the canonical internal name for this flag. + FLAGS_ON are the bitwise-or of the features that enabling the extension + adds, or zero if enabling this extension has no effect on other features. + FLAGS_OFF are the bitwise-or of the features that disabling the extension + removes, or zero if disabling this extension has no effect on other + features. FEAT_STRING is a string containing the entries in the 'Features' field of /proc/cpuinfo on a GNU/Linux system that correspond to this architecture extension being available. Sometimes multiple entries are needed to enable the extension (for example, the 'crypto' extension depends on four entries: aes, pmull, sha1, sha2 being present). In that case this field - should contain a whitespace-separated list of the strings in 'Features' + should contain a space (" ") separated list of the strings in 'Features' that are required. Their order is not important. */ -AARCH64_OPT_EXTENSION ("fp", AARCH64_FL_FP, - AARCH64_FL_FPSIMD | AARCH64_FL_CRYPTO, "fp") -AARCH64_OPT_EXTENSION ("simd", AARCH64_FL_FPSIMD, - AARCH64_FL_SIMD | AARCH64_FL_CRYPTO, "asimd") -AARCH64_OPT_EXTENSION("crypto", AARCH64_FL_CRYPTO | AARCH64_FL_FPSIMD, AARCH64_FL_CRYPTO, "aes pmull sha1 sha2") -AARCH64_OPT_EXTENSION("crc", AARCH64_FL_CRC, AARCH64_FL_CRC, "crc32") -AARCH64_OPT_EXTENSION("lse", AARCH64_FL_LSE, AARCH64_FL_LSE, "atomics") +/* Enabling "fp" just enables "fp". + Disabling "fp" also disables "simd", "crypto". */ +AARCH64_OPT_EXTENSION("fp", AARCH64_FL_FP, 0, AARCH64_FL_SIMD | AARCH64_FL_CRYPTO, "fp") + +/* Enabling "simd" also enables "fp". + Disabling "simd" also disables "crypto". */ +AARCH64_OPT_EXTENSION("simd", AARCH64_FL_SIMD, AARCH64_FL_FP, AARCH64_FL_CRYPTO, "asimd") + +/* Enabling "crypto" also enables "fp", "simd". + Disabling "crypto" just disables "crypto". */ +AARCH64_OPT_EXTENSION("crypto", AARCH64_FL_CRYPTO, AARCH64_FL_FP | AARCH64_FL_SIMD, 0, "aes pmull sha1 sha2") + +/* Enabling or disabling "crc" only changes "crc". */ +AARCH64_OPT_EXTENSION("crc", AARCH64_FL_CRC, 0, 0, "crc32") + +/* Enabling or disabling "lse" only changes "lse". */ +AARCH64_OPT_EXTENSION("lse", AARCH64_FL_LSE, 0, 0, "atomics") diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index e85132f484a..9bf433594c5 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -262,6 +262,18 @@ enum aarch64_extra_tuning_flags }; #undef AARCH64_EXTRA_TUNING_OPTION +/* Enum describing the various ways that the + aarch64_parse_{arch,tune,cpu,extension} functions can fail. + This way their callers can choose what kind of error to give. */ + +enum aarch64_parse_opt_result +{ + AARCH64_PARSE_OK, /* Parsing was successful. */ + AARCH64_PARSE_MISSING_ARG, /* Missing argument. */ + AARCH64_PARSE_INVALID_FEATURE, /* Invalid feature modifier. */ + AARCH64_PARSE_INVALID_ARG /* Invalid arch, tune, cpu arg. */ +}; + extern struct tune_params aarch64_tune_params; HOST_WIDE_INT aarch64_initial_elimination_offset (unsigned, unsigned); @@ -279,8 +291,6 @@ bool aarch64_float_const_zero_rtx_p (rtx); bool aarch64_function_arg_regno_p (unsigned); bool aarch64_gen_movmemqi (rtx *); bool aarch64_gimple_fold_builtin (gimple_stmt_iterator *); -bool aarch64_handle_option (struct gcc_options *, struct gcc_options *, - const struct cl_decoded_option *, location_t); bool aarch64_is_extend_from_extract (machine_mode, rtx, rtx); bool aarch64_is_long_call_p (rtx); bool aarch64_is_noplt_call_p (rtx); @@ -314,7 +324,6 @@ bool aarch64_uimm12_shift (HOST_WIDE_INT); bool aarch64_use_return_insn_p (void); const char *aarch64_mangle_builtin_type (const_tree); const char *aarch64_output_casesi (rtx *); -const char *aarch64_rewrite_selected_cpu (const char *name); enum aarch64_symbol_type aarch64_classify_symbol (rtx, rtx); enum aarch64_symbol_type aarch64_classify_tls_symbol (rtx); @@ -335,7 +344,6 @@ rtx aarch64_simd_gen_const_vector_dup (machine_mode, int); bool aarch64_simd_mem_operand_p (rtx); rtx aarch64_simd_vect_par_cnst_half (machine_mode, bool); rtx aarch64_tls_get_addr (void); -std::string aarch64_get_extension_string_for_isa_flags (unsigned long); tree aarch64_fold_builtin (tree, int, tree *, bool); unsigned aarch64_dbx_register_number (unsigned); unsigned aarch64_trampoline_size (void); @@ -428,4 +436,14 @@ bool extract_base_offset_in_addr (rtx mem, rtx *base, rtx *offset); bool aarch64_operands_ok_for_ldpstp (rtx *, bool, enum machine_mode); bool aarch64_operands_adjust_ok_for_ldpstp (rtx *, bool, enum machine_mode); extern bool aarch64_nopcrelative_literal_loads; + +/* Defined in common/config/aarch64-common.c. */ +bool aarch64_handle_option (struct gcc_options *, struct gcc_options *, + const struct cl_decoded_option *, location_t); +const char *aarch64_rewrite_selected_cpu (const char *name); +enum aarch64_parse_opt_result aarch64_parse_extension (const char *, + unsigned long *); +std::string aarch64_get_extension_string_for_isa_flags (unsigned long, + unsigned long); + #endif /* GCC_AARCH64_PROTOS_H */ diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 47f41ab2197..1a20ed2a525 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -629,7 +629,7 @@ struct aarch64_option_extension /* ISA extensions in AArch64. */ static const struct aarch64_option_extension all_extensions[] = { -#define AARCH64_OPT_EXTENSION(NAME, FLAGS_ON, FLAGS_OFF, FEATURE_STRING) \ +#define AARCH64_OPT_EXTENSION(NAME, X, FLAGS_ON, FLAGS_OFF, FEATURE_STRING) \ {NAME, FLAGS_ON, FLAGS_OFF}, #include "aarch64-option-extensions.def" #undef AARCH64_OPT_EXTENSION @@ -7293,83 +7293,6 @@ aarch64_add_stmt_cost (void *data, int count, enum vect_cost_for_stmt kind, static void initialize_aarch64_code_model (struct gcc_options *); -/* Enum describing the various ways that the - aarch64_parse_{arch,tune,cpu,extension} functions can fail. - This way their callers can choose what kind of error to give. */ - -enum aarch64_parse_opt_result -{ - AARCH64_PARSE_OK, /* Parsing was successful. */ - AARCH64_PARSE_MISSING_ARG, /* Missing argument. */ - AARCH64_PARSE_INVALID_FEATURE, /* Invalid feature modifier. */ - AARCH64_PARSE_INVALID_ARG /* Invalid arch, tune, cpu arg. */ -}; - -/* Parse the architecture extension string STR and update ISA_FLAGS - with the architecture features turned on or off. Return a - aarch64_parse_opt_result describing the result. */ - -static enum aarch64_parse_opt_result -aarch64_parse_extension (char *str, unsigned long *isa_flags) -{ - /* The extension string is parsed left to right. */ - const struct aarch64_option_extension *opt = NULL; - - /* Flag to say whether we are adding or removing an extension. */ - int adding_ext = -1; - - while (str != NULL && *str != 0) - { - char *ext; - size_t len; - - str++; - ext = strchr (str, '+'); - - if (ext != NULL) - len = ext - str; - else - len = strlen (str); - - if (len >= 2 && strncmp (str, "no", 2) == 0) - { - adding_ext = 0; - len -= 2; - str += 2; - } - else if (len > 0) - adding_ext = 1; - - if (len == 0) - return AARCH64_PARSE_MISSING_ARG; - - - /* Scan over the extensions table trying to find an exact match. */ - for (opt = all_extensions; opt->name != NULL; opt++) - { - if (strlen (opt->name) == len && strncmp (opt->name, str, len) == 0) - { - /* Add or remove the extension. */ - if (adding_ext) - *isa_flags |= opt->flags_on; - else - *isa_flags &= ~(opt->flags_off); - break; - } - } - - if (opt->name == NULL) - { - /* Extension not found in list. */ - return AARCH64_PARSE_INVALID_FEATURE; - } - - str = ext; - }; - - return AARCH64_PARSE_OK; -} - /* Parse the TO_PARSE string and put the architecture struct that it selects into RES and the architectural features into ISA_FLAGS. Return an aarch64_parse_opt_result describing the parse result. @@ -8155,7 +8078,7 @@ aarch64_option_print (FILE *file, int indent, struct cl_target_option *ptr) unsigned long isa_flags = ptr->x_aarch64_isa_flags; const struct processor *arch = aarch64_get_arch (ptr->x_explicit_arch); std::string extension - = aarch64_get_extension_string_for_isa_flags (isa_flags); + = aarch64_get_extension_string_for_isa_flags (isa_flags, arch->flags); fprintf (file, "%*sselected tune = %s\n", indent, "", cpu->name); fprintf (file, "%*sselected arch = %s%s\n", indent, "", @@ -10842,6 +10765,10 @@ aarch64_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global) return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type; } +/* The last .arch and .tune assembly strings that we printed. */ +static std::string aarch64_last_printed_arch_string; +static std::string aarch64_last_printed_tune_string; + /* Implement ASM_DECLARE_FUNCTION_NAME. Output the ISA features used by the function fndecl. */ @@ -10863,24 +10790,58 @@ aarch64_declare_function_name (FILE *stream, const char* name, unsigned long isa_flags = targ_options->x_aarch64_isa_flags; std::string extension - = aarch64_get_extension_string_for_isa_flags (isa_flags); - asm_fprintf (asm_out_file, "\t.arch %s%s\n", - this_arch->name, extension.c_str ()); + = aarch64_get_extension_string_for_isa_flags (isa_flags, + this_arch->flags); + /* Only update the assembler .arch string if it is distinct from the last + such string we printed. */ + std::string to_print = this_arch->name + extension; + if (to_print != aarch64_last_printed_arch_string) + { + asm_fprintf (asm_out_file, "\t.arch %s\n", to_print.c_str ()); + aarch64_last_printed_arch_string = to_print; + } /* Print the cpu name we're tuning for in the comments, might be - useful to readers of the generated asm. */ - + useful to readers of the generated asm. Do it only when it changes + from function to function and verbose assembly is requested. */ const struct processor *this_tune = aarch64_get_tune_cpu (targ_options->x_explicit_tune_core); - asm_fprintf (asm_out_file, "\t" ASM_COMMENT_START ".tune %s\n", - this_tune->name); + if (flag_debug_asm && aarch64_last_printed_tune_string != this_tune->name) + { + asm_fprintf (asm_out_file, "\t" ASM_COMMENT_START ".tune %s\n", + this_tune->name); + aarch64_last_printed_tune_string = this_tune->name; + } /* Don't forget the type directive for ELF. */ ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function"); ASM_OUTPUT_LABEL (stream, name); } +/* Implements TARGET_ASM_FILE_START. Output the assembly header. */ + +static void +aarch64_start_file (void) +{ + struct cl_target_option *default_options + = TREE_TARGET_OPTION (target_option_default_node); + + const struct processor *default_arch + = aarch64_get_arch (default_options->x_explicit_arch); + unsigned long default_isa_flags = default_options->x_aarch64_isa_flags; + std::string extension + = aarch64_get_extension_string_for_isa_flags (default_isa_flags, + default_arch->flags); + + aarch64_last_printed_arch_string = default_arch->name + extension; + aarch64_last_printed_tune_string = ""; + asm_fprintf (asm_out_file, "\t.arch %s\n", + aarch64_last_printed_arch_string.c_str ()); + + default_file_start (); +} + /* Emit load exclusive. */ static void @@ -13579,6 +13540,9 @@ aarch64_unspec_may_trap_p (const_rtx x, unsigned flags) #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ hook_bool_const_tree_hwi_hwi_const_tree_true +#undef TARGET_ASM_FILE_START +#define TARGET_ASM_FILE_START aarch64_start_file + #undef TARGET_ASM_OUTPUT_MI_THUNK #define TARGET_ASM_OUTPUT_MI_THUNK aarch64_output_mi_thunk diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 10506a79d8e..759e6a2934e 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -147,7 +147,7 @@ extern unsigned aarch64_architecture_version; /* Architecture flags that effect instruction selection. */ #define AARCH64_FL_FOR_ARCH8 (AARCH64_FL_FPSIMD) #define AARCH64_FL_FOR_ARCH8_1 \ - (AARCH64_FL_FOR_ARCH8 | AARCH64_FL_LSE | AARCH64_FL_V8_1) + (AARCH64_FL_FOR_ARCH8 | AARCH64_FL_LSE | AARCH64_FL_CRC | AARCH64_FL_V8_1) /* Macros to test ISA flags. */ diff --git a/gcc/config/aarch64/driver-aarch64.c b/gcc/config/aarch64/driver-aarch64.c index ae4d5a00ec5..e51b083034a 100644 --- a/gcc/config/aarch64/driver-aarch64.c +++ b/gcc/config/aarch64/driver-aarch64.c @@ -18,17 +18,25 @@ <http://www.gnu.org/licenses/>. */ #include "config.h" +#define INCLUDE_STRING #include "system.h" +#include "coretypes.h" +#include "tm.h" -struct arch_extension +/* Defined in common/config/aarch64/aarch64-common.c. */ +std::string aarch64_get_extension_string_for_isa_flags (unsigned long, + unsigned long); + +struct aarch64_arch_extension { const char *ext; + unsigned int flag; const char *feat_string; }; -#define AARCH64_OPT_EXTENSION(EXT_NAME, FLAGS_ON, FLAGS_OFF, FEATURE_STRING) \ - { EXT_NAME, FEATURE_STRING }, -static struct arch_extension ext_to_feat_string[] = +#define AARCH64_OPT_EXTENSION(EXT_NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, FEATURE_STRING) \ + { EXT_NAME, FLAG_CANONICAL, FEATURE_STRING }, +static struct aarch64_arch_extension aarch64_extensions[] = { #include "aarch64-option-extensions.def" }; @@ -41,15 +49,16 @@ struct aarch64_core_data const char* arch; const char* implementer_id; const char* part_no; + const unsigned long flags; }; #define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART) \ - { CORE_NAME, #ARCH, IMP, PART }, + { CORE_NAME, #ARCH, IMP, PART, FLAGS }, -static struct aarch64_core_data cpu_data [] = +static struct aarch64_core_data aarch64_cpu_data[] = { #include "aarch64-cores.def" - { NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, 0 } }; #undef AARCH64_CORE @@ -58,37 +67,37 @@ struct aarch64_arch_driver_info { const char* id; const char* name; + const unsigned long flags; }; #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \ - { #ARCH_IDENT, NAME }, + { #ARCH_IDENT, NAME, FLAGS }, -static struct aarch64_arch_driver_info aarch64_arches [] = +static struct aarch64_arch_driver_info aarch64_arches[] = { #include "aarch64-arches.def" - {NULL, NULL} + {NULL, NULL, 0} }; #undef AARCH64_ARCH -/* Return the full architecture name string corresponding to the - identifier ID. */ +/* Return an aarch64_arch_driver_info for the architecture described + by ID, or NULL if ID describes something we don't know about. */ -static const char* -get_arch_name_from_id (const char* id) +static struct aarch64_arch_driver_info* +get_arch_from_id (const char* id) { unsigned int i = 0; for (i = 0; aarch64_arches[i].id != NULL; i++) { if (strcmp (id, aarch64_arches[i].id) == 0) - return aarch64_arches[i].name; + return &aarch64_arches[i]; } return NULL; } - /* Check wether the string CORE contains the same CPU part numbers as BL_STRING. For example CORE="{0xd03, 0xd07}" and BL_STRING="0xd07.0xd03" should return true. */ @@ -97,7 +106,7 @@ static bool valid_bL_string_p (const char** core, const char* bL_string) { return strstr (bL_string, core[0]) != NULL - && strstr (bL_string, core[1]) != NULL; + && strstr (bL_string, core[1]) != NULL; } /* Return true iff ARR contains STR in one of its two elements. */ @@ -141,7 +150,7 @@ host_detect_local_cpu (int argc, const char **argv) { const char *arch_id = NULL; const char *res = NULL; - static const int num_exts = ARRAY_SIZE (ext_to_feat_string); + static const int num_exts = ARRAY_SIZE (aarch64_extensions); char buf[128]; FILE *f = NULL; bool arch = false; @@ -155,6 +164,8 @@ host_detect_local_cpu (int argc, const char **argv) unsigned int n_imps = 0; bool processed_exts = false; const char *ext_string = ""; + unsigned long extension_flags = 0; + unsigned long default_flags = 0; gcc_assert (argc); @@ -183,60 +194,71 @@ host_detect_local_cpu (int argc, const char **argv) { if (strstr (buf, "implementer") != NULL) { - for (i = 0; cpu_data[i].name != NULL; i++) - if (strstr (buf, cpu_data[i].implementer_id) != NULL - && !contains_string_p (imps, cpu_data[i].implementer_id)) + for (i = 0; aarch64_cpu_data[i].name != NULL; i++) + if (strstr (buf, aarch64_cpu_data[i].implementer_id) != NULL + && !contains_string_p (imps, + aarch64_cpu_data[i].implementer_id)) { - if (n_imps == 2) - goto not_found; + if (n_imps == 2) + goto not_found; - imps[n_imps++] = cpu_data[i].implementer_id; + imps[n_imps++] = aarch64_cpu_data[i].implementer_id; - break; + break; } - continue; + continue; } if (strstr (buf, "part") != NULL) { - for (i = 0; cpu_data[i].name != NULL; i++) - if (strstr (buf, cpu_data[i].part_no) != NULL - && !contains_string_p (cores, cpu_data[i].part_no)) + for (i = 0; aarch64_cpu_data[i].name != NULL; i++) + if (strstr (buf, aarch64_cpu_data[i].part_no) != NULL + && !contains_string_p (cores, aarch64_cpu_data[i].part_no)) { - if (n_cores == 2) - goto not_found; + if (n_cores == 2) + goto not_found; - cores[n_cores++] = cpu_data[i].part_no; - core_idx = i; - arch_id = cpu_data[i].arch; - break; + cores[n_cores++] = aarch64_cpu_data[i].part_no; + core_idx = i; + arch_id = aarch64_cpu_data[i].arch; + break; } - continue; - } + continue; + } if (!tune && !processed_exts && strstr (buf, "Features") != NULL) - { - for (i = 0; i < num_exts; i++) - { - bool enabled = true; - char *p = NULL; - char *feat_string = concat (ext_to_feat_string[i].feat_string, NULL); - - p = strtok (feat_string, " "); - - while (p != NULL) - { - if (strstr (buf, p) == NULL) - { - enabled = false; - break; - } - p = strtok (NULL, " "); - } - ext_string = concat (ext_string, "+", enabled ? "" : "no", - ext_to_feat_string[i].ext, NULL); - } - processed_exts = true; - } + { + for (i = 0; i < num_exts; i++) + { + char *p = NULL; + char *feat_string + = concat (aarch64_extensions[i].feat_string, NULL); + bool enabled = true; + + /* This may be a multi-token feature string. We need + to match all parts, which could be in any order. + If this isn't a multi-token feature string, strtok is + just going to return a pointer to feat_string. */ + p = strtok (feat_string, " "); + while (p != NULL) + { + if (strstr (buf, p) == NULL) + { + /* Failed to match this token. Turn off the + features we'd otherwise enable. */ + enabled = false; + break; + } + p = strtok (NULL, " "); + } + + if (enabled) + extension_flags |= aarch64_extensions[i].flag; + else + extension_flags &= ~(aarch64_extensions[i].flag); + } + + processed_exts = true; + } } fclose (f); @@ -251,44 +273,56 @@ host_detect_local_cpu (int argc, const char **argv) if (arch) { - const char* arch_name = get_arch_name_from_id (arch_id); + struct aarch64_arch_driver_info* arch_info = get_arch_from_id (arch_id); /* We got some arch indentifier that's not in aarch64-arches.def? */ - if (!arch_name) - goto not_found; + if (!arch_info) + goto not_found; - res = concat ("-march=", arch_name, NULL); + res = concat ("-march=", arch_info->name, NULL); + default_flags = arch_info->flags; } /* We have big.LITTLE. */ else if (n_cores == 2) { - for (i = 0; cpu_data[i].name != NULL; i++) - { - if (strchr (cpu_data[i].part_no, '.') != NULL - && strncmp (cpu_data[i].implementer_id, imps[0], strlen (imps[0]) - 1) == 0 - && valid_bL_string_p (cores, cpu_data[i].part_no)) - { - res = concat ("-m", cpu ? "cpu" : "tune", "=", cpu_data[i].name, NULL); - break; - } - } + for (i = 0; aarch64_cpu_data[i].name != NULL; i++) + { + if (strchr (aarch64_cpu_data[i].part_no, '.') != NULL + && strncmp (aarch64_cpu_data[i].implementer_id, + imps[0], + strlen (imps[0]) - 1) == 0 + && valid_bL_string_p (cores, aarch64_cpu_data[i].part_no)) + { + res = concat ("-m", + cpu ? "cpu" : "tune", "=", + aarch64_cpu_data[i].name, + NULL); + default_flags = aarch64_cpu_data[i].flags; + break; + } + } if (!res) - goto not_found; + goto not_found; } /* The simple, non-big.LITTLE case. */ else { - if (strncmp (cpu_data[core_idx].implementer_id, imps[0], - strlen (imps[0]) - 1) != 0) - goto not_found; + if (strncmp (aarch64_cpu_data[core_idx].implementer_id, imps[0], + strlen (imps[0]) - 1) != 0) + goto not_found; res = concat ("-m", cpu ? "cpu" : "tune", "=", - cpu_data[core_idx].name, NULL); + aarch64_cpu_data[core_idx].name, NULL); + default_flags = aarch64_cpu_data[core_idx].flags; } if (tune) return res; + ext_string + = aarch64_get_extension_string_for_isa_flags (extension_flags, + default_flags).c_str (); + res = concat (res, ext_string, NULL); return res; diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 5cf1efca8dd..b2d46f10646 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -1597,6 +1597,9 @@ ARM target prefers @code{LDRD} and @code{STRD} instructions over @subsubsection AArch64-specific attributes @table @code +@item aarch64_asm_<ext>_ok +AArch64 assembler supports the architecture extension @code{ext} via the +@code{.arch_extension} pseudo-op. @item aarch64_tiny AArch64 target which generates instruction sequences for tiny memory model. @item aarch64_small diff --git a/gcc/testsuite/gcc.target/aarch64/assembler_arch_1.c b/gcc/testsuite/gcc.target/aarch64/assembler_arch_1.c new file mode 100644 index 00000000000..5deea5cf0ee --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/assembler_arch_1.c @@ -0,0 +1,21 @@ +/* { dg-do assemble } */ +/* { dg-require-effective-target aarch64_asm_lse_ok } */ +/* { dg-options "-march=armv8-a" } */ + +/* Make sure that the function header in assembly doesn't override + user asm arch_extension directives. */ + +__asm__ (".arch_extension lse"); + +void +foo (int i, int *v) +{ + register int w0 asm ("w0") = i; + register int *x1 asm ("x1") = v; + + asm volatile ( + "\tstset %w[i], %[v]\n" + : [i] "+r" (w0), [v] "+Q" (v) + : "r" (x1) + : "x30"); +} diff --git a/gcc/testsuite/gcc.target/aarch64/mgeneral-regs_4.c b/gcc/testsuite/gcc.target/aarch64/mgeneral-regs_4.c index 8eb50aafa2b..49b74d9e265 100644 --- a/gcc/testsuite/gcc.target/aarch64/mgeneral-regs_4.c +++ b/gcc/testsuite/gcc.target/aarch64/mgeneral-regs_4.c @@ -6,4 +6,4 @@ test (void) return 1; } -/* { dg-final { scan-assembler "\.arch.*fp.*simd" } } */ +/* { dg-final { scan-assembler-times "\\.arch armv8-a\n" 1 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/target_attr_1.c b/gcc/testsuite/gcc.target/aarch64/target_attr_1.c index 852ce1e9f06..0527d0c3d61 100644 --- a/gcc/testsuite/gcc.target/aarch64/target_attr_1.c +++ b/gcc/testsuite/gcc.target/aarch64/target_attr_1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mcpu=thunderx -save-temps" } */ +/* { dg-options "-O2 -mcpu=thunderx -dA" } */ /* Test that cpu attribute overrides the command-line -mcpu. */ diff --git a/gcc/testsuite/gcc.target/aarch64/target_attr_15.c b/gcc/testsuite/gcc.target/aarch64/target_attr_15.c index 02091c6c542..2d8c7b955ce 100644 --- a/gcc/testsuite/gcc.target/aarch64/target_attr_15.c +++ b/gcc/testsuite/gcc.target/aarch64/target_attr_15.c @@ -10,6 +10,4 @@ foo (int a) return a + 1; } -/* { dg-final { scan-assembler-not "\\+fp" } } */ -/* { dg-final { scan-assembler-not "\\+crypto" } } */ -/* { dg-final { scan-assembler-not "\\+simd" } } */ +/* { dg-final { scan-assembler-times "\\.arch armv8-a\\+nofp\\+nosimd\n" 1 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/target_attr_7.c b/gcc/testsuite/gcc.target/aarch64/target_attr_7.c index 32a840378ab..818d327705f 100644 --- a/gcc/testsuite/gcc.target/aarch64/target_attr_7.c +++ b/gcc/testsuite/gcc.target/aarch64/target_attr_7.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mcpu=thunderx -save-temps" } */ +/* { dg-options "-O2 -mcpu=thunderx -dA" } */ /* Make sure that #pragma overrides command line option and target attribute overrides the pragma. */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index ef6d1f0dda5..771a0d4d593 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -6304,6 +6304,23 @@ proc check_effective_target_aarch64_tiny { } { } } +# Create functions to check that the AArch64 assembler supports the +# various architecture extensions via the .arch_extension pseudo-op. + +foreach { aarch64_ext } { "fp" "simd" "crypto" "crc" "lse"} { + eval [string map [list FUNC $aarch64_ext] { + proc check_effective_target_aarch64_asm_FUNC_ok { } { + if { [istarget aarch64*-*-*] } { + return [check_no_compiler_messages aarch64_FUNC_assembler object { + __asm__ (".arch_extension FUNC"); + } "-march=armv8-a+FUNC"] + } else { + return 0 + } + } + }] +} + proc check_effective_target_aarch64_small { } { if { [istarget aarch64*-*-*] } { return [check_no_compiler_messages aarch64_small object { |