* gas/config/tc-arm.c (md_pseduo_table): Add .arch_extension directive.
authorMatthew Gretton-Dann <matthew.gretton-dann@arm.com>
Thu, 23 Sep 2010 15:11:56 +0000 (15:11 +0000)
committerMatthew Gretton-Dann <matthew.gretton-dann@arm.com>
Thu, 23 Sep 2010 15:11:56 +0000 (15:11 +0000)
(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
gas/config/tc-arm.c
gas/doc/c-arm.texi

index 0df70c70ec4467237c1ef82378b661f08748a40e..70015a0a373c02cbf144d4690d370389099c0d13 100644 (file)
@@ -1,3 +1,18 @@
+2010-09-23  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>
+
+       * 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  <amodra@gmail.com>
 
        * config/tc-mn10300.c (tc_gen_reloc): Replace absolute symbols
index 136e04e4b6addc9d5b5fbc9c11ff3a30c648bde8..fde0bc47b2a8d13f3c6b92c949ef9614882e6a7f 100644 (file)
@@ -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;
 
index f64b554359d1dadb29ad9c568784c16774dcb218..479d6fa93aca5ac3cb53278892e5da6eef6d6b81 100644 (file)
@@ -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