[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