This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][MIPS] Implement .module directive


Hi Richard,

To cut down the patch for FPXX I have extracted the .module
implementation. There is one functional change when compared to the
previous implementation from the FPXX patch... The code that infers
register size information is now moved into the
file_mips_check_options function as it needs to apply after any
.module arch=xxx or .module mipsxxx directive.

I have only added 3 tests for this just to check that error handling
is deferred until code is seen and that command line options are
overridden. A number of tests in the FPXX patch will also use the
.module directive. I think the testsuite, as exists, covers the
behaviour of the command line options so that is tested. Personally
I don't think it is necessary to cover all the .module options
explicitly, what do you think? 

This patch assumes that the MSA fix has been applied as it moves the
logic changed in that patch:
http://sourceware.org/ml/binutils/2014-05/msg00175.html

Regards,
Matthew

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): 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.
---
 gas/config/tc-mips.c                        |  602 +++++++++++++++------------
 gas/doc/c-mips.texi                         |   14 +
 gas/testsuite/gas/mips/mips-gp32-fp64.l     |    4 +-
 gas/testsuite/gas/mips/mips-gp64-fp32-pic.l |    4 +-
 gas/testsuite/gas/mips/mips-gp64-fp32.l     |    4 +-
 gas/testsuite/gas/mips/mips.exp             |    8 +-
 gas/testsuite/gas/mips/module-defer-warn1.d |    7 +
 gas/testsuite/gas/mips/module-defer-warn1.s |    2 +
 gas/testsuite/gas/mips/module-defer-warn2.l |    3 +
 gas/testsuite/gas/mips/module-defer-warn2.s |    2 +
 gas/testsuite/gas/mips/module-override.d    |    7 +
 gas/testsuite/gas/mips/module-override.s    |    1 +
 12 files changed, 374 insertions(+), 284 deletions(-)
 create mode 100644 gas/testsuite/gas/mips/module-defer-warn1.d
 create mode 100644 gas/testsuite/gas/mips/module-defer-warn1.s
 create mode 100644 gas/testsuite/gas/mips/module-defer-warn2.l
 create mode 100644 gas/testsuite/gas/mips/module-defer-warn2.s
 create mode 100644 gas/testsuite/gas/mips/module-override.d
 create mode 100644 gas/testsuite/gas/mips/module-override.s

diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 9ae6096..0f89bb9 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -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);
@@ -1692,6 +1692,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.  */
@@ -1979,14 +1980,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 +3633,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
+     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))
+	/* -mips3d and -mdmx imply 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;
+
+  /* MIPS3D and MDMX 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 +3773,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 +13620,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 +13762,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 +13856,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 +13872,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 +14029,7 @@ md_parse_option (int c, char *arg)
   return 1;
 }
 

-/* 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 +14056,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 +14094,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 +14113,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))
-	/* -mips3d and -mdmx imply 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 +15000,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 +15012,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 +15041,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 +15076,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 +15087,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 +15096,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 +15188,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 +15303,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 +15382,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 +15487,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 +15517,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 +15566,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 +15802,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 +17425,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 +18403,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 ();
 }
diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi
index 2165c20..d2795e7 100644
--- a/gas/doc/c-mips.texi
+++ b/gas/doc/c-mips.texi
@@ -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}
diff --git a/gas/testsuite/gas/mips/mips-gp32-fp64.l b/gas/testsuite/gas/mips/mips-gp32-fp64.l
index de3f3b0..82b7b17 100644
--- a/gas/testsuite/gas/mips/mips-gp32-fp64.l
+++ b/gas/testsuite/gas/mips/mips-gp32-fp64.l
@@ -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
diff --git a/gas/testsuite/gas/mips/mips-gp64-fp32-pic.l b/gas/testsuite/gas/mips/mips-gp64-fp32-pic.l
index 2d37303..a02481a 100644
--- a/gas/testsuite/gas/mips/mips-gp64-fp32-pic.l
+++ b/gas/testsuite/gas/mips/mips-gp64-fp32-pic.l
@@ -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
diff --git a/gas/testsuite/gas/mips/mips-gp64-fp32.l b/gas/testsuite/gas/mips/mips-gp64-fp32.l
index e72f085..5fd9e34 100644
--- a/gas/testsuite/gas/mips/mips-gp64-fp32.l
+++ b/gas/testsuite/gas/mips/mips-gp64-fp32.l
@@ -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
diff --git a/gas/testsuite/gas/mips/mips.exp b/gas/testsuite/gas/mips/mips.exp
index 7ccbed5..aaa9c4c 100644
--- a/gas/testsuite/gas/mips/mips.exp
+++ b/gas/testsuite/gas/mips/mips.exp
@@ -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 -64 -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
index 0000000..d5ee70e
--- /dev/null
+++ b/gas/testsuite/gas/mips/module-defer-warn1.d
@@ -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
index 0000000..d9cbf39
--- /dev/null
+++ b/gas/testsuite/gas/mips/module-defer-warn1.s
@@ -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
index 0000000..f03ad48
--- /dev/null
+++ b/gas/testsuite/gas/mips/module-defer-warn2.l
@@ -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
index 0000000..f7353e5
--- /dev/null
+++ b/gas/testsuite/gas/mips/module-defer-warn2.s
@@ -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
index 0000000..0305b02
--- /dev/null
+++ b/gas/testsuite/gas/mips/module-override.d
@@ -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
index 0000000..05f4a17
--- /dev/null
+++ b/gas/testsuite/gas/mips/module-override.s
@@ -0,0 +1 @@
+.module mips2
-- 
1.7.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]