[binutils-gdb] x86: optimize MOVZX in a few cases
Jan Beulich
jbeulich@sourceware.org
Fri Jan 9 07:48:56 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=141a0400236ce22bd8d1839d4f92d3a3a3309fb3
commit 141a0400236ce22bd8d1839d4f92d3a3a3309fb3
Author: Jan Beulich <jbeulich@suse.com>
Date: Fri Jan 9 08:44:40 2026 +0100
x86: optimize MOVZX in a few cases
There are shorter encoding options available, so space optimization is
possible.
Diff:
---
gas/config/tc-i386.c | 63 ++++++++++++++++++++++++++++++++++
gas/testsuite/gas/i386/i386.exp | 2 ++
gas/testsuite/gas/i386/optimize-2.d | 3 ++
gas/testsuite/gas/i386/optimize-2.s | 4 +++
gas/testsuite/gas/i386/optimize-2b.d | 3 ++
gas/testsuite/gas/i386/optimize16-O2.d | 15 ++++++++
gas/testsuite/gas/i386/optimize16-Os.d | 15 ++++++++
gas/testsuite/gas/i386/optimize16.s | 10 ++++++
opcodes/i386-opc.tbl | 6 ++--
opcodes/i386-tbl.h | 6 ++--
10 files changed, 121 insertions(+), 6 deletions(-)
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index c7b47eb7e24..b317536cc60 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -5204,6 +5204,69 @@ optimize_encoding (void)
return;
}
+ if (optimize_for_space
+ && i.tm.opcode_space == SPACE_0F
+ && (i.tm.base_opcode | 1) == 0xb7
+ && i.reg_operands == 2
+ && !i.op[0].regs->reg_flags
+ && !i.op[1].regs->reg_flags
+ && (i.types[0].bitfield.byte
+ ? i.types[1].bitfield.word
+ && i.op[0].regs->reg_num < 4
+ && i.op[1].regs->reg_num == i.op[0].regs->reg_num
+ && (!i.suffix || i.suffix == WORD_MNEM_SUFFIX)
+ : i.types[1].bitfield.dword
+ && flag_code == CODE_16BIT
+ && i.op[0].regs->reg_type.bitfield.baseindex
+ && i.op[0].regs->reg_num != EBP_REG_NUM))
+ {
+ /* Optimize: -Os:
+ movzb %r8, %r16 -> mov $0, %r8h
+
+ %r8 being one of %al, %cl, %dl, or %bl, with %r16 being the
+ matching 16-bit reg.
+ */
+
+ i.tm.opcode_space = SPACE_BASE;
+ i.tm.opcode_modifier.w = 0;
+ i.reg_operands = 1;
+ if (i.types[0].bitfield.byte)
+ {
+ i.tm.base_opcode = 0xb0;
+ i.tm.opcode_modifier.modrm = 0;
+ copy_operand (1, 0);
+ i.op[1].regs += 4;
+
+ im_expressions[0].X_op = O_constant;
+ im_expressions[0].X_add_number = 0;
+ i.op[0].imms = &im_expressions[0];
+ operand_type_set (&i.types[0], 0);
+ i.types[0].bitfield.imm8 = 1;
+ i.tm.operand_types[0] = i.types[0];
+ i.tm.operand_types[0].bitfield.class = ClassNone;
+ i.imm_operands = 1;
+
+ i.suffix = 0;
+ return;
+ }
+
+ /* In 16-bit mode, optimize: -Os:
+ movzw %r16, %r32 -> lea (%r16), %r32
+
+ %r16 being one of %bx, %si, or %di.
+ */
+ i.tm.base_opcode = 0x8d;
+
+ i.base_reg = i.op[0].regs;
+ operand_type_set (&i.types[0], 0);
+ i.types[0].bitfield.baseindex = 1;
+ i.tm.operand_types[0] = i.types[0];
+ i.op[0].disps = NULL;
+ i.flags[0] = Operand_Mem;
+ i.mem_operands = 1;
+ return;
+ }
+
if (optimize_for_space
&& (i.tm.mnem_off == MN_test
|| (i.tm.base_opcode == 0xf6
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index ac9e0b31923..b52d86d6d4f 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -651,6 +651,8 @@ if [gas_32_check] then {
run_dump_test "optimize-6b"
run_list_test "optimize-7" "-I${srcdir}/$subdir -march=+noavx2 -al"
run_list_test "optimize-8" "-Os"
+ run_dump_test "optimize16-O2"
+ run_dump_test "optimize16-Os"
run_dump_test "noopt"
run_dump_test "lea-optimize"
run_dump_test "lea16-optimize"
diff --git a/gas/testsuite/gas/i386/optimize-2.d b/gas/testsuite/gas/i386/optimize-2.d
index b9a7b0b0f4a..2738b84b80d 100644
--- a/gas/testsuite/gas/i386/optimize-2.d
+++ b/gas/testsuite/gas/i386/optimize-2.d
@@ -28,8 +28,11 @@ Disassembly of section .text:
+[a-f0-9]+: 66 98 cbtw
+[a-f0-9]+: 98 cwtl
+[a-f0-9]+: 98 cwtl
+ +[a-f0-9]+: b4 00 mov \$(0x)?0,%ah
+ +[a-f0-9]+: b5 00 mov \$(0x)?0,%ch
+[a-f0-9]+: 66 98 cbtw
+[a-f0-9]+: 98 cwtl
+ +[a-f0-9]+: b6 00 mov \$(0x)?0,%dh
+[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 375a95a467f..b2b1cc112df 100644
--- a/gas/testsuite/gas/i386/optimize-2.s
+++ b/gas/testsuite/gas/i386/optimize-2.s
@@ -28,9 +28,13 @@ _start:
movsw %ax, %eax
movswl %ax, %eax
+ movzb %al, %ax
+ movzbw %cl, %cx
+
.intel_syntax noprefix
movsx ax, al
movsx eax, ax
+ movzx dx, dl
.att_syntax prefix
shl $1, %dl
diff --git a/gas/testsuite/gas/i386/optimize-2b.d b/gas/testsuite/gas/i386/optimize-2b.d
index 9f5c4889e3f..3e92acfd869 100644
--- a/gas/testsuite/gas/i386/optimize-2b.d
+++ b/gas/testsuite/gas/i386/optimize-2b.d
@@ -29,8 +29,11 @@ Disassembly of section .text:
+[a-f0-9]+: 66 98 cbtw
+[a-f0-9]+: 98 cwtl
+[a-f0-9]+: 98 cwtl
+ +[a-f0-9]+: 66 0f b6 c0 movzbw %al,%ax
+ +[a-f0-9]+: 66 0f b6 c9 movzbw %cl,%cx
+[a-f0-9]+: 66 98 cbtw
+[a-f0-9]+: 98 cwtl
+ +[a-f0-9]+: 66 0f b6 d2 movzbw %dl,%dx
+[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/optimize16-O2.d b/gas/testsuite/gas/i386/optimize16-O2.d
new file mode 100644
index 00000000000..0e59fc16ef2
--- /dev/null
+++ b/gas/testsuite/gas/i386/optimize16-O2.d
@@ -0,0 +1,15 @@
+#name: 16-bit optimized encoding with -O2
+#source: optimize16.s
+#as: -O2
+#objdump: -drwMi8086
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+: 66 0f b7 c3 movzwl %bx,%eax
+ +[a-f0-9]+: 66 0f b7 ce movzwl %si,%ecx
+ +[a-f0-9]+: 66 0f b7 d7 movzwl %di,%edx
+#pass
diff --git a/gas/testsuite/gas/i386/optimize16-Os.d b/gas/testsuite/gas/i386/optimize16-Os.d
new file mode 100644
index 00000000000..df4c97c734a
--- /dev/null
+++ b/gas/testsuite/gas/i386/optimize16-Os.d
@@ -0,0 +1,15 @@
+#name: 16-bit optimized encoding with -Os
+#source: optimize16.s
+#as: -Os
+#objdump: -drwMi8086
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+ +[a-f0-9]+: 66 8d 07 lea \(%bx\),%eax
+ +[a-f0-9]+: 66 8d 0c lea \(%si\),%ecx
+ +[a-f0-9]+: 66 8d 15 lea \(%di\),%edx
+#pass
diff --git a/gas/testsuite/gas/i386/optimize16.s b/gas/testsuite/gas/i386/optimize16.s
new file mode 100644
index 00000000000..517f887779e
--- /dev/null
+++ b/gas/testsuite/gas/i386/optimize16.s
@@ -0,0 +1,10 @@
+# Check 16-bit instructions with optimized encoding
+
+ .code16
+ .text
+_start:
+ movzw %bx, %eax
+ movzwl %si, %ecx
+ .intel_syntax noprefix
+ movzx edx, di
+ .att_syntax prefix
diff --git a/opcodes/i386-opc.tbl b/opcodes/i386-opc.tbl
index 63f4f31c301..5797a634de3 100644
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -230,11 +230,11 @@ movsxd, 0x63, x64, Amd64|Modrm|NoSuf, { Reg32|Unspecified|BaseIndex, Reg16 }
movsxd, 0x63, x64, Intel64|Modrm|NoSuf, { Reg16|Unspecified|BaseIndex, Reg16 }
// Move with zero extend.
-movzb, 0xfb6, i386, Modrm|No_bSuf|No_sSuf, { Reg8|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-movzw, 0xfb7, i386, Modrm|No_bSuf|No_wSuf|No_sSuf, { Reg16|Unspecified|BaseIndex, Reg32|Reg64 }
+movzb, 0xfb6, i386, Modrm|No_bSuf|No_sSuf|Optimize, { Reg8|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
+movzw, 0xfb7, i386, Modrm|No_bSuf|No_wSuf|No_sSuf|Optimize, { Reg16|Unspecified|BaseIndex, Reg32|Reg64 }
// The 64-bit variant is not particularly useful since the zero extend
// 32->64 is implicit, but we can encode them.
-movzx, 0xfb6, i386, W|Modrm|No_lSuf|No_sSuf|No_qSuf, { Reg8|Reg16|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
+movzx, 0xfb6, i386, W|Modrm|No_lSuf|No_sSuf|No_qSuf|Optimize, { Reg8|Reg16|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
// Push instructions.
push, 0x50, No64, ImplicitStackOp|No_bSuf|No_sSuf|No_qSuf, { Reg16|Reg32 }
diff --git a/opcodes/i386-tbl.h b/opcodes/i386-tbl.h
index a97dd6487aa..da96efc6fda 100644
--- a/opcodes/i386-tbl.h
+++ b/opcodes/i386-tbl.h
@@ -294,7 +294,7 @@ static const insn_template i386_optab[] =
0, 0, 0, 0, 0, 0 } } } },
{ MN_movzb, 0xb6, 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 } },
@@ -304,7 +304,7 @@ static const insn_template i386_optab[] =
0, 0, 0, 0, 0, 0 } } } },
{ MN_movzw, 0xb7, 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 } },
@@ -314,7 +314,7 @@ static const insn_template i386_optab[] =
0, 0, 0, 0, 0, 0 } } } },
{ MN_movzx, 0xb6, 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 } },
More information about the Binutils-cvs
mailing list