Add support for a __gcc_isr pseudo isntruction to the AVR assembler.
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index 7deacad1cbbce985885d233ef0b249afbf46c28d..456be9e07cf805665a27f52e219c8275ebf00165 100644 (file)
 #define HLE_PREFIX     REP_PREFIX
 #define BND_PREFIX     REP_PREFIX
 #define LOCK_PREFIX    5
-#define REX_PREFIX     6       /* must come last.  */
-#define MAX_PREFIXES   7       /* max prefixes per opcode */
+/* Only one of NOTRACK_PREFIX and SEG_PREFIX can be used at the same
+   time.  */
+#define NOTRACK_PREFIX 6
+#define REX_PREFIX     7       /* must come last.  */
+#define MAX_PREFIXES   8       /* max prefixes per opcode */
 
 /* we define the syntax here (modulo base,index,scale syntax) */
 #define REGISTER_PREFIX '%'
@@ -354,8 +357,13 @@ struct _i386_insn
     /* Compressed disp8*N attribute.  */
     unsigned int memshift;
 
-    /* Swap operand in encoding.  */
-    unsigned int swap_operand;
+    /* Prefer load or store in encoding.  */
+    enum
+      {
+       dir_encoding_default = 0,
+       dir_encoding_load,
+       dir_encoding_store
+      } dir_encoding;
 
     /* Prefer 8bit or 32bit displacement in encoding.  */
     enum
@@ -365,6 +373,15 @@ struct _i386_insn
        disp_encoding_32bit
       } disp_encoding;
 
+    /* How to encode vector instructions.  */
+    enum
+      {
+       vex_encoding_default = 0,
+       vex_encoding_vex2,
+       vex_encoding_vex3,
+       vex_encoding_evex
+      } vec_encoding;
+
     /* REP prefix.  */
     const char *rep_prefix;
 
@@ -374,8 +391,8 @@ struct _i386_insn
     /* Have BND prefix.  */
     const char *bnd_prefix;
 
-    /* Need VREX to support upper 16 registers.  */
-    int need_vrex;
+    /* Have NOTRACK prefix.  */
+    const char *notrack_prefix;
 
     /* Error message.  */
     enum i386_error error;
@@ -403,7 +420,7 @@ static const struct RC_name RC_NamesTable[] =
 
 /* List of chars besides those in app.c:symbol_chars that can start an
    operand.  Used to prevent the scrubber eating vital white-space.  */
-const char extra_symbol_chars[] = "*%-([{"
+const char extra_symbol_chars[] = "*%-([{}"
 #ifdef LEX_AT
        "@"
 #endif
@@ -2133,6 +2150,7 @@ enum PREFIX_GROUP
   PREFIX_EXIST = 0,
   PREFIX_LOCK,
   PREFIX_REP,
+  PREFIX_DS,
   PREFIX_OTHER
 };
 
@@ -2141,7 +2159,8 @@ enum PREFIX_GROUP
    same class already exists.
    b. PREFIX_LOCK if lock prefix is added.
    c. PREFIX_REP if rep/repne prefix is added.
-   d. PREFIX_OTHER if other prefix is added.
+   d. PREFIX_DS if ds prefix is added.
+   e. PREFIX_OTHER if other prefix is added.
  */
 
 static enum PREFIX_GROUP
@@ -2166,8 +2185,10 @@ add_prefix (unsigned int prefix)
        default:
          abort ();
 
-       case CS_PREFIX_OPCODE:
        case DS_PREFIX_OPCODE:
+         ret = PREFIX_DS;
+         /* Fall through.  */
+       case CS_PREFIX_OPCODE:
        case ES_PREFIX_OPCODE:
        case FS_PREFIX_OPCODE:
        case GS_PREFIX_OPCODE:
@@ -2597,6 +2618,9 @@ md_begin (void)
 {
   const char *hash_err;
 
+  /* Support pseudo prefixes like {disp32}.  */
+  lex_type ['{'] = LEX_BEGIN_NAME;
+
   /* Initialize op_hash hash table.  */
   op_hash = hash_new ();
 
@@ -2678,7 +2702,10 @@ md_begin (void)
            operand_chars[c] = c;
          }
        else if (c == '{' || c == '}')
-         operand_chars[c] = c;
+         {
+           mnemonic_chars[c] = c;
+           operand_chars[c] = c;
+         }
 
        if (ISALPHA (c) || ISDIGIT (c))
          identifier_chars[c] = c;
@@ -3144,10 +3171,11 @@ build_vex_prefix (const insn_template *t)
 
   /* Use 2-byte VEX prefix by swapping destination and source
      operand.  */
-  if (!i.swap_operand
+  if (i.vec_encoding != vex_encoding_vex3
+      && i.dir_encoding == dir_encoding_default
       && i.operands == i.reg_operands
       && i.tm.opcode_modifier.vexopcode == VEX0F
-      && i.tm.opcode_modifier.s
+      && i.tm.opcode_modifier.load
       && i.rex == REX_B)
     {
       unsigned int xchg = i.operands - 1;
@@ -3196,7 +3224,8 @@ build_vex_prefix (const insn_template *t)
     }
 
   /* Use 2-byte VEX prefix if possible.  */
-  if (i.tm.opcode_modifier.vexopcode == VEX0F
+  if (i.vec_encoding != vex_encoding_vex3
+      && i.tm.opcode_modifier.vexopcode == VEX0F
       && i.tm.opcode_modifier.vexw != VEXW1
       && (i.rex & (REX_W | REX_X | REX_B)) == 0)
     {
@@ -3683,6 +3712,10 @@ md_assemble (char *line)
   if (i.bnd_prefix && !i.tm.opcode_modifier.bndprefixok)
     as_bad (_("expecting valid branch instruction after `bnd'"));
 
+  /* Check NOTRACK prefix.  */
+  if (i.notrack_prefix && !i.tm.opcode_modifier.notrackprefixok)
+    as_bad (_("expecting indirect branch instruction after `notrack'"));
+
   if (i.tm.cpu_flags.bitfield.cpumpx)
     {
       if (flag_code == CODE_64BIT && i.prefix[ADDR_PREFIX])
@@ -3905,21 +3938,83 @@ parse_insn (char *line, char *mnemonic)
                      current_templates->start->name);
              return NULL;
            }
-         /* Add prefix, checking for repeated prefixes.  */
-         switch (add_prefix (current_templates->start->base_opcode))
+         if (current_templates->start->opcode_length == 0)
            {
-           case PREFIX_EXIST:
-             return NULL;
-           case PREFIX_REP:
-             if (current_templates->start->cpu_flags.bitfield.cpuhle)
-               i.hle_prefix = current_templates->start->name;
-             else if (current_templates->start->cpu_flags.bitfield.cpumpx)
-               i.bnd_prefix = current_templates->start->name;
+             /* Handle pseudo prefixes.  */
+             switch (current_templates->start->base_opcode)
+               {
+               case 0x0:
+                 /* {disp8} */
+                 i.disp_encoding = disp_encoding_8bit;
+                 break;
+               case 0x1:
+                 /* {disp32} */
+                 i.disp_encoding = disp_encoding_32bit;
+                 break;
+               case 0x2:
+                 /* {load} */
+                 i.dir_encoding = dir_encoding_load;
+                 break;
+               case 0x3:
+                 /* {store} */
+                 i.dir_encoding = dir_encoding_store;
+                 break;
+               case 0x4:
+                 /* {vex2} */
+                 i.vec_encoding = vex_encoding_vex2;
+                 break;
+               case 0x5:
+                 /* {vex3} */
+                 i.vec_encoding = vex_encoding_vex3;
+                 break;
+               case 0x6:
+                 /* {evex} */
+                 i.vec_encoding = vex_encoding_evex;
+                 break;
+               default:
+                 abort ();
+               }
+           }
+         else
+           {
+             /* Add prefix, checking for repeated prefixes.  */
+             enum PREFIX_GROUP p
+               = add_prefix (current_templates->start->base_opcode);
+             if (p == PREFIX_DS
+                 && current_templates->start->cpu_flags.bitfield.cpucet)
+               {
+                 i.notrack_prefix = current_templates->start->name;
+                 /* Move NOTRACK_PREFIX_OPCODE to NOTRACK_PREFIX slot so
+                    that it is placed before others.  */
+                 i.prefix[SEG_PREFIX] = 0;
+                 i.prefix[NOTRACK_PREFIX] = NOTRACK_PREFIX_OPCODE;
+               }
              else
-               i.rep_prefix = current_templates->start->name;
-             break;
-           default:
-             break;
+               {
+                 switch (p)
+                   {
+                   case PREFIX_EXIST:
+                     return NULL;
+                   case PREFIX_REP:
+                     if (current_templates->start->cpu_flags.bitfield.cpuhle)
+                       i.hle_prefix = current_templates->start->name;
+                     else if (current_templates->start->cpu_flags.bitfield.cpumpx)
+                       i.bnd_prefix = current_templates->start->name;
+                     else
+                       i.rep_prefix = current_templates->start->name;
+                     break;
+                   default:
+                     break;
+                   }
+
+                 if (i.notrack_prefix != NULL)
+                   {
+                     /* There must be no other prefixes after NOTRACK
+                        prefix.  */
+                     as_bad (_("expecting no other prefixes after `notrack'"));
+                     return NULL;
+                   }
+               }
            }
          /* Skip past PREFIX_SEPARATOR and reset token_start.  */
          token_start = ++l;
@@ -3933,7 +4028,7 @@ parse_insn (char *line, char *mnemonic)
       /* Check if we should swap operand or force 32bit displacement in
         encoding.  */
       if (mnem_p - 2 == dot_p && dot_p[1] == 's')
-       i.swap_operand = 1;
+       i.dir_encoding = dir_encoding_store;
       else if (mnem_p - 3 == dot_p
               && dot_p[1] == 'd'
               && dot_p[2] == '8')
@@ -4721,15 +4816,27 @@ check_VecOperands (const insn_template *t)
 static int
 VEX_check_operands (const insn_template *t)
 {
-  /* VREX is only valid with EVEX prefix.  */
-  if (i.need_vrex && !t->opcode_modifier.evex)
+  if (i.vec_encoding == vex_encoding_evex)
     {
-      i.error = invalid_register_operand;
-      return 1;
+      /* This instruction must be encoded with EVEX prefix.  */
+      if (!t->opcode_modifier.evex)
+       {
+         i.error = unsupported;
+         return 1;
+       }
+      return 0;
     }
 
   if (!t->opcode_modifier.vex)
-    return 0;
+    {
+      /* This instruction template doesn't have VEX prefix.  */
+      if (i.vec_encoding != vex_encoding_default)
+       {
+         i.error = unsupported;
+         return 1;
+       }
+      return 0;
+    }
 
   /* Only check VEX_Imm4, which must be the first operand.  */
   if (t->operand_types[0].bitfield.vec_imm4)
@@ -4967,20 +5074,17 @@ match_template (char mnem_suffix)
              && operand_type_equal (&i.types [0], &acc32)
              && operand_type_equal (&i.types [1], &acc32))
            continue;
-         if (i.swap_operand)
-           {
-             /* If we swap operand in encoding, we either match
-                the next one or reverse direction of operands.  */
-             if (t->opcode_modifier.s)
-               continue;
-             else if (t->opcode_modifier.d)
-               goto check_reverse;
-           }
+         /* If we want store form, we reverse direction of operands.  */
+         if (i.dir_encoding == dir_encoding_store
+             && t->opcode_modifier.d)
+           goto check_reverse;
          /* Fall through.  */
 
        case 3:
-         /* If we swap operand in encoding, we match the next one.  */
-         if (i.swap_operand && t->opcode_modifier.s)
+         /* If we want store form, we skip the current load.  */
+         if (i.dir_encoding == dir_encoding_store
+             && i.mem_operands == 0
+             && t->opcode_modifier.load)
            continue;
          /* Fall through.  */
        case 4:
@@ -9725,11 +9829,13 @@ parse_real_register (char *reg_string, char **end_op)
      mode.  */
   if ((r->reg_flags & RegVRex))
     {
+      if (i.vec_encoding == vex_encoding_default)
+       i.vec_encoding = vex_encoding_evex;
+
       if (!cpu_arch_flags.bitfield.cpuvrex
+         || i.vec_encoding != vex_encoding_evex
          || flag_code != CODE_64BIT)
        return (const reg_entry *) NULL;
-
-      i.need_vrex = 1;
     }
 
   if (((r->reg_flags & (RegRex64 | RegRex))
@@ -9774,7 +9880,7 @@ parse_register (char *reg_string, char **end_op)
                && (valueT) e->X_add_number < i386_regtab_size);
          r = i386_regtab + e->X_add_number;
          if ((r->reg_flags & RegVRex))
-           i.need_vrex = 1;
+           i.vec_encoding = vex_encoding_evex;
          *end_op = input_line_pointer;
        }
       *input_line_pointer = c;
This page took 0.029232 seconds and 4 git commands to generate.