Hi. This patch improves aarch64 feature modifier hints.
May I please ask ARM folks to test the patch? Thanks, Martin gcc/ChangeLog: 2018-07-18 Martin Liska <mli...@suse.cz> PR driver/83193 * common/config/aarch64/aarch64-common.c (aarch64_parse_extension): Set invalid_extension when there's any. (aarch64_get_all_extension_candidates): New function. (aarch64_rewrite_selected_cpu): Pass NULL as new argument. * config/aarch64/aarch64-protos.h (aarch64_get_all_extension_candidates): Declare new function. * config/aarch64/aarch64.c (aarch64_parse_arch): Record invalid_feature. (aarch64_parse_cpu): Likewise. (aarch64_print_hint_for_feature_modifier): New. (aarch64_validate_mcpu): Record invalid feature modifier and print hint for it. (aarch64_validate_march): Likewise. (aarch64_handle_attr_arch): Likewise. (aarch64_handle_attr_cpu): Likewise. (aarch64_handle_attr_isa_flags): Likewise. gcc/testsuite/ChangeLog: 2018-07-18 Martin Liska <mli...@suse.cz> PR driver/83193 * gcc.target/aarch64/spellcheck_7.c: New test. * gcc.target/aarch64/spellcheck_8.c: New test. --- gcc/common/config/aarch64/aarch64-common.c | 20 +++++- gcc/config/aarch64/aarch64-protos.h | 4 +- gcc/config/aarch64/aarch64.c | 67 +++++++++++++++---- .../gcc.target/aarch64/spellcheck_7.c | 11 +++ .../gcc.target/aarch64/spellcheck_8.c | 12 ++++ 5 files changed, 97 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/spellcheck_7.c create mode 100644 gcc/testsuite/gcc.target/aarch64/spellcheck_8.c
diff --git a/gcc/common/config/aarch64/aarch64-common.c b/gcc/common/config/aarch64/aarch64-common.c index 292fb818705..c2994514004 100644 --- a/gcc/common/config/aarch64/aarch64-common.c +++ b/gcc/common/config/aarch64/aarch64-common.c @@ -175,7 +175,8 @@ static const struct arch_to_arch_name all_architectures[] = aarch64_parse_opt_result describing the result. */ enum aarch64_parse_opt_result -aarch64_parse_extension (const char *str, unsigned long *isa_flags) +aarch64_parse_extension (const char *str, unsigned long *isa_flags, + char **invalid_extension) { /* The extension string is parsed left to right. */ const struct aarch64_option_extension *opt = NULL; @@ -226,6 +227,11 @@ aarch64_parse_extension (const char *str, unsigned long *isa_flags) if (opt->name == NULL) { /* Extension not found in list. */ + if (invalid_extension) + { + *invalid_extension = xstrdup (str); + (*invalid_extension)[len] = '\0'; + } return AARCH64_PARSE_INVALID_FEATURE; } @@ -235,6 +241,16 @@ aarch64_parse_extension (const char *str, unsigned long *isa_flags) return AARCH64_PARSE_OK; } +/* Append all extension candidates and put them to CANDIDATES vector. */ + +void +aarch64_get_all_extension_candidates (auto_vec<const char *> *candidates) +{ + const struct aarch64_option_extension *opt; + for (opt = all_extensions; opt->name != NULL; opt++) + candidates->safe_push (opt->name); +} + /* 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 @@ -322,7 +338,7 @@ aarch64_rewrite_selected_cpu (const char *name) 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); + aarch64_parse_extension (extension_str.c_str (), &extensions, NULL); std::string outstr = a_to_an->arch_name + aarch64_get_extension_string_for_isa_flags (extensions, diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index bc11a781c4b..4db274fb85d 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -550,7 +550,9 @@ 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 *); + unsigned long *, + char **); +void aarch64_get_all_extension_candidates (auto_vec<const char *> *candidates); std::string aarch64_get_extension_string_for_isa_flags (unsigned long, unsigned long); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 1369704da3e..6fa03e4b091 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -10229,7 +10229,7 @@ static void initialize_aarch64_code_model (struct gcc_options *); static enum aarch64_parse_opt_result aarch64_parse_arch (const char *to_parse, const struct processor **res, - unsigned long *isa_flags) + unsigned long *isa_flags, char **invalid_feature) { char *ext; const struct processor *arch; @@ -10260,7 +10260,7 @@ aarch64_parse_arch (const char *to_parse, const struct processor **res, { /* TO_PARSE string contains at least one extension. */ enum aarch64_parse_opt_result ext_res - = aarch64_parse_extension (ext, &isa_temp); + = aarch64_parse_extension (ext, &isa_temp, invalid_feature); if (ext_res != AARCH64_PARSE_OK) return ext_res; @@ -10284,7 +10284,7 @@ aarch64_parse_arch (const char *to_parse, const struct processor **res, static enum aarch64_parse_opt_result aarch64_parse_cpu (const char *to_parse, const struct processor **res, - unsigned long *isa_flags) + unsigned long *isa_flags, char **invalid_feature) { char *ext; const struct processor *cpu; @@ -10316,7 +10316,7 @@ aarch64_parse_cpu (const char *to_parse, const struct processor **res, { /* TO_PARSE string contains at least one extension. */ enum aarch64_parse_opt_result ext_res - = aarch64_parse_extension (ext, &isa_temp); + = aarch64_parse_extension (ext, &isa_temp, invalid_feature); if (ext_res != AARCH64_PARSE_OK) return ext_res; @@ -10764,6 +10764,26 @@ aarch64_print_hint_for_arch (const char *str) aarch64_print_hint_for_core_or_arch (str, true); } + +/* Print a hint with a suggestion for a feature modifier name + that most closely resembles what the user passed in STR. */ + +void +aarch64_print_hint_for_feature_modifier (const char *str) +{ + auto_vec<const char *> candidates; + aarch64_get_all_extension_candidates (&candidates); + char *s; + const char *hint = candidates_list_and_hint (str, s, candidates); + if (hint) + inform (input_location, "valid arguments are: %s;" + " did you mean %qs?", s, hint); + else + inform (input_location, "valid arguments are: %s;", s); + + XDELETEVEC (s); +} + /* Validate a command-line -mcpu option. Parse the cpu and extensions (if any) specified in STR and throw errors if appropriate. Put the results if they are valid in RES and ISA_FLAGS. Return whether the option is @@ -10773,8 +10793,9 @@ static bool aarch64_validate_mcpu (const char *str, const struct processor **res, unsigned long *isa_flags) { + char *invalid_feature; enum aarch64_parse_opt_result parse_res - = aarch64_parse_cpu (str, res, isa_flags); + = aarch64_parse_cpu (str, res, isa_flags, &invalid_feature); if (parse_res == AARCH64_PARSE_OK) return true; @@ -10789,7 +10810,10 @@ aarch64_validate_mcpu (const char *str, const struct processor **res, aarch64_print_hint_for_core (str); break; case AARCH64_PARSE_INVALID_FEATURE: - error ("invalid feature modifier in %<-mcpu=%s%>", str); + error ("invalid feature modifier %qs in %<-mcpu=%s%>", + invalid_feature, str); + aarch64_print_hint_for_feature_modifier (invalid_feature); + free (invalid_feature); break; default: gcc_unreachable (); @@ -10807,8 +10831,9 @@ static bool aarch64_validate_march (const char *str, const struct processor **res, unsigned long *isa_flags) { + char *invalid_feature; enum aarch64_parse_opt_result parse_res - = aarch64_parse_arch (str, res, isa_flags); + = aarch64_parse_arch (str, res, isa_flags, &invalid_feature); if (parse_res == AARCH64_PARSE_OK) return true; @@ -10823,7 +10848,10 @@ aarch64_validate_march (const char *str, const struct processor **res, aarch64_print_hint_for_arch (str); break; case AARCH64_PARSE_INVALID_FEATURE: - error ("invalid feature modifier in %<-march=%s%>", str); + error ("invalid feature modifier %qs in %<-march=%s%>", + invalid_feature, str); + aarch64_print_hint_for_feature_modifier (invalid_feature); + free (invalid_feature); break; default: gcc_unreachable (); @@ -11223,8 +11251,9 @@ static bool aarch64_handle_attr_arch (const char *str) { const struct processor *tmp_arch = NULL; + char *invalid_feature; enum aarch64_parse_opt_result parse_res - = aarch64_parse_arch (str, &tmp_arch, &aarch64_isa_flags); + = aarch64_parse_arch (str, &tmp_arch, &aarch64_isa_flags, &invalid_feature); if (parse_res == AARCH64_PARSE_OK) { @@ -11244,7 +11273,10 @@ aarch64_handle_attr_arch (const char *str) aarch64_print_hint_for_arch (str); break; case AARCH64_PARSE_INVALID_FEATURE: - error ("invalid value (\"%s\") in %<target()%> pragma or attribute", str); + error ("invalid feature modified %s of value (\"%s\") in " + "%<target()%> pragma or attribute", invalid_feature, str); + aarch64_print_hint_for_feature_modifier (invalid_feature); + free (invalid_feature); break; default: gcc_unreachable (); @@ -11259,8 +11291,9 @@ static bool aarch64_handle_attr_cpu (const char *str) { const struct processor *tmp_cpu = NULL; + char *invalid_feature; enum aarch64_parse_opt_result parse_res - = aarch64_parse_cpu (str, &tmp_cpu, &aarch64_isa_flags); + = aarch64_parse_cpu (str, &tmp_cpu, &aarch64_isa_flags, &invalid_feature); if (parse_res == AARCH64_PARSE_OK) { @@ -11283,7 +11316,10 @@ aarch64_handle_attr_cpu (const char *str) aarch64_print_hint_for_core (str); break; case AARCH64_PARSE_INVALID_FEATURE: - error ("invalid value (\"%s\") in %<target()%> pragma or attribute", str); + error ("invalid feature modified %s of value (\"%s\") in " + "%<target()%> pragma or attribute", invalid_feature, str); + aarch64_print_hint_for_feature_modifier (invalid_feature); + free (invalid_feature); break; default: gcc_unreachable (); @@ -11341,7 +11377,8 @@ aarch64_handle_attr_isa_flags (char *str) str += 8; } - parse_res = aarch64_parse_extension (str, &isa_flags); + char *invalid_feature; + parse_res = aarch64_parse_extension (str, &isa_flags, &invalid_feature); if (parse_res == AARCH64_PARSE_OK) { @@ -11356,7 +11393,9 @@ aarch64_handle_attr_isa_flags (char *str) break; case AARCH64_PARSE_INVALID_FEATURE: - error ("invalid value (\"%s\") in %<target()%> pragma or attribute", str); + error ("invalid feature modified %s of value (\"%s\") in " + "%<target()%> pragma or attribute", invalid_feature, str); + free (invalid_feature); break; default: diff --git a/gcc/testsuite/gcc.target/aarch64/spellcheck_7.c b/gcc/testsuite/gcc.target/aarch64/spellcheck_7.c new file mode 100644 index 00000000000..1350b865162 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/spellcheck_7.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-march=*" } { "" } } */ +/* { dg-options "-march=armv8-a+typo" } */ + +void +foo () +{ +} + +/* { dg-error "invalid feature modifier .typo. in .-march=armv8-a\\+typo." "" { target *-*-* } 0 } */ +/* { dg-message "valid arguments are: \[^\n\r]*;'?" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.target/aarch64/spellcheck_8.c b/gcc/testsuite/gcc.target/aarch64/spellcheck_8.c new file mode 100644 index 00000000000..321678e5ef6 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/spellcheck_8.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-march=*" } { "" } } */ +/* { dg-options "-march=armv8-a+cripto" } */ + +void +foo () +{ +} + +/* { dg-error "invalid feature modifier .cripto. in .-march=armv8-a\\+cripto." "" { target *-*-* } 0 } */ +/* { dg-message "valid arguments are: \[^\n\r]*; did you mean .crypto.?" "" { target *-*-* } 0 } */ +