aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2022-07-06 15:40:04 +0200
committerJan Beulich <jbeulich@suse.com>2022-07-06 15:40:04 +0200
commit8bd915b770e12eff67f6218f2d727069d04d5752 (patch)
tree33f15463f72a7894f528757b209b85aab3ffec5a /gas
parent3d0738af2a6dac3c729126f2ceb3af6529da7348 (diff)
downloadfsf-binutils-gdb-8bd915b770e12eff67f6218f2d727069d04d5752.zip
fsf-binutils-gdb-8bd915b770e12eff67f6218f2d727069d04d5752.tar.gz
fsf-binutils-gdb-8bd915b770e12eff67f6218f2d727069d04d5752.tar.bz2
x86: make D attribute usable for XOP and FMA4 insns
This once again allows to reduce redundancy in (and size of) the opcode table. Don't go as far as also making D work on the two 5-operand XOP insns: This would significantly complicate the code, as there the first (immediate) operand would need special treatment in several places. Note that the .s suffix isn't being enabled to have any effect, for being deprecated. Whereas neither {load} nor {store} pseudo prefixes make sense here, as the respective operands are inputs (loads) only anyway, regardless of order. Hence there is (as before) no way for the programmer to request the alternative encoding to be used for register- only insns. Note further that it is always the first original template which is retained (and altered), to make sure the same encoding as before is used for register-only insns. This has the slightly odd (but pre- existing) effect of XOP register-only insns having XOP.W clear, but FMA4 ones having VEX.W set.
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-i386.c42
1 files changed, 35 insertions, 7 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 31b10d2..9cd33a9 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -2087,12 +2087,18 @@ operand_size_match (const insn_template *t)
}
/* Check reverse. */
- gas_assert (i.operands >= 2 && i.operands <= 3);
+ gas_assert ((i.operands >= 2 && i.operands <= 3)
+ || t->opcode_modifier.vexsources);
for (j = 0; j < i.operands; j++)
{
unsigned int given = i.operands - j - 1;
+ /* For 4- and 5-operand insns VEX.W controls just the first two
+ register operands. */
+ if (t->opcode_modifier.vexsources)
+ given = j < 2 ? 1 - j : j;
+
if (t->operand_types[j].bitfield.class == Reg
&& !match_operand_size (t, j, given))
goto mismatch;
@@ -6722,18 +6728,19 @@ match_template (char mnem_suffix)
if (!(size_match & MATCH_REVERSE))
continue;
/* Try reversing direction of operands. */
- overlap0 = operand_type_and (i.types[0], operand_types[i.operands - 1]);
- overlap1 = operand_type_and (i.types[i.operands - 1], operand_types[0]);
+ j = t->opcode_modifier.vexsources ? 1 : i.operands - 1;
+ overlap0 = operand_type_and (i.types[0], operand_types[j]);
+ overlap1 = operand_type_and (i.types[j], operand_types[0]);
overlap2 = operand_type_and (i.types[1], operand_types[1]);
gas_assert (t->operands != 3 || !check_register);
if (!operand_type_match (overlap0, i.types[0])
- || !operand_type_match (overlap1, i.types[i.operands - 1])
+ || !operand_type_match (overlap1, i.types[j])
|| (t->operands == 3
&& !operand_type_match (overlap2, i.types[1]))
|| (check_register
&& !operand_type_register_match (i.types[0],
- operand_types[i.operands - 1],
- i.types[i.operands - 1],
+ operand_types[j],
+ i.types[j],
operand_types[0])))
{
/* Does not match either direction. */
@@ -6745,6 +6752,11 @@ match_template (char mnem_suffix)
found_reverse_match = 0;
else if (operand_types[0].bitfield.tbyte)
found_reverse_match = Opcode_FloatD;
+ else if (t->opcode_modifier.vexsources)
+ {
+ found_reverse_match = Opcode_VexW;
+ goto check_operands_345;
+ }
else if (operand_types[0].bitfield.xmmword
|| operand_types[i.operands - 1].bitfield.xmmword
|| operand_types[0].bitfield.class == RegMMX
@@ -6760,6 +6772,7 @@ match_template (char mnem_suffix)
else
{
/* Found a forward 2 operand match here. */
+ check_operands_345:
switch (t->operands)
{
case 5:
@@ -6928,8 +6941,12 @@ match_template (char mnem_suffix)
i.tm.operand_types[addr_prefix_disp]
= operand_types[addr_prefix_disp];
- if (found_reverse_match)
+ switch (found_reverse_match)
{
+ case 0:
+ break;
+
+ default:
/* If we found a reverse match we must alter the opcode direction
bit and clear/flip the regmem modifier one. found_reverse_match
holds bits to change (different for int & float insns). */
@@ -6946,6 +6963,17 @@ match_template (char mnem_suffix)
= i.tm.opcode_modifier.modrm && i.tm.opcode_modifier.d
&& i.tm.operands > 2U - i.tm.opcode_modifier.sse2avx
&& !i.tm.opcode_modifier.regmem;
+ break;
+
+ case Opcode_VexW:
+ /* Only the first two register operands need reversing, alongside
+ flipping VEX.W. */
+ i.tm.opcode_modifier.vexw ^= VEXW0 ^ VEXW1;
+
+ j = i.tm.operand_types[0].bitfield.imm8;
+ i.tm.operand_types[j] = operand_types[j + 1];
+ i.tm.operand_types[j + 1] = operand_types[j];
+ break;
}
return t;