[v6,5/5] x86: replace adhoc (partly wrong) ambiguous operand checking for MOVSX/MOVZX

Message ID 5f0c33ba-6af8-05e2-f1b8-82e5b10b0a68@suse.com
State New
Headers show
Series
  • x86: operand size handling improvements
Related show

Commit Message

Jan Beulich Feb. 12, 2020, 10:06 a.m.
For these to get treatment consistent with other operand size checking
the special logic shouldn't live in md_assemble(), but process_suffix().
And there's more logic involved than simply zapping the suffix, in
particular to enforce the general "suffix trumps register size" rule in
AT&T mode. The cases where behavior is being corrected can be seen from
the testcase adjustments (as mentioned in the commit introducing these
tests some cases had wrong expectations at that point, but it seemed
better to separate testcase introduction from actual code changes).

Note however that MOVS[BW]* and MOVZ[BW]* still won't be fully
consistent, due to the objection to fold MOVS* templates just like was
done for MOVZ* in c07315e0c6 ("x86: allow suffix-less movzw and 64-bit
movzb").

Note further that the assembler change points out (and this patch fixes)
a wrong Intel syntax test introduced by bc31405ebb2c ("x86-64: Properly
encode and decode movsxd"): When source code specifies a 16-bit
destination register, disassembly expectations shouldn't have been to
find a 32-bit one.

gas/
2020-02-XX  Jan Beulich  <jbeulich@suse.com>

	PR gas/25438
	* config/tc-i386.c (md_assemble): Move movsx/movzx special
	casing ...
	(process_suffix): ... here. Consider just the first operand
	initially.
	(check_long_reg): Drop opcode 0x63 special case again.
	* testsuite/gas/i386/movx16.l, testsuite/gas/i386/movx32.l,
	testsuite/gas/i386/movx64.l, testsuite/gas/i386/noreg16.l,
	testsuite/gas/i386/noreg32.l, testsuite/gas/i386/noreg64.l,
	testsuite/gas/i386/x86-64-movsxd-intel.d,
	testsuite/gas/i386/x86-64-movsxd.d: Adjust expectations.

opcodes/
2020-02-XX  Jan Beulich  <jbeulich@suse.com>

	PR gas/25438
	* i386-opc.tbl (movsx): Fold patterns. Also allow Reg32 as
	destination for Cpu64-only variant.
	(movsxd): Also allow Reg32 as destination. Drop Rex64.
	(movzx): Fold patterns.
	* i386-tbl.h: Re-generate.
---
v6: Move to end of series.
v5: Re-base.
v4: Re-base.
v3: Re-base.
v2: Undo No_lSuf addition to MOVSXD template. Drop bogus / pointless
    !i.tm.opcode_modifier.rex64 part of conditional in md_assemble().
    Re-base over changes earlier in the series.

Comments

H.J. Lu Feb. 12, 2020, 12:50 p.m. | #1
On Wed, Feb 12, 2020 at 2:06 AM Jan Beulich <jbeulich@suse.com> wrote:
>

> For these to get treatment consistent with other operand size checking

> the special logic shouldn't live in md_assemble(), but process_suffix().

> And there's more logic involved than simply zapping the suffix, in

> particular to enforce the general "suffix trumps register size" rule in

> AT&T mode. The cases where behavior is being corrected can be seen from

> the testcase adjustments (as mentioned in the commit introducing these

> tests some cases had wrong expectations at that point, but it seemed

> better to separate testcase introduction from actual code changes).

>

> Note however that MOVS[BW]* and MOVZ[BW]* still won't be fully

> consistent, due to the objection to fold MOVS* templates just like was

> done for MOVZ* in c07315e0c6 ("x86: allow suffix-less movzw and 64-bit

> movzb").

>

> Note further that the assembler change points out (and this patch fixes)

> a wrong Intel syntax test introduced by bc31405ebb2c ("x86-64: Properly

> encode and decode movsxd"): When source code specifies a 16-bit

> destination register, disassembly expectations shouldn't have been to

> find a 32-bit one.

>

> gas/

> 2020-02-XX  Jan Beulich  <jbeulich@suse.com>

>

>         PR gas/25438

>         * config/tc-i386.c (md_assemble): Move movsx/movzx special

>         casing ...

>         (process_suffix): ... here. Consider just the first operand

>         initially.

>         (check_long_reg): Drop opcode 0x63 special case again.

>         * testsuite/gas/i386/movx16.l, testsuite/gas/i386/movx32.l,

>         testsuite/gas/i386/movx64.l, testsuite/gas/i386/noreg16.l,

>         testsuite/gas/i386/noreg32.l, testsuite/gas/i386/noreg64.l,

>         testsuite/gas/i386/x86-64-movsxd-intel.d,

>         testsuite/gas/i386/x86-64-movsxd.d: Adjust expectations.

>

> opcodes/

> 2020-02-XX  Jan Beulich  <jbeulich@suse.com>

>

>         PR gas/25438

>         * i386-opc.tbl (movsx): Fold patterns. Also allow Reg32 as

>         destination for Cpu64-only variant.

>         (movsxd): Also allow Reg32 as destination. Drop Rex64.

>         (movzx): Fold patterns.

>         * i386-tbl.h: Re-generate.


Please combine patch 4 and patch 5 into a single patch.   But  we need
to first change incorrect register size from warning to error.

-- 
H.J.
Jan Beulich Feb. 12, 2020, 1:19 p.m. | #2
On 12.02.2020 13:50, H.J. Lu wrote:
> On Wed, Feb 12, 2020 at 2:06 AM Jan Beulich <jbeulich@suse.com> wrote:

>>

>> For these to get treatment consistent with other operand size checking

>> the special logic shouldn't live in md_assemble(), but process_suffix().

>> And there's more logic involved than simply zapping the suffix, in

>> particular to enforce the general "suffix trumps register size" rule in

>> AT&T mode. The cases where behavior is being corrected can be seen from

>> the testcase adjustments (as mentioned in the commit introducing these

>> tests some cases had wrong expectations at that point, but it seemed

>> better to separate testcase introduction from actual code changes).

>>

>> Note however that MOVS[BW]* and MOVZ[BW]* still won't be fully

>> consistent, due to the objection to fold MOVS* templates just like was

>> done for MOVZ* in c07315e0c6 ("x86: allow suffix-less movzw and 64-bit

>> movzb").

>>

>> Note further that the assembler change points out (and this patch fixes)

>> a wrong Intel syntax test introduced by bc31405ebb2c ("x86-64: Properly

>> encode and decode movsxd"): When source code specifies a 16-bit

>> destination register, disassembly expectations shouldn't have been to

>> find a 32-bit one.

>>

>> gas/

>> 2020-02-XX  Jan Beulich  <jbeulich@suse.com>

>>

>>         PR gas/25438

>>         * config/tc-i386.c (md_assemble): Move movsx/movzx special

>>         casing ...

>>         (process_suffix): ... here. Consider just the first operand

>>         initially.

>>         (check_long_reg): Drop opcode 0x63 special case again.

>>         * testsuite/gas/i386/movx16.l, testsuite/gas/i386/movx32.l,

>>         testsuite/gas/i386/movx64.l, testsuite/gas/i386/noreg16.l,

>>         testsuite/gas/i386/noreg32.l, testsuite/gas/i386/noreg64.l,

>>         testsuite/gas/i386/x86-64-movsxd-intel.d,

>>         testsuite/gas/i386/x86-64-movsxd.d: Adjust expectations.

>>

>> opcodes/

>> 2020-02-XX  Jan Beulich  <jbeulich@suse.com>

>>

>>         PR gas/25438

>>         * i386-opc.tbl (movsx): Fold patterns. Also allow Reg32 as

>>         destination for Cpu64-only variant.

>>         (movsxd): Also allow Reg32 as destination. Drop Rex64.

>>         (movzx): Fold patterns.

>>         * i386-tbl.h: Re-generate.

> 

> Please combine patch 4 and patch 5 into a single patch.


As indicated before, I'll be fine doing so for committing, but I
don't think it should be combined any earlier (for making review
harder). Please clarify whether your response is meant to indicate
"Okay when folded".

>   But  we need

> to first change incorrect register size from warning to error.


We did already, didn't we, by adjusting check_{byte,word,long}_reg()?

Jan
H.J. Lu Feb. 12, 2020, 1:28 p.m. | #3
On Wed, Feb 12, 2020 at 5:19 AM Jan Beulich <jbeulich@suse.com> wrote:
>

> On 12.02.2020 13:50, H.J. Lu wrote:

> > On Wed, Feb 12, 2020 at 2:06 AM Jan Beulich <jbeulich@suse.com> wrote:

> >>

> >> For these to get treatment consistent with other operand size checking

> >> the special logic shouldn't live in md_assemble(), but process_suffix().

> >> And there's more logic involved than simply zapping the suffix, in

> >> particular to enforce the general "suffix trumps register size" rule in

> >> AT&T mode. The cases where behavior is being corrected can be seen from

> >> the testcase adjustments (as mentioned in the commit introducing these

> >> tests some cases had wrong expectations at that point, but it seemed

> >> better to separate testcase introduction from actual code changes).

> >>

> >> Note however that MOVS[BW]* and MOVZ[BW]* still won't be fully

> >> consistent, due to the objection to fold MOVS* templates just like was

> >> done for MOVZ* in c07315e0c6 ("x86: allow suffix-less movzw and 64-bit

> >> movzb").

> >>

> >> Note further that the assembler change points out (and this patch fixes)

> >> a wrong Intel syntax test introduced by bc31405ebb2c ("x86-64: Properly

> >> encode and decode movsxd"): When source code specifies a 16-bit

> >> destination register, disassembly expectations shouldn't have been to

> >> find a 32-bit one.

> >>

> >> gas/

> >> 2020-02-XX  Jan Beulich  <jbeulich@suse.com>

> >>

> >>         PR gas/25438

> >>         * config/tc-i386.c (md_assemble): Move movsx/movzx special

> >>         casing ...

> >>         (process_suffix): ... here. Consider just the first operand

> >>         initially.

> >>         (check_long_reg): Drop opcode 0x63 special case again.

> >>         * testsuite/gas/i386/movx16.l, testsuite/gas/i386/movx32.l,

> >>         testsuite/gas/i386/movx64.l, testsuite/gas/i386/noreg16.l,

> >>         testsuite/gas/i386/noreg32.l, testsuite/gas/i386/noreg64.l,

> >>         testsuite/gas/i386/x86-64-movsxd-intel.d,

> >>         testsuite/gas/i386/x86-64-movsxd.d: Adjust expectations.

> >>

> >> opcodes/

> >> 2020-02-XX  Jan Beulich  <jbeulich@suse.com>

> >>

> >>         PR gas/25438

> >>         * i386-opc.tbl (movsx): Fold patterns. Also allow Reg32 as

> >>         destination for Cpu64-only variant.

> >>         (movsxd): Also allow Reg32 as destination. Drop Rex64.

> >>         (movzx): Fold patterns.

> >>         * i386-tbl.h: Re-generate.

> >

> > Please combine patch 4 and patch 5 into a single patch.

>

> As indicated before, I'll be fine doing so for committing, but I

> don't think it should be combined any earlier (for making review

> harder). Please clarify whether your response is meant to indicate

> "Okay when folded".


It is harder to review when tests are moved and changed later.
Please squash the second patch into the first one just for review
purpose.

> >   But  we need

> > to first change incorrect register size from warning to error.

>

> We did already, didn't we, by adjusting check_{byte,word,long}_reg()?

>


That is good to know.

-- 
H.J.

Patch

--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -4381,22 +4381,6 @@  md_assemble (char *line)
        : as_bad) (_("SSE instruction `%s' is used"), i.tm.name);
     }
 
-  /* Zap movzx and movsx suffix.  The suffix has been set from
-     "word ptr" or "byte ptr" on the source operand in Intel syntax
-     or extracted from mnemonic in AT&T syntax.  But we'll use
-     the destination register to choose the suffix for encoding.  */
-  if ((i.tm.base_opcode & ~9) == 0x0fb6)
-    {
-      /* In Intel syntax, there must be a suffix.  In AT&T syntax, if
-	 there is no suffix, the default will be byte extension.  */
-      if (i.reg_operands != 2
-	  && !i.suffix
-	  && intel_syntax)
-	as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
-
-      i.suffix = 0;
-    }
-
   if (i.tm.opcode_modifier.fwait)
     if (!add_prefix (FWAIT_OPCODE))
       return;
@@ -6313,6 +6297,15 @@  process_suffix (void)
   else if (i.reg_operands
 	   && (i.operands > 1 || i.types[0].bitfield.class == Reg))
     {
+      unsigned int numop = i.operands;
+
+      /* movsx/movzx want only their source operand considered here, for the
+	 ambiguity checking below.  The suffix will be replaced afterwards
+	 to represent the destination (register).  */
+      if (((i.tm.base_opcode | 8) == 0xfbe && i.tm.opcode_modifier.w)
+	  || (i.tm.base_opcode == 0x63 && i.tm.cpu_flags.bitfield.cpu64))
+	--i.operands;
+
       /* If there's no instruction mnemonic suffix we try to invent one
 	 based on GPR operands.  */
       if (!i.suffix)
@@ -6341,6 +6334,13 @@  process_suffix (void)
 		  continue;
 		break;
 	      }
+
+	  /* As an exception, movsx/movzx with a word register destination
+	     silently default to a byte source in AT&T mode, as their word
+	     memory source case isn't really useful.  */
+	  if ((i.tm.base_opcode | 8) == 0xfbe && i.tm.opcode_modifier.w
+	      && !i.suffix && !intel_syntax && i.types[1].bitfield.word)
+	    i.suffix = BYTE_MNEM_SUFFIX;
 	}
       else if (i.suffix == BYTE_MNEM_SUFFIX)
 	{
@@ -6387,6 +6387,9 @@  process_suffix (void)
 	;
       else
 	abort ();
+
+      /* Undo the movsx/movzx change done above.  */
+      i.operands = numop;
     }
   else if (i.tm.opcode_modifier.defaultsize && !i.suffix)
     {
@@ -6540,6 +6543,10 @@  process_suffix (void)
 
 	  if (i.tm.opcode_modifier.floatmf)
 	    i.suffix = SHORT_MNEM_SUFFIX;
+	  else if ((i.tm.base_opcode | 8) == 0xfbe
+		   || (i.tm.base_opcode == 0x63
+		       && i.tm.cpu_flags.bitfield.cpu64))
+	    /* handled below */;
 	  else if (evex)
 	    i.tm.opcode_modifier.evex = evex;
 	  else if (flag_code == CODE_16BIT)
@@ -6551,6 +6558,32 @@  process_suffix (void)
 	}
     }
 
+  if ((i.tm.base_opcode | 8) == 0xfbe
+      || (i.tm.base_opcode == 0x63 && i.tm.cpu_flags.bitfield.cpu64))
+    {
+      /* In Intel syntax, movsx/movzx must have a "suffix" (checked above).
+	 In AT&T syntax, if there is no suffix (warned about above), the default
+	 will be byte extension.  */
+      if (i.tm.opcode_modifier.w && i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
+	i.tm.base_opcode |= 1;
+
+      /* For further processing, the suffix should represent the destination
+	 (register).  This is already the case when one was used with
+	 mov[sz][bw]*, but we need to replace it for mov[sz]x, or if there was
+	 no suffix to begin with.  */
+      if (i.tm.opcode_modifier.w || i.tm.base_opcode == 0x63 || !i.suffix)
+	{
+	  if (i.types[1].bitfield.word)
+	    i.suffix = WORD_MNEM_SUFFIX;
+	  else if (i.types[1].bitfield.qword)
+	    i.suffix = QWORD_MNEM_SUFFIX;
+	  else
+	    i.suffix = LONG_MNEM_SUFFIX;
+
+	  i.tm.opcode_modifier.w = 0;
+	}
+    }
+
   if (!i.tm.opcode_modifier.modrm && i.reg_operands && i.tm.operands < 3)
     i.short_form = (i.tm.operand_types[0].bitfield.class == Reg)
 		   != (i.tm.operand_types[1].bitfield.class == Reg);
@@ -6757,9 +6790,7 @@  check_long_reg (void)
 	     && i.tm.operand_types[op].bitfield.dword)
       {
 	if (intel_syntax
-	    && (i.tm.opcode_modifier.toqword
-		/* Also convert to QWORD for MOVSXD.  */
-		|| i.tm.base_opcode == 0x63)
+	    && i.tm.opcode_modifier.toqword
 	    && i.types[0].bitfield.class != RegSIMD)
 	  {
 	    /* Convert to QWORD.  We want REX byte. */
--- a/gas/testsuite/gas/i386/movx16.l
+++ b/gas/testsuite/gas/i386/movx16.l
@@ -6,7 +6,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movsx	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 0FBEC8[ 	]+movsx	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movsx	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 0FBFC8[ 	]+movsx	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movsx	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 660FBEC8[ 	]+movsx	%al, %ecx
@@ -30,7 +30,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movsxw	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 0FBFC8[ 	]+movsxw	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%al, %ecx
@@ -103,7 +103,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzx	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 0FB6C8[ 	]+movzx	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movzx	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 0FB7C8[ 	]+movzx	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzx	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 660FB6C8[ 	]+movzx	%al, %ecx
@@ -127,7 +127,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movzxw	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 0FB7C8[ 	]+movzxw	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%al, %ecx
@@ -154,7 +154,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 660FB6C8[ 	]+movzbw	%al, %ecx
+[ 	]*[1-9][0-9]*[ 	]+movzbw	%al, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%ax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%eax, %ecx
 [ 	]*[1-9][0-9]*[ 	]*
@@ -162,7 +162,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%ax, %cl
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 0FB6C8[ 	]+movzbl	%al, %cx
+[ 	]*[1-9][0-9]*[ 	]+movzbl	%al, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
--- a/gas/testsuite/gas/i386/movx32.l
+++ b/gas/testsuite/gas/i386/movx32.l
@@ -6,7 +6,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movsx	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 660FBEC8[ 	]+movsx	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movsx	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 660FBFC8[ 	]+movsx	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movsx	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 0FBEC8[ 	]+movsx	%al, %ecx
@@ -30,7 +30,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movsxw	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 660FBFC8[ 	]+movsxw	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%al, %ecx
@@ -103,7 +103,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzx	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 660FB6C8[ 	]+movzx	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movzx	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 660FB7C8[ 	]+movzx	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzx	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 0FB6C8[ 	]+movzx	%al, %ecx
@@ -127,7 +127,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movzxw	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 660FB7C8[ 	]+movzxw	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%al, %ecx
@@ -154,7 +154,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 0FB6C8[ 	]+movzbw	%al, %ecx
+[ 	]*[1-9][0-9]*[ 	]+movzbw	%al, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%ax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%eax, %ecx
 [ 	]*[1-9][0-9]*[ 	]*
@@ -162,7 +162,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%ax, %cl
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 660FB6C8[ 	]+movzbl	%al, %cx
+[ 	]*[1-9][0-9]*[ 	]+movzbl	%al, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
--- a/gas/testsuite/gas/i386/movx64.l
+++ b/gas/testsuite/gas/i386/movx64.l
@@ -7,13 +7,13 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movsx	%rax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 660FBEC8[ 	]+movsx	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movsx	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 660FBFC8[ 	]+movsx	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movsx	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movsx	%rax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 0FBEC8[ 	]+movsx	%al, %ecx
 [ 	]*[1-9][0-9]* \?\?\?\? 0FBFC8[ 	]+movsx	%ax, %ecx
-[ 	]*[1-9][0-9]*[ 	]+movsx	%eax, %ecx
+[ 	]*[1-9][0-9]* \?\?\?\? 63C8[ 	]+movsx	%eax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movsx	%rax, %ecx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 480FBEC8[ 	]+movsx	%al, %rcx
@@ -47,7 +47,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%rax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movsxw	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 660FBFC8[ 	]+movsxw	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movsxw	%rax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
@@ -73,7 +73,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movsxl	%al, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movsxl	%ax, %ecx
-[ 	]*[1-9][0-9]*[ 	]+movsxl	%eax, %ecx
+[ 	]*[1-9][0-9]* \?\?\?\? 63C8[ 	]+movsxl	%eax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movsxl	%rax, %ecx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movsxl	%al, %rcx
@@ -248,7 +248,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzx	%rax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]* \?\?\?\? 660FB6C8[ 	]+movzx	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movzx	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 660FB7C8[ 	]+movzx	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzx	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzx	%rax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
@@ -288,7 +288,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%rax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%al, %cx
-[ 	]*[1-9][0-9]*[ 	]+movzxw	%ax, %cx
+[ 	]*[1-9][0-9]* \?\?\?\? 660FB7C8[ 	]+movzxw	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzxw	%rax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
@@ -372,12 +372,12 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%rax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 0FB6C8[ 	]+movzbw	%al, %ecx
+[ 	]*[1-9][0-9]*[ 	]+movzbw	%al, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%ax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%eax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%rax, %ecx
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 480FB6C8[ 	]+movzbw	%al, %rcx
+[ 	]*[1-9][0-9]*[ 	]+movzbw	%al, %rcx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%ax, %rcx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%eax, %rcx
 [ 	]*[1-9][0-9]*[ 	]+movzbw	%rax, %rcx
@@ -387,7 +387,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%rax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 660FB6C8[ 	]+movzbl	%al, %cx
+[ 	]*[1-9][0-9]*[ 	]+movzbl	%al, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%rax, %cx
@@ -397,7 +397,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%eax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%rax, %ecx
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 480FB6C8[ 	]+movzbl	%al, %rcx
+[ 	]*[1-9][0-9]*[ 	]+movzbl	%al, %rcx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%ax, %rcx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%eax, %rcx
 [ 	]*[1-9][0-9]*[ 	]+movzbl	%rax, %rcx
@@ -407,12 +407,12 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzbq	%eax, %cl
 [ 	]*[1-9][0-9]*[ 	]+movzbq	%rax, %cl
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 660FB6C8[ 	]+movzbq	%al, %cx
+[ 	]*[1-9][0-9]*[ 	]+movzbq	%al, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbq	%ax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbq	%eax, %cx
 [ 	]*[1-9][0-9]*[ 	]+movzbq	%rax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
-[ 	]*[1-9][0-9]* \?\?\?\? 0FB6C8[ 	]+movzbq	%al, %ecx
+[ 	]*[1-9][0-9]*[ 	]+movzbq	%al, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbq	%ax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbq	%eax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzbq	%rax, %ecx
@@ -458,7 +458,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzwl	%rax, %ecx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movzwl	%al, %rcx
-[ 	]*[1-9][0-9]* \?\?\?\? 480FB7C8[ 	]+movzwl	%ax, %rcx
+[ 	]*[1-9][0-9]*[ 	]+movzwl	%ax, %rcx
 [ 	]*[1-9][0-9]*[ 	]+movzwl	%eax, %rcx
 [ 	]*[1-9][0-9]*[ 	]+movzwl	%rax, %rcx
 [ 	]*[1-9][0-9]*[ 	]*
@@ -473,7 +473,7 @@ 
 [ 	]*[1-9][0-9]*[ 	]+movzwq	%rax, %cx
 [ 	]*[1-9][0-9]*[ 	]*
 [ 	]*[1-9][0-9]*[ 	]+movzwq	%al, %ecx
-[ 	]*[1-9][0-9]* \?\?\?\? 0FB7C8[ 	]+movzwq	%ax, %ecx
+[ 	]*[1-9][0-9]*[ 	]+movzwq	%ax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzwq	%eax, %ecx
 [ 	]*[1-9][0-9]*[ 	]+movzwq	%rax, %ecx
 [ 	]*[1-9][0-9]*[ 	]*
--- a/gas/testsuite/gas/i386/noreg16.l
+++ b/gas/testsuite/gas/i386/noreg16.l
@@ -56,6 +56,8 @@ 
 .*:[1-9][0-9]*: Warning: .* `mov'
 .*:[1-9][0-9]*: Warning: .* `movs'
 .*:[1-9][0-9]*: Warning: .* `movs'
+.*:[1-9][0-9]*: Warning: .* `movsx'
+.*:[1-9][0-9]*: Warning: .* `movzx'
 .*:[1-9][0-9]*: Warning: .* `mul'
 .*:[1-9][0-9]*: Warning: .* `neg'
 .*:[1-9][0-9]*: Warning: .* `nop'
--- a/gas/testsuite/gas/i386/noreg32.l
+++ b/gas/testsuite/gas/i386/noreg32.l
@@ -61,6 +61,8 @@ 
 .*:[1-9][0-9]*: Warning: .* `mov'
 .*:[1-9][0-9]*: Warning: .* `movs'
 .*:[1-9][0-9]*: Warning: .* `movs'
+.*:[1-9][0-9]*: Warning: .* `movsx'
+.*:[1-9][0-9]*: Warning: .* `movzx'
 .*:[1-9][0-9]*: Warning: .* `mul'
 .*:[1-9][0-9]*: Warning: .* `neg'
 .*:[1-9][0-9]*: Warning: .* `nop'
--- a/gas/testsuite/gas/i386/noreg64.l
+++ b/gas/testsuite/gas/i386/noreg64.l
@@ -67,6 +67,10 @@ 
 .*:[1-9][0-9]*: Warning: .* `mov'
 .*:[1-9][0-9]*: Warning: .* `movs'
 .*:[1-9][0-9]*: Warning: .* `movs'
+.*:[1-9][0-9]*: Warning: .* `movsx'
+.*:[1-9][0-9]*: Warning: .* `movsx'
+.*:[1-9][0-9]*: Warning: .* `movzx'
+.*:[1-9][0-9]*: Warning: .* `movzx'
 .*:[1-9][0-9]*: Warning: .* `mul'
 .*:[1-9][0-9]*: Warning: .* `neg'
 .*:[1-9][0-9]*: Warning: .* `nop'
--- a/gas/testsuite/gas/i386/x86-64-movsxd-intel.d
+++ b/gas/testsuite/gas/i386/x86-64-movsxd-intel.d
@@ -21,6 +21,6 @@  Disassembly of section .text:
  +[a-f0-9]+:	63 08                	movsxd ecx,DWORD PTR \[rax\]
  +[a-f0-9]+:	63 08                	movsxd ecx,DWORD PTR \[rax\]
  +[a-f0-9]+:	66 63 c8             	movsxd cx,eax
- +[a-f0-9]+:	63 08                	movsxd ecx,DWORD PTR \[rax\]
+ +[a-f0-9]+:	66 63 08             	movsxd cx,DWORD PTR \[rax\]
  +[a-f0-9]+:	66 63 08             	movsxd cx,DWORD PTR \[rax\]
 #pass
--- a/gas/testsuite/gas/i386/x86-64-movsxd.d
+++ b/gas/testsuite/gas/i386/x86-64-movsxd.d
@@ -20,6 +20,6 @@  Disassembly of section .text:
  +[a-f0-9]+:	63 08                	movsxd \(%rax\),%ecx
  +[a-f0-9]+:	63 08                	movsxd \(%rax\),%ecx
  +[a-f0-9]+:	66 63 c8             	movsxd %eax,%cx
- +[a-f0-9]+:	63 08                	movsxd \(%rax\),%ecx
+ +[a-f0-9]+:	66 63 08             	movsxd \(%rax\),%cx
  +[a-f0-9]+:	66 63 08             	movsxd \(%rax\),%cx
 #pass
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -132,13 +132,9 @@  movswl, 2, 0xfbf, None, 2, Cpu386, Modrm
 movsbq, 2, 0xfbe, None, 2, Cpu64, Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|Rex64, { Reg8|Byte|Unspecified|BaseIndex, Reg64 }
 movswq, 2, 0xfbf, None, 2, Cpu64, Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|Rex64, { Reg16|Word|Unspecified|BaseIndex, Reg64 }
 movslq, 2, 0x63, None, 1, Cpu64, Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|Rex64, { Reg32|Dword|Unspecified|BaseIndex, Reg64 }
-// Intel Syntax next 3 insns
-movsx, 2, 0xfbe, None, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|ATTSyntax, { Reg8|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-movsx, 2, 0xfbf, None, 2, Cpu386, Modrm|No_bSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|ATTSyntax, { Reg16|Unspecified|BaseIndex, Reg32|Reg64 }
-movsx, 2, 0x63, None, 1, Cpu64, Modrm|No_bSuf|No_wSuf|No_sSuf|No_qSuf|No_ldSuf|Rex64|ATTSyntax, { Reg32|Unspecified|BaseIndex, Reg64 }
-movsx, 2, 0xfbe, None, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|IntelSyntax, { Reg8|Byte|BaseIndex, Reg16|Reg32|Reg64 }
-movsx, 2, 0xfbf, None, 2, Cpu386, Modrm|No_bSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|IntelSyntax, { Reg16|Word|BaseIndex, Reg32|Reg64 }
-movsx, 2, 0x63, None, 1, Cpu64, Modrm|No_bSuf|No_wSuf|No_sSuf|No_qSuf|No_ldSuf|Rex64|IntelSyntax, { Reg32|Dword|BaseIndex, Reg64 }
+// Intel Syntax next 2 insns
+movsx, 2, 0xfbe, None, 2, Cpu386, W|Modrm|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Reg16|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
+movsx, 2, 0x63, None, 1, Cpu64, Modrm|No_bSuf|No_wSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg32|Unspecified|BaseIndex, Reg32|Reg64 }
 movsxd, 2, 0x63, None, 1, Cpu64, Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg32|Unspecified|BaseIndex, Reg32|Reg64 }
 movsxd, 2, 0x63, None, 1, Cpu64, Amd64|Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg32|Unspecified|BaseIndex, Reg16 }
 movsxd, 2, 0x63, None, 1, Cpu64, Intel64|Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg16|Unspecified|BaseIndex, Reg16 }
@@ -146,12 +142,9 @@  movsxd, 2, 0x63, None, 1, Cpu64, Intel64
 // Move with zero extend.
 movzb, 2, 0xfb6, None, 2, Cpu386, Modrm|No_bSuf|No_sSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
 movzw, 2, 0xfb7, None, 2, Cpu386, Modrm|No_bSuf|No_wSuf|No_sSuf|No_ldSuf, { Reg16|Word|Unspecified|BaseIndex, Reg32|Reg64 }
-// Intel Syntax next 2 insns (the 64-bit variants are not particulary
+// Intel Syntax next insn (the 64-bit variant is not particulary
 // useful since the zero extend 32->64 is implicit, but we can encode them).
-movzx, 2, 0xfb6, None, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|ATTSyntax, { Reg8|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-movzx, 2, 0xfb7, None, 2, Cpu386, Modrm|No_bSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|ATTSyntax, { Reg16|Unspecified|BaseIndex, Reg32|Reg64 }
-movzx, 2, 0xfb6, None, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|IntelSyntax, { Reg8|Byte|BaseIndex, Reg16|Reg32|Reg64 }
-movzx, 2, 0xfb7, None, 2, Cpu386, Modrm|No_bSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|IntelSyntax, { Reg16|Word|BaseIndex, Reg32|Reg64 }
+movzx, 2, 0xfb6, None, 2, Cpu386, W|Modrm|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Reg16|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
 
 // Push instructions.
 push, 1, 0x50, None, 1, CpuNo64, No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg16|Reg32 }