Add MIPS .module directive
authormfortune <matthew.fortune@imgtec.com>
Tue, 20 May 2014 12:28:20 +0000 (13:28 +0100)
committermfortune <matthew.fortune@imgtec.com>
Tue, 20 May 2014 22:46:43 +0000 (23:46 +0100)
gas/

* config/tc-mips.c (file_mips_opts_checked): New static global.
(s_module): New static function.
(file_ase): Remove.
(mips_pseudo_table): Add .module handler.
(mips_set_ase): Add opts argument and use instead of mips_opts.
  (md_assemble): Use file_mips_check_options.
(md_parse_option): Update to use file_mips_opts instead of mips_opts.
(mips_set_architecture): Delete function.  Moved to...
(mips_after_parse_args): Here.  All logic now applies to
file_mips_opts first and then copies the final state to mips_opts.
Move error checking and defaults inference to mips_check_options and
file_mips_check_options.
(mips_check_options): New static function.  Common option checking for
command line, .module and .set.  Use .module values in error messages
instead of refering to command line options.
(file_mips_check_options): New static function.  A wrapper for
mips_check_options with file_mips_opts.  Updates BFD arch based on
final options.
(s_mipsset): Split into s_mipsset and parse_code_option.  Settings
supported by both .set and .module are moved to parse_code_option.
Warnings and errors are kept in s_mipsset because when
parse_code_option is used with s_module the warnings are deferred
until code is generated.  Any setting supporting 'default' value is
kept in s_mipsset as it is not applicable to s_module. Inferred
settings are also kept in s_mipsset as s_module does not infer any
settings.  Use mips_check_options.
(parse_code_option): New static function derived from s_mipsset.
(s_module): New static function that implements .module.  Allows file
level settings to be changed until code is generated.
(s_cpload, s_cpsetup, s_cplocal): Use file_mips_check_options.
(s_cprestore, s_cpreturn, s_cpadd, mips_address_bytes): Likewise.
(mips_elf_final_processing): Update file_ase to file_mips_opts.ase.
(md_mips_end): Use file_mips_check_options.
* doc/c-mips.texi: Document .module.

gas/testsuite

* gas/mips/mips.exp: Add new tests.  Use 64-bit ABI for relax-bc1any.
Fix micromips arch definition to use mips64r2 consistently.
* gas/mips/module-defer-warn1.s: New.
* gas/mips/module-defer-warn1.d: New.
* gas/mips/module-defer-warn2.s: New.
* gas/mips/module-defer-warn2.l: New.
* gas/mips/module-override.d: New.
* gas/mips/module-override.s: New.
* gas/mips/mips-gp32-fp64.l: Update expected output.
* gas/mips/mips-gp64-fp32-pic.l: Update expected output.
* gas/mips/mips-gp64-fp32.l: Update expected output.

12 files changed:
gas/config/tc-mips.c
gas/doc/c-mips.texi
gas/testsuite/gas/mips/mips-gp32-fp64.l
gas/testsuite/gas/mips/mips-gp64-fp32-pic.l
gas/testsuite/gas/mips/mips-gp64-fp32.l
gas/testsuite/gas/mips/mips.exp
gas/testsuite/gas/mips/module-defer-warn1.d [new file with mode: 0644]
gas/testsuite/gas/mips/module-defer-warn1.s [new file with mode: 0644]
gas/testsuite/gas/mips/module-defer-warn2.l [new file with mode: 0644]
gas/testsuite/gas/mips/module-defer-warn2.s [new file with mode: 0644]
gas/testsuite/gas/mips/module-override.d [new file with mode: 0644]
gas/testsuite/gas/mips/module-override.s [new file with mode: 0644]

index dbf9c6e..4814a69 100644 (file)
@@ -259,6 +259,9 @@ struct mips_set_options
   bfd_boolean single_float;
 };
 
+/* Specifies whether module level options have been checked yet.  */
+static bfd_boolean file_mips_opts_checked = FALSE;
+
 /* True if -mnan=2008, false if -mnan=legacy.  */
 static bfd_boolean mips_flag_nan2008 = FALSE;
 
@@ -286,10 +289,6 @@ static struct mips_set_options mips_opts =
   /* soft_float */ FALSE, /* single_float */ FALSE
 };
 
-/* The set of ASEs that were selected on the command line, either
-   explicitly via ASE options or implicitly through things like -march.  */
-static unsigned int file_ase;
-
 /* Which bits of file_ase were explicitly set or cleared by ASE options.  */
 static unsigned int file_ase_explicit;
 
@@ -1295,6 +1294,7 @@ static void s_ehword (int);
 static void s_cpadd (int);
 static void s_insn (int);
 static void s_nan (int);
+static void s_module (int);
 static void s_mips_ent (int);
 static void s_mips_end (int);
 static void s_mips_frame (int);
@@ -1307,6 +1307,7 @@ static bfd_boolean pic_need_relax (symbolS *, asection *);
 static int relaxed_branch_length (fragS *, asection *, int);
 static int relaxed_micromips_16bit_branch_length (fragS *, asection *, int);
 static int relaxed_micromips_32bit_branch_length (fragS *, asection *, int);
+static void file_mips_check_options (void);
 
 /* Table and functions used to map between CPU/ISA names, and
    ISA levels, and CPU numbers.  */
@@ -1692,6 +1693,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"cpadd", s_cpadd, 0},
   {"insn", s_insn, 0},
   {"nan", s_nan, 0},
+  {"module", s_module, 0},
 
   /* Relatively generic pseudo-ops that happen to be used on MIPS
      chips.  */
@@ -1759,6 +1761,7 @@ static const pseudo_typeS mips_nonecoff_pseudo_table[] =
 int
 mips_address_bytes (void)
 {
+  file_mips_check_options ();
   return HAVE_64BIT_ADDRESSES ? 8 : 4;
 }
 
@@ -1979,14 +1982,15 @@ mips_check_isa_supports_ases (void)
    that were affected.  */
 
 static unsigned int
-mips_set_ase (const struct mips_ase *ase, bfd_boolean enabled_p)
+mips_set_ase (const struct mips_ase *ase, struct mips_set_options *opts,
+             bfd_boolean enabled_p)
 {
   unsigned int mask;
 
   mask = mips_ase_mask (ase->flags);
-  mips_opts.ase &= ~mask;
+  opts->ase &= ~mask;
   if (enabled_p)
-    mips_opts.ase |= ase->flags;
+    opts->ase |= ase->flags;
   return mask;
 }
 
@@ -3631,6 +3635,139 @@ md_begin (void)
     init_vr4120_conflicts ();
 }
 
+/* Perform consistency checks on the current options.  */
+
+static void
+mips_check_options (struct mips_set_options *opts, bfd_boolean abi_checks)
+{
+  /* Check the size of integer registers agrees with the ABI and ISA.  */
+  if (opts->gp == 64 && !ISA_HAS_64BIT_REGS (opts->isa))
+    as_bad (_("`gp=64' used with a 32-bit processor"));
+  else if (abi_checks
+          && opts->gp == 32 && ABI_NEEDS_64BIT_REGS (mips_abi))
+    as_bad (_("`gp=32' used with a 64-bit ABI"));
+  else if (abi_checks
+          && opts->gp == 64 && ABI_NEEDS_32BIT_REGS (mips_abi))
+    as_bad (_("`gp=64' used with a 32-bit ABI"));
+
+  /* Check the size of the float registers agrees with the ABI and ISA.  */
+  switch (opts->fp)
+    {
+    case 64:
+      if (!ISA_HAS_64BIT_FPRS (opts->isa))
+       as_bad (_("`fp=64' used with a 32-bit fpu"));
+      else if (abi_checks
+              && ABI_NEEDS_32BIT_REGS (mips_abi)
+              && !ISA_HAS_MXHC1 (opts->isa))
+       as_warn (_("`fp=64' used with a 32-bit ABI"));
+      break;
+    case 32:
+      if (abi_checks
+         && ABI_NEEDS_64BIT_REGS (mips_abi))
+       as_warn (_("`fp=32' used with a 64-bit ABI"));
+      break;
+    default:
+      as_bad (_("Unknown size of floating point registers"));
+      break;
+    }
+
+  if (opts->micromips == 1 && opts->mips16 == 1)
+    as_bad (_("`mips16' cannot be used with `micromips'"));
+}
+
+/* Perform consistency checks on the module level options exactly once.
+   This is a deferred check that happens:
+     at the first .set directive
+     or, at the first pseudo op that generates code (inc .dc.a)
+     or, at the first instruction
+     or, at the end.  */
+
+static void
+file_mips_check_options (void)
+{
+  const struct mips_cpu_info *arch_info = 0;
+
+  if (file_mips_opts_checked)
+    return;
+
+  /* The following code determines the register size.
+     Similar code was added to GCC 3.3 (see override_options() in
+     config/mips/mips.c).  The GAS and GCC code should be kept in sync
+     as much as possible.  */
+
+  if (file_mips_opts.gp < 0)
+    {
+      /* Infer the integer register size from the ABI and processor.
+        Restrict ourselves to 32-bit registers if that's all the
+        processor has, or if the ABI cannot handle 64-bit registers.  */
+      file_mips_opts.gp = (ABI_NEEDS_32BIT_REGS (mips_abi)
+                          || !ISA_HAS_64BIT_REGS (file_mips_opts.isa))
+                         ? 32 : 64;
+    }
+
+  if (file_mips_opts.fp < 0)
+    {
+      /* No user specified float register size.
+        ??? GAS treats single-float processors as though they had 64-bit
+        float registers (although it complains when double-precision
+        instructions are used).  As things stand, saying they have 32-bit
+        registers would lead to spurious "register must be even" messages.
+        So here we assume float registers are never smaller than the
+        integer ones.  */
+      if (file_mips_opts.gp == 64)
+       /* 64-bit integer registers implies 64-bit float registers.  */
+       file_mips_opts.fp = 64;
+      else if ((file_mips_opts.ase & FP64_ASES)
+              && ISA_HAS_64BIT_FPRS (file_mips_opts.isa))
+       /* Handle ASEs that require 64-bit float registers, if possible.  */
+       file_mips_opts.fp = 64;
+      else
+       /* 32-bit float registers.  */
+       file_mips_opts.fp = 32;
+    }
+
+  arch_info = mips_cpu_info_from_arch (file_mips_opts.arch);
+
+  /* End of GCC-shared inference code.  */
+
+  /* This flag is set when we have a 64-bit capable CPU but use only
+     32-bit wide registers.  Note that EABI does not use it.  */
+  if (ISA_HAS_64BIT_REGS (file_mips_opts.isa)
+      && ((mips_abi == NO_ABI && file_mips_opts.gp == 32)
+         || mips_abi == O32_ABI))
+    mips_32bitmode = 1;
+
+  if (file_mips_opts.isa == ISA_MIPS1 && mips_trap)
+    as_bad (_("trap exception not supported at ISA 1"));
+
+  /* If the selected architecture includes support for ASEs, enable
+     generation of code for them.  */
+  if (file_mips_opts.mips16 == -1)
+    file_mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_opts.arch)) ? 1 : 0;
+  if (file_mips_opts.micromips == -1)
+    file_mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_opts.arch))
+                               ? 1 : 0;
+
+  /* Some ASEs require 64-bit FPRs, so -mfp32 should stop those ASEs from
+     being selected implicitly.  */
+  if (file_mips_opts.fp != 64)
+    file_ase_explicit |= ASE_MIPS3D | ASE_MDMX | ASE_MSA;
+
+  /* If the user didn't explicitly select or deselect a particular ASE,
+     use the default setting for the CPU.  */
+  file_mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
+
+  /* Set up the current options.  These may change throughout assembly.  */
+  mips_opts = file_mips_opts;
+
+  mips_check_isa_supports_ases ();
+  mips_check_options (&file_mips_opts, TRUE);
+  file_mips_opts_checked = TRUE;
+
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_opts.arch))
+    as_warn (_("could not set architecture and machine"));
+}
+
 void
 md_assemble (char *str)
 {
@@ -3638,6 +3775,8 @@ md_assemble (char *str)
   bfd_reloc_code_real_type unused_reloc[3]
     = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
+  file_mips_check_options ();
+
   imm_expr.X_op = O_absent;
   offset_expr.X_op = O_absent;
   offset_reloc[0] = BFD_RELOC_UNUSED;
@@ -13483,7 +13622,7 @@ md_parse_option (int c, char *arg)
   for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
     if (c == mips_ases[i].option_on || c == mips_ases[i].option_off)
       {
-       file_ase_explicit |= mips_set_ase (&mips_ases[i],
+       file_ase_explicit |= mips_set_ase (&mips_ases[i], &file_mips_opts,
                                           c == mips_ases[i].option_on);
        return 1;
       }
@@ -13625,32 +13764,32 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_MICROMIPS:
-      if (mips_opts.mips16 == 1)
+      if (file_mips_opts.mips16 == 1)
        {
          as_bad (_("-mmicromips cannot be used with -mips16"));
          return 0;
        }
-      mips_opts.micromips = 1;
+      file_mips_opts.micromips = 1;
       mips_no_prev_insn ();
       break;
 
     case OPTION_NO_MICROMIPS:
-      mips_opts.micromips = 0;
+      file_mips_opts.micromips = 0;
       mips_no_prev_insn ();
       break;
 
     case OPTION_MIPS16:
-      if (mips_opts.micromips == 1)
+      if (file_mips_opts.micromips == 1)
        {
          as_bad (_("-mips16 cannot be used with -micromips"));
          return 0;
        }
-      mips_opts.mips16 = 1;
+      file_mips_opts.mips16 = 1;
       mips_no_prev_insn ();
       break;
 
     case OPTION_NO_MIPS16:
-      mips_opts.mips16 = 0;
+      file_mips_opts.mips16 = 0;
       mips_no_prev_insn ();
       break;
 
@@ -13719,11 +13858,11 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_INSN32:
-      mips_opts.insn32 = TRUE;
+      file_mips_opts.insn32 = TRUE;
       break;
 
     case OPTION_NO_INSN32:
-      mips_opts.insn32 = FALSE;
+      file_mips_opts.insn32 = FALSE;
       break;
 
     case OPTION_MSHARED:
@@ -13735,11 +13874,11 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_MSYM32:
-      mips_opts.sym32 = TRUE;
+      file_mips_opts.sym32 = TRUE;
       break;
 
     case OPTION_MNO_SYM32:
-      mips_opts.sym32 = FALSE;
+      file_mips_opts.sym32 = FALSE;
       break;
 
       /* When generating ELF code, we permit -KPIC and -call_shared to
@@ -13892,22 +14031,7 @@ md_parse_option (int c, char *arg)
   return 1;
 }
 \f
-/* Set up globals to generate code for the ISA or processor
-   described by INFO.  */
-
-static void
-mips_set_architecture (const struct mips_cpu_info *info)
-{
-  if (info != 0)
-    {
-      file_mips_opts.arch = info->cpu;
-      mips_opts.arch = info->cpu;
-      mips_opts.isa = info->isa;
-    }
-}
-
-
-/* Likewise for tuning.  */
+/* Set up globals to tune for the ISA or processor described by INFO.  */
 
 static void
 mips_set_tune (const struct mips_cpu_info *info)
@@ -13934,7 +14058,7 @@ mips_after_parse_args (void)
   if (mips_abi == NO_ABI)
     mips_abi = MIPS_DEFAULT_ABI;
 
-  /* The following code determines the architecture and register size.
+  /* The following code determines the architecture.
      Similar code was added to GCC 3.3 (see override_options() in
      config/mips/mips.c).  The GAS and GCC code should be kept in sync
      as much as possible.  */
@@ -13972,7 +14096,14 @@ mips_after_parse_args (void)
     as_bad (_("-march=%s is not compatible with the selected ABI"),
            arch_info->name);
 
-  mips_set_architecture (arch_info);
+  file_mips_opts.arch = arch_info->cpu;
+  file_mips_opts.isa = arch_info->isa;
+
+  /* Set up initial mips_opts state.  */
+  mips_opts = file_mips_opts;
+
+  /* The register size inference code is now placed in
+     file_mips_check_options.  */
 
   /* Optimize for file_mips_opts.arch, unless -mtune selects a different
      processor.  */
@@ -13984,103 +14115,6 @@ mips_after_parse_args (void)
   else
     mips_set_tune (tune_info);
 
-  if (file_mips_opts.gp >= 0)
-    {
-      /* The user specified the size of the integer registers.  Make sure
-        it agrees with the ABI and ISA.  */
-      if (file_mips_opts.gp == 64 && !ISA_HAS_64BIT_REGS (mips_opts.isa))
-       as_bad (_("-mgp64 used with a 32-bit processor"));
-      else if (file_mips_opts.gp == 32 && ABI_NEEDS_64BIT_REGS (mips_abi))
-       as_bad (_("-mgp32 used with a 64-bit ABI"));
-      else if (file_mips_opts.gp == 64 && ABI_NEEDS_32BIT_REGS (mips_abi))
-       as_bad (_("-mgp64 used with a 32-bit ABI"));
-    }
-  else
-    {
-      /* Infer the integer register size from the ABI and processor.
-        Restrict ourselves to 32-bit registers if that's all the
-        processor has, or if the ABI cannot handle 64-bit registers.  */
-      file_mips_opts.gp = (ABI_NEEDS_32BIT_REGS (mips_abi)
-                          || !ISA_HAS_64BIT_REGS (mips_opts.isa))
-                         ? 32 : 64;
-    }
-
-  switch (file_mips_opts.fp)
-    {
-    default:
-    case -1:
-      /* No user specified float register size.
-        ??? GAS treats single-float processors as though they had 64-bit
-        float registers (although it complains when double-precision
-        instructions are used).  As things stand, saying they have 32-bit
-        registers would lead to spurious "register must be even" messages.
-        So here we assume float registers are never smaller than the
-        integer ones.  */
-      if (file_mips_opts.gp == 64)
-       /* 64-bit integer registers implies 64-bit float registers.  */
-       file_mips_opts.fp = 64;
-      else if ((mips_opts.ase & FP64_ASES)
-              && ISA_HAS_64BIT_FPRS (mips_opts.isa))
-       /* Handle ASEs that require 64-bit float registers, if possible.  */
-       file_mips_opts.fp = 64;
-      else
-       /* 32-bit float registers.  */
-       file_mips_opts.fp = 32;
-      break;
-
-    /* The user specified the size of the float registers.  Check if it
-       agrees with the ABI and ISA.  */
-    case 64:
-      if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
-       as_bad (_("-mfp64 used with a 32-bit fpu"));
-      else if (ABI_NEEDS_32BIT_REGS (mips_abi)
-              && !ISA_HAS_MXHC1 (mips_opts.isa))
-       as_warn (_("-mfp64 used with a 32-bit ABI"));
-      break;
-    case 32:
-      if (ABI_NEEDS_64BIT_REGS (mips_abi))
-       as_warn (_("-mfp32 used with a 64-bit ABI"));
-      break;
-    }
-
-  /* End of GCC-shared inference code.  */
-
-  /* This flag is set when we have a 64-bit capable CPU but use only
-     32-bit wide registers.  Note that EABI does not use it.  */
-  if (ISA_HAS_64BIT_REGS (mips_opts.isa)
-      && ((mips_abi == NO_ABI && file_mips_opts.gp == 32)
-         || mips_abi == O32_ABI))
-    mips_32bitmode = 1;
-
-  if (mips_opts.isa == ISA_MIPS1 && mips_trap)
-    as_bad (_("trap exception not supported at ISA 1"));
-
-  /* If the selected architecture includes support for ASEs, enable
-     generation of code for them.  */
-  if (mips_opts.mips16 == -1)
-    mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_opts.arch)) ? 1 : 0;
-  if (mips_opts.micromips == -1)
-    mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_opts.arch))
-                          ? 1 : 0;
-
-  /* MIPS3D, MDMX and MSA require 64-bit FPRs, so -mfp32 should stop those
-     ASEs from being selected implicitly.  */
-  if (file_mips_opts.fp != 64)
-    file_ase_explicit |= ASE_MIPS3D | ASE_MDMX | ASE_MSA;
-
-  /* If the user didn't explicitly select or deselect a particular ASE,
-     use the default setting for the CPU.  */
-  mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
-
-  file_mips_opts.isa = mips_opts.isa;
-  file_mips_opts.ase = mips_opts.ase;
-  mips_opts.gp = file_mips_opts.gp;
-  mips_opts.fp = file_mips_opts.fp;
-  mips_opts.soft_float = file_mips_opts.soft_float;
-  mips_opts.single_float = file_mips_opts.single_float;
-
-  mips_check_isa_supports_ases ();
-
   if (mips_flag_mdebug < 0)
     mips_flag_mdebug = 0;
 }
@@ -14968,30 +15002,11 @@ struct mips_option_stack
 
 static struct mips_option_stack *mips_opts_stack;
 
-/* Handle the .set pseudo-op.  */
-
-static void
-s_mipsset (int x ATTRIBUTE_UNUSED)
+static bfd_boolean
+parse_code_option (char * name)
 {
-  char *name = input_line_pointer, ch;
   const struct mips_ase *ase;
-
-  while (!is_end_of_line[(unsigned char) *input_line_pointer])
-    ++input_line_pointer;
-  ch = *input_line_pointer;
-  *input_line_pointer = '\0';
-
-  if (strcmp (name, "reorder") == 0)
-    {
-      if (mips_opts.noreorder)
-       end_noreorder ();
-    }
-  else if (strcmp (name, "noreorder") == 0)
-    {
-      if (!mips_opts.noreorder)
-       start_noreorder ();
-    }
-  else if (strncmp (name, "at=", 3) == 0)
+  if (strncmp (name, "at=", 3) == 0)
     {
       char *s = name + 3;
 
@@ -14999,61 +15014,25 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        as_bad (_("unrecognized register name `%s'"), s);
     }
   else if (strcmp (name, "at") == 0)
-    {
-      mips_opts.at = ATREG;
-    }
+    mips_opts.at = ATREG;
   else if (strcmp (name, "noat") == 0)
-    {
-      mips_opts.at = ZERO;
-    }
-  else if (strcmp (name, "macro") == 0)
-    {
-      mips_opts.warn_about_macros = 0;
-    }
-  else if (strcmp (name, "nomacro") == 0)
-    {
-      if (mips_opts.noreorder == 0)
-       as_bad (_("`noreorder' must be set before `nomacro'"));
-      mips_opts.warn_about_macros = 1;
-    }
+    mips_opts.at = ZERO;
   else if (strcmp (name, "move") == 0 || strcmp (name, "novolatile") == 0)
-    {
-      mips_opts.nomove = 0;
-    }
+    mips_opts.nomove = 0;
   else if (strcmp (name, "nomove") == 0 || strcmp (name, "volatile") == 0)
-    {
-      mips_opts.nomove = 1;
-    }
+    mips_opts.nomove = 1;
   else if (strcmp (name, "bopt") == 0)
-    {
-      mips_opts.nobopt = 0;
-    }
+    mips_opts.nobopt = 0;
   else if (strcmp (name, "nobopt") == 0)
-    {
-      mips_opts.nobopt = 1;
-    }
-  else if (strcmp (name, "gp=default") == 0)
-    mips_opts.gp = file_mips_opts.gp;
+    mips_opts.nobopt = 1;
   else if (strcmp (name, "gp=32") == 0)
     mips_opts.gp = 32;
   else if (strcmp (name, "gp=64") == 0)
-    {
-      if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
-       as_warn (_("%s isa does not support 64-bit registers"),
-                mips_cpu_info_from_isa (mips_opts.isa)->name);
-      mips_opts.gp = 64;
-    }
-  else if (strcmp (name, "fp=default") == 0)
-    mips_opts.fp = file_mips_opts.fp;
+    mips_opts.gp = 64;
   else if (strcmp (name, "fp=32") == 0)
     mips_opts.fp = 32;
   else if (strcmp (name, "fp=64") == 0)
-    {
-      if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
-       as_warn (_("%s isa does not support 64-bit floating point registers"),
-                mips_cpu_info_from_isa (mips_opts.isa)->name);
-      mips_opts.fp = 64;
-    }
+    mips_opts.fp = 64;
   else if (strcmp (name, "softfloat") == 0)
     mips_opts.soft_float = 1;
   else if (strcmp (name, "hardfloat") == 0)
@@ -15064,45 +15043,29 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     mips_opts.single_float = 0;
   else if (strcmp (name, "mips16") == 0
           || strcmp (name, "MIPS-16") == 0)
-    {
-      if (mips_opts.micromips == 1)
-       as_fatal (_("`mips16' cannot be used with `micromips'"));
-      mips_opts.mips16 = 1;
-    }
+    mips_opts.mips16 = 1;
   else if (strcmp (name, "nomips16") == 0
           || strcmp (name, "noMIPS-16") == 0)
     mips_opts.mips16 = 0;
   else if (strcmp (name, "micromips") == 0)
-    {
-      if (mips_opts.mips16 == 1)
-       as_fatal (_("`micromips' cannot be used with `mips16'"));
-      mips_opts.micromips = 1;
-    }
+    mips_opts.micromips = 1;
   else if (strcmp (name, "nomicromips") == 0)
     mips_opts.micromips = 0;
   else if (name[0] == 'n'
           && name[1] == 'o'
           && (ase = mips_lookup_ase (name + 2)))
-    mips_set_ase (ase, FALSE);
+    mips_set_ase (ase, &mips_opts, FALSE);
   else if ((ase = mips_lookup_ase (name)))
-    mips_set_ase (ase, TRUE);
+    mips_set_ase (ase, &mips_opts, TRUE);
   else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
     {
-      int reset = 0;
-
       /* Permit the user to change the ISA and architecture on the fly.
         Needless to say, misuse can cause serious problems.  */
-      if (strcmp (name, "mips0") == 0 || strcmp (name, "arch=default") == 0)
-       {
-         reset = 1;
-         mips_opts.isa = file_mips_opts.isa;
-         mips_opts.arch = file_mips_opts.arch;
-       }
-      else if (strncmp (name, "arch=", 5) == 0)
+      if (strncmp (name, "arch=", 5) == 0)
        {
          const struct mips_cpu_info *p;
 
-         p = mips_parse_cpu("internal use", name + 5);
+         p = mips_parse_cpu ("internal use", name + 5);
          if (!p)
            as_bad (_("unknown architecture %s"), name + 5);
          else
@@ -15115,7 +15078,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        {
          const struct mips_cpu_info *p;
 
-         p = mips_parse_cpu("internal use", name);
+         p = mips_parse_cpu ("internal use", name);
          if (!p)
            as_bad (_("unknown ISA level %s"), name + 4);
          else
@@ -15126,46 +15089,6 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        }
       else
        as_bad (_("unknown ISA or architecture %s"), name);
-
-      switch (mips_opts.isa)
-       {
-       case  0:
-         break;
-       case ISA_MIPS1:
-       case ISA_MIPS2:
-       case ISA_MIPS32:
-       case ISA_MIPS32R2:
-       case ISA_MIPS32R3:
-       case ISA_MIPS32R5:
-         mips_opts.gp = 32;
-         mips_opts.fp = 32;
-         break;
-       case ISA_MIPS3:
-       case ISA_MIPS4:
-       case ISA_MIPS5:
-       case ISA_MIPS64:
-       case ISA_MIPS64R2:
-       case ISA_MIPS64R3:
-       case ISA_MIPS64R5:
-         mips_opts.gp = 64;
-         if (mips_opts.arch == CPU_R5900)
-           {
-               mips_opts.fp = 32;
-           }
-         else
-           {
-         mips_opts.fp = 64;
-           }
-         break;
-       default:
-         as_bad (_("unknown ISA level %s"), name + 4);
-         break;
-       }
-      if (reset)
-       {
-         mips_opts.gp = file_mips_opts.gp;
-         mips_opts.fp = file_mips_opts.fp;
-       }
     }
   else if (strcmp (name, "autoextend") == 0)
     mips_opts.noautoextend = 0;
@@ -15175,6 +15098,68 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     mips_opts.insn32 = TRUE;
   else if (strcmp (name, "noinsn32") == 0)
     mips_opts.insn32 = FALSE;
+  else if (strcmp (name, "sym32") == 0)
+    mips_opts.sym32 = TRUE;
+  else if (strcmp (name, "nosym32") == 0)
+    mips_opts.sym32 = FALSE;
+  else
+    return FALSE;
+  return TRUE;
+}
+
+/* Handle the .set pseudo-op.  */
+
+static void
+s_mipsset (int x ATTRIBUTE_UNUSED)
+{
+  char *name = input_line_pointer, ch;
+  int prev_isa = mips_opts.isa;
+
+  file_mips_check_options ();
+
+  while (!is_end_of_line[(unsigned char) *input_line_pointer])
+    ++input_line_pointer;
+  ch = *input_line_pointer;
+  *input_line_pointer = '\0';
+
+  if (strchr (name, ','))
+    {
+      /* Generic ".set" directive; use the generic handler.  */
+      *input_line_pointer = ch;
+      input_line_pointer = name;
+      s_set (0);
+      return;
+    }
+
+  if (strcmp (name, "reorder") == 0)
+    {
+      if (mips_opts.noreorder)
+       end_noreorder ();
+    }
+  else if (strcmp (name, "noreorder") == 0)
+    {
+      if (!mips_opts.noreorder)
+       start_noreorder ();
+    }
+  else if (strcmp (name, "macro") == 0)
+    mips_opts.warn_about_macros = 0;
+  else if (strcmp (name, "nomacro") == 0)
+    {
+      if (mips_opts.noreorder == 0)
+       as_bad (_("`noreorder' must be set before `nomacro'"));
+      mips_opts.warn_about_macros = 1;
+    }
+  else if (strcmp (name, "gp=default") == 0)
+    mips_opts.gp = file_mips_opts.gp;
+  else if (strcmp (name, "fp=default") == 0)
+    mips_opts.fp = file_mips_opts.fp;
+  else if (strcmp (name, "mips0") == 0 || strcmp (name, "arch=default") == 0)
+    {
+      mips_opts.isa = file_mips_opts.isa;
+      mips_opts.arch = file_mips_opts.arch;
+      mips_opts.gp = file_mips_opts.gp;
+      mips_opts.fp = file_mips_opts.fp;
+    }
   else if (strcmp (name, "push") == 0)
     {
       struct mips_option_stack *s;
@@ -15205,23 +15190,75 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
          free (s);
        }
     }
-  else if (strcmp (name, "sym32") == 0)
-    mips_opts.sym32 = TRUE;
-  else if (strcmp (name, "nosym32") == 0)
-    mips_opts.sym32 = FALSE;
-  else if (strchr (name, ','))
+  else if (!parse_code_option (name))
+    as_warn (_("tried to set unrecognized symbol: %s\n"), name);
+
+  /* The use of .set [arch|cpu]= historically 'fixes' the width of gp and fp
+     registers based on what is supported by the arch/cpu.  */
+  if (mips_opts.isa != prev_isa)
     {
-      /* Generic ".set" directive; use the generic handler.  */
-      *input_line_pointer = ch;
-      input_line_pointer = name;
-      s_set (0);
-      return;
+      switch (mips_opts.isa)
+       {
+       case 0:
+         break;
+       case ISA_MIPS1:
+       case ISA_MIPS2:
+       case ISA_MIPS32:
+       case ISA_MIPS32R2:
+       case ISA_MIPS32R3:
+       case ISA_MIPS32R5:
+         mips_opts.gp = 32;
+         mips_opts.fp = 32;
+         break;
+       case ISA_MIPS3:
+       case ISA_MIPS4:
+       case ISA_MIPS5:
+       case ISA_MIPS64:
+       case ISA_MIPS64R2:
+       case ISA_MIPS64R3:
+       case ISA_MIPS64R5:
+         mips_opts.gp = 64;
+         if (mips_opts.arch == CPU_R5900)
+           mips_opts.fp = 32;
+         else
+           mips_opts.fp = 64;
+         break;
+       default:
+         as_bad (_("unknown ISA level %s"), name + 4);
+         break;
+       }
     }
-  else
+
+  mips_check_options (&mips_opts, FALSE);
+
+  mips_check_isa_supports_ases ();
+  *input_line_pointer = ch;
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the .module pseudo-op.  */
+
+static void
+s_module (int ignore ATTRIBUTE_UNUSED)
+{
+  char *name = input_line_pointer, ch;
+
+  while (!is_end_of_line[(unsigned char) *input_line_pointer])
+    ++input_line_pointer;
+  ch = *input_line_pointer;
+  *input_line_pointer = '\0';
+
+  if (!file_mips_opts_checked)
     {
-      as_warn (_("tried to set unrecognized symbol: %s\n"), name);
+      if (!parse_code_option (name))
+       as_bad (_(".module used with unrecognized symbol: %s\n"), name);
+
+      /* Update module level settings from mips_opts.  */
+      file_mips_opts = mips_opts;
     }
-  mips_check_isa_supports_ases ();
+  else
+    as_bad (_(".module is not permitted after generating code"));
+
   *input_line_pointer = ch;
   demand_empty_rest_of_line ();
 }
@@ -15268,6 +15305,8 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
   int reg;
   int in_shared;
 
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, or if this is NewABI code,
      .cpload is ignored.  */
   if (mips_pic != SVR4_PIC || HAVE_NEWABI)
@@ -15345,6 +15384,8 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
   expressionS ex_sym;
   int reg1;
 
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, .cpsetup is ignored.
      We also need NewABI support.  */
   if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
@@ -15448,6 +15489,8 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
 static void
 s_cplocal (int ignore ATTRIBUTE_UNUSED)
 {
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, or if this is not NewABI code,
      .cplocal is ignored.  */
   if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
@@ -15476,6 +15519,8 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS ex;
 
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, or if this is NewABI code,
      .cprestore is ignored.  */
   if (mips_pic != SVR4_PIC || HAVE_NEWABI)
@@ -15523,6 +15568,8 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS ex;
 
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, .cpreturn is ignored.
      We also need NewABI support.  */
   if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
@@ -15757,6 +15804,8 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED)
 {
   int reg;
 
+  file_mips_check_options ();
+
   /* This is ignored when not generating SVR4 PIC code.  */
   if (mips_pic != SVR4_PIC)
     {
@@ -17378,7 +17427,7 @@ mips_elf_final_processing (void)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
   if (file_ase_micromips)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
-  if (file_ase & ASE_MDMX)
+  if (file_mips_opts.ase & ASE_MDMX)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MDMX;
 
   /* Set the MIPS ELF ABI flags.  */
@@ -18356,4 +18405,7 @@ md_mips_end (void)
   mips_emit_delays ();
   if (cur_proc_ptr)
     as_warn (_("missing .end at end of assembly"));
+
+  /* Just in case no code was emitted, do the consistency check.  */
+  file_mips_check_options ();
 }
index 2165c20..d2795e7 100644 (file)
@@ -693,6 +693,20 @@ Traditional MIPS assemblers do not support this directive.
 @node MIPS assembly options
 @section Directives to control code generation
 
+@cindex MIPS directives to override command line options
+@kindex @code{.module}
+The @code{.module} directive allows command line options to be set directly
+from assembly.  The format of the directive matches the @code{.set}
+directive but only those options which are relevant to a whole module are
+supported.  The effect of a @code{.module} directive is the same as the
+corresponding command line option.  Where @code{.set} directives support
+returning to a default then the @code{.module} directives do not as they
+define the defaults.
+
+These module-level directives must appear first in assembly.
+
+Traditional MIPS assemblers do not support this directive.
+
 @cindex MIPS 32-bit microMIPS instruction generation override
 @kindex @code{.set insn32}
 @kindex @code{.set noinsn32}
index de3f3b0..82b7b17 100644 (file)
@@ -1,2 +1,2 @@
-Assembler messages:
-Warning: -mfp64 used with a 32-bit ABI
+.*Assembler messages:
+.* Warning: `fp=64' used with a 32-bit ABI
index 2d37303..a02481a 100644 (file)
@@ -1,2 +1,2 @@
-Assembler messages:
-Warning: -mfp32 used with a 64-bit ABI
+.*Assembler messages:
+.*:16: Warning: `fp=32' used with a 64-bit ABI
index e72f085..5fd9e34 100644 (file)
@@ -1,5 +1,5 @@
-Assembler messages:
-Warning: -mfp32 used with a 64-bit ABI
+.*Assembler messages:
+.* Warning: `fp=32' used with a 64-bit ABI
 .*:92: Warning: macro instruction expanded into multiple instructions in a branch delay slot
 .*:96: Warning: macro instruction expanded into multiple instructions in a branch delay slot
 .*:100: Warning: macro instruction expanded into multiple instructions in a branch delay slot
index 7ccbed5..c3135ca 100644 (file)
@@ -442,7 +442,7 @@ mips_arch_create mips64r5 64        mips64r3 { mips32r5 ror } \
 mips_arch_create mips16        32      {}      {} \
                        { -march=mips1 -mips16 } { -mmips:16 }
 mips_arch_create micromips 64  mips64r2 {} \
-                       { -march=mips64 -mmicromips } {}
+                       { -march=mips64r2 -mmicromips } {}
 mips_arch_create r3000         32      mips1   {} \
                        { -march=r3000 -mtune=r3000 } { -mmips:3000 }
 mips_arch_create r3900         32      mips1   { gpr_ilocks } \
@@ -787,7 +787,7 @@ if { [istarget mips*-*-vxworks*] } {
     run_dump_test "relax-swap1-mips2"
     run_dump_test "relax-swap2"
     run_dump_test_arches "relax-swap3" [mips_arch_list_all]
-    run_list_test_arches "relax-bc1any" "-mips3d -relax-branch" \
+    run_list_test_arches "relax-bc1any" "-mips3d -mabi=o64 -relax-branch" \
                                        [mips_arch_list_matching mips64 \
                                            !micromips]
     run_list_test_arches "relax-bposge" "-mdsp -relax-branch" \
@@ -1200,4 +1200,8 @@ if { [istarget mips*-*-vxworks*] } {
 
     run_dump_test "attr-gnu-abi-fp-1"
     run_dump_test "attr-gnu-abi-msa-1"
+
+    run_dump_test "module-override"
+    run_dump_test "module-defer-warn1"
+    run_list_test "module-defer-warn2" -32
 }
diff --git a/gas/testsuite/gas/mips/module-defer-warn1.d b/gas/testsuite/gas/mips/module-defer-warn1.d
new file mode 100644 (file)
index 0000000..d5ee70e
--- /dev/null
@@ -0,0 +1,7 @@
+# name: .module deferred warnings
+# source: module-defer-warn1.s
+# objdump: -p
+# as: -32 -march=mips2 -mgp64
+
+.*:.*file format.*elf.*mips.*
+private flags = 1.......: .*\[mips2\].*
diff --git a/gas/testsuite/gas/mips/module-defer-warn1.s b/gas/testsuite/gas/mips/module-defer-warn1.s
new file mode 100644 (file)
index 0000000..d9cbf39
--- /dev/null
@@ -0,0 +1,2 @@
+.module gp=32
+addiu $2, $2, 1
diff --git a/gas/testsuite/gas/mips/module-defer-warn2.l b/gas/testsuite/gas/mips/module-defer-warn2.l
new file mode 100644 (file)
index 0000000..f03ad48
--- /dev/null
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: `gp=64' used with a 32-bit processor
+.*:2: Error: `fp=64' used with a 32-bit fpu
diff --git a/gas/testsuite/gas/mips/module-defer-warn2.s b/gas/testsuite/gas/mips/module-defer-warn2.s
new file mode 100644 (file)
index 0000000..f7353e5
--- /dev/null
@@ -0,0 +1,2 @@
+.module gp=64
+addiu $2, $2, 1
diff --git a/gas/testsuite/gas/mips/module-override.d b/gas/testsuite/gas/mips/module-override.d
new file mode 100644 (file)
index 0000000..0305b02
--- /dev/null
@@ -0,0 +1,7 @@
+# name: .module command line override
+# source: module-override.s
+# objdump: -p
+# as: -32 -march=mips32r2
+
+.*:.*file format.*elf.*mips.*
+private flags = 1.......: .*\[mips2\].*
diff --git a/gas/testsuite/gas/mips/module-override.s b/gas/testsuite/gas/mips/module-override.s
new file mode 100644 (file)
index 0000000..05f4a17
--- /dev/null
@@ -0,0 +1 @@
+.module mips2