From 691338631685cad7a3b8d8e330df408c999e423a Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 23 Sep 2010 15:11:56 +0000 Subject: [PATCH] * gas/config/tc-arm.c (md_pseduo_table): Add .arch_extension directive. (arm_option_extension_value_table): Add. (arm_extensions): Change type. (arm_option_cpu_table): Rename... (arm_option_fpu_table): ...to this. (arm_fpus): Change type. (arm_parse_extension): Enforce alphabetical order. Allow extensions to be removed. (arm_parse_arch): Allow extensions to be specified with -march. (s_arm_arch_extension): Add. (s_arm_fpu): Update for type changes. * gas/doc/c-arm.texi: Document changes to infrastructure. --- gas/ChangeLog | 15 ++++ gas/config/tc-arm.c | 170 +++++++++++++++++++++++++++++++++++++++----- gas/doc/c-arm.texi | 37 ++++++++-- 3 files changed, 199 insertions(+), 23 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 0df70c70ec4..70015a0a373 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,18 @@ +2010-09-23 Matthew Gretton-Dann + + * config/tc-arm.c (md_pseduo_table): Add .arch_extension directive. + (arm_option_extension_value_table): Add. + (arm_extensions): Change type. + (arm_option_cpu_table): Rename... + (arm_option_fpu_table): ...to this. + (arm_fpus): Change type. + (arm_parse_extension): Enforce alphabetical order. Allow + extensions to be removed. + (arm_parse_arch): Allow extensions to be specified with -march. + (s_arm_arch_extension): Add. + (s_arm_fpu): Update for type changes. + * doc/c-arm.texi: Document changes to infrastructure. + 2010-09-23 Alan Modra * config/tc-mn10300.c (tc_gen_reloc): Replace absolute symbols diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 136e04e4b6a..fde0bc47b2a 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -4270,6 +4270,7 @@ static void s_arm_arch (int); static void s_arm_object_arch (int); static void s_arm_cpu (int); static void s_arm_fpu (int); +static void s_arm_arch_extension (int); #ifdef TE_PE @@ -4323,6 +4324,7 @@ const pseudo_typeS md_pseudo_table[] = { "arch", s_arm_arch, 0 }, { "object_arch", s_arm_object_arch, 0 }, { "fpu", s_arm_fpu, 0 }, + { "arch_extension", s_arm_arch_extension, 0 }, #ifdef OBJ_ELF { "word", s_arm_elf_cons, 4 }, { "long", s_arm_elf_cons, 4 }, @@ -22451,25 +22453,35 @@ static const struct arm_arch_option_table arm_archs[] = {NULL, ARM_ARCH_NONE, ARM_ARCH_NONE} }; -/* ISA extensions in the co-processor space. */ -struct arm_option_cpu_value_table +/* ISA extensions in the co-processor and main instruction set space. */ +struct arm_option_extension_value_table { char *name; const arm_feature_set value; + const arm_feature_set allowed_archs; }; -static const struct arm_option_cpu_value_table arm_extensions[] = +/* The following table must be in alphabetical order with a NULL last entry. + */ +static const struct arm_option_extension_value_table arm_extensions[] = { - {"maverick", ARM_FEATURE (0, ARM_CEXT_MAVERICK)}, - {"xscale", ARM_FEATURE (0, ARM_CEXT_XSCALE)}, - {"iwmmxt", ARM_FEATURE (0, ARM_CEXT_IWMMXT)}, - {"iwmmxt2", ARM_FEATURE (0, ARM_CEXT_IWMMXT2)}, - {NULL, ARM_ARCH_NONE} + {"iwmmxt", ARM_FEATURE (0, ARM_CEXT_IWMMXT), ARM_ANY}, + {"iwmmxt2", ARM_FEATURE (0, ARM_CEXT_IWMMXT2), ARM_ANY}, + {"maverick", ARM_FEATURE (0, ARM_CEXT_MAVERICK), ARM_ANY}, + {"xscale", ARM_FEATURE (0, ARM_CEXT_XSCALE), ARM_ANY}, + {NULL, ARM_ARCH_NONE, ARM_ARCH_NONE} +}; + +/* ISA floating-point and Advanced SIMD extensions. */ +struct arm_option_fpu_value_table +{ + char *name; + const arm_feature_set value; }; /* This list should, at a minimum, contain all the fpu names recognized by GCC. */ -static const struct arm_option_cpu_value_table arm_fpus[] = +static const struct arm_option_fpu_value_table arm_fpus[] = { {"softfpa", FPU_NONE}, {"fpe", FPU_ARCH_FPE}, @@ -22547,15 +22559,23 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p) arm_feature_set *ext_set = (arm_feature_set *) xmalloc (sizeof (arm_feature_set)); + /* We insist on extensions being specified in alphabetical order, and with + extensions being added before being removed. We achieve this by having + the global ARM_EXTENSIONS table in alphabetical order, and using the + ADDING_VALUE variable to indicate whether we are adding an extension (1) + or removing it (0) and only allowing it to change in the order + -1 -> 1 -> 0. */ + const struct arm_option_extension_value_table * opt = NULL; + int adding_value = -1; + /* Copy the feature set, so that we can modify it. */ *ext_set = **opt_p; *opt_p = ext_set; while (str != NULL && *str != 0) { - const struct arm_option_cpu_value_table * opt; char * ext; - int optlen; + size_t optlen; if (*str != '+') { @@ -22571,24 +22591,86 @@ arm_parse_extension (char * str, const arm_feature_set **opt_p) else optlen = strlen (str); + if (optlen >= 2 + && strncmp (str, "no", 2) == 0) + { + if (adding_value != 0) + { + adding_value = 0; + opt = arm_extensions; + } + + optlen -= 2; + str += 2; + } + else if (optlen > 0) + { + if (adding_value == -1) + { + adding_value = 1; + opt = arm_extensions; + } + else if (adding_value != 1) + { + as_bad (_("must specify extensions to add before specifying " + "those to remove")); + return FALSE; + } + } + if (optlen == 0) { as_bad (_("missing architectural extension")); return FALSE; } - for (opt = arm_extensions; opt->name != NULL; opt++) - if (strncmp (opt->name, str, optlen) == 0) + gas_assert (adding_value != -1); + gas_assert (opt != NULL); + + /* Scan over the options table trying to find an exact match. */ + for (; opt->name != NULL; opt++) + if (strncmp (opt->name, str, optlen) == 0 + && strlen (opt->name) == optlen) { - ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value); + /* Check we can apply the extension to this architecture. */ + if (!ARM_CPU_HAS_FEATURE (*ext_set, opt->allowed_archs)) + { + as_bad (_("extension does not apply to the base architecture")); + return FALSE; + } + + /* Add or remove the extension. */ + if (adding_value) + ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value); + else + ARM_CLEAR_FEATURE (*ext_set, *ext_set, opt->value); + break; } if (opt->name == NULL) { - as_bad (_("unknown architectural extension `%s'"), str); + /* Did we fail to find an extension because it wasn't specified in + alphabetical order, or because it does not exist? */ + + for (opt = arm_extensions; opt->name != NULL; opt++) + if (strncmp (opt->name, str, optlen) == 0) + break; + + if (opt->name == NULL) + as_bad (_("unknown architectural extension `%s'"), str); + else + as_bad (_("architectural extensions must be specified in " + "alphabetical order")); + return FALSE; } + else + { + /* We should skip the extension we've just matched the next time + round. */ + opt++; + } str = ext; }; @@ -22659,7 +22741,7 @@ arm_parse_arch (char * str) } for (opt = arm_archs; opt->name != NULL; opt++) - if (streq (opt->name, str)) + if (strncmp (opt->name, str, optlen) == 0) { march_cpu_opt = &opt->value; march_fpu_opt = &opt->default_fpu; @@ -22678,7 +22760,7 @@ arm_parse_arch (char * str) static bfd_boolean arm_parse_fpu (char * str) { - const struct arm_option_cpu_value_table * opt; + const struct arm_option_fpu_value_table * opt; for (opt = arm_fpus; opt->name != NULL; opt++) if (streq (opt->name, str)) @@ -23183,12 +23265,64 @@ s_arm_object_arch (int ignored ATTRIBUTE_UNUSED) ignore_rest_of_line (); } +/* Parse a .arch_extension directive. */ + +static void +s_arm_arch_extension (int ignored ATTRIBUTE_UNUSED) +{ + const struct arm_option_extension_value_table *opt; + char saved_char; + char *name; + int adding_value = 1; + + name = input_line_pointer; + while (*input_line_pointer && !ISSPACE (*input_line_pointer)) + input_line_pointer++; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + + if (strlen (name) >= 2 + && strncmp (name, "no", 2) == 0) + { + adding_value = 0; + name += 2; + } + + for (opt = arm_extensions; opt->name != NULL; opt++) + if (streq (opt->name, name)) + { + if (!ARM_CPU_HAS_FEATURE (*mcpu_cpu_opt, opt->allowed_archs)) + { + as_bad (_("architectural extension `%s' is not allowed for the " + "current base architecture"), name); + break; + } + + if (adding_value) + ARM_MERGE_FEATURE_SETS (selected_cpu, selected_cpu, opt->value); + else + ARM_CLEAR_FEATURE (selected_cpu, selected_cpu, opt->value); + + mcpu_cpu_opt = &selected_cpu; + ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt); + *input_line_pointer = saved_char; + demand_empty_rest_of_line (); + return; + } + + if (opt->name == NULL) + as_bad (_("unknown architecture `%s'\n"), name); + + *input_line_pointer = saved_char; + ignore_rest_of_line (); +} + /* Parse a .fpu directive. */ static void s_arm_fpu (int ignored ATTRIBUTE_UNUSED) { - const struct arm_option_cpu_value_table *opt; + const struct arm_option_fpu_value_table *opt; char saved_char; char *name; diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi index f64b554359d..479d6fa93ac 100644 --- a/gas/doc/c-arm.texi +++ b/gas/doc/c-arm.texi @@ -133,12 +133,24 @@ assembler to accept instructions valid for any ARM processor. In addition to the basic instruction set, the assembler can be told to accept various extension mnemonics that extend the processor using the co-processor instruction space. For example, @code{-mcpu=arm920+maverick} -is equivalent to specifying @code{-mcpu=ep9312}. The following extensions -are currently supported: -@code{+maverick} -@code{+iwmmxt} +is equivalent to specifying @code{-mcpu=ep9312}. + +Multiple extensions may be specified, separated by a @code{+}. The +extensions should be specified in ascending alphabetical order. + +Extension mnemonics may also be removed from those the assembler accepts. +This is done be prepending @code{no} to the option that adds the extension. +Extensions that are removed should be listed after all extensions which have +been added, again in ascending alphabetical order. For example, +@code{-mcpu=ep9312+nomaverick} is equivalent to specifying @code{-mcpu=arm920}. + + +The following extensions are currently supported: +@code{iwmmxt}, +@code{iwmmxt2}, +@code{maverick}, and -@code{+xscale}. +@code{xscale}. @cindex @code{-march=} command line option, ARM @item -march=@var{architecture}[+@var{extension}@dots{}] @@ -503,6 +515,18 @@ boundary). This is for compatibility with ARM's own assembler. Select the target architecture. Valid values for @var{name} are the same as for the @option{-march} commandline option. +Specifying @code{.arch} clears any previously selected architecture +extensions. + +@cindex @code{.arch_extension} directive, ARM +@item .arch_extension @var{name} +Add or remove an architecture extension to the target architecture. Valid +values for @var{name} are the same as those accepted as architectural +extensions by the @option{-mcpu} commandline option. + +@code{.arch_extension} may be used multiple times to add or remove extensions +incrementally to the architecture being compiled for. + @cindex @code{.arm} directive, ARM @item .arm This performs the same action as @var{.code 32}. @@ -537,6 +561,9 @@ selects Thumb, with the value 32 selecting ARM. Select the target processor. Valid values for @var{name} are the same as for the @option{-mcpu} commandline option. +Specifying @code{.cpu} clears any previously selected architecture +extensions. + @c DDDDDDDDDDDDDDDDDDDDDDDDDD @cindex @code{.dn} and @code{.qn} directives, ARM -- 2.30.2