[binutils-gdb] x86: optimize MOVSX between accumulator regs

Jan Beulich jbeulich@sourceware.org
Fri Jan 9 07:48:51 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b689d0ea0363ffdd172a489e3d91ac1d1f1790d5

commit b689d0ea0363ffdd172a489e3d91ac1d1f1790d5
Author: Jan Beulich <jbeulich@suse.com>
Date:   Fri Jan 9 08:44:30 2026 +0100

    x86: optimize MOVSX between accumulator regs
    
    Except on the K6 CBW/CWDE/CDQE perform equally well, but are shorter to
    encode.

Diff:
---
 gas/config/tc-i386.c                        | 30 +++++++++++++++++++++++++++++
 gas/testsuite/gas/i386/optimize-2.d         |  6 ++++++
 gas/testsuite/gas/i386/optimize-2.s         | 11 +++++++++++
 gas/testsuite/gas/i386/optimize-2b.d        |  6 ++++++
 gas/testsuite/gas/i386/x86-64-optimize-3.d  | 10 ++++++++++
 gas/testsuite/gas/i386/x86-64-optimize-3.s  | 16 +++++++++++++++
 gas/testsuite/gas/i386/x86-64-optimize-3b.d | 10 ++++++++++
 opcodes/i386-opc.tbl                        | 12 ++++++------
 opcodes/i386-tbl.h                          | 12 ++++++------
 9 files changed, 101 insertions(+), 12 deletions(-)

diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 28b1f4192d8..c7b47eb7e24 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -5174,6 +5174,36 @@ optimize_encoding (void)
       i.seg[0] = NULL;
     }
 
+  if (((i.tm.opcode_space == SPACE_0F
+        && (i.tm.base_opcode | 1) == 0xbf
+        && (i.types[0].bitfield.byte
+	    ? i.types[1].bitfield.word
+	    : i.types[1].bitfield.dword))
+       || (i.tm.opcode_space == SPACE_BASE
+	   && i.tm.base_opcode == 0x63
+	   && i.types[1].bitfield.qword))
+      && i.reg_operands == 2
+      && i.op[0].regs->reg_type.bitfield.instance == Accum
+      && i.op[1].regs->reg_type.bitfield.instance == Accum
+      && (cpu_arch_tune != PROCESSOR_K6 || optimize_for_space))
+    {
+      /* Optimize: -O:
+	   movsb     %al, %ax    -> cbw
+	   movsw     %ax, %eax   -> cwde
+	   movsl     %eax, %rax  -> cdqe
+       */
+      i.tm.opcode_space = SPACE_BASE;
+      i.tm.base_opcode = 0x98;
+      i.tm.opcode_modifier.modrm = 0;
+      /* Leave the destination register in place for process_suffix() to take
+	 care of operand sizing.  This will end up as short_form encoding,
+	 with the register number being 0 (i.e. not altering the opcode).  */
+      i.reg_operands = 1;
+      i.op[0].regs = i.op[1].regs;
+      i.tm.operand_types[1].bitfield.class = ClassNone;
+      return;
+    }
+
   if (optimize_for_space
       && (i.tm.mnem_off == MN_test
           || (i.tm.base_opcode == 0xf6
diff --git a/gas/testsuite/gas/i386/optimize-2.d b/gas/testsuite/gas/i386/optimize-2.d
index 89551d19978..b9a7b0b0f4a 100644
--- a/gas/testsuite/gas/i386/optimize-2.d
+++ b/gas/testsuite/gas/i386/optimize-2.d
@@ -24,6 +24,12 @@ Disassembly of section .text:
  +[a-f0-9]+:	09 f6                	or     %esi,%esi
  +[a-f0-9]+:	87 0a                	xchg   %ecx,\(%edx\)
  +[a-f0-9]+:	87 11                	xchg   %edx,\(%ecx\)
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	98                   	cwtl
  +[a-f0-9]+:	d0 e2                	shl    \$1,%dl
  +[a-f0-9]+:	d0 e2                	shl    \$1,%dl
  +[a-f0-9]+:	66 d1 e2             	shl    \$1,%dx
diff --git a/gas/testsuite/gas/i386/optimize-2.s b/gas/testsuite/gas/i386/optimize-2.s
index 1ddaab05540..375a95a467f 100644
--- a/gas/testsuite/gas/i386/optimize-2.s
+++ b/gas/testsuite/gas/i386/optimize-2.s
@@ -22,6 +22,17 @@ _start:
 	lock xchg %ecx, (%edx)
 	lock xchg (%ecx), %edx
 
+	movsb	%al, %ax
+	movsbw	%al, %ax
+
+	movsw	%ax, %eax
+	movswl	%ax, %eax
+
+	.intel_syntax noprefix
+	movsx	ax, al
+	movsx	eax, ax
+	.att_syntax prefix
+
 	shl	$1, %dl
 	shl	%dl
 
diff --git a/gas/testsuite/gas/i386/optimize-2b.d b/gas/testsuite/gas/i386/optimize-2b.d
index 3fe8945142b..9f5c4889e3f 100644
--- a/gas/testsuite/gas/i386/optimize-2b.d
+++ b/gas/testsuite/gas/i386/optimize-2b.d
@@ -25,6 +25,12 @@ Disassembly of section .text:
  +[a-f0-9]+:	85 f6                	test   %esi,%esi
  +[a-f0-9]+:	87 0a                	xchg   %ecx,\(%edx\)
  +[a-f0-9]+:	87 11                	xchg   %edx,\(%ecx\)
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	98                   	cwtl
  +[a-f0-9]+:	00 d2                	add    %dl,%dl
  +[a-f0-9]+:	00 d2                	add    %dl,%dl
  +[a-f0-9]+:	66 01 d2             	add    %dx,%dx
diff --git a/gas/testsuite/gas/i386/x86-64-optimize-3.d b/gas/testsuite/gas/i386/x86-64-optimize-3.d
index 51513c828e4..c91503aa8f9 100644
--- a/gas/testsuite/gas/i386/x86-64-optimize-3.d
+++ b/gas/testsuite/gas/i386/x86-64-optimize-3.d
@@ -80,6 +80,16 @@ Disassembly of section .text:
  +[a-f0-9]+:	66 09 f6             	or     %si,%si
  +[a-f0-9]+:	09 ff                	or     %edi,%edi
  +[a-f0-9]+:	4d 09 c0             	or     %r8,%r8
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	48 98                	cltq
+ +[a-f0-9]+:	48 98                	cltq
+ +[a-f0-9]+:	48 98                	cltq
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	48 98                	cltq
  +[a-f0-9]+:	c5 f1 55 e9          	vandnpd %xmm1,%xmm1,%xmm5
  +[a-f0-9]+:	c5 f9 6f d1          	vmovdqa %xmm1,%xmm2
  +[a-f0-9]+:	c5 f9 6f d1          	vmovdqa %xmm1,%xmm2
diff --git a/gas/testsuite/gas/i386/x86-64-optimize-3.s b/gas/testsuite/gas/i386/x86-64-optimize-3.s
index b2cf16d05ff..4fd29aeec98 100644
--- a/gas/testsuite/gas/i386/x86-64-optimize-3.s
+++ b/gas/testsuite/gas/i386/x86-64-optimize-3.s
@@ -39,6 +39,22 @@ _start:
 	or	%edi, %edi
 	or	%r8, %r8
 
+	movsb	%al, %ax
+	movsbw	%al, %ax
+
+	movsw	%ax, %eax
+	movswl	%ax, %eax
+
+	movsl	%eax, %rax
+	movslq	%eax, %rax
+	movsxd	%eax, %rax
+
+	.intel_syntax noprefix
+	movsx	ax, al
+	movsx	eax, ax
+	movsx	rax, eax
+	.att_syntax prefix
+
 	vandnpd	%zmm1, %zmm1, %zmm5
 
 	vmovdqa32	%xmm1, %xmm2
diff --git a/gas/testsuite/gas/i386/x86-64-optimize-3b.d b/gas/testsuite/gas/i386/x86-64-optimize-3b.d
index abfc8f91781..2a8fd3a0f41 100644
--- a/gas/testsuite/gas/i386/x86-64-optimize-3b.d
+++ b/gas/testsuite/gas/i386/x86-64-optimize-3b.d
@@ -81,6 +81,16 @@ Disassembly of section .text:
  +[a-f0-9]+:	66 85 f6             	test   %si,%si
  +[a-f0-9]+:	09 ff                	or     %edi,%edi
  +[a-f0-9]+:	4d 85 c0             	test   %r8,%r8
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	48 98                	cltq
+ +[a-f0-9]+:	48 98                	cltq
+ +[a-f0-9]+:	48 98                	cltq
+ +[a-f0-9]+:	66 98                	cbtw
+ +[a-f0-9]+:	98                   	cwtl
+ +[a-f0-9]+:	48 98                	cltq
  +[a-f0-9]+:	c5 f1 55 e9          	vandnpd %xmm1,%xmm1,%xmm5
  +[a-f0-9]+:	c5 f9 6f d1          	vmovdqa %xmm1,%xmm2
  +[a-f0-9]+:	c5 f9 6f d1          	vmovdqa %xmm1,%xmm2
diff --git a/opcodes/i386-opc.tbl b/opcodes/i386-opc.tbl
index 4d247b5c7f4..63f4f31c301 100644
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -220,12 +220,12 @@ movbe, 0x60, Movbe&APX_F, D|Modrm|CheckOperandSize|No_bSuf|No_sSuf|EVexMap4, { R
 bswap, 0xfc8, i486, No_bSuf|No_wSuf|No_sSuf, { Reg32|Reg64 }
 
 // Move with sign extend.
-movsb, 0xfbe, i386, Modrm|No_bSuf|No_sSuf, { Reg8|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-movsw, 0xfbf, i386, Modrm|No_bSuf|No_wSuf|No_sSuf, { Reg16|Unspecified|BaseIndex, Reg32|Reg64 }
-movsl, 0x63, x64, Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf, { Reg32|Unspecified|BaseIndex, Reg64 }
-movsx, 0xfbe, i386, W|Modrm|No_lSuf|No_sSuf|No_qSuf, { Reg8|Reg16|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-movsx, 0x63, x64, Modrm|No_bSuf|No_wSuf|No_sSuf|No_qSuf, { Reg32|Unspecified|BaseIndex, Reg32|Reg64 }
-movsxd, 0x63, x64, Modrm|NoSuf, { Reg32|Unspecified|BaseIndex, Reg32|Reg64 }
+movsb, 0xfbe, i386, Modrm|No_bSuf|No_sSuf|Optimize, { Reg8|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
+movsw, 0xfbf, i386, Modrm|No_bSuf|No_wSuf|No_sSuf|Optimize, { Reg16|Unspecified|BaseIndex, Reg32|Reg64 }
+movsl, 0x63, x64, Modrm|No_bSuf|No_wSuf|No_lSuf|No_sSuf|Optimize, { Reg32|Unspecified|BaseIndex, Reg64 }
+movsx, 0xfbe, i386, W|Modrm|No_lSuf|No_sSuf|No_qSuf|Optimize, { Reg8|Reg16|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
+movsx, 0x63, x64, Modrm|No_bSuf|No_wSuf|No_sSuf|No_qSuf|Optimize, { Reg32|Unspecified|BaseIndex, Reg32|Reg64 }
+movsxd, 0x63, x64, Modrm|NoSuf|Optimize, { Reg32|Unspecified|BaseIndex, Reg32|Reg64 }
 movsxd, 0x63, x64, Amd64|Modrm|NoSuf, { Reg32|Unspecified|BaseIndex, Reg16 }
 movsxd, 0x63, x64, Intel64|Modrm|NoSuf, { Reg16|Unspecified|BaseIndex, Reg16 }
 
diff --git a/opcodes/i386-tbl.h b/opcodes/i386-tbl.h
index 33dee8b02d0..a97dd6487aa 100644
--- a/opcodes/i386-tbl.h
+++ b/opcodes/i386-tbl.h
@@ -214,7 +214,7 @@ static const insn_template i386_optab[] =
 	  0, 0, 0, 0, 0, 0 } } } },
   { MN_movsb, 0xbe, 2, SPACE_0F, None,
     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,
-      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
       0, 0 },
     { { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
@@ -224,7 +224,7 @@ static const insn_template i386_optab[] =
 	  0, 0, 0, 0, 0, 0 } } } },
   { MN_movsw, 0xbf, 2, SPACE_0F, None,
     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0,
-      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
       0, 0 },
     { { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
@@ -234,7 +234,7 @@ static const insn_template i386_optab[] =
 	  0, 0, 0, 0, 0, 0 } } } },
   { MN_movsl, 0x63, 2, SPACE_BASE, None,
     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
-      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
       0, 0 },
     { { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
@@ -244,7 +244,7 @@ static const insn_template i386_optab[] =
 	  0, 0, 0, 0, 0, 0 } } } },
   { MN_movsx, 0xbe, 2, SPACE_0F, None,
     { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
-      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
       0, 0 },
     { { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
@@ -254,7 +254,7 @@ static const insn_template i386_optab[] =
 	  0, 0, 0, 0, 0, 0 } } } },
   { MN_movsx, 0x63, 2, SPACE_BASE, None,
     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0,
-      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
       0, 0 },
     { { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
@@ -264,7 +264,7 @@ static const insn_template i386_optab[] =
 	  0, 0, 0, 0, 0, 0 } } } },
   { MN_movsxd, 0x63, 2, SPACE_BASE, None,
     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
-      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
       0, 0 },
     { { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },


More information about the Binutils-cvs mailing list