From 8bd915b770e12eff67f6218f2d727069d04d5752 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 6 Jul 2022 15:40:04 +0200 Subject: 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. --- gas/config/tc-i386.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'gas') 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; -- cgit v1.1