aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-07-25 15:28:07 -0700
committerH.J. Lu <hjl.tools@gmail.com>2018-07-25 15:28:24 -0700
commit4a1b91eabbe77f4d906a0895121d76a0653c3cf3 (patch)
tree675d4da6c17c95157f9a312626af39ac098b27d6 /gas
parent506f5c41cab71dbc3e562ba367d2dc6b355b64a6 (diff)
downloadbinutils-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/ChangeLog9
-rw-r--r--gas/config/tc-i386.c44
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