summaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@nildram.co.uk>2013-06-20 19:25:20 +0000
committerRichard Sandiford <rsandifo@nildram.co.uk>2013-06-20 19:25:20 +0000
commit6b16d7a87bdce016bcf9b58f55c214e52fe304aa (patch)
tree2edf9b426cd82570453101eeb9cfcf19d7125427 /gas/config
parentd28d40f8746326216e8999660d820f56b560d6b1 (diff)
downloadbinutils-redhat-6b16d7a87bdce016bcf9b58f55c214e52fe304aa.tar.gz
gas/
* config/tc-mips.c (ISA_SUPPORTS_SMARTMIPS, ISA_SUPPORTS_DSP_ASE) (ISA_SUPPORTS_DSP64_ASE, ISA_SUPPORTS_DSPR2_ASE, ISA_SUPPORTS_EVA_ASE) (ISA_SUPPORTS_MT_ASE, ISA_SUPPORTS_MCU_ASE, ISA_SUPPORTS_VIRT_ASE) (ISA_SUPPORTS_VIRT64_ASE): Delete. (mips_ase): New structure. (mips_ases): New table. (FP64_ASES): New macro. (mips_ase_groups): New array. (mips_isa_rev, mips_ase_mask, mips_check_isa_supports_ase) (mips_check_isa_supports_ases, mips_set_ase, mips_lookup_ase): New functions. (is_opcode_valid): Use mips_ases to get the 64-bit ASE flags. (md_parse_option): Use mips_ases and mips_set_ase instead of separate case statements for each ASE option. (mips_after_parse_args): Use FP64_ASES. Use mips_check_isa_supports_ases to check the ASEs against other options. (s_mipsset): Use mips_ases and mips_set_ase instead of separate if statements for each ASE option. Use mips_check_isa_supports_ases, even when a non-ASE option is specified. gas/testsuite/ * gas/mips/ase-errors-1.s, gas/mips/ase-errors-1.l, gas/mips/ase-errors-2.s, gas/mips/ase-errors-2.l, gas/mips/ase-errors-3.s, gas/mips/ase-errors-3.l, gas/mips/ase-errors-4.s, gas/mips/ase-errors-4.l: New tests. * gas/mips/mips.exp: Run them.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-mips.c441
1 files changed, 217 insertions, 224 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 4a4f827180..df1a5a015e 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -330,38 +330,6 @@ static int file_ase_micromips;
|| ((EXPR)->X_op == O_symbol && (EXPR)->X_add_number == 0))
#endif
-#define ISA_SUPPORTS_SMARTMIPS (mips_opts.isa == ISA_MIPS32 \
- || mips_opts.isa == ISA_MIPS32R2)
-
-#define ISA_SUPPORTS_DSP_ASE (mips_opts.isa == ISA_MIPS32R2 \
- || mips_opts.isa == ISA_MIPS64R2 \
- || mips_opts.micromips)
-
-#define ISA_SUPPORTS_DSP64_ASE (mips_opts.isa == ISA_MIPS64R2)
-
-#define ISA_SUPPORTS_DSPR2_ASE (mips_opts.isa == ISA_MIPS32R2 \
- || mips_opts.isa == ISA_MIPS64R2 \
- || mips_opts.micromips)
-
-#define ISA_SUPPORTS_EVA_ASE (mips_opts.isa == ISA_MIPS32R2 \
- || mips_opts.isa == ISA_MIPS64R2 \
- || mips_opts.micromips)
-
-#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2 \
- || mips_opts.isa == ISA_MIPS64R2)
-
-#define ISA_SUPPORTS_MCU_ASE (mips_opts.isa == ISA_MIPS32R2 \
- || mips_opts.isa == ISA_MIPS64R2 \
- || mips_opts.micromips)
-
-#define ISA_SUPPORTS_VIRT_ASE (mips_opts.isa == ISA_MIPS32R2 \
- || mips_opts.isa == ISA_MIPS64R2 \
- || mips_opts.micromips)
-
-#define ISA_SUPPORTS_VIRT64_ASE (mips_opts.isa == ISA_MIPS64R2 \
- || (mips_opts.micromips \
- && ISA_HAS_64BIT_REGS (mips_opts.isa)))
-
/* The argument of the -march= flag. The architecture we are assembling. */
static int file_mips_arch = CPU_UNKNOWN;
static const char *mips_arch_string;
@@ -1603,6 +1571,84 @@ struct option md_longopts[] =
};
size_t md_longopts_size = sizeof (md_longopts);
+/* Information about either an Application Specific Extension or an
+ optional architecture feature that, for simplicity, we treat in the
+ same way as an ASE. */
+struct mips_ase
+{
+ /* The name of the ASE, used in both the command-line and .set options. */
+ const char *name;
+
+ /* The associated ASE_* flags. If the ASE is available on both 32-bit
+ and 64-bit architectures, the flags here refer to the subset that
+ is available on both. */
+ unsigned int flags;
+
+ /* The ASE_* flag used for instructions that are available on 64-bit
+ architectures but that are not included in FLAGS. */
+ unsigned int flags64;
+
+ /* The command-line options that turn the ASE on and off. */
+ int option_on;
+ int option_off;
+
+ /* The minimum required architecture revisions for MIPS32, MIPS64,
+ microMIPS32 and microMIPS64, or -1 if the extension isn't supported. */
+ int mips32_rev;
+ int mips64_rev;
+ int micromips32_rev;
+ int micromips64_rev;
+};
+
+/* A table of all supported ASEs. */
+static const struct mips_ase mips_ases[] = {
+ { "dsp", ASE_DSP, ASE_DSP64,
+ OPTION_DSP, OPTION_NO_DSP,
+ 2, 2, 2, 2 },
+
+ { "dspr2", ASE_DSP | ASE_DSPR2, 0,
+ OPTION_DSPR2, OPTION_NO_DSPR2,
+ 2, 2, 2, 2 },
+
+ { "eva", ASE_EVA, 0,
+ OPTION_EVA, OPTION_NO_EVA,
+ 2, 2, 2, 2 },
+
+ { "mcu", ASE_MCU, 0,
+ OPTION_MCU, OPTION_NO_MCU,
+ 2, 2, 2, 2 },
+
+ /* Deprecated in MIPS64r5, but we don't implement that yet. */
+ { "mdmx", ASE_MDMX, 0,
+ OPTION_MDMX, OPTION_NO_MDMX,
+ -1, 1, -1, -1 },
+
+ /* Requires 64-bit FPRs, so the minimum MIPS32 revision is 2. */
+ { "mips3d", ASE_MIPS3D, 0,
+ OPTION_MIPS3D, OPTION_NO_MIPS3D,
+ 2, 1, -1, -1 },
+
+ { "mt", ASE_MT, 0,
+ OPTION_MT, OPTION_NO_MT,
+ 2, 2, -1, -1 },
+
+ { "smartmips", ASE_SMARTMIPS, 0,
+ OPTION_SMARTMIPS, OPTION_NO_SMARTMIPS,
+ 1, -1, -1, -1 },
+
+ { "virt", ASE_VIRT, ASE_VIRT64,
+ OPTION_VIRT, OPTION_NO_VIRT,
+ 2, 2, 2, 2 }
+};
+
+/* The set of ASEs that require -mfp64. */
+#define FP64_ASES (ASE_MIPS3D | ASE_MDMX)
+
+/* Groups of ASE_* flags that represent different revisions of an ASE. */
+static const unsigned int mips_ase_groups[] = {
+ ASE_DSP | ASE_DSPR2
+};
+
/* Pseudo-op table.
The following pseudo-ops from the Kane and Heinrich MIPS book
@@ -1842,6 +1888,119 @@ mips_target_format (void)
}
}
+/* Return the ISA revision that is currently in use, or 0 if we are
+ generating code for MIPS V or below. */
+
+static int
+mips_isa_rev (void)
+{
+ if (mips_opts.isa == ISA_MIPS32R2 || mips_opts.isa == ISA_MIPS64R2)
+ return 2;
+
+ /* microMIPS implies revision 2 or above. */
+ if (mips_opts.micromips)
+ return 2;
+
+ if (mips_opts.isa == ISA_MIPS32 || mips_opts.isa == ISA_MIPS64)
+ return 1;
+
+ return 0;
+}
+
+/* Return the mask of all ASEs that are revisions of those in FLAGS. */
+
+static unsigned int
+mips_ase_mask (unsigned int flags)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE (mips_ase_groups); i++)
+ if (flags & mips_ase_groups[i])
+ flags |= mips_ase_groups[i];
+ return flags;
+}
+
+/* Check whether the current ISA supports ASE. Issue a warning if
+ appropriate. */
+
+static void
+mips_check_isa_supports_ase (const struct mips_ase *ase)
+{
+ const char *base;
+ int min_rev, size;
+ static unsigned int warned_isa;
+ static unsigned int warned_fp32;
+
+ if (ISA_HAS_64BIT_REGS (mips_opts.isa))
+ min_rev = mips_opts.micromips ? ase->micromips64_rev : ase->mips64_rev;
+ else
+ min_rev = mips_opts.micromips ? ase->micromips32_rev : ase->mips32_rev;
+ if ((min_rev < 0 || mips_isa_rev () < min_rev)
+ && (warned_isa & ase->flags) != ase->flags)
+ {
+ warned_isa |= ase->flags;
+ base = mips_opts.micromips ? "microMIPS" : "MIPS";
+ size = ISA_HAS_64BIT_REGS (mips_opts.isa) ? 64 : 32;
+ if (min_rev < 0)
+ as_warn (_("The %d-bit %s architecture does not support the"
+ " `%s' extension"), size, base, ase->name);
+ else
+ as_warn (_("The `%s' extension requires %s%d revision %d or greater"),
+ ase->name, base, size, min_rev);
+ }
+ if ((ase->flags & FP64_ASES)
+ && mips_opts.fp32
+ && (warned_fp32 & ase->flags) != ase->flags)
+ {
+ warned_fp32 |= ase->flags;
+ as_warn (_("The `%s' extension requires 64-bit FPRs"), ase->name);
+ }
+}
+
+/* Check all enabled ASEs to see whether they are supported by the
+ chosen architecture. */
+
+static void
+mips_check_isa_supports_ases (void)
+{
+ unsigned int i, mask;
+
+ for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+ {
+ mask = mips_ase_mask (mips_ases[i].flags);
+ if ((mips_opts.ase & mask) == mips_ases[i].flags)
+ mips_check_isa_supports_ase (&mips_ases[i]);
+ }
+}
+
+/* Set the state of ASE to ENABLED_P. Return the mask of ASE_* flags
+ that were affected. */
+
+static unsigned int
+mips_set_ase (const struct mips_ase *ase, bfd_boolean enabled_p)
+{
+ unsigned int mask;
+
+ mask = mips_ase_mask (ase->flags);
+ mips_opts.ase &= ~mask;
+ if (enabled_p)
+ mips_opts.ase |= ase->flags;
+ return mask;
+}
+
+/* Return the ASE called NAME, or null if none. */
+
+static const struct mips_ase *
+mips_lookup_ase (const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+ if (strcmp (name, mips_ases[i].name) == 0)
+ return &mips_ases[i];
+ return NULL;
+}
+
/* Return the length of a microMIPS instruction in bytes. If bits of
the mask beyond the low 16 are 0, then it is a 16-bit instruction.
Otherwise assume a 32-bit instruction; 48-bit instructions (0x1f
@@ -2446,11 +2605,12 @@ is_opcode_valid (const struct mips_opcode *mo)
int isa = mips_opts.isa;
int ase = mips_opts.ase;
int fp_s, fp_d;
+ unsigned int i;
- if ((ase & ASE_DSP) && ISA_SUPPORTS_DSP64_ASE)
- ase |= ASE_DSP64;
- if ((ase & ASE_VIRT) && ISA_SUPPORTS_VIRT64_ASE)
- ase |= ASE_VIRT64;
+ if (ISA_HAS_64BIT_REGS (mips_opts.isa))
+ for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+ if ((ase & mips_ases[i].flags) == mips_ases[i].flags)
+ ase |= mips_ases[i].flags64;
if (!opcode_is_member (mo, isa, ase, mips_opts.arch))
return FALSE;
@@ -14872,6 +15032,16 @@ mips_set_option_string (const char **string_ptr, const char *new_value)
int
md_parse_option (int c, char *arg)
{
+ unsigned int i;
+
+ 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],
+ c == mips_ases[i].option_on);
+ return 1;
+ }
+
switch (c)
{
case OPTION_CONSTRUCT_FLOATS:
@@ -14992,63 +15162,6 @@ md_parse_option (int c, char *arg)
case OPTION_NO_M3900:
break;
- case OPTION_MDMX:
- mips_opts.ase |= ASE_MDMX;
- file_ase_explicit |= ASE_MDMX;
- break;
-
- case OPTION_NO_MDMX:
- mips_opts.ase &= ~ASE_MDMX;
- file_ase_explicit |= ASE_MDMX;
- break;
-
- case OPTION_DSP:
- mips_opts.ase |= ASE_DSP;
- mips_opts.ase &= ~ASE_DSPR2;
- file_ase_explicit |= ASE_DSP | ASE_DSPR2;
- break;
-
- case OPTION_DSPR2:
- mips_opts.ase |= ASE_DSP | ASE_DSPR2;
- file_ase_explicit |= ASE_DSP | ASE_DSPR2;
- break;
-
- case OPTION_NO_DSP:
- case OPTION_NO_DSPR2:
- mips_opts.ase &= ~(ASE_DSP | ASE_DSPR2);
- file_ase_explicit |= ASE_DSP | ASE_DSPR2;
- break;
-
- case OPTION_EVA:
- mips_opts.ase |= ASE_EVA;
- file_ase_explicit |= ASE_EVA;
- break;
-
- case OPTION_NO_EVA:
- mips_opts.ase &= ~ASE_EVA;
- file_ase_explicit |= ASE_EVA;
- break;
-
- case OPTION_MT:
- mips_opts.ase |= ASE_MT;
- file_ase_explicit |= ASE_MT;
- break;
-
- case OPTION_NO_MT:
- mips_opts.ase &= ~ASE_MT;
- file_ase_explicit |= ASE_MT;
- break;
-
- case OPTION_MCU:
- mips_opts.ase |= ASE_MCU;
- file_ase_explicit |= ASE_MCU;
- break;
-
- case OPTION_NO_MCU:
- mips_opts.ase &= ~ASE_MCU;
- file_ase_explicit |= ASE_MCU;
- break;
-
case OPTION_MICROMIPS:
if (mips_opts.mips16 == 1)
{
@@ -15064,16 +15177,6 @@ md_parse_option (int c, char *arg)
mips_no_prev_insn ();
break;
- case OPTION_VIRT:
- mips_opts.ase |= ASE_VIRT;
- file_ase_explicit |= ASE_VIRT;
- break;
-
- case OPTION_NO_VIRT:
- mips_opts.ase &= ~ASE_VIRT;
- file_ase_explicit |= ASE_VIRT;
- break;
-
case OPTION_MIPS16:
if (mips_opts.micromips == 1)
{
@@ -15089,26 +15192,6 @@ md_parse_option (int c, char *arg)
mips_no_prev_insn ();
break;
- case OPTION_MIPS3D:
- mips_opts.ase |= ASE_MIPS3D;
- file_ase_explicit |= ASE_MIPS3D;
- break;
-
- case OPTION_NO_MIPS3D:
- mips_opts.ase &= ~ASE_MIPS3D;
- file_ase_explicit |= ASE_MIPS3D;
- break;
-
- case OPTION_SMARTMIPS:
- mips_opts.ase |= ASE_SMARTMIPS;
- file_ase_explicit |= ASE_SMARTMIPS;
- break;
-
- case OPTION_NO_SMARTMIPS:
- mips_opts.ase &= ~ASE_SMARTMIPS;
- file_ase_explicit |= ASE_SMARTMIPS;
- break;
-
case OPTION_FIX_24K:
mips_fix_24k = 1;
break;
@@ -15484,7 +15567,7 @@ mips_after_parse_args (void)
if (file_mips_gp32 == 0)
/* 64-bit integer registers implies 64-bit float registers. */
file_mips_fp32 = 0;
- else if ((mips_opts.ase & (ASE_MIPS3D | ASE_MDMX))
+ 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_fp32 = 0;
@@ -15536,40 +15619,6 @@ mips_after_parse_args (void)
use the default setting for the CPU. */
mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
- if ((mips_opts.ase & ASE_MIPS3D) && file_mips_fp32 == 1)
- as_bad (_("-mfp32 used with -mips3d"));
-
- if ((mips_opts.ase & ASE_MDMX) && file_mips_fp32 == 1)
- as_bad (_("-mfp32 used with -mdmx"));
-
- if ((mips_opts.ase & ASE_SMARTMIPS) && !ISA_SUPPORTS_SMARTMIPS)
- as_warn (_("%s ISA does not support SmartMIPS"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
-
- if ((mips_opts.ase & ASE_DSP) && !ISA_SUPPORTS_DSP_ASE)
- as_warn (_("%s ISA does not support DSP ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
-
- if ((mips_opts.ase & ASE_DSPR2) && !ISA_SUPPORTS_DSPR2_ASE)
- as_warn (_("%s ISA does not support DSP R2 ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
-
- if ((mips_opts.ase & ASE_EVA) && !ISA_SUPPORTS_EVA_ASE)
- as_warn (_("%s ISA does not support EVA ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
-
- if ((mips_opts.ase & ASE_MT) && !ISA_SUPPORTS_MT_ASE)
- as_warn (_("%s ISA does not support MT ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
-
- if ((mips_opts.ase & ASE_MCU) && !ISA_SUPPORTS_MCU_ASE)
- as_warn (_("%s ISA does not support MCU ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
-
- if ((mips_opts.ase & ASE_VIRT) && !ISA_SUPPORTS_VIRT_ASE)
- as_warn (_("%s ISA does not support Virtualization ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
-
file_mips_isa = mips_opts.isa;
file_ase = mips_opts.ase;
mips_opts.gp32 = file_mips_gp32;
@@ -15577,6 +15626,8 @@ mips_after_parse_args (void)
mips_opts.soft_float = file_mips_soft_float;
mips_opts.single_float = file_mips_single_float;
+ mips_check_isa_supports_ases ();
+
if (mips_flag_mdebug < 0)
{
#ifdef OBJ_MAYBE_ECOFF
@@ -16481,6 +16532,7 @@ static void
s_mipsset (int x ATTRIBUTE_UNUSED)
{
char *name = input_line_pointer, ch;
+ const struct mips_ase *ase;
while (!is_end_of_line[(unsigned char) *input_line_pointer])
++input_line_pointer;
@@ -16586,72 +16638,12 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
}
else if (strcmp (name, "nomicromips") == 0)
mips_opts.micromips = 0;
- else if (strcmp (name, "smartmips") == 0)
- {
- if (!ISA_SUPPORTS_SMARTMIPS)
- as_warn (_("%s ISA does not support SmartMIPS ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.ase |= ASE_SMARTMIPS;
- }
- else if (strcmp (name, "nosmartmips") == 0)
- mips_opts.ase &= ~ASE_SMARTMIPS;
- else if (strcmp (name, "mips3d") == 0)
- mips_opts.ase |= ASE_MIPS3D;
- else if (strcmp (name, "nomips3d") == 0)
- mips_opts.ase &= ~ASE_MIPS3D;
- else if (strcmp (name, "mdmx") == 0)
- mips_opts.ase |= ASE_MDMX;
- else if (strcmp (name, "nomdmx") == 0)
- mips_opts.ase &= ~ASE_MDMX;
- else if (strcmp (name, "dsp") == 0)
- {
- if (!ISA_SUPPORTS_DSP_ASE)
- as_warn (_("%s ISA does not support DSP ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.ase |= ASE_DSP;
- mips_opts.ase &= ~ASE_DSPR2;
- }
- else if (strcmp (name, "dspr2") == 0)
- {
- if (!ISA_SUPPORTS_DSPR2_ASE)
- as_warn (_("%s ISA does not support DSP R2 ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.ase |= ASE_DSP | ASE_DSPR2;
- }
- else if (strcmp (name, "nodsp") == 0
- || strcmp (name, "nodspr2") == 0)
- mips_opts.ase &= ~(ASE_DSP | ASE_DSPR2);
- else if (strcmp (name, "eva") == 0)
- {
- if (!ISA_SUPPORTS_EVA_ASE)
- as_warn (_("%s ISA does not support EVA ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.ase |= ASE_EVA;
- }
- else if (strcmp (name, "noeva") == 0)
- mips_opts.ase &= ~ASE_EVA;
- else if (strcmp (name, "mt") == 0)
- {
- if (!ISA_SUPPORTS_MT_ASE)
- as_warn (_("%s ISA does not support MT ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.ase |= ASE_MT;
- }
- else if (strcmp (name, "nomt") == 0)
- mips_opts.ase &= ~ASE_MT;
- else if (strcmp (name, "mcu") == 0)
- mips_opts.ase |= ASE_MCU;
- else if (strcmp (name, "nomcu") == 0)
- mips_opts.ase &= ~ASE_MCU;
- else if (strcmp (name, "virt") == 0)
- {
- if (!ISA_SUPPORTS_VIRT_ASE)
- as_warn (_("%s ISA does not support Virtualization ASE"),
- mips_cpu_info_from_isa (mips_opts.isa)->name);
- mips_opts.ase |= ASE_VIRT;
- }
- else if (strcmp (name, "novirt") == 0)
- mips_opts.ase &= ~ASE_VIRT;
+ else if (name[0] == 'n'
+ && name[1] == 'o'
+ && (ase = mips_lookup_ase (name + 2)))
+ mips_set_ase (ase, FALSE);
+ else if ((ase = mips_lookup_ase (name)))
+ mips_set_ase (ase, TRUE);
else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
{
int reset = 0;
@@ -16779,6 +16771,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
{
as_warn (_("Tried to set unrecognized symbol: %s\n"), name);
}
+ mips_check_isa_supports_ases ();
*input_line_pointer = ch;
demand_empty_rest_of_line ();
}