include/opcode/
authorRichard Sandiford <rdsandiford@googlemail.com>
Mon, 19 Aug 2013 18:57:00 +0000 (18:57 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Mon, 19 Aug 2013 18:57:00 +0000 (18:57 +0000)
* mips.h (OP_OPTIONAL_REG): New mips_operand_type.
(mips_optional_operand_p): New function.

opcodes/
* mips-formats.h (OPTIONAL_REG, OPTIONAL_MAPPED_REG): New macros.
* micromips-opc.c (decode_micromips_operand): Use OPTIONAL_REG
and OPTIONAL_MAPPED_REG.
* mips-opc.c (decode_mips_operand): Likewise.
* mips16-opc.c (decode_mips16_operand): Likewise.
* mips-dis.c (print_insn_arg): Handle OP_OPTIONAL_REG.

gas/
* config/tc-mips.c (operand_reg_mask, match_operand): Handle
OP_OPTIONAL_REG.
(mips_ip, mips16_ip): Use mips_optional_operand_p to check
for optional operands.

gas/ChangeLog
gas/config/tc-mips.c
include/opcode/ChangeLog
include/opcode/mips.h
opcodes/ChangeLog
opcodes/micromips-opc.c
opcodes/mips-dis.c
opcodes/mips-formats.h
opcodes/mips-opc.c
opcodes/mips16-opc.c

index f0ca044..92ad6f6 100644 (file)
@@ -1,3 +1,10 @@
+2013-08-19  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * config/tc-mips.c (operand_reg_mask, match_operand): Handle
+       OP_OPTIONAL_REG.
+       (mips_ip, mips16_ip): Use mips_optional_operand_p to check
+       for optional operands.
+
 2013-08-16  Alan Modra  <amodra@gmail.com>
 
        * config/tc-ppc.c (ppc_elf_cons): Allow @l and other reloc
index f35dbe0..814b218 100644 (file)
@@ -3868,6 +3868,7 @@ operand_reg_mask (const struct mips_cl_insn *insn,
       abort ();
 
     case OP_REG:
+    case OP_OPTIONAL_REG:
       {
        const struct mips_reg_operand *reg_op;
 
@@ -5283,6 +5284,7 @@ match_operand (struct mips_arg_info *arg,
       return match_msb_operand (arg, operand);
 
     case OP_REG:
+    case OP_OPTIONAL_REG:
       return match_reg_operand (arg, operand);
 
     case OP_REG_PAIR:
@@ -12393,7 +12395,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
   const struct mips_operand *operand;
   struct mips_arg_info arg;
   struct mips_operand_token *tokens;
-  bfd_boolean optional_reg;
   unsigned int opcode_extra;
 
   insn_error = NULL;
@@ -12522,17 +12523,17 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              /* Handle unary instructions in which only one operand is given.
                 The source is then the same as the destination.  */
              if (arg.opnum == 1 && *args == ',')
-               switch (args[1])
-                 {
-                 case 'r':
-                 case 'v':
-                 case 'w':
-                 case 'W':
-                 case 'V':
-                   arg.token = tokens;
-                   arg.argnum = 1;
-                   continue;
-                 }
+               {
+                 operand = (mips_opts.micromips
+                            ? decode_micromips_operand (args + 1)
+                            : decode_mips_operand (args + 1));
+                 if (operand && mips_optional_operand_p (operand))
+                   {
+                     arg.token = tokens;
+                     arg.argnum = 1;
+                     continue;
+                   }
+               }
 
              /* Treat elided base registers as $0.  */
              if (strcmp (args, "(b)") == 0)
@@ -12593,7 +12594,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
             other operands.  */
          arg.opnum += 1;
          arg.lax_max = FALSE;
-         optional_reg = FALSE;
          switch (*args)
            {
            case '+':
@@ -12668,17 +12668,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                arg.soft_match = FALSE;
              break;
 
-           case 'r':
-           case 'v':
-           case 'w':
-           case 'W':
-           case 'V':
-             /* We have already matched a comma by this point, so the register
-                is only optional if there is another operand to come.  */
-             gas_assert (arg.opnum == 2);
-             optional_reg = (args[1] == ',');
-             break;
-
            case 'I':
              if (match_const_int (&arg, &imm_expr.X_add_number, 0))
                imm_expr.X_op = O_constant;
@@ -12766,16 +12755,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              c = args[1];
              switch (c)
                {
-               case 't':
-               case 'c':
-               case 'e':
-                 /* We have already matched a comma by this point,
-                    so the register is only optional if there is another
-                    operand to come.  */
-                 gas_assert (arg.opnum == 2);
-                 optional_reg = (args[2] == ',');
-                 break;
-
                case 'D':
                case 'E':
                  if (!forced_insn_length)
@@ -12795,7 +12774,12 @@ mips_ip (char *str, struct mips_cl_insn *ip)
          if (!operand)
            abort ();
 
-         if (optional_reg
+         /* Skip prefixes.  */
+         if (*args == '+' || *args == 'm')
+           args++;
+
+         if (mips_optional_operand_p (operand)
+             && args[1] == ','
              && (arg.token[0].type != OT_REG
                  || arg.token[1].type == OT_END))
            {
@@ -12808,10 +12792,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
          if (!match_operand (&arg, operand))
            break;
 
-         /* Skip prefixes.  */
-         if (*args == '+' || *args == 'm')
-           args++;
-
          continue;
        }
       /* Args don't match.  */
@@ -12848,7 +12828,6 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
   const struct mips_operand *ext_operand;
   struct mips_arg_info arg;
   struct mips_operand_token *tokens;
-  bfd_boolean optional_reg;
 
   insn_error = NULL;
 
@@ -12961,14 +12940,15 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              /* Handle unary instructions in which only one operand is given.
                 The source is then the same as the destination.  */
              if (arg.opnum == 1 && *args == ',')
-               switch (args[1])
-                 {
-                 case 'v':
-                 case 'w':
-                   arg.token = tokens;
-                   arg.argnum = 1;
-                   continue;
-                 }
+               {
+                 operand = decode_mips16_operand (args[1], FALSE);
+                 if (operand && mips_optional_operand_p (operand))
+                   {
+                     arg.token = tokens;
+                     arg.argnum = 1;
+                     continue;
+                   }
+               }
 
              /* Fail the match if there were too few operands.  */
              if (*args)
@@ -13020,15 +13000,9 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
            }
 
          arg.opnum += 1;
-         optional_reg = FALSE;
          c = *args;
          switch (c)
            {
-           case 'v':
-           case 'w':
-             optional_reg = (args[1] == ',');
-             break;
-
            case 'p':
            case 'q':
            case 'A':
@@ -13094,7 +13068,8 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                }
            }
 
-         if (optional_reg
+         if (mips_optional_operand_p (operand)
+             && args[1] == ','
              && (arg.token[0].type != OT_REG
                  || arg.token[1].type == OT_END))
            {
index cdf578a..19fd1b3 100644 (file)
@@ -1,3 +1,8 @@
+2013-08-19  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * mips.h (OP_OPTIONAL_REG): New mips_operand_type.
+       (mips_optional_operand_p): New function.
+
 2013-08-04  Jürgen Urban  <JuergenUrban@gmx.de>
            Richard Sandiford  <rdsandiford@googlemail.com>
 
index ae6983b..6860fa7 100644 (file)
@@ -346,6 +346,10 @@ enum mips_operand_type {
   /* Described by mips_reg_operand.  */
   OP_REG,
 
+  /* Like OP_REG, but can be omitted if the register is the same as the
+     previous operand.  */
+  OP_OPTIONAL_REG,
+
   /* Described by mips_reg_pair_operand.  */
   OP_REG_PAIR,
 
@@ -574,6 +578,15 @@ struct mips_pcrel_operand
   unsigned int flip_isa_bit : 1;
 };
 
+/* Return true if the assembly syntax allows OPERAND to be omitted.  */
+
+static inline bfd_boolean
+mips_optional_operand_p (const struct mips_operand *operand)
+{
+  return (operand->type == OP_OPTIONAL_REG
+         || operand->type == OP_REPEAT_PREV_REG);
+}
+
 /* Return a version of INSN in which the field specified by OPERAND
    has value UVAL.  */
 
index 58cd107..b4840ee 100644 (file)
@@ -1,3 +1,12 @@
+2013-08-19  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * mips-formats.h (OPTIONAL_REG, OPTIONAL_MAPPED_REG): New macros.
+       * micromips-opc.c (decode_micromips_operand): Use OPTIONAL_REG
+       and OPTIONAL_MAPPED_REG.
+       * mips-opc.c (decode_mips_operand): Likewise.
+       * mips16-opc.c (decode_mips16_operand): Likewise.
+       * mips-dis.c (print_insn_arg): Handle OP_OPTIONAL_REG.
+
 2013-08-19  H.J. Lu  <hongjiu.lu@intel.com>
 
        * i386-dis.c (PREFIX_EVEX_0F3A3E): Removed.
index 5243d4c..33dd57e 100644 (file)
@@ -53,9 +53,9 @@ decode_micromips_operand (const char *p)
        {
        case 'a': MAPPED_REG (0, 0, GP, reg_28_map);
        case 'b': MAPPED_REG (3, 23, GP, reg_m16_map);
-       case 'c': MAPPED_REG (3, 4, GP, reg_m16_map);
+       case 'c': OPTIONAL_MAPPED_REG (3, 4, GP, reg_m16_map);
        case 'd': MAPPED_REG (3, 7, GP, reg_m16_map);
-       case 'e': MAPPED_REG (3, 1, GP, reg_m16_map);
+       case 'e': OPTIONAL_MAPPED_REG (3, 1, GP, reg_m16_map);
        case 'f': MAPPED_REG (3, 3, GP, reg_m16_map);
        case 'g': MAPPED_REG (3, 0, GP, reg_m16_map);
        case 'h': REG_PAIR (3, 7, GP, reg_h_map);
@@ -144,7 +144,7 @@ decode_micromips_operand (const char *p)
     case 'R': REG (5, 6, FP);
     case 'S': REG (5, 16, FP);
     case 'T': REG (5, 21, FP);
-    case 'V': REG (5, 16, FP);
+    case 'V': OPTIONAL_REG (5, 16, FP);
 
     case 'a': JUMP (26, 0, 1);
     case 'b': REG (5, 16, GP);
@@ -158,12 +158,12 @@ decode_micromips_operand (const char *p)
     case 'o': SINT (16, 0);
     case 'p': BRANCH (16, 0, 1);
     case 'q': HINT (10, 6);
-    case 'r': REG (5, 16, GP);
+    case 'r': OPTIONAL_REG (5, 16, GP);
     case 's': REG (5, 16, GP);
     case 't': REG (5, 21, GP);
     case 'u': HINT (16, 0);
-    case 'v': REG (5, 16, GP);
-    case 'w': REG (5, 21, GP);
+    case 'v': OPTIONAL_REG (5, 16, GP);
+    case 'w': OPTIONAL_REG (5, 21, GP);
     case 'y': REG (5, 6, GP);
     case 'z': MAPPED_REG (0, 0, GP, reg_0_map);
     }
index 1d1c724..dce4d86 100644 (file)
@@ -1042,6 +1042,7 @@ print_insn_arg (struct disassemble_info *info,
       break;
 
     case OP_REG:
+    case OP_OPTIONAL_REG:
       {
        const struct mips_reg_operand *reg_op;
 
index 49a0623..4b5aaaf 100644 (file)
     return &op.root; \
   }
 
+#define OPTIONAL_REG(SIZE, LSB, BANK) \
+  { \
+    static const struct mips_reg_operand op = { \
+      { OP_OPTIONAL_REG, SIZE, LSB }, OP_REG_##BANK, 0 \
+    }; \
+    return &op.root; \
+  }
+
 #define MAPPED_REG(SIZE, LSB, BANK, MAP) \
   { \
     typedef char ATTRIBUTE_UNUSED \
     return &op.root; \
   }
 
+#define OPTIONAL_MAPPED_REG(SIZE, LSB, BANK, MAP) \
+  { \
+    typedef char ATTRIBUTE_UNUSED \
+      static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)]; \
+    static const struct mips_reg_operand op = { \
+      { OP_OPTIONAL_REG, SIZE, LSB }, OP_REG_##BANK, MAP \
+    }; \
+    return &op.root; \
+  }
+
 #define REG_PAIR(SIZE, LSB, BANK, MAP) \
   { \
     typedef char ATTRIBUTE_UNUSED \
index feb96a5..7fdc938 100644 (file)
@@ -134,8 +134,8 @@ decode_mips_operand (const char *p)
     case 'S': REG (5, 11, FP);
     case 'T': REG (5, 16, FP);
     case 'U': SPECIAL (10, 11, CLO_CLZ_DEST);
-    case 'V': REG (5, 11, FP);
-    case 'W': REG (5, 16, FP);
+    case 'V': OPTIONAL_REG (5, 11, FP);
+    case 'W': OPTIONAL_REG (5, 16, FP);
     case 'X': REG (5, 6, VEC);
     case 'Y': REG (5, 11, VEC);
     case 'Z': REG (5, 16, VEC);
@@ -153,12 +153,12 @@ decode_mips_operand (const char *p)
     case 'o': SINT (16, 0);
     case 'p': BRANCH (16, 0, 2);
     case 'q': HINT (10, 6);
-    case 'r': REG (5, 21, GP);
+    case 'r': OPTIONAL_REG (5, 21, GP);
     case 's': REG (5, 21, GP);
     case 't': REG (5, 16, GP);
     case 'u': HINT (16, 0);
-    case 'v': REG (5, 21, GP);
-    case 'w': REG (5, 16, GP);
+    case 'v': OPTIONAL_REG (5, 21, GP);
+    case 'w': OPTIONAL_REG (5, 16, GP);
     case 'x': REG (0, 0, GP);
     case 'z': MAPPED_REG (0, 0, GP, reg_0_map);
     }
index 9948741..598f823 100644 (file)
@@ -66,8 +66,8 @@ decode_mips16_operand (char type, bfd_boolean extended_p)
     case 'i': JALX (26, 0, 2);
     case 'l': SPECIAL (6, 5, ENTRY_EXIT_LIST);
     case 'm': SPECIAL (7, 0, SAVE_RESTORE_LIST);
-    case 'v': MAPPED_REG (3, 8, GP, reg_m16_map);
-    case 'w': MAPPED_REG (3, 5, GP, reg_m16_map);
+    case 'v': OPTIONAL_MAPPED_REG (3, 8, GP, reg_m16_map);
+    case 'w': OPTIONAL_MAPPED_REG (3, 5, GP, reg_m16_map);
     case 'x': MAPPED_REG (3, 8, GP, reg_m16_map);
     case 'y': MAPPED_REG (3, 5, GP, reg_m16_map);
     case 'z': MAPPED_REG (3, 2, GP, reg_m16_map);