Dandling memory pointers in Ada catchpoints with GDB/MI.
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index dd61d72a641c890542392a31e6e275b09f3d73bc..08ad7bab665b38133913336ae204d0d1033c6969 100644 (file)
@@ -1329,6 +1329,8 @@ enum options
     OPTION_NO_MT,
     OPTION_VIRT,
     OPTION_NO_VIRT,
+    OPTION_MSA,
+    OPTION_NO_MSA,
     OPTION_SMARTMIPS,
     OPTION_NO_SMARTMIPS,
     OPTION_DSPR2,
@@ -1440,6 +1442,8 @@ struct option md_longopts[] =
   {"mno-mcu", no_argument, NULL, OPTION_NO_MCU},
   {"mvirt", no_argument, NULL, OPTION_VIRT},
   {"mno-virt", no_argument, NULL, OPTION_NO_VIRT},
+  {"mmsa", no_argument, NULL, OPTION_MSA},
+  {"mno-msa", no_argument, NULL, OPTION_NO_MSA},
 
   /* Old-style architecture options.  Don't add more of these.  */
   {"m4650", no_argument, NULL, OPTION_M4650},
@@ -1586,6 +1590,10 @@ static const struct mips_ase mips_ases[] = {
 
   { "virt", ASE_VIRT, ASE_VIRT64,
     OPTION_VIRT, OPTION_NO_VIRT,
+    2, 2, 2, 2 },
+
+  { "msa", ASE_MSA, ASE_MSA64,
+    OPTION_MSA, OPTION_NO_MSA,
     2, 2, 2, 2 }
 };
 
@@ -2347,7 +2355,7 @@ struct regname {
 };
 
 #define RNUM_MASK      0x00000ff
-#define RTYPE_MASK     0x0efff00
+#define RTYPE_MASK     0x0ffff00
 #define RTYPE_NUM      0x0000100
 #define RTYPE_FPU      0x0000200
 #define RTYPE_FCC      0x0000400
@@ -2363,6 +2371,7 @@ struct regname {
 #define RTYPE_R5900_Q  0x0100000
 #define RTYPE_R5900_R  0x0200000
 #define RTYPE_R5900_ACC        0x0400000
+#define RTYPE_MSA      0x0800000
 #define RWARN          0x8000000
 
 #define GENERIC_REGISTER_NUMBERS \
@@ -2747,8 +2756,11 @@ enum mips_operand_token_type {
   /* A 4-bit XYZW channel mask.  */
   OT_CHANNELS,
 
-  /* An element of a vector, e.g. $v0[1].  */
-  OT_REG_ELEMENT,
+  /* A constant vector index, e.g. [1].  */
+  OT_INTEGER_INDEX,
+
+  /* A register vector index, e.g. [$2].  */
+  OT_REG_INDEX,
 
   /* A continuous range of registers, e.g. $s0-$s4.  */
   OT_REG_RANGE,
@@ -2777,17 +2789,14 @@ struct mips_operand_token
   enum mips_operand_token_type type;
   union
   {
-    /* The register symbol value for an OT_REG.  */
+    /* The register symbol value for an OT_REG or OT_REG_INDEX.  */
     unsigned int regno;
 
     /* The 4-bit channel mask for an OT_CHANNEL_SUFFIX.  */
     unsigned int channels;
 
-    /* The register symbol value and index for an OT_REG_ELEMENT.  */
-    struct {
-      unsigned int regno;
-      addressT index;
-    } reg_element;
+    /* The integer value of an OT_INTEGER_INDEX.  */
+    addressT index;
 
     /* The two register symbol values involved in an OT_REG_RANGE.  */
     struct {
@@ -2948,20 +2957,32 @@ mips_parse_argument_token (char *s, char float_format)
          mips_add_token (&token, OT_REG_RANGE);
          return s;
        }
-      else if (*s == '[')
-       {
-         /* A vector element.  */
-         expressionS element;
 
+      /* Add the register itself.  */
+      token.u.regno = regno1;
+      mips_add_token (&token, OT_REG);
+
+      /* Check for a vector index.  */
+      if (*s == '[')
+       {
          ++s;
          SKIP_SPACE_TABS (s);
-         my_getExpression (&element, s);
-         if (element.X_op != O_constant)
+         if (mips_parse_register (&s, &token.u.regno, NULL))
+           mips_add_token (&token, OT_REG_INDEX);
+         else
            {
-             set_insn_error (0, _("vector element must be constant"));
-             return 0;
+             expressionS element;
+
+             my_getExpression (&element, s);
+             if (element.X_op != O_constant)
+               {
+                 set_insn_error (0, _("vector element must be constant"));
+                 return 0;
+               }
+             s = expr_end;
+             token.u.index = element.X_add_number;
+             mips_add_token (&token, OT_INTEGER_INDEX);
            }
-         s = expr_end;
          SKIP_SPACE_TABS (s);
          if (*s != ']')
            {
@@ -2969,16 +2990,7 @@ mips_parse_argument_token (char *s, char float_format)
              return 0;
            }
          ++s;
-
-         token.u.reg_element.regno = regno1;
-         token.u.reg_element.index = element.X_add_number;
-         mips_add_token (&token, OT_REG_ELEMENT);
-         return s;
        }
-
-      /* Looks like just a plain register.  */
-      token.u.regno = regno1;
-      mips_add_token (&token, OT_REG);
       return s;
     }
 
@@ -3460,6 +3472,10 @@ md_begin (void)
       symbol_table_insert (symbol_new (regname, reg_section,
                                       RTYPE_VI | i, &zero_address_frag));
 
+      /* MSA register.  */
+      snprintf (regname, sizeof (regname) - 1, "$w%d", i);
+      symbol_table_insert (symbol_new (regname, reg_section,
+                                      RTYPE_MSA | i, &zero_address_frag));
     }
 
   obstack_init (&mips_operand_tokens);
@@ -4005,6 +4021,7 @@ operand_reg_mask (const struct mips_cl_insn *insn,
     case OP_PC:
     case OP_VU0_SUFFIX:
     case OP_VU0_MATCH_SUFFIX:
+    case OP_IMM_INDEX:
       abort ();
 
     case OP_REG:
@@ -4050,6 +4067,11 @@ operand_reg_mask (const struct mips_cl_insn *insn,
       if ((vsel & 0x18) == 0x18)
        return 0;
       return 1 << (uval & 31);
+
+    case OP_REG_INDEX:
+      if (!(type_mask & (1 << OP_REG_GP)))
+       return 0;
+      return 1 << insn_extract_operand (insn, operand);
     }
   abort ();
 }
@@ -4139,7 +4161,8 @@ fpr_read_mask (const struct mips_cl_insn *ip)
   unsigned long pinfo;
   unsigned int mask;
 
-  mask = insn_reg_mask (ip, (1 << OP_REG_FP) | (1 << OP_REG_VEC),
+  mask = insn_reg_mask (ip, ((1 << OP_REG_FP) | (1 << OP_REG_VEC)
+                            | (1 << OP_REG_MSA)),
                        insn_read_mask (ip->insn_mo));
   pinfo = ip->insn_mo->pinfo;
   /* Conservatively treat all operands to an FP_D instruction are doubles.
@@ -4157,7 +4180,8 @@ fpr_write_mask (const struct mips_cl_insn *ip)
   unsigned long pinfo;
   unsigned int mask;
 
-  mask = insn_reg_mask (ip, (1 << OP_REG_FP) | (1 << OP_REG_VEC),
+  mask = insn_reg_mask (ip, ((1 << OP_REG_FP) | (1 << OP_REG_VEC)
+                            | (1 << OP_REG_MSA)),
                        insn_write_mask (ip->insn_mo));
   pinfo = ip->insn_mo->pinfo;
   /* Conservatively treat all operands to an FP_D instruction are doubles.
@@ -4408,6 +4432,12 @@ convert_reg_type (const struct mips_opcode *opcode,
 
     case OP_REG_R5900_ACC:
       return RTYPE_R5900_ACC;
+
+    case OP_REG_MSA:
+      return RTYPE_MSA;
+
+    case OP_REG_MSA_CTRL:
+      return RTYPE_NUM;
     }
   abort ();
 }
@@ -5078,7 +5108,7 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
   uval = mips_extract_operand (operand, opcode->match);
   is_qh = (uval != 0);
 
-  if (arg->token->type == OT_REG || arg->token->type == OT_REG_ELEMENT)
+  if (arg->token->type == OT_REG)
     {
       if ((opcode->membership & INSN_5400)
          && strcmp (opcode->name, "rzu.ob") == 0)
@@ -5088,20 +5118,21 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
          return FALSE;
        }
 
+      if (!match_regno (arg, OP_REG_VEC, arg->token->u.regno, &regno))
+       return FALSE;
+      ++arg->token;
+
       /* Check whether this is a vector register or a broadcast of
         a single element.  */
-      if (arg->token->type == OT_REG_ELEMENT)
+      if (arg->token->type == OT_INTEGER_INDEX)
        {
-         if (!match_regno (arg, OP_REG_VEC, arg->token->u.reg_element.regno,
-                           &regno))
-           return FALSE;
-         if (arg->token->u.reg_element.index > (is_qh ? 3 : 7))
+         if (arg->token->u.index > (is_qh ? 3 : 7))
            {
              set_insn_error (arg->argnum, _("invalid element selector"));
              return FALSE;
            }
-         else
-           uval |= arg->token->u.reg_element.index << (is_qh ? 2 : 1) << 5;
+         uval |= arg->token->u.index << (is_qh ? 2 : 1) << 5;
+         ++arg->token;
        }
       else
        {
@@ -5115,15 +5146,12 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
              return FALSE;
            }
 
-         if (!match_regno (arg, OP_REG_VEC, arg->token->u.regno, &regno))
-           return FALSE;
          if (is_qh)
            uval |= MDMX_FMTSEL_VEC_QH << 5;
          else
            uval |= MDMX_FMTSEL_VEC_OB << 5;
        }
       uval |= regno;
-      ++arg->token;
     }
   else
     {
@@ -5146,6 +5174,47 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
   return TRUE;
 }
 
+/* OP_IMM_INDEX matcher.  */
+
+static bfd_boolean
+match_imm_index_operand (struct mips_arg_info *arg,
+                        const struct mips_operand *operand)
+{
+  unsigned int max_val;
+
+  if (arg->token->type != OT_INTEGER_INDEX)
+    return FALSE;
+
+  max_val = (1 << operand->size) - 1;
+  if (arg->token->u.index > max_val)
+    {
+      match_out_of_range (arg);
+      return FALSE;
+    }
+  insn_insert_operand (arg->insn, operand, arg->token->u.index);
+  ++arg->token;
+  return TRUE;
+}
+
+/* OP_REG_INDEX matcher.  */
+
+static bfd_boolean
+match_reg_index_operand (struct mips_arg_info *arg,
+                        const struct mips_operand *operand)
+{
+  unsigned int regno;
+
+  if (arg->token->type != OT_REG_INDEX)
+    return FALSE;
+
+  if (!match_regno (arg, OP_REG_GP, arg->token->u.regno, &regno))
+    return FALSE;
+
+  insn_insert_operand (arg->insn, operand, regno);
+  ++arg->token;
+  return TRUE;
+}
+
 /* OP_PC matcher.  */
 
 static bfd_boolean
@@ -5426,6 +5495,12 @@ match_operand (struct mips_arg_info *arg,
 
     case OP_VU0_MATCH_SUFFIX:
       return match_vu0_suffix_operand (arg, operand, TRUE);
+
+    case OP_IMM_INDEX:
+      return match_imm_index_operand (arg, operand);
+
+    case OP_REG_INDEX:
+      return match_reg_index_operand (arg, operand);
     }
   abort ();
 }
@@ -5997,6 +6072,7 @@ can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr,
 {
   unsigned long pinfo, pinfo2, prev_pinfo, prev_pinfo2;
   unsigned int gpr_read, gpr_write, prev_gpr_read, prev_gpr_write;
+  unsigned int fpr_read, prev_fpr_write;
 
   /* -O2 and above is required for this optimization.  */
   if (mips_optimize < 2)
@@ -6071,6 +6147,11 @@ can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr,
   if (gpr_read & prev_gpr_write)
     return FALSE;
 
+  fpr_read = fpr_read_mask (ip);
+  prev_fpr_write = fpr_write_mask (&history[0]);
+  if (fpr_read & prev_fpr_write)
+    return FALSE;
+
   /* If the branch writes a register that the previous
      instruction sets, we can not swap.  */
   gpr_write = gpr_write_mask (ip);
@@ -16539,11 +16620,21 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              switch ((insn >> 28) & 0xf)
                {
                case 4:
-                 /* bc[0-3][tf]l? instructions can have the condition
-                    reversed by tweaking a single TF bit, and their
-                    opcodes all have 0x4???????.  */
-                 gas_assert ((insn & 0xf3e00000) == 0x41000000);
-                 insn ^= 0x00010000;
+                 if ((insn & 0xff000000) == 0x47000000
+                     || (insn & 0xff600000) == 0x45600000)
+                   {
+                     /* BZ.df/BNZ.df, BZ.V/BNZ.V can have the condition
+                        reversed by tweaking bit 23.  */
+                     insn ^= 0x00800000;
+                   }
+                 else
+                   {
+                     /* bc[0-3][tf]l? instructions can have the condition
+                        reversed by tweaking a single TF bit, and their
+                        opcodes all have 0x4???????.  */
+                     gas_assert ((insn & 0xf3e00000) == 0x41000000);
+                     insn ^= 0x00010000;
+                   }
                  break;
 
                case 0:
@@ -16810,6 +16901,11 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                   || (insn & 0xffe30000) == 0x42800000         /* bc2f  */
                   || (insn & 0xffe30000) == 0x42a00000)        /* bc2t  */
            insn ^= 0x00200000;
+         else if ((insn & 0xff000000) == 0x83000000            /* BZ.df
+                                                                  BNZ.df  */
+                   || (insn & 0xff600000) == 0x81600000)       /* BZ.V
+                                                                  BNZ.V */
+           insn ^= 0x00800000;
          else
            abort ();
 
@@ -18021,6 +18117,9 @@ MIPS options:\n\
 -mmcu                  generate MCU instructions\n\
 -mno-mcu               do not generate MCU instructions\n"));
   fprintf (stream, _("\
+-mmsa                  generate MSA instructions\n\
+-mno-msa               do not generate MSA instructions\n"));
+  fprintf (stream, _("\
 -mvirt                 generate Virtualization instructions\n\
 -mno-virt              do not generate Virtualization instructions\n"));
   fprintf (stream, _("\
This page took 0.032219 seconds and 4 git commands to generate.