[PATCH] x86: Expand Broadcast to 3 bits
H.J. Lu
hongjiu.lu@intel.com
Thu Jul 26 03:25:00 GMT 2018
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.
I will check it in shortly.
H.J.
---
gas/
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.
opcodes/
2018-07-25 H.J. Lu <hongjiu.lu@intel.com>
Igor Tsimbalist <igor.v.tsimbalist@intel.com>
* 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.
---
gas/config/tc-i386.c | 44 ++-
opcodes/i386-gen.c | 61 +++-
opcodes/i386-opc.h | 13 +-
opcodes/i386-tbl.h | 786 +++++++++++++++++++++----------------------
4 files changed, 495 insertions(+), 409 deletions(-)
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index bcd2904044..3f8bd93224 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
diff --git a/opcodes/i386-gen.c b/opcodes/i386-gen.c
index 860d318087..ff5b8c1da9 100644
--- a/opcodes/i386-gen.c
+++ b/opcodes/i386-gen.c
@@ -1023,8 +1023,58 @@ output_opcode_modifier (FILE *table, bitfield *modifier, unsigned int size)
fprintf (table, "%d },\n", modifier[i].value);
}
+static int
+adjust_broadcast_modifier (char **opnd)
+{
+ char *str, *next, *last, *op;
+ int bcst_type = INT_MAX;
+
+ /* Skip the immediate operand. */
+ op = opnd[0];
+ if (strcasecmp(op, "Imm8") == 0)
+ op = opnd[1];
+
+ op = xstrdup (op);
+ last = op + strlen (op);
+ for (next = op; next && next < last; )
+ {
+ str = next_field (next, '|', &next, last);
+ if (str)
+ {
+ if (strcasecmp(str, "Byte") == 0)
+ {
+ /* The smalest broadcast type, no need to check
+ further. */
+ bcst_type = BYTE_BROADCAST;
+ break;
+ }
+ else if (strcasecmp(str, "Word") == 0
+ && bcst_type > WORD_BROADCAST)
+ {
+ bcst_type = WORD_BROADCAST;
+ }
+ else if (strcasecmp(str, "Dword") == 0
+ && bcst_type > DWORD_BROADCAST)
+ {
+ bcst_type = DWORD_BROADCAST;
+ }
+ else if (strcasecmp(str, "Qword") == 0
+ && bcst_type > QWORD_BROADCAST)
+ {
+ bcst_type = QWORD_BROADCAST;
+ }
+ }
+ }
+ free (op);
+
+ if (bcst_type == INT_MAX)
+ fail (_("unknown broadcast operand: %s\n"), op);
+
+ return bcst_type;
+}
+
static void
-process_i386_opcode_modifier (FILE *table, char *mod, int lineno)
+process_i386_opcode_modifier (FILE *table, char *mod, char **opnd, int lineno)
{
char *str, *next, *last;
bitfield modifiers [ARRAY_SIZE (opcode_modifiers)];
@@ -1042,7 +1092,10 @@ process_i386_opcode_modifier (FILE *table, char *mod, int lineno)
str = next_field (next, '|', &next, last);
if (str)
{
- set_bitfield (str, modifiers, 1, ARRAY_SIZE (modifiers),
+ int val = 1;
+ if (strcasecmp(str, "Broadcast") == 0)
+ val = adjust_broadcast_modifier (opnd);
+ set_bitfield (str, modifiers, val, ARRAY_SIZE (modifiers),
lineno);
if (strcasecmp(str, "IsString") == 0)
active_isstring = 1;
@@ -1201,7 +1254,7 @@ output_i386_opcode (FILE *table, const char *name, char *str,
process_i386_cpu_flag (table, cpu_flags, 0, ",", " ", lineno);
- process_i386_opcode_modifier (table, opcode_modifier, lineno);
+ process_i386_opcode_modifier (table, opcode_modifier, operand_types, lineno);
fprintf (table, " { ");
@@ -1394,7 +1447,7 @@ process_i386_opcodes (FILE *table)
process_i386_cpu_flag (table, "0", 0, ",", " ", -1);
- process_i386_opcode_modifier (table, "0", -1);
+ process_i386_opcode_modifier (table, "0", NULL, -1);
fprintf (table, " { ");
process_i386_operand_type (table, "0", stage_opcodes, "\t ", -1);
diff --git a/opcodes/i386-opc.h b/opcodes/i386-opc.h
index cb7875dc87..25d8d2765b 100644
--- a/opcodes/i386-opc.h
+++ b/opcodes/i386-opc.h
@@ -561,6 +561,17 @@ enum
#define BOTH_MASKING 3
Masking,
+ /* AVX512 broadcast support. The number of bytes to broadcast is
+ 1 << (Broadcast - 1):
+ 1: Byte broadcast.
+ 2: Word broadcast.
+ 3: Dword broadcast.
+ 4: Qword broadcast.
+ */
+#define BYTE_BROADCAST 1
+#define WORD_BROADCAST 2
+#define DWORD_BROADCAST 3
+#define QWORD_BROADCAST 4
Broadcast,
/* Static rounding control is supported. */
@@ -650,7 +661,7 @@ typedef struct i386_opcode_modifier
unsigned int noavx:1;
unsigned int evex:3;
unsigned int masking:2;
- unsigned int broadcast:1;
+ unsigned int broadcast:3;
unsigned int staticrounding:1;
unsigned int sae:1;
unsigned int disp8memshift:3;
More information about the Binutils
mailing list