gas/
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index aa88394786bb4881032e97964ec71e7357bf402a..6ee4010ce9dcf70f36e1f9f13294ff92f5723048 100644 (file)
@@ -32,7 +32,6 @@
 #include "subsegs.h"
 #include "dwarf2dbg.h"
 #include "dw2gencfi.h"
-#include "opcode/i386.h"
 #include "elf/x86-64.h"
 
 #ifndef REGISTER_WARNINGS
@@ -499,6 +498,8 @@ static const arch_entry cpu_arch[] =
    CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3},
   {".ssse3", PROCESSOR_UNKNOWN,
    CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3},
+  {".sse4.1", PROCESSOR_UNKNOWN,
+   CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1},
   {".3dnow", PROCESSOR_UNKNOWN,
    CpuMMX|Cpu3dnow},
   {".3dnowa", PROCESSOR_UNKNOWN,
@@ -992,9 +993,9 @@ add_prefix (unsigned int prefix)
   if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16
       && flag_code == CODE_64BIT)
     {
-      if ((i.prefix[REX_PREFIX] & prefix & REX_MODE64)
-         || ((i.prefix[REX_PREFIX] & (REX_EXTX | REX_EXTY | REX_EXTZ))
-             && (prefix & (REX_EXTX | REX_EXTY | REX_EXTZ))))
+      if ((i.prefix[REX_PREFIX] & prefix & REX_W)
+         || ((i.prefix[REX_PREFIX] & (REX_R | REX_X | REX_B))
+             && (prefix & (REX_R | REX_X | REX_B))))
        ret = 0;
       q = REX_PREFIX;
     }
@@ -1238,10 +1239,9 @@ md_begin ()
   reg_hash = hash_new ();
   {
     const reg_entry *regtab;
+    unsigned int regtab_size = i386_regtab_size;
 
-    for (regtab = i386_regtab;
-        regtab < i386_regtab + sizeof (i386_regtab) / sizeof (i386_regtab[0]);
-        regtab++)
+    for (regtab = i386_regtab; regtab_size--; regtab++)
       {
        hash_err = hash_insert (reg_hash, regtab->reg_name, (PTR) regtab);
        if (hash_err)
@@ -1296,6 +1296,7 @@ md_begin ()
 #endif
     digit_chars['-'] = '-';
     mnemonic_chars['-'] = '-';
+    mnemonic_chars['.'] = '.';
     identifier_chars['_'] = '_';
     identifier_chars['.'] = '.';
 
@@ -1355,10 +1356,10 @@ pi (char *line, i386_insn *x)
   fprintf (stdout, "  sib:  base %x  index %x  scale %x\n",
           x->sib.base, x->sib.index, x->sib.scale);
   fprintf (stdout, "  rex: 64bit %x  extX %x  extY %x  extZ %x\n",
-          (x->rex & REX_MODE64) != 0,
-          (x->rex & REX_EXTX) != 0,
-          (x->rex & REX_EXTY) != 0,
-          (x->rex & REX_EXTZ) != 0);
+          (x->rex & REX_W) != 0,
+          (x->rex & REX_R) != 0,
+          (x->rex & REX_X) != 0,
+          (x->rex & REX_B) != 0);
   for (i = 0; i < x->operands; i++)
     {
       fprintf (stdout, "    #%d:  ", i + 1);
@@ -1766,7 +1767,7 @@ md_assemble (line)
       /* Undo SYSV386_COMPAT brokenness when in Intel mode.  See i386.h  */
       if (SYSV386_COMPAT
          && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
-       i.tm.base_opcode ^= FloatR;
+       i.tm.base_opcode ^= Opcode_FloatR;
 
       /* Zap movzx and movsx suffix.  The suffix may have been set from
         "word ptr" or "byte ptr" on the source operand, but we'll use
@@ -1880,7 +1881,7 @@ md_assemble (line)
     }
 
   if ((i.tm.opcode_modifier & Rex64) != 0)
-    i.rex |= REX_MODE64;
+    i.rex |= REX_W;
 
   /* For 8 bit registers we need an empty rex prefix.  Also if the
      instruction already has a prefix, we need to convert old
@@ -2623,6 +2624,15 @@ match_template (void)
            continue;
          break;
        case 2:
+         /* xchg %eax, %eax is a special case. It is an aliase for nop
+            only in 32bit mode and we can use opcode 0x90.  In 64bit
+            mode, we can't use 0x90 for xchg %eax, %eax since it should
+            zero-extend %eax to %rax.  */
+         if (flag_code == CODE_64BIT
+             && t->base_opcode == 0x90
+             && i.types [0] == (Acc | Reg32)
+             && i.types [1] == (Acc | Reg32))
+           continue;
        case 3:
        case 4:
          overlap1 = i.types[1] & operand_types[1];
@@ -2657,7 +2667,14 @@ match_template (void)
                }
              /* found_reverse_match holds which of D or FloatDR
                 we've found.  */
-             found_reverse_match = t->opcode_modifier & (D | FloatDR);
+             if ((t->opcode_modifier & D))
+               found_reverse_match = Opcode_D;
+             else if ((t->opcode_modifier & FloatD))
+               found_reverse_match = Opcode_FloatD;
+             else
+               found_reverse_match = 0;
+             if ((t->opcode_modifier & FloatR))
+               found_reverse_match |= Opcode_FloatR;
            }
          else
            {
@@ -2969,8 +2986,8 @@ process_suffix (void)
          if (i.operands != 2
              || i.types [0] != (Acc | Reg64)
              || i.types [1] != (Acc | Reg64)
-             || strcmp (i.tm.name, "xchg") != 0)
-         i.rex |= REX_MODE64;
+             || i.tm.base_opcode != 0x90)
+           i.rex |= REX_W;
        }
 
       /* Size floating point instruction.  */
@@ -3262,14 +3279,47 @@ process_operands (void)
      is converted into xor %reg, %reg.  */
   if (i.tm.opcode_modifier & regKludge)
     {
-      unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1;
-      /* Pretend we saw the extra register operand.  */
-      assert (i.reg_operands == 1
-             && i.op[first_reg_op + 1].regs == 0);
-      i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs;
-      i.types[first_reg_op + 1] = i.types[first_reg_op];
-      i.operands++;
-      i.reg_operands++;
+       if ((i.tm.cpu_flags & CpuSSE4_1))
+        {
+          /* The first operand in instruction blendvpd, blendvps and
+             pblendvb in SSE4.1 is implicit and must be xmm0.  */
+          assert (i.operands == 3
+                  && i.reg_operands >= 2
+                  && i.types[0] == RegXMM);
+          if (i.op[0].regs->reg_num != 0)
+            {
+              if (intel_syntax)
+                as_bad (_("the last operand of `%s' must be `%sxmm0'"),
+                        i.tm.name, register_prefix);
+              else
+                as_bad (_("the first operand of `%s' must be `%sxmm0'"),
+                        i.tm.name, register_prefix);
+              return 0;
+            }
+          i.op[0] = i.op[1];
+          i.op[1] = i.op[2];
+          i.types[0] = i.types[1];
+          i.types[1] = i.types[2];
+          i.operands--;
+          i.reg_operands--;
+
+          /* We need to adjust fields in i.tm since they are used by
+             build_modrm_byte.  */
+          i.tm.operand_types [0] = i.tm.operand_types [1];
+          i.tm.operand_types [1] = i.tm.operand_types [2];
+          i.tm.operands--;
+        }
+       else
+        {
+          unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1;
+          /* Pretend we saw the extra register operand.  */
+          assert (i.reg_operands == 1
+                  && i.op[first_reg_op + 1].regs == 0);
+          i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs;
+          i.types[first_reg_op + 1] = i.types[first_reg_op];
+          i.operands++;
+          i.reg_operands++;
+        }
     }
 
   if (i.tm.opcode_modifier & ShortForm)
@@ -3284,7 +3334,7 @@ process_operands (void)
            }
          i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
          if ((i.op[0].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_EXTZ;
+           i.rex |= REX_B;
        }
       else
        {
@@ -3293,7 +3343,7 @@ process_operands (void)
          /* Register goes in low 3 bits of opcode.  */
          i.tm.base_opcode |= i.op[op].regs->reg_num;
          if ((i.op[op].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_EXTZ;
+           i.rex |= REX_B;
          if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0)
            {
              /* Warn about some common errors, but press on regardless.
@@ -3322,7 +3372,7 @@ process_operands (void)
 
       default_seg = build_modrm_byte ();
     }
-  else if ((i.tm.base_opcode & ~(D | W)) == MOV_AX_DISP32)
+  else if ((i.tm.base_opcode & ~0x3) == MOV_AX_DISP32)
     {
       default_seg = &ds;
     }
@@ -3397,29 +3447,29 @@ build_modrm_byte (void)
         destination operand, then we assume the source operand may
         sometimes be a memory operand and so we need to store the
         destination in the i.rm.reg field.  */
-      if ((i.tm.operand_types[dest] & AnyMem) == 0)
+      if ((i.tm.operand_types[dest] & (AnyMem | RegMem)) == 0)
        {
          i.rm.reg = i.op[dest].regs->reg_num;
          i.rm.regmem = i.op[source].regs->reg_num;
          if ((i.op[dest].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_EXTX;
+           i.rex |= REX_R;
          if ((i.op[source].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_EXTZ;
+           i.rex |= REX_B;
        }
       else
        {
          i.rm.reg = i.op[source].regs->reg_num;
          i.rm.regmem = i.op[dest].regs->reg_num;
          if ((i.op[dest].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_EXTZ;
+           i.rex |= REX_B;
          if ((i.op[source].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_EXTX;
+           i.rex |= REX_R;
        }
-      if (flag_code != CODE_64BIT && (i.rex & (REX_EXTX | REX_EXTZ)))
+      if (flag_code != CODE_64BIT && (i.rex & (REX_R | REX_B)))
        {
          if (!((i.types[0] | i.types[1]) & Control))
            abort ();
-         i.rex &= ~(REX_EXTX | REX_EXTZ);
+         i.rex &= ~(REX_R | REX_B);
          add_prefix (LOCK_PREFIX_OPCODE);
        }
     }
@@ -3481,7 +3531,7 @@ build_modrm_byte (void)
                  else
                    i.types[op] |= Disp32S;
                  if ((i.index_reg->reg_flags & RegRex) != 0)
-                   i.rex |= REX_EXTY;
+                   i.rex |= REX_X;
                }
            }
          /* RIP addressing for 64bit mode.  */
@@ -3534,7 +3584,7 @@ build_modrm_byte (void)
 
              i.rm.regmem = i.base_reg->reg_num;
              if ((i.base_reg->reg_flags & RegRex) != 0)
-               i.rex |= REX_EXTZ;
+               i.rex |= REX_B;
              i.sib.base = i.base_reg->reg_num;
              /* x86-64 ignores REX prefix bit here to avoid decoder
                 complications.  */
@@ -3571,7 +3621,7 @@ build_modrm_byte (void)
                  i.sib.index = i.index_reg->reg_num;
                  i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
                  if ((i.index_reg->reg_flags & RegRex) != 0)
-                   i.rex |= REX_EXTY;
+                   i.rex |= REX_X;
                }
 
              if (i.disp_operands
@@ -3619,13 +3669,13 @@ build_modrm_byte (void)
            {
              i.rm.regmem = i.op[op].regs->reg_num;
              if ((i.op[op].regs->reg_flags & RegRex) != 0)
-               i.rex |= REX_EXTZ;
+               i.rex |= REX_B;
            }
          else
            {
              i.rm.reg = i.op[op].regs->reg_num;
              if ((i.op[op].regs->reg_flags & RegRex) != 0)
-               i.rex |= REX_EXTX;
+               i.rex |= REX_R;
            }
 
          /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we
@@ -3878,11 +3928,10 @@ output_insn (void)
       unsigned char *q;
       unsigned int prefix;
 
-      /* All opcodes on i386 have either 1 or 2 bytes.  Supplemental
-        Streaming SIMD extensions 3 Instructions have 3 bytes.  We may
-        use one more higher byte to specify a prefix the instruction
-        requires.  */
-      if ((i.tm.cpu_flags & CpuSSSE3) != 0)
+      /* All opcodes on i386 have either 1 or 2 bytes.  SSSE3 and
+        SSE4.1 instructions have 3 bytes.  We may use one more higher
+        byte to specify a prefix the instruction requires.  */
+      if ((i.tm.cpu_flags & (CpuSSSE3 | CpuSSE4_1)) != 0)
        {
          if (i.tm.base_opcode & 0xff000000)
            {
@@ -3923,7 +3972,7 @@ output_insn (void)
        }
       else
        {
-         if ((i.tm.cpu_flags & CpuSSSE3) != 0)
+         if ((i.tm.cpu_flags & (CpuSSSE3 | CpuSSE4_1)) != 0)
            {
              p = frag_more (3);
              *p++ = (i.tm.base_opcode >> 16) & 0xff;
@@ -5786,7 +5835,7 @@ parse_register (char *reg_string, char **end_op)
 
          know (e->X_op == O_register);
          know (e->X_add_number >= 0
-               && (valueT) e->X_add_number < ARRAY_SIZE (i386_regtab));
+               && (valueT) e->X_add_number < i386_regtab_size);
          r = i386_regtab + e->X_add_number;
          *end_op = input_line_pointer;
        }
This page took 0.031059 seconds and 4 git commands to generate.