[ARC] Add checking for LP_COUNT reg usage, improve error reporting.
[deliverable/binutils-gdb.git] / gas / config / tc-arc.c
index c0bc3e45a4fffedb688911c8f5fd1803aa5ce541..f5cbc8b9f25193951d0afc918da9cc15063d48e7 100644 (file)
@@ -451,7 +451,23 @@ static const struct cpu_type
 };
 
 /* Information about the cpu/variant we're assembling for.  */
-static struct cpu_type selected_cpu;
+static struct cpu_type selected_cpu = { 0, 0, 0, 0, 0 };
+
+/* A table with options.  */
+static const struct feature_type
+{
+  unsigned feature;
+  unsigned cpus;
+  const char *name;
+}
+  feature_list[] =
+{
+  { ARC_CD, ARC_OPCODE_ARCV2, "code-density" },
+  { ARC_NPS400, ARC_OPCODE_ARC700, "nps400" },
+  { ARC_SPFP, ARC_OPCODE_ARCFPX, "single-precision FPX" },
+  { ARC_DPFP, ARC_OPCODE_ARCFPX, "double-precision FPX" },
+  { ARC_FPUDA, ARC_OPCODE_ARCv2EM, "double assist FP" }
+};
 
 /* Used by the arc_reloc_op table.  Order is important.  */
 #define O_gotoff  O_md1     /* @gotoff relocation.  */
@@ -775,6 +791,27 @@ md_number_to_chars_midend (char *buf, unsigned long long val, int n)
     }
 }
 
+/* Check if a feature is allowed for a specific CPU.  */
+
+static void
+arc_check_feature (void)
+{
+  unsigned i;
+
+  if (!selected_cpu.features
+      || !selected_cpu.name)
+    return;
+  for (i = 0; (i < ARRAY_SIZE (feature_list)); i++)
+    {
+      if ((selected_cpu.features & feature_list[i].feature)
+         && !(selected_cpu.flags & feature_list[i].cpus))
+       {
+         as_bad (_("invalid %s option for %s cpu"), feature_list[i].name,
+                 selected_cpu.name);
+       }
+    }
+}
+
 /* Select an appropriate entry from CPU_TYPES based on ARG and initialise
    the relevant static global variables.  Parameter SEL describes where
    this selection originated from.  */
@@ -790,6 +827,10 @@ arc_select_cpu (const char *arg, enum mach_selection_type sel)
   gas_assert (sel != MACH_SELECTION_FROM_DEFAULT
               || mach_selection_mode == MACH_SELECTION_NONE);
 
+  if ((mach_selection_mode == MACH_SELECTION_FROM_CPU_DIRECTIVE)
+      && (sel == MACH_SELECTION_FROM_CPU_DIRECTIVE))
+    as_bad (_("Multiple .cpu directives found"));
+
   /* Look for a matching entry in CPU_TYPES array.  */
   for (i = 0; cpu_types[i].name; ++i)
     {
@@ -807,22 +848,25 @@ arc_select_cpu (const char *arg, enum mach_selection_type sel)
                   && selected_cpu.mach != cpu_types[i].mach)
                 {
                   as_warn (_("Command-line value overrides \".cpu\" directive"));
-                  return;
                 }
+             return;
             }
 
-          /* Initialise static global data about selected machine type.  */
-          selected_cpu.flags = cpu_types[i].flags;
-          selected_cpu.name = cpu_types[i].name;
-          selected_cpu.features = cpu_types[i].features;
-          selected_cpu.mach = cpu_types[i].mach;
-          cpu_flags = cpu_types[i].eflags;
+         /* Initialise static global data about selected machine type.  */
+         selected_cpu.flags = cpu_types[i].flags;
+         selected_cpu.name = cpu_types[i].name;
+         selected_cpu.features |= cpu_types[i].features;
+         selected_cpu.mach = cpu_types[i].mach;
+         cpu_flags = cpu_types[i].eflags;
           break;
         }
     }
 
   if (!cpu_types[i].name)
     as_fatal (_("unknown architecture: %s\n"), arg);
+
+  /* Check if set features are compatible with the chosen CPU.  */
+  arc_check_feature ();
   gas_assert (cpu_flags != 0);
   selected_cpu.eflags = (arc_initial_eflag & ~EF_ARC_MACH_MSK) | cpu_flags;
   mach_selection_mode = sel;
@@ -1666,7 +1710,8 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
                   int *pntok,
                   struct arc_flags *first_pflag,
                   int nflgs,
-                  int *pcpumatch)
+                  int *pcpumatch,
+                  const char **errmsg)
 {
   const struct arc_opcode *opcode;
   struct arc_opcode_hash_entry_iterator iter;
@@ -1720,9 +1765,22 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
          switch (operand->flags & ARC_OPERAND_TYPECHECK_MASK)
            {
             case ARC_OPERAND_ADDRTYPE:
-              /* Check to be an address type.  */
-              if (tok[tokidx].X_op != O_addrtype)
-                goto match_failed;
+             {
+               *errmsg = NULL;
+
+               /* Check to be an address type.  */
+               if (tok[tokidx].X_op != O_addrtype)
+                 goto match_failed;
+
+               /* All address type operands need to have an insert
+                  method in order to check that we have the correct
+                  address type.  */
+               gas_assert (operand->insert != NULL);
+               (*operand->insert) (0, tok[tokidx].X_add_number,
+                                   errmsg);
+               if (*errmsg != NULL)
+                 goto match_failed;
+             }
               break;
 
            case ARC_OPERAND_IR:
@@ -1746,11 +1804,11 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
              /* Special handling?  */
              if (operand->insert)
                {
-                 const char *errmsg = NULL;
+                 *errmsg = NULL;
                  (*operand->insert)(0,
                                     regno (tok[tokidx].X_add_number),
-                                    &errmsg);
-                 if (errmsg)
+                                    errmsg);
+                 if (*errmsg)
                    {
                      if (operand->flags & ARC_OPERAND_IGNORE)
                        {
@@ -1866,11 +1924,11 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
                    {
                      if (operand->insert)
                        {
-                         const char *errmsg = NULL;
+                         *errmsg = NULL;
                          (*operand->insert)(0,
                                             tok[tokidx].X_add_number,
-                                            &errmsg);
-                         if (errmsg)
+                                            errmsg);
+                         if (*errmsg)
                            goto match_failed;
                        }
                      else if (!(operand->flags & ARC_OPERAND_IGNORE))
@@ -1891,11 +1949,11 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
                      regs |= get_register (tok[tokidx].X_op_symbol);
                      if (operand->insert)
                        {
-                         const char *errmsg = NULL;
+                         *errmsg = NULL;
                          (*operand->insert)(0,
                                             regs,
-                                            &errmsg);
-                         if (errmsg)
+                                            errmsg);
+                         if (*errmsg)
                            goto match_failed;
                        }
                      else
@@ -2269,6 +2327,7 @@ assemble_tokens (const char *opname,
   bfd_boolean found_something = FALSE;
   const struct arc_opcode_hash_entry *entry;
   int cpumatch = 1;
+  const char *errmsg = NULL;
 
   /* Search opcodes.  */
   entry = arc_find_opcode (opname);
@@ -2285,7 +2344,7 @@ assemble_tokens (const char *opname,
                frag_now->fr_file, frag_now->fr_line, opname);
       found_something = TRUE;
       opcode = find_opcode_match (entry, tok, &ntok, pflags,
-                                 nflgs, &cpumatch);
+                                 nflgs, &cpumatch, &errmsg);
       if (opcode != NULL)
        {
          struct arc_insn insn;
@@ -2299,7 +2358,10 @@ assemble_tokens (const char *opname,
   if (found_something)
     {
       if (cpumatch)
-       as_bad (_("inappropriate arguments for opcode '%s'"), opname);
+       if (errmsg)
+         as_bad (_("%s for instruction '%s'"), errmsg, opname);
+       else
+         as_bad (_("inappropriate arguments for opcode '%s'"), opname);
       else
        as_bad (_("opcode '%s' not supported for target %s"), opname,
                selected_cpu.name);
@@ -2602,7 +2664,7 @@ md_pcrel_from_section (fixS *fixP,
          /* The hardware calculates relative to the start of the
             insn, but this relocation is relative to location of the
             LIMM, compensate.  The base always needs to be
-            substracted by 4 as we do not support this type of PCrel
+            subtracted by 4 as we do not support this type of PCrel
             relocation for short instructions.  */
          base -= 4;
          /* Fall through.  */
@@ -3291,11 +3353,8 @@ md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
       break;
 
     case OPTION_CD:
-      /* This option has an effect only on ARC EM.  */
-      if (selected_cpu.flags & ARC_OPCODE_ARCv2EM)
-       selected_cpu.features |= ARC_CD;
-      else
-       as_warn (_("Code density option invalid for selected CPU"));
+      selected_cpu.features |= ARC_CD;
+      arc_check_feature ();
       break;
 
     case OPTION_RELAX:
@@ -3304,22 +3363,22 @@ md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
 
     case OPTION_NPS400:
       selected_cpu.features |= ARC_NPS400;
+      arc_check_feature ();
       break;
 
     case OPTION_SPFP:
       selected_cpu.features |= ARC_SPFP;
+      arc_check_feature ();
       break;
 
     case OPTION_DPFP:
       selected_cpu.features |= ARC_DPFP;
+      arc_check_feature ();
       break;
 
     case OPTION_FPUDA:
-      /* This option has an effect only on ARC EM.  */
-      if (selected_cpu.flags & ARC_OPCODE_ARCv2EM)
-       selected_cpu.features |= ARC_FPUDA;
-      else
-       as_warn (_("FPUDA invalid for selected CPU"));
+      selected_cpu.features |= ARC_FPUDA;
+      arc_check_feature ();
       break;
 
     /* Dummy options are accepted but have no effect.  */
This page took 0.027064 seconds and 4 git commands to generate.