x86-64: accept 64-bit LFS/LGS/LSS forms with suffix or operand size specifier
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index 75ea225efddfddf0c071da027689bcb9e3908d45..b62af342684a7d29e73ac620e5256e74a1777777 100644 (file)
@@ -353,6 +353,9 @@ struct _i386_insn
     unsigned int prefixes;
     unsigned char prefix[MAX_PREFIXES];
 
+    /* The operand to a branch insn indicates an absolute branch.  */
+    bfd_boolean jumpabsolute;
+
     /* Has MMX register operands.  */
     bfd_boolean has_regmmx;
 
@@ -2063,11 +2066,9 @@ operand_size_match (const insn_template *t)
 {
   unsigned int j, match = MATCH_STRAIGHT;
 
-  /* Don't check jump instructions.  */
+  /* Don't check non-absolute jump instructions.  */
   if (t->opcode_modifier.jump
-      || t->opcode_modifier.jumpbyte
-      || t->opcode_modifier.jumpdword
-      || t->opcode_modifier.jumpintersegment)
+      && t->opcode_modifier.jump != JUMP_ABSOLUTE)
     return match;
 
   /* Check memory and accumulator operand size.  */
@@ -2075,7 +2076,7 @@ operand_size_match (const insn_template *t)
     {
       if (i.types[j].bitfield.class != Reg
          && i.types[j].bitfield.class != RegSIMD
-         && t->operand_types[j].bitfield.anysize)
+         && t->opcode_modifier.anysize)
        continue;
 
       if (t->operand_types[j].bitfield.class == Reg
@@ -2147,7 +2148,6 @@ operand_type_match (i386_operand_type overlap,
 {
   i386_operand_type temp = overlap;
 
-  temp.bitfield.jumpabsolute = 0;
   temp.bitfield.unspecified = 0;
   temp.bitfield.byte = 0;
   temp.bitfield.word = 0;
@@ -2161,8 +2161,7 @@ operand_type_match (i386_operand_type overlap,
   if (operand_type_all_zero (&temp))
     goto mismatch;
 
-  if (given.bitfield.baseindex == overlap.bitfield.baseindex
-      && given.bitfield.jumpabsolute == overlap.bitfield.jumpabsolute)
+  if (given.bitfield.baseindex == overlap.bitfield.baseindex)
     return 1;
 
 mismatch:
@@ -3155,13 +3154,11 @@ const type_names[] =
   { OPERAND_TYPE_FLOATREG, "FReg" },
   { OPERAND_TYPE_FLOATACC, "FAcc" },
   { OPERAND_TYPE_SREG, "SReg" },
-  { OPERAND_TYPE_JUMPABSOLUTE, "Jump Absolute" },
   { OPERAND_TYPE_REGMMX, "rMMX" },
   { OPERAND_TYPE_REGXMM, "rXMM" },
   { OPERAND_TYPE_REGYMM, "rYMM" },
   { OPERAND_TYPE_REGZMM, "rZMM" },
   { OPERAND_TYPE_REGMASK, "Mask reg" },
-  { OPERAND_TYPE_ESSEG, "es" },
 };
 
 static void
@@ -3850,52 +3847,6 @@ process_immext (void)
 {
   expressionS *exp;
 
-  if ((i.tm.cpu_flags.bitfield.cpusse3 || i.tm.cpu_flags.bitfield.cpusvme)
-      && i.operands > 0)
-    {
-      /* MONITOR/MWAIT as well as SVME instructions have fixed operands
-        with an opcode suffix which is coded in the same place as an
-        8-bit immediate field would be.
-        Here we check those operands and remove them afterwards.  */
-      unsigned int x;
-
-      for (x = 0; x < i.operands; x++)
-       if (register_number (i.op[x].regs) != x)
-         as_bad (_("can't use register '%s%s' as operand %d in '%s'."),
-                 register_prefix, i.op[x].regs->reg_name, x + 1,
-                 i.tm.name);
-
-      i.operands = 0;
-    }
-
-  if (i.tm.cpu_flags.bitfield.cpumwaitx && i.operands > 0)
-    {
-      /* MONITORX/MWAITX instructions have fixed operands with an opcode
-        suffix which is coded in the same place as an 8-bit immediate
-        field would be.
-        Here we check those operands and remove them afterwards.  */
-      unsigned int x;
-
-      if (i.operands != 3)
-       abort();
-
-      for (x = 0; x < 2; x++)
-       if (register_number (i.op[x].regs) != x)
-         goto bad_register_operand;
-
-      /* Check for third operand for mwaitx/monitorx insn.  */
-      if (register_number (i.op[x].regs)
-         != (x + (i.tm.extension_opcode == 0xfb)))
-       {
-bad_register_operand:
-         as_bad (_("can't use register '%s%s' as operand %d in '%s'."),
-                 register_prefix, i.op[x].regs->reg_name, x+1,
-                 i.tm.name);
-       }
-
-      i.operands = 0;
-    }
-
   /* These AMD 3DNow! and SSE2 instructions have an opcode suffix
      which is coded in the same place as an 8-bit immediate field
      would be.  Here we fake an 8-bit immediate operand from the
@@ -4432,8 +4383,9 @@ md_assemble (char *line)
     }
 
   /* Check string instruction segment overrides.  */
-  if (i.tm.opcode_modifier.isstring && i.mem_operands != 0)
+  if (i.tm.opcode_modifier.isstring >= IS_STRING_ES_OP0)
     {
+      gas_assert (i.mem_operands);
       if (!check_string ())
        return;
       i.disp_operands = 0;
@@ -4508,9 +4460,9 @@ md_assemble (char *line)
       i.imm_operands = 0;
     }
 
-  if ((i.tm.opcode_modifier.jump
-       || i.tm.opcode_modifier.jumpbyte
-       || i.tm.opcode_modifier.jumpdword)
+  if ((i.tm.opcode_modifier.jump == JUMP
+       || i.tm.opcode_modifier.jump == JUMP_BYTE
+       || i.tm.opcode_modifier.jump == JUMP_DWORD)
       && i.op[0].disps->X_op == O_constant)
     {
       /* Convert "jmp constant" (and "call constant") to a jump (call) to
@@ -4810,8 +4762,8 @@ check_suffix:
        }
     }
 
-  if (current_templates->start->opcode_modifier.jump
-      || current_templates->start->opcode_modifier.jumpbyte)
+  if (current_templates->start->opcode_modifier.jump == JUMP
+      || current_templates->start->opcode_modifier.jump == JUMP_BYTE)
     {
       /* Check for a branch hint.  We allow ",pt" and ",pn" for
         predict taken and predict not taken respectively.
@@ -5789,6 +5741,18 @@ match_template (char mnem_suffix)
       if (!size_match)
        continue;
 
+      /* This is intentionally not
+
+        if (i.jumpabsolute != (t->opcode_modifier.jump == JUMP_ABSOLUTE))
+
+        as the case of a missing * on the operand is accepted (perhaps with
+        a warning, issued further down).  */
+      if (i.jumpabsolute && t->opcode_modifier.jump != JUMP_ABSOLUTE)
+       {
+         i.error = operand_type_mismatch;
+         continue;
+       }
+
       for (j = 0; j < MAX_OPERANDS; j++)
        operand_types[j] = t->operand_types[j];
 
@@ -6166,11 +6130,8 @@ check_reverse:
   if (!quiet_warnings)
     {
       if (!intel_syntax
-         && (i.types[0].bitfield.jumpabsolute
-             != operand_types[0].bitfield.jumpabsolute))
-       {
-         as_warn (_("indirect %s without `*'"), t->name);
-       }
+         && (i.jumpabsolute != (t->opcode_modifier.jump == JUMP_ABSOLUTE)))
+       as_warn (_("indirect %s without `*'"), t->name);
 
       if (t->opcode_modifier.isprefix
          && t->opcode_modifier.ignoresize)
@@ -6214,35 +6175,24 @@ check_reverse:
 static int
 check_string (void)
 {
-  unsigned int mem_op = i.flags[0] & Operand_Mem ? 0 : 1;
+  unsigned int es_op = i.tm.opcode_modifier.isstring - IS_STRING_ES_OP0;
+  unsigned int op = i.tm.operand_types[0].bitfield.baseindex ? es_op : 0;
 
-  if (i.tm.operand_types[mem_op].bitfield.esseg)
+  if (i.seg[op] != NULL && i.seg[op] != &es)
     {
-      if (i.seg[0] != NULL && i.seg[0] != &es)
-       {
-         as_bad (_("`%s' operand %d must use `%ses' segment"),
-                 i.tm.name,
-                 intel_syntax ? i.tm.operands - mem_op : mem_op + 1,
-                 register_prefix);
-         return 0;
-       }
-      /* There's only ever one segment override allowed per instruction.
-        This instruction possibly has a legal segment override on the
-        second operand, so copy the segment to where non-string
-        instructions store it, allowing common code.  */
-      i.seg[0] = i.seg[1];
-    }
-  else if (i.tm.operand_types[mem_op + 1].bitfield.esseg)
-    {
-      if (i.seg[1] != NULL && i.seg[1] != &es)
-       {
-         as_bad (_("`%s' operand %d must use `%ses' segment"),
-                 i.tm.name,
-                 intel_syntax ? i.tm.operands - mem_op - 1 : mem_op + 2,
-                 register_prefix);
-         return 0;
-       }
+      as_bad (_("`%s' operand %u must use `%ses' segment"),
+             i.tm.name,
+             intel_syntax ? i.tm.operands - es_op : es_op + 1,
+             register_prefix);
+      return 0;
     }
+
+  /* There's only ever one segment override allowed per instruction.
+     This instruction possibly has a legal segment override on the
+     second operand, so copy the segment to where non-string
+     instructions store it, allowing common code.  */
+  i.seg[op] = i.seg[1];
+
   return 1;
 }
 
@@ -6257,10 +6207,11 @@ process_suffix (void)
     i.suffix = LONG_MNEM_SUFFIX;
   else if (i.tm.opcode_modifier.size == SIZE64)
     i.suffix = QWORD_MNEM_SUFFIX;
-  else if (i.reg_operands)
+  else if (i.reg_operands
+          && (i.operands > 1 || i.types[0].bitfield.class == Reg))
     {
       /* If there's no instruction mnemonic suffix we try to invent one
-        based on register operands.  */
+        based on GPR operands.  */
       if (!i.suffix)
        {
          /* We take i.suffix from the last register operand specified,
@@ -6361,27 +6312,34 @@ process_suffix (void)
   else if (i.tm.opcode_modifier.defaultsize
           && !i.suffix
           /* exclude fldenv/frstor/fsave/fstenv */
-          && i.tm.opcode_modifier.no_ssuf)
+          && i.tm.opcode_modifier.no_ssuf
+          /* exclude sysret */
+          && i.tm.base_opcode != 0x0f07)
     {
-      if (stackop_size == LONG_MNEM_SUFFIX
-         && i.tm.base_opcode == 0xcf)
+      i.suffix = stackop_size;
+      if (stackop_size == LONG_MNEM_SUFFIX)
        {
          /* stackop_size is set to LONG_MNEM_SUFFIX for the
             .code16gcc directive to support 16-bit mode with
             32-bit address.  For IRET without a suffix, generate
             16-bit IRET (opcode 0xcf) to return from an interrupt
             handler.  */
-         i.suffix = WORD_MNEM_SUFFIX;
-         as_warn (_("generating 16-bit `iret' for .code16gcc directive"));
+         if (i.tm.base_opcode == 0xcf)
+           {
+             i.suffix = WORD_MNEM_SUFFIX;
+             as_warn (_("generating 16-bit `iret' for .code16gcc directive"));
+           }
+         /* Warn about changed behavior for segment register push/pop.  */
+         else if ((i.tm.base_opcode | 1) == 0x07)
+           as_warn (_("generating 32-bit `%s', unlike earlier gas versions"),
+                    i.tm.name);
        }
-      else
-       i.suffix = stackop_size;
     }
   else if (intel_syntax
           && !i.suffix
-          && (i.tm.operand_types[0].bitfield.jumpabsolute
-              || i.tm.opcode_modifier.jumpbyte
-              || i.tm.opcode_modifier.jumpintersegment
+          && (i.tm.opcode_modifier.jump == JUMP_ABSOLUTE
+              || i.tm.opcode_modifier.jump == JUMP_BYTE
+              || i.tm.opcode_modifier.jump == JUMP_INTERSEGMENT
               || (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */
                   && i.tm.extension_opcode <= 3)))
     {
@@ -6473,7 +6431,7 @@ process_suffix (void)
       if (i.reg_operands > 0
          && i.types[0].bitfield.class == Reg
          && i.tm.opcode_modifier.addrprefixopreg
-         && (i.tm.opcode_modifier.immext
+         && (i.tm.operand_types[0].bitfield.instance == Accum
              || i.operands == 1))
        {
          /* The address size override prefix changes the size of the
@@ -6491,11 +6449,11 @@ process_suffix (void)
               && !is_any_vex_encoding (&i.tm)
               && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
                   || (flag_code == CODE_64BIT
-                      && i.tm.opcode_modifier.jumpbyte)))
+                      && i.tm.opcode_modifier.jump == JUMP_BYTE)))
        {
          unsigned int prefix = DATA_PREFIX_OPCODE;
 
-         if (i.tm.opcode_modifier.jumpbyte) /* jcxz, loop */
+         if (i.tm.opcode_modifier.jump == JUMP_BYTE) /* jcxz, loop */
            prefix = ADDR_PREFIX_OPCODE;
 
          if (!add_prefix (prefix))
@@ -6523,7 +6481,7 @@ process_suffix (void)
   if (i.reg_operands != 0
       && i.operands > 1
       && i.tm.opcode_modifier.addrprefixopreg
-      && !i.tm.opcode_modifier.immext)
+      && i.tm.operand_types[0].bitfield.instance != Accum)
     {
       /* Check invalid register operand when the address size override
         prefix changes the size of register operands.  */
@@ -7946,7 +7904,7 @@ output_jump (void)
   fixS *fixP;
   bfd_reloc_code_real_type jump_reloc = i.reloc[0];
 
-  if (i.tm.opcode_modifier.jumpbyte)
+  if (i.tm.opcode_modifier.jump == JUMP_BYTE)
     {
       /* This is a loop or jecxz type instruction.  */
       size = 1;
@@ -8301,15 +8259,9 @@ output_insn (void)
          || i.tm.cpu_flags.bitfield.cpu687
          || i.tm.cpu_flags.bitfield.cpufisttp)
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_X87;
-      /* Don't set GNU_PROPERTY_X86_FEATURE_2_MMX for prefetchtXXX nor
-        Xfence instructions.  */
-      if (i.tm.base_opcode != 0xf18
-         && i.tm.base_opcode != 0xf0d
-         && i.tm.base_opcode != 0xfaef8
-         && (i.has_regmmx
-             || i.tm.cpu_flags.bitfield.cpummx
-             || i.tm.cpu_flags.bitfield.cpua3dnow
-             || i.tm.cpu_flags.bitfield.cpua3dnowa))
+      if (i.has_regmmx
+         || i.tm.base_opcode == 0xf77 /* emms */
+         || i.tm.base_opcode == 0xf0e /* femms */)
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_MMX;
       if (i.has_regxmm)
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XMM;
@@ -8337,12 +8289,12 @@ output_insn (void)
   insn_start_off = frag_now_fix ();
 
   /* Output jumps.  */
-  if (i.tm.opcode_modifier.jump)
+  if (i.tm.opcode_modifier.jump == JUMP)
     output_branch ();
-  else if (i.tm.opcode_modifier.jumpbyte
-          || i.tm.opcode_modifier.jumpdword)
+  else if (i.tm.opcode_modifier.jump == JUMP_BYTE
+          || i.tm.opcode_modifier.jump == JUMP_DWORD)
     output_jump ();
-  else if (i.tm.opcode_modifier.jumpintersegment)
+  else if (i.tm.opcode_modifier.jump == JUMP_INTERSEGMENT)
     output_interseg_jump ();
   else
     {
@@ -9521,9 +9473,9 @@ i386_displacement (char *disp_start, char *disp_end)
     }
 
   operand_type_set (&bigdisp, 0);
-  if ((i.types[this_operand].bitfield.jumpabsolute)
-      || (!current_templates->start->opcode_modifier.jump
-         && !current_templates->start->opcode_modifier.jumpdword))
+  if (i.jumpabsolute
+      || (current_templates->start->opcode_modifier.jump != JUMP
+         && current_templates->start->opcode_modifier.jump != JUMP_DWORD))
     {
       bigdisp.bitfield.disp32 = 1;
       override = (i.prefix[ADDR_PREFIX] != 0);
@@ -9826,16 +9778,16 @@ i386_index_check (const char *operand_string)
 
       if (current_templates->start->opcode_modifier.repprefixok)
        {
-         i386_operand_type type = current_templates->end[-1].operand_types[0];
+         int es_op = current_templates->end[-1].opcode_modifier.isstring
+                     - IS_STRING_ES_OP0;
+         int op = 0;
 
-         if (!type.bitfield.baseindex
+         if (!current_templates->end[-1].operand_types[0].bitfield.baseindex
              || ((!i.mem_operands != !intel_syntax)
                  && current_templates->end[-1].operand_types[1]
                     .bitfield.baseindex))
-           type = current_templates->end[-1].operand_types[1];
-         expected_reg = hash_find (reg_hash,
-                                   di_si[addr_mode][type.bitfield.esseg]);
-
+           op = 1;
+         expected_reg = hash_find (reg_hash, di_si[addr_mode][op == es_op]);
        }
       else
        expected_reg = hash_find (reg_hash, bx[addr_mode]);
@@ -10052,7 +10004,7 @@ i386_att_operand (char *operand_string)
       ++op_string;
       if (is_space_char (*op_string))
        ++op_string;
-      i.types[this_operand].bitfield.jumpabsolute = 1;
+      i.jumpabsolute = TRUE;
     }
 
   /* Check if operand is a register.  */
@@ -10108,7 +10060,7 @@ i386_att_operand (char *operand_string)
              ++op_string;
              if (is_space_char (*op_string))
                ++op_string;
-             i.types[this_operand].bitfield.jumpabsolute = 1;
+             i.jumpabsolute = TRUE;
            }
          goto do_memory_reference;
        }
@@ -10142,7 +10094,7 @@ i386_att_operand (char *operand_string)
   else if (*op_string == IMMEDIATE_PREFIX)
     {
       ++op_string;
-      if (i.types[this_operand].bitfield.jumpabsolute)
+      if (i.jumpabsolute)
        {
          as_bad (_("immediate operand illegal with absolute jump"));
          return 0;
This page took 0.05286 seconds and 4 git commands to generate.