diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2018-07-25 15:28:07 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2018-07-25 15:28:24 -0700 |
commit | 4a1b91eabbe77f4d906a0895121d76a0653c3cf3 (patch) | |
tree | 675d4da6c17c95157f9a312626af39ac098b27d6 /gas | |
parent | 506f5c41cab71dbc3e562ba367d2dc6b355b64a6 (diff) | |
download | binutils-4a1b91eabbe77f4d906a0895121d76a0653c3cf3.zip binutils-4a1b91eabbe77f4d906a0895121d76a0653c3cf3.tar.gz binutils-4a1b91eabbe77f4d906a0895121d76a0653c3cf3.tar.bz2 |
x86: Expand Broadcast to 3 bits
Expand Broadcast to 3 bits so that the number of bytes to broadcast
can be computed as 1 << (Broadcast - 1). Use it to simplify x86
assembler.
gas/
* config/tc-i386.c (Broadcast_Operation): Add bytes.
(build_evex_prefix): Use i.broadcast->bytes.
(match_broadcast_size): New function.
(check_VecOperands): Use the broadcast field to compute the
number of bytes to broadcast directly. Set i.broadcast->bytes.
Use match_broadcast_size.
opcodes/
* i386-gen.c (adjust_broadcast_modifier): New function.
(process_i386_opcode_modifier): Add an argument for operands.
Adjust the Broadcast value based on operands.
(output_i386_opcode): Pass operand_types to
process_i386_opcode_modifier.
(process_i386_opcodes): Pass NULL as operands to
process_i386_opcode_modifier.
* i386-opc.h (BYTE_BROADCAST): New.
(WORD_BROADCAST): Likewise.
(DWORD_BROADCAST): Likewise.
(QWORD_BROADCAST): Likewise.
(i386_opcode_modifier): Expand broadcast to 3 bits.
* i386-tbl.h: Regenerated.
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 9 | ||||
-rw-r--r-- | gas/config/tc-i386.c | 44 |
2 files changed, 42 insertions, 11 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index b881625..e0de16e 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +2018-07-25 H.J. Lu <hongjiu.lu@intel.com> + + * config/tc-i386.c (Broadcast_Operation): Add bytes. + (build_evex_prefix): Use i.broadcast->bytes. + (match_broadcast_size): New function. + (check_VecOperands): Use the broadcast field to compute the + number of bytes to broadcast directly. Set i.broadcast->bytes. + Use match_broadcast_size. + 2018-07-25 Thomas Preud'homme <thomas.preudhomme@linaro.org> * doc/c-arm.texi (.arch directive): Clarify that name must not include diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index bcd2904..3f8bd93 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -230,6 +230,9 @@ struct Broadcast_Operation /* Index of broadcasted operand. */ int operand; + + /* Number of bytes to broadcast. */ + int bytes; }; static struct Broadcast_Operation broadcast_op; @@ -3639,8 +3642,7 @@ build_evex_prefix (void) } else if (i.broadcast && (int) op == i.broadcast->operand) { - switch ((i.tm.operand_types[op].bitfield.dword ? 4 : 8) - * i.broadcast->type) + switch (i.broadcast->bytes) { case 64: i.tm.opcode_modifier.evex = EVEX512; @@ -5008,6 +5010,22 @@ optimize_disp (void) } } +/* Return 1 if there is a match in broadcast bytes between operand + GIVEN and instruction template T. */ + +static INLINE int +match_broadcast_size (const insn_template *t, unsigned int given) +{ + return ((t->opcode_modifier.broadcast == BYTE_BROADCAST + && i.types[given].bitfield.byte) + || (t->opcode_modifier.broadcast == WORD_BROADCAST + && i.types[given].bitfield.word) + || (t->opcode_modifier.broadcast == DWORD_BROADCAST + && i.types[given].bitfield.dword) + || (t->opcode_modifier.broadcast == QWORD_BROADCAST + && i.types[given].bitfield.qword)); +} + /* Check if operands are valid for the instruction. */ static int @@ -5126,23 +5144,29 @@ check_VecOperands (const insn_template *t) i386_operand_type type, overlap; /* Check if specified broadcast is supported in this instruction, - and it's applied to memory operand of DWORD or QWORD type. */ + and its broadcast bytes match the memory operand. */ op = i.broadcast->operand; if (!t->opcode_modifier.broadcast || !i.types[op].bitfield.mem || (!i.types[op].bitfield.unspecified - && (t->operand_types[op].bitfield.dword - ? !i.types[op].bitfield.dword - : !i.types[op].bitfield.qword))) + && !match_broadcast_size (t, op))) { bad_broadcast: i.error = unsupported_broadcast; return 1; } + i.broadcast->bytes = ((1 << (t->opcode_modifier.broadcast - 1)) + * i.broadcast->type); operand_type_set (&type, 0); - switch ((t->operand_types[op].bitfield.dword ? 4 : 8) * i.broadcast->type) + switch (i.broadcast->bytes) { + case 2: + type.bitfield.word = 1; + break; + case 4: + type.bitfield.dword = 1; + break; case 8: type.bitfield.qword = 1; break; @@ -5189,9 +5213,7 @@ check_VecOperands (const insn_template *t) break; gas_assert (op < i.operands); /* Check size of the memory operand. */ - if (t->operand_types[op].bitfield.dword - ? i.types[op].bitfield.dword - : i.types[op].bitfield.qword) + if (match_broadcast_size (t, op)) { i.error = broadcast_needed; return 1; @@ -5245,7 +5267,7 @@ check_VecOperands (const insn_template *t) && i.disp_encoding != disp_encoding_32bit) { if (i.broadcast) - i.memshift = t->operand_types[op].bitfield.dword ? 2 : 3; + i.memshift = t->opcode_modifier.broadcast - 1; else if (t->opcode_modifier.disp8memshift != DISP8_SHIFT_VL) i.memshift = t->opcode_modifier.disp8memshift; else |