@@ -205,6 +205,78 @@ static constexpr aarch64_processor_info all_cores[] =
205205};
206206
207207
208+ /* Print a list of CANDIDATES for an argument, and try to suggest a specific
209+ close match. */
210+
211+ inline static void
212+ aarch64_print_hint_candidates (const char *str,
213+ const auto_vec<const char *> & candidates)
214+ {
215+ char *s;
216+ const char *hint = candidates_list_and_hint (str, s, candidates);
217+ if (hint)
218+ inform (input_location, " valid arguments are: %s;"
219+ " did you mean %qs?" , s, hint);
220+ else
221+ inform (input_location, " valid arguments are: %s" , s);
222+
223+ XDELETEVEC (s);
224+ }
225+
226+ /* Append all architecture extension candidates to the CANDIDATES vector. */
227+
228+ void
229+ aarch64_get_all_extension_candidates (auto_vec<const char *> *candidates)
230+ {
231+ const struct aarch64_extension_info *opt;
232+ for (opt = all_extensions; opt->name != NULL ; opt++)
233+ candidates->safe_push (opt->name );
234+ }
235+
236+ /* Print a hint with a suggestion for an extension name
237+ that most closely resembles what the user passed in STR. */
238+
239+ void
240+ aarch64_print_hint_for_extensions (const char *str)
241+ {
242+ auto_vec<const char *> candidates;
243+ aarch64_get_all_extension_candidates (&candidates);
244+ aarch64_print_hint_candidates (str, candidates);
245+ }
246+
247+ /* Print a hint with a suggestion for an architecture name that most closely
248+ resembles what the user passed in STR. */
249+
250+ void
251+ aarch64_print_hint_for_arch (const char *str)
252+ {
253+ auto_vec<const char *> candidates;
254+ const struct aarch64_arch_info *entry = all_architectures;
255+ for (; entry->name != NULL ; entry++)
256+ candidates.safe_push (entry->name );
257+
258+ #ifdef HAVE_LOCAL_CPU_DETECT
259+ /* Add also "native" as possible value. */
260+ candidates.safe_push (" native" );
261+ #endif
262+
263+ aarch64_print_hint_candidates (str, candidates);
264+ }
265+
266+ /* Print a hint with a suggestion for a core name that most closely resembles
267+ what the user passed in STR. */
268+
269+ void
270+ aarch64_print_hint_for_core (const char *str)
271+ {
272+ auto_vec<const char *> candidates;
273+ const struct aarch64_processor_info *entry = all_cores;
274+ for (; entry->name != NULL ; entry++)
275+ candidates.safe_push (entry->name );
276+ aarch64_print_hint_candidates (str, candidates);
277+ }
278+
279+
208280/* Parse the architecture extension string STR and update ISA_FLAGS
209281 with the architecture features turned on or off. Return a
210282 aarch_parse_opt_result describing the result.
@@ -275,16 +347,266 @@ aarch64_parse_extension (const char *str, aarch64_feature_flags *isa_flags,
275347 return AARCH_PARSE_OK;
276348}
277349
278- /* Append all architecture extension candidates to the CANDIDATES vector. */
350+ /* Parse the TO_PARSE string and put the architecture that it
351+ selects into RES_ARCH and the architectural features into RES_FLAGS.
352+ Return an aarch_parse_opt_result describing the parse result.
353+ If there is an error parsing, RES_ARCH and RES_FLAGS are left unchanged.
354+ When the TO_PARSE string contains an invalid extension,
355+ a copy of the string is created and stored to INVALID_EXTENSION. */
279356
280- void
281- aarch64_get_all_extension_candidates (auto_vec<const char *> *candidates)
357+ enum aarch_parse_opt_result
358+ aarch64_parse_arch (const char *to_parse, aarch64_arch *res_arch,
359+ aarch64_feature_flags *res_flags,
360+ std::string *invalid_extension)
282361{
283- const struct aarch64_extension_info *opt;
284- for (opt = all_extensions; opt->name != NULL ; opt++)
285- candidates->safe_push (opt->name );
362+ const char *ext;
363+ const struct aarch64_arch_info *arch;
364+ size_t len;
365+
366+ ext = strchr (to_parse, ' +' );
367+
368+ if (ext != NULL )
369+ len = ext - to_parse;
370+ else
371+ len = strlen (to_parse);
372+
373+ if (len == 0 )
374+ return AARCH_PARSE_MISSING_ARG;
375+
376+
377+ /* Loop through the list of supported ARCHes to find a match. */
378+ for (arch = all_architectures; arch->name != NULL ; arch++)
379+ {
380+ if (strlen (arch->name ) == len
381+ && strncmp (arch->name , to_parse, len) == 0 )
382+ {
383+ auto isa_flags = arch->flags ;
384+
385+ if (ext != NULL )
386+ {
387+ /* TO_PARSE string contains at least one extension. */
388+ enum aarch_parse_opt_result ext_res
389+ = aarch64_parse_extension (ext, &isa_flags, invalid_extension);
390+
391+ if (ext_res != AARCH_PARSE_OK)
392+ return ext_res;
393+ }
394+ /* Extension parsing was successful. Confirm the result
395+ arch and ISA flags. */
396+ *res_arch = arch->arch ;
397+ *res_flags = isa_flags;
398+ return AARCH_PARSE_OK;
399+ }
400+ }
401+
402+ /* ARCH name not found in list. */
403+ return AARCH_PARSE_INVALID_ARG;
404+ }
405+
406+ /* Parse the TO_PARSE string and put the result tuning in RES_CPU and the
407+ architecture flags in RES_FLAGS. Return an aarch_parse_opt_result
408+ describing the parse result. If there is an error parsing, RES_CPU and
409+ RES_FLAGS are left unchanged.
410+ When the TO_PARSE string contains an invalid extension,
411+ a copy of the string is created and stored to INVALID_EXTENSION. */
412+
413+ enum aarch_parse_opt_result
414+ aarch64_parse_cpu (const char *to_parse, aarch64_cpu *res_cpu,
415+ aarch64_feature_flags *res_flags,
416+ std::string *invalid_extension)
417+ {
418+ const char *ext;
419+ const struct aarch64_processor_info *cpu;
420+ size_t len;
421+
422+ ext = strchr (to_parse, ' +' );
423+
424+ if (ext != NULL )
425+ len = ext - to_parse;
426+ else
427+ len = strlen (to_parse);
428+
429+ if (len == 0 )
430+ return AARCH_PARSE_MISSING_ARG;
431+
432+
433+ /* Loop through the list of supported CPUs to find a match. */
434+ for (cpu = all_cores; cpu->name != NULL ; cpu++)
435+ {
436+ if (strlen (cpu->name ) == len && strncmp (cpu->name , to_parse, len) == 0 )
437+ {
438+ auto isa_flags = cpu->flags ;
439+
440+ if (ext != NULL )
441+ {
442+ /* TO_PARSE string contains at least one extension. */
443+ enum aarch_parse_opt_result ext_res
444+ = aarch64_parse_extension (ext, &isa_flags, invalid_extension);
445+
446+ if (ext_res != AARCH_PARSE_OK)
447+ return ext_res;
448+ }
449+ /* Extension parsing was successfull. Confirm the result
450+ cpu and ISA flags. */
451+ *res_cpu = cpu->processor ;
452+ *res_flags = isa_flags;
453+ return AARCH_PARSE_OK;
454+ }
455+ }
456+
457+ /* CPU name not found in list. */
458+ return AARCH_PARSE_INVALID_ARG;
286459}
287460
461+ /* Parse the TO_PARSE string and put the cpu it selects into RES_CPU.
462+ Return an aarch_parse_opt_result describing the parse result.
463+ If the parsing fails then RES_CPU does not change. */
464+
465+ enum aarch_parse_opt_result
466+ aarch64_parse_tune (const char *to_parse, aarch64_cpu *res_cpu)
467+ {
468+ const struct aarch64_processor_info *cpu;
469+
470+ /* Loop through the list of supported CPUs to find a match. */
471+ for (cpu = all_cores; cpu->name != NULL ; cpu++)
472+ {
473+ if (strcmp (cpu->name , to_parse) == 0 )
474+ {
475+ *res_cpu = cpu->processor ;
476+ return AARCH_PARSE_OK;
477+ }
478+ }
479+
480+ /* CPU name not found in list. */
481+ return AARCH_PARSE_INVALID_ARG;
482+ }
483+
484+
485+ /* Validate a command-line -march option. Parse the arch and extensions
486+ (if any) specified in STR and throw errors if appropriate. Put the
487+ results, if they are valid, in RES_ARCH and RES_FLAGS. Return whether the
488+ option is valid. */
489+
490+ bool
491+ aarch64_validate_march (const char *str, aarch64_arch *res_arch,
492+ aarch64_feature_flags *res_flags)
493+ {
494+ std::string invalid_extension;
495+ enum aarch_parse_opt_result parse_res
496+ = aarch64_parse_arch (str, res_arch, res_flags, &invalid_extension);
497+
498+ if (parse_res == AARCH_PARSE_OK)
499+ return true ;
500+
501+ switch (parse_res)
502+ {
503+ case AARCH_PARSE_MISSING_ARG:
504+ error (" missing arch name in %<-march=%s%>" , str);
505+ break ;
506+ case AARCH_PARSE_INVALID_ARG:
507+ {
508+ error (" unknown value %qs for %<-march%>" , str);
509+ aarch64_print_hint_for_arch (str);
510+ /* A common user error is confusing -march and -mcpu.
511+ If the -march string matches a known CPU suggest -mcpu. */
512+ aarch64_cpu temp_cpu;
513+ aarch64_feature_flags temp_flags;
514+ parse_res = aarch64_parse_cpu (str, &temp_cpu, &temp_flags,
515+ &invalid_extension);
516+ if (parse_res == AARCH_PARSE_OK)
517+ inform (input_location, " did you mean %<-mcpu=%s%>?" , str);
518+ break ;
519+ }
520+ case AARCH_PARSE_INVALID_FEATURE:
521+ error (" invalid feature modifier %qs in %<-march=%s%>" ,
522+ invalid_extension.c_str (), str);
523+ aarch64_print_hint_for_extensions (invalid_extension.c_str ());
524+ break ;
525+ default :
526+ gcc_unreachable ();
527+ }
528+
529+ return false ;
530+ }
531+
532+ /* Validate a command-line -mcpu option. Parse the cpu and extensions (if any)
533+ specified in STR and throw errors if appropriate. Put the results if
534+ they are valid in RES_CPU and RES_FLAGS. Return whether the option is
535+ valid. */
536+
537+ bool
538+ aarch64_validate_mcpu (const char *str, aarch64_cpu *res_cpu,
539+ aarch64_feature_flags *res_flags)
540+ {
541+ std::string invalid_extension;
542+ enum aarch_parse_opt_result parse_res
543+ = aarch64_parse_cpu (str, res_cpu, res_flags, &invalid_extension);
544+
545+ if (parse_res == AARCH_PARSE_OK)
546+ return true ;
547+
548+ switch (parse_res)
549+ {
550+ case AARCH_PARSE_MISSING_ARG:
551+ error (" missing cpu name in %<-mcpu=%s%>" , str);
552+ break ;
553+ case AARCH_PARSE_INVALID_ARG:
554+ {
555+ error (" unknown value %qs for %<-mcpu%>" , str);
556+ aarch64_print_hint_for_core (str);
557+ /* A common user error is confusing -march and -mcpu.
558+ If the -mcpu string matches a known architecture then suggest
559+ -march=. */
560+ aarch64_arch temp_arch;
561+ aarch64_feature_flags temp_flags;
562+ parse_res = aarch64_parse_arch (str, &temp_arch, &temp_flags,
563+ &invalid_extension);
564+ if (parse_res == AARCH_PARSE_OK)
565+ inform (input_location, " did you mean %<-march=%s%>?" , str);
566+ break ;
567+ }
568+ case AARCH_PARSE_INVALID_FEATURE:
569+ error (" invalid feature modifier %qs in %<-mcpu=%s%>" ,
570+ invalid_extension.c_str (), str);
571+ aarch64_print_hint_for_extensions (invalid_extension.c_str ());
572+ break ;
573+ default :
574+ gcc_unreachable ();
575+ }
576+
577+ return false ;
578+ }
579+
580+ /* Validate a command-line -mtune option. Parse the cpu
581+ specified in STR and throw errors if appropriate. Put the
582+ result, if it is valid, in RES_CPU. Return whether the option is
583+ valid. */
584+
585+ bool
586+ aarch64_validate_mtune (const char *str, aarch64_cpu *res_cpu)
587+ {
588+ enum aarch_parse_opt_result parse_res
589+ = aarch64_parse_tune (str, res_cpu);
590+
591+ if (parse_res == AARCH_PARSE_OK)
592+ return true ;
593+
594+ switch (parse_res)
595+ {
596+ case AARCH_PARSE_MISSING_ARG:
597+ error (" missing cpu name in %<-mtune=%s%>" , str);
598+ break ;
599+ case AARCH_PARSE_INVALID_ARG:
600+ error (" unknown value %qs for %<-mtune%>" , str);
601+ aarch64_print_hint_for_core (str);
602+ break ;
603+ default :
604+ gcc_unreachable ();
605+ }
606+ return false ;
607+ }
608+
609+
288610/* Return a string representation of ISA_FLAGS. DEFAULT_ARCH_FLAGS
289611 gives the default set of flags which are implied by whatever -march
290612 we'd put out. Our job is to figure out the minimal set of "+" and
0 commit comments