From ae9a0a51e851eac3cdcd2a6791bf05480211c169 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 24 Feb 2023 14:00:11 +0100 Subject: [PATCH] x86: allow to request ModR/M encoding Several insns have a (typically shorter) non-ModR/M and a (typically longer) ModR/M encoding. In most cases the former is used by default. This isn't too dissimilar from register-only insns sometimes having two encoding forms. In those cases {load} or {store} can be used to control the encoding used. Extend this to ModR/M-less encodings which have a ModR/M counterpart (note that BSWAP hasn't). For insn reading and writing their (explicit) memory operand, both prefixes are honored; otherwise only the applicable one is. Note that for some forms of XCHG, {store} has already been performing this function, apparently as an unnoticed side effect of adding D to the template. --- gas/config/tc-i386.c | 67 +++++++++++++++++-- gas/testsuite/gas/i386/pseudos.d | 89 ++++++++++++++++++++++++- gas/testsuite/gas/i386/pseudos.s | 28 ++++++++ gas/testsuite/gas/i386/x86-64-pseudos.d | 85 +++++++++++++++++++++++ gas/testsuite/gas/i386/x86-64-pseudos.s | 36 ++++++++++ 5 files changed, 296 insertions(+), 9 deletions(-) diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 3df0a47a030..a9314f560b7 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -6883,19 +6883,40 @@ match_template (char mnem_suffix) case 1: if (!operand_type_match (overlap0, i.types[0])) continue; + + /* Allow the ModR/M encoding to be requested by using the {load} or + {store} pseudo prefix on an applicable insn. */ + if (!t->opcode_modifier.modrm + && i.reg_operands == 1 + && ((i.dir_encoding == dir_encoding_load + && t->mnem_off != MN_pop) + || (i.dir_encoding == dir_encoding_store + && t->mnem_off != MN_push)) + /* Avoid BSWAP. */ + && t->mnem_off != MN_bswap) + continue; break; + case 2: /* xchg %eax, %eax is a special case. It is an alias 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 - && t->opcode_space == SPACE_BASE - && i.types[0].bitfield.instance == Accum - && i.types[0].bitfield.dword - && i.types[1].bitfield.instance == Accum) - continue; + if (t->base_opcode == 0x90 + && t->opcode_space == SPACE_BASE) + { + if (flag_code == CODE_64BIT + && i.types[0].bitfield.instance == Accum + && i.types[0].bitfield.dword + && i.types[1].bitfield.instance == Accum) + continue; + + /* Allow the ModR/M encoding to be requested by using the + {load} or {store} pseudo prefix. */ + if (i.dir_encoding == dir_encoding_load + || i.dir_encoding == dir_encoding_store) + continue; + } if (t->base_opcode == MOV_AX_DISP32 && t->opcode_space == SPACE_BASE @@ -6909,6 +6930,38 @@ match_template (char mnem_suffix) match the accumulator-only encoding of mov. */ if (i.hle_prefix) continue; + + /* Allow the ModR/M encoding to be requested by using a suitable + {load} or {store} pseudo prefix. */ + if (i.dir_encoding == (i.types[0].bitfield.instance == Accum + ? dir_encoding_store + : dir_encoding_load) + && !i.types[0].bitfield.disp64 + && !i.types[1].bitfield.disp64) + continue; + } + + /* Allow the ModR/M encoding to be requested by using the {load} or + {store} pseudo prefix on an applicable insn. */ + if (!t->opcode_modifier.modrm + && i.reg_operands == 1 + && i.imm_operands == 1 + && (i.dir_encoding == dir_encoding_load + || i.dir_encoding == dir_encoding_store) + && t->opcode_space == SPACE_BASE) + { + if (t->base_opcode == 0xb0 /* mov $imm, %reg */ + && i.dir_encoding == dir_encoding_store) + continue; + + if ((t->base_opcode | 0x38) == 0x3c /* $imm, %acc */ + && (t->base_opcode != 0x3c /* cmp $imm, %acc */ + || i.dir_encoding == dir_encoding_load)) + continue; + + if (t->base_opcode == 0xa8 /* test $imm, %acc */ + && i.dir_encoding == dir_encoding_load) + continue; } /* Fall through. */ diff --git a/gas/testsuite/gas/i386/pseudos.d b/gas/testsuite/gas/i386/pseudos.d index 0df9b7265aa..98e1149c19b 100644 --- a/gas/testsuite/gas/i386/pseudos.d +++ b/gas/testsuite/gas/i386/pseudos.d @@ -54,10 +54,10 @@ Disassembly of section .text: +[a-f0-9]+: 31 c8 xor %ecx,%eax +[a-f0-9]+: 33 c1 xor %ecx,%eax +[a-f0-9]+: 31 c8 xor %ecx,%eax - +[a-f0-9]+: a1 78 56 34 12 mov 0x12345678,%eax + +[a-f0-9]+: 8b 05 78 56 34 12 mov 0x12345678,%eax +[a-f0-9]+: a3 78 56 34 12 mov %eax,0x12345678 +[a-f0-9]+: a1 78 56 34 12 mov 0x12345678,%eax - +[a-f0-9]+: a3 78 56 34 12 mov %eax,0x12345678 + +[a-f0-9]+: 89 05 78 56 34 12 mov %eax,0x12345678 +[a-f0-9]+: 89 07 mov %eax,\(%edi\) +[a-f0-9]+: 8b 07 mov \(%edi\),%eax +[a-f0-9]+: 89 07 mov %eax,\(%edi\) @@ -126,6 +126,91 @@ Disassembly of section .text: +[a-f0-9]+: 33 07 xor \(%edi\),%eax +[a-f0-9]+: 31 07 xor %eax,\(%edi\) +[a-f0-9]+: 33 07 xor \(%edi\),%eax + +[a-f0-9]+: b0 12 mov \$0x12,%al + +[a-f0-9]+: b8 45 03 00 00 mov \$0x345,%eax + +[a-f0-9]+: b0 12 mov \$0x12,%al + +[a-f0-9]+: b8 45 03 00 00 mov \$0x345,%eax + +[a-f0-9]+: c6 c0 12 mov \$0x12,%al + +[a-f0-9]+: c7 c0 45 03 00 00 mov \$0x345,%eax + +[a-f0-9]+: 14 12 adc \$0x12,%al + +[a-f0-9]+: 15 45 03 00 00 adc \$0x345,%eax + +[a-f0-9]+: 80 d0 12 adc \$0x12,%al + +[a-f0-9]+: 81 d0 45 03 00 00 adc \$0x345,%eax + +[a-f0-9]+: 80 d0 12 adc \$0x12,%al + +[a-f0-9]+: 81 d0 45 03 00 00 adc \$0x345,%eax + +[a-f0-9]+: 04 12 add \$0x12,%al + +[a-f0-9]+: 05 45 03 00 00 add \$0x345,%eax + +[a-f0-9]+: 80 c0 12 add \$0x12,%al + +[a-f0-9]+: 81 c0 45 03 00 00 add \$0x345,%eax + +[a-f0-9]+: 80 c0 12 add \$0x12,%al + +[a-f0-9]+: 81 c0 45 03 00 00 add \$0x345,%eax + +[a-f0-9]+: 24 12 and \$0x12,%al + +[a-f0-9]+: 25 45 03 00 00 and \$0x345,%eax + +[a-f0-9]+: 80 e0 12 and \$0x12,%al + +[a-f0-9]+: 81 e0 45 03 00 00 and \$0x345,%eax + +[a-f0-9]+: 80 e0 12 and \$0x12,%al + +[a-f0-9]+: 81 e0 45 03 00 00 and \$0x345,%eax + +[a-f0-9]+: 3c 12 cmp \$0x12,%al + +[a-f0-9]+: 3d 45 03 00 00 cmp \$0x345,%eax + +[a-f0-9]+: 80 f8 12 cmp \$0x12,%al + +[a-f0-9]+: 81 f8 45 03 00 00 cmp \$0x345,%eax + +[a-f0-9]+: 3c 12 cmp \$0x12,%al + +[a-f0-9]+: 3d 45 03 00 00 cmp \$0x345,%eax + +[a-f0-9]+: 0c 12 or \$0x12,%al + +[a-f0-9]+: 0d 45 03 00 00 or \$0x345,%eax + +[a-f0-9]+: 80 c8 12 or \$0x12,%al + +[a-f0-9]+: 81 c8 45 03 00 00 or \$0x345,%eax + +[a-f0-9]+: 80 c8 12 or \$0x12,%al + +[a-f0-9]+: 81 c8 45 03 00 00 or \$0x345,%eax + +[a-f0-9]+: 1c 12 sbb \$0x12,%al + +[a-f0-9]+: 1d 45 03 00 00 sbb \$0x345,%eax + +[a-f0-9]+: 80 d8 12 sbb \$0x12,%al + +[a-f0-9]+: 81 d8 45 03 00 00 sbb \$0x345,%eax + +[a-f0-9]+: 80 d8 12 sbb \$0x12,%al + +[a-f0-9]+: 81 d8 45 03 00 00 sbb \$0x345,%eax + +[a-f0-9]+: 2c 12 sub \$0x12,%al + +[a-f0-9]+: 2d 45 03 00 00 sub \$0x345,%eax + +[a-f0-9]+: 80 e8 12 sub \$0x12,%al + +[a-f0-9]+: 81 e8 45 03 00 00 sub \$0x345,%eax + +[a-f0-9]+: 80 e8 12 sub \$0x12,%al + +[a-f0-9]+: 81 e8 45 03 00 00 sub \$0x345,%eax + +[a-f0-9]+: a8 12 test \$0x12,%al + +[a-f0-9]+: a9 45 03 00 00 test \$0x345,%eax + +[a-f0-9]+: f6 c0 12 test \$0x12,%al + +[a-f0-9]+: f7 c0 45 03 00 00 test \$0x345,%eax + +[a-f0-9]+: a8 12 test \$0x12,%al + +[a-f0-9]+: a9 45 03 00 00 test \$0x345,%eax + +[a-f0-9]+: 34 12 xor \$0x12,%al + +[a-f0-9]+: 35 45 03 00 00 xor \$0x345,%eax + +[a-f0-9]+: 80 f0 12 xor \$0x12,%al + +[a-f0-9]+: 81 f0 45 03 00 00 xor \$0x345,%eax + +[a-f0-9]+: 80 f0 12 xor \$0x12,%al + +[a-f0-9]+: 81 f0 45 03 00 00 xor \$0x345,%eax + +[a-f0-9]+: 41 inc %ecx + +[a-f0-9]+: ff c1 inc %ecx + +[a-f0-9]+: ff c1 inc %ecx + +[a-f0-9]+: 49 dec %ecx + +[a-f0-9]+: ff c9 dec %ecx + +[a-f0-9]+: ff c9 dec %ecx + +[a-f0-9]+: 51 push %ecx + +[a-f0-9]+: ff f1 push %ecx + +[a-f0-9]+: 51 push %ecx + +[a-f0-9]+: 59 pop %ecx + +[a-f0-9]+: 59 pop %ecx + +[a-f0-9]+: 8f c1 pop %ecx + +[a-f0-9]+: 0f c9 bswap %ecx + +[a-f0-9]+: 0f c9 bswap %ecx + +[a-f0-9]+: 0f c9 bswap %ecx + +[a-f0-9]+: 87 ce xchg %ecx,%esi + +[a-f0-9]+: 87 f1 xchg %esi,%ecx + +[a-f0-9]+: 87 f1 xchg %esi,%ecx + +[a-f0-9]+: 87 ce xchg %ecx,%esi + +[a-f0-9]+: 96 xchg %eax,%esi + +[a-f0-9]+: 87 f0 xchg %esi,%eax + +[a-f0-9]+: 87 c6 xchg %eax,%esi + +[a-f0-9]+: 91 xchg %eax,%ecx + +[a-f0-9]+: 87 c1 xchg %eax,%ecx + +[a-f0-9]+: 87 c8 xchg %ecx,%eax +[a-f0-9]+: d8 c0 fadd %st\(0\),%st +[a-f0-9]+: d8 c0 fadd %st\(0\),%st +[a-f0-9]+: dc c0 fadd %st,%st\(0\) diff --git a/gas/testsuite/gas/i386/pseudos.s b/gas/testsuite/gas/i386/pseudos.s index 34a461c262e..7e3600eb250 100644 --- a/gas/testsuite/gas/i386/pseudos.s +++ b/gas/testsuite/gas/i386/pseudos.s @@ -124,6 +124,34 @@ _start: {store} xor %eax, (%edi) {store} xor (%edi), %eax + .irp m, mov, adc, add, and, cmp, or, sbb, sub, test, xor + \m $0x12, %al + \m $0x345, %eax + {load} \m $0x12, %al # bogus for MOV + {load} \m $0x345, %eax # bogus for MOV + {store} \m $0x12, %al + {store} \m $0x345, %eax + .endr + + .irp m, inc, dec, push, pop, bswap + \m %ecx + {load} \m %ecx # bogus for POP + {store} \m %ecx # bogus for PUSH + .endr + + xchg %ecx, %esi + xchg %esi, %ecx + {load} xchg %ecx, %esi + {store} xchg %ecx, %esi + + xchg %eax, %esi + {load} xchg %eax, %esi + {store} xchg %eax, %esi + + xchg %ecx, %eax + {load} xchg %ecx, %eax + {store} xchg %ecx, %eax + fadd %st, %st {load} fadd %st, %st {store} fadd %st, %st diff --git a/gas/testsuite/gas/i386/x86-64-pseudos.d b/gas/testsuite/gas/i386/x86-64-pseudos.d index fb71942046d..0cc75ef2457 100644 --- a/gas/testsuite/gas/i386/x86-64-pseudos.d +++ b/gas/testsuite/gas/i386/x86-64-pseudos.d @@ -137,6 +137,91 @@ Disassembly of section .text: +[a-f0-9]+: 33 07 xor \(%rdi\),%eax +[a-f0-9]+: 31 07 xor %eax,\(%rdi\) +[a-f0-9]+: 33 07 xor \(%rdi\),%eax + +[a-f0-9]+: b0 12 mov \$0x12,%al + +[a-f0-9]+: b8 45 03 00 00 mov \$0x345,%eax + +[a-f0-9]+: b0 12 mov \$0x12,%al + +[a-f0-9]+: b8 45 03 00 00 mov \$0x345,%eax + +[a-f0-9]+: c6 c0 12 mov \$0x12,%al + +[a-f0-9]+: c7 c0 45 03 00 00 mov \$0x345,%eax + +[a-f0-9]+: 14 12 adc \$0x12,%al + +[a-f0-9]+: 15 45 03 00 00 adc \$0x345,%eax + +[a-f0-9]+: 80 d0 12 adc \$0x12,%al + +[a-f0-9]+: 81 d0 45 03 00 00 adc \$0x345,%eax + +[a-f0-9]+: 80 d0 12 adc \$0x12,%al + +[a-f0-9]+: 81 d0 45 03 00 00 adc \$0x345,%eax + +[a-f0-9]+: 04 12 add \$0x12,%al + +[a-f0-9]+: 05 45 03 00 00 add \$0x345,%eax + +[a-f0-9]+: 80 c0 12 add \$0x12,%al + +[a-f0-9]+: 81 c0 45 03 00 00 add \$0x345,%eax + +[a-f0-9]+: 80 c0 12 add \$0x12,%al + +[a-f0-9]+: 81 c0 45 03 00 00 add \$0x345,%eax + +[a-f0-9]+: 24 12 and \$0x12,%al + +[a-f0-9]+: 25 45 03 00 00 and \$0x345,%eax + +[a-f0-9]+: 80 e0 12 and \$0x12,%al + +[a-f0-9]+: 81 e0 45 03 00 00 and \$0x345,%eax + +[a-f0-9]+: 80 e0 12 and \$0x12,%al + +[a-f0-9]+: 81 e0 45 03 00 00 and \$0x345,%eax + +[a-f0-9]+: 3c 12 cmp \$0x12,%al + +[a-f0-9]+: 3d 45 03 00 00 cmp \$0x345,%eax + +[a-f0-9]+: 80 f8 12 cmp \$0x12,%al + +[a-f0-9]+: 81 f8 45 03 00 00 cmp \$0x345,%eax + +[a-f0-9]+: 3c 12 cmp \$0x12,%al + +[a-f0-9]+: 3d 45 03 00 00 cmp \$0x345,%eax + +[a-f0-9]+: 0c 12 or \$0x12,%al + +[a-f0-9]+: 0d 45 03 00 00 or \$0x345,%eax + +[a-f0-9]+: 80 c8 12 or \$0x12,%al + +[a-f0-9]+: 81 c8 45 03 00 00 or \$0x345,%eax + +[a-f0-9]+: 80 c8 12 or \$0x12,%al + +[a-f0-9]+: 81 c8 45 03 00 00 or \$0x345,%eax + +[a-f0-9]+: 1c 12 sbb \$0x12,%al + +[a-f0-9]+: 1d 45 03 00 00 sbb \$0x345,%eax + +[a-f0-9]+: 80 d8 12 sbb \$0x12,%al + +[a-f0-9]+: 81 d8 45 03 00 00 sbb \$0x345,%eax + +[a-f0-9]+: 80 d8 12 sbb \$0x12,%al + +[a-f0-9]+: 81 d8 45 03 00 00 sbb \$0x345,%eax + +[a-f0-9]+: 2c 12 sub \$0x12,%al + +[a-f0-9]+: 2d 45 03 00 00 sub \$0x345,%eax + +[a-f0-9]+: 80 e8 12 sub \$0x12,%al + +[a-f0-9]+: 81 e8 45 03 00 00 sub \$0x345,%eax + +[a-f0-9]+: 80 e8 12 sub \$0x12,%al + +[a-f0-9]+: 81 e8 45 03 00 00 sub \$0x345,%eax + +[a-f0-9]+: a8 12 test \$0x12,%al + +[a-f0-9]+: a9 45 03 00 00 test \$0x345,%eax + +[a-f0-9]+: f6 c0 12 test \$0x12,%al + +[a-f0-9]+: f7 c0 45 03 00 00 test \$0x345,%eax + +[a-f0-9]+: a8 12 test \$0x12,%al + +[a-f0-9]+: a9 45 03 00 00 test \$0x345,%eax + +[a-f0-9]+: 34 12 xor \$0x12,%al + +[a-f0-9]+: 35 45 03 00 00 xor \$0x345,%eax + +[a-f0-9]+: 80 f0 12 xor \$0x12,%al + +[a-f0-9]+: 81 f0 45 03 00 00 xor \$0x345,%eax + +[a-f0-9]+: 80 f0 12 xor \$0x12,%al + +[a-f0-9]+: 81 f0 45 03 00 00 xor \$0x345,%eax + +[a-f0-9]+: 48 b9 89 67 45 23 01 00 00 00 movabs \$0x123456789,%rcx + +[a-f0-9]+: 48 b9 89 67 45 23 01 00 00 00 movabs \$0x123456789,%rcx + +[a-f0-9]+: 48 b9 89 67 45 23 01 00 00 00 movabs \$0x123456789,%rcx + +[a-f0-9]+: 48 b9 78 56 34 12 00 00 00 00 movabs \$0x12345678,%rcx + +[a-f0-9]+: 48 b9 78 56 34 12 00 00 00 00 movabs \$0x12345678,%rcx + +[a-f0-9]+: 48 b9 78 56 34 12 00 00 00 00 movabs \$0x12345678,%rcx + +[a-f0-9]+: 51 push %rcx + +[a-f0-9]+: ff f1 push %rcx + +[a-f0-9]+: 51 push %rcx + +[a-f0-9]+: 59 pop %rcx + +[a-f0-9]+: 59 pop %rcx + +[a-f0-9]+: 8f c1 pop %rcx + +[a-f0-9]+: 48 0f c9 bswap %rcx + +[a-f0-9]+: 48 0f c9 bswap %rcx + +[a-f0-9]+: 48 0f c9 bswap %rcx + +[a-f0-9]+: 87 ce xchg %ecx,%esi + +[a-f0-9]+: 87 f1 xchg %esi,%ecx + +[a-f0-9]+: 87 f1 xchg %esi,%ecx + +[a-f0-9]+: 87 ce xchg %ecx,%esi + +[a-f0-9]+: 96 xchg %eax,%esi + +[a-f0-9]+: 87 f0 xchg %esi,%eax + +[a-f0-9]+: 87 c6 xchg %eax,%esi + +[a-f0-9]+: 91 xchg %eax,%ecx + +[a-f0-9]+: 87 c1 xchg %eax,%ecx + +[a-f0-9]+: 87 c8 xchg %ecx,%eax +[a-f0-9]+: d8 c0 fadd %st\(0\),%st +[a-f0-9]+: d8 c0 fadd %st\(0\),%st +[a-f0-9]+: dc c0 fadd %st,%st\(0\) diff --git a/gas/testsuite/gas/i386/x86-64-pseudos.s b/gas/testsuite/gas/i386/x86-64-pseudos.s index 3818df9708e..08fac8381c6 100644 --- a/gas/testsuite/gas/i386/x86-64-pseudos.s +++ b/gas/testsuite/gas/i386/x86-64-pseudos.s @@ -135,6 +135,42 @@ _start: {store} xor %eax, (%rdi) {store} xor (%rdi), %eax + .irp m, mov, adc, add, and, cmp, or, sbb, sub, test, xor + \m $0x12, %al + \m $0x345, %eax + {load} \m $0x12, %al # bogus for MOV + {load} \m $0x345, %eax # bogus for MOV + {store} \m $0x12, %al + {store} \m $0x345, %eax + .endr + + # There should be no effect of the pseudo-prefixes on any of these. + mov $0x123456789, %rcx + {load} mov $0x123456789, %rcx + {store} mov $0x123456789, %rcx + movabs $0x12345678, %rcx + {load} movabs $0x12345678, %rcx + {store} movabs $0x12345678, %rcx + + .irp m, push, pop, bswap + \m %rcx + {load} \m %rcx # bogus for POP + {store} \m %rcx # bogus for PUSH + .endr + + xchg %ecx, %esi + xchg %esi, %ecx + {load} xchg %ecx, %esi + {store} xchg %ecx, %esi + + xchg %eax, %esi + {load} xchg %eax, %esi + {store} xchg %eax, %esi + + xchg %ecx, %eax + {load} xchg %ecx, %eax + {store} xchg %ecx, %eax + fadd %st, %st {load} fadd %st, %st {store} fadd %st, %st -- 2.30.2