mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-09 04:21:49 +08:00
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.
This commit is contained in:
parent
506f5c41ca
commit
4a1b91eabb
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,3 +1,20 @@
|
||||
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.
|
||||
|
||||
2018-07-24 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR 23430
|
||||
|
@ -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)
|
||||
{
|
||||
if (bcst_type > WORD_BROADCAST)
|
||||
bcst_type = WORD_BROADCAST;
|
||||
}
|
||||
else if (strcasecmp(str, "Dword") == 0)
|
||||
{
|
||||
if (bcst_type > DWORD_BROADCAST)
|
||||
bcst_type = DWORD_BROADCAST;
|
||||
}
|
||||
else if (strcasecmp(str, "Qword") == 0)
|
||||
{
|
||||
if (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);
|
||||
|
@ -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;
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user