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:
H.J. Lu 2018-07-25 15:28:07 -07:00
parent 506f5c41ca
commit 4a1b91eabb
6 changed files with 521 additions and 409 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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