public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Jan Beulich <jbeulich@suse.com>
To: Binutils <binutils@sourceware.org>
Cc: "H.J. Lu" <hjl.tools@gmail.com>,
	"Jiang, Haochen" <haochen.jiang@intel.com>
Subject: [PATCH v2 02/14] x86: parse VEX and alike specifiers for .insn
Date: Fri, 10 Mar 2023 11:19:50 +0100	[thread overview]
Message-ID: <8df023f9-58a5-dca7-badd-f3354ed18442@suse.com> (raw)
In-Reply-To: <b3625235-faf6-00ad-69c2-82583531fe43@suse.com>

All encoding spaces can be used this way; there's a certain risk that
the bits presently reserved could be used for other purposes down the
road, but people using .insn are expected to know what they're doing
anyway. Plus this way there's at least _some_ way to have those bits
set.

For now this will only allow operand-less insns to be encoded this way.
---
For now only numeric parts of the specifiers are handled in a case-
insensitive manner. All other parts have to use upper case letters.

--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -307,6 +307,9 @@ struct _i386_insn
     unsigned int prefixes;
     unsigned char prefix[MAX_PREFIXES];
 
+    /* .insn allows for reserved opcode spaces.  */
+    unsigned char insn_opcode_space;
+
     /* Register is in low 3 bits of opcode.  */
     bool short_form;
 
@@ -568,6 +571,9 @@ static expressionS im_expressions[MAX_IM
 /* Current operand we are working on.  */
 static int this_operand = -1;
 
+/* Are we processing a .insn directive?  */
+#define dot_insn() (i.tm.mnem_off == MN__insn)
+
 /* We support four different modes.  FLAG_CODE variable is used to distinguish
    these.  */
 
@@ -3648,6 +3654,8 @@ build_vex_prefix (const insn_template *t
     vector_length = avxscalar;
   else if (i.tm.opcode_modifier.vex == VEX256)
     vector_length = 1;
+  else if (dot_insn () && i.tm.opcode_modifier.vex == VEX128)
+    vector_length = 0;
   else
     {
       unsigned int op;
@@ -3715,7 +3723,9 @@ build_vex_prefix (const insn_template *t
 
       /* The high 3 bits of the second VEX byte are 1's compliment
 	 of RXB bits from REX.  */
-      i.vex.bytes[1] = (~i.rex & 0x7) << 5 | i.tm.opcode_space;
+      i.vex.bytes[1] = ((~i.rex & 7) << 5)
+		       | (!dot_insn () ? i.tm.opcode_space
+				       : i.insn_opcode_space);
 
       i.vex.bytes[2] = (w << 7
 			| register_specifier << 3
@@ -3851,7 +3861,9 @@ build_evex_prefix (void)
      bits from REX.  */
   gas_assert (i.tm.opcode_space >= SPACE_0F);
   gas_assert (i.tm.opcode_space <= SPACE_EVEXMAP6);
-  i.vex.bytes[1] = (~i.rex & 0x7) << 5 | i.tm.opcode_space;
+  i.vex.bytes[1] = ((~i.rex & 7) << 5)
+		   | (!dot_insn () ? i.tm.opcode_space
+				   : i.insn_opcode_space);
 
   /* The fifth bit of the second EVEX byte is 1's compliment of the
      REX_R bit in VREX.  */
@@ -3968,6 +3980,13 @@ build_evex_prefix (void)
 	case EVEX512:
 	  vec_length = 2 << 5;
 	  break;
+	case EVEX_L3:
+	  if (dot_insn ())
+	    {
+	      vec_length = 3 << 5;
+	      break;
+	    }
+	  /* Fall through.  */
 	default:
 	  abort ();
 	  break;
@@ -10742,6 +10761,7 @@ s_insn (int dummy ATTRIBUTE_UNUSED)
   bad:
       *saved_ilp = saved_char;
       ignore_rest_of_line ();
+      i.tm.mnem_off = 0;
       return;
     }
   line += end - line;
@@ -10764,6 +10784,9 @@ s_insn (int dummy ATTRIBUTE_UNUSED)
 	  && (*e == '.' || is_space_char (*e)))
 	{
 	  xop = true;
+	  /* Arrange for build_vex_prefix() to emit 0x8f.  */
+	  i.tm.opcode_space = SPACE_XOP08;
+	  i.insn_opcode_space = n;
 	  line = e;
 	}
     }
@@ -10787,6 +10810,188 @@ s_insn (int dummy ATTRIBUTE_UNUSED)
 
   if (line > end && *line == '.')
     {
+      /* Length specifier (VEX.L, XOP.L, EVEX.L'L).  */
+      switch (line[1])
+	{
+	case 'L':
+	  switch (line[2])
+	    {
+	    case '0':
+	      if (evex)
+		i.tm.opcode_modifier.evex = EVEX128;
+	      else
+		i.tm.opcode_modifier.vex = VEX128;
+	      break;
+
+	    case '1':
+	      if (evex)
+		i.tm.opcode_modifier.evex = EVEX256;
+	      else
+		i.tm.opcode_modifier.vex = VEX256;
+	      break;
+
+	    case '2':
+	      if (evex)
+		i.tm.opcode_modifier.evex = EVEX512;
+	      break;
+
+	    case '3':
+	      if (evex)
+		i.tm.opcode_modifier.evex = EVEX_L3;
+	      break;
+
+	    case 'I':
+	      if (line[3] == 'G')
+		{
+		  if (evex)
+		    i.tm.opcode_modifier.evex = EVEXLIG;
+		  else
+		    i.tm.opcode_modifier.vex = VEXScalar; /* LIG */
+		  ++line;
+		}
+	      break;
+	    }
+
+	  if (i.tm.opcode_modifier.vex || i.tm.opcode_modifier.evex)
+	    line += 3;
+	  break;
+
+	case '1':
+	  if (line[2] == '2' && line[3] == '8')
+	    {
+	      if (evex)
+		i.tm.opcode_modifier.evex = EVEX128;
+	      else
+		i.tm.opcode_modifier.vex = VEX128;
+	      line += 4;
+	    }
+	  break;
+
+	case '2':
+	  if (line[2] == '5' && line[3] == '6')
+	    {
+	      if (evex)
+		i.tm.opcode_modifier.evex = EVEX256;
+	      else
+		i.tm.opcode_modifier.vex = VEX256;
+	      line += 4;
+	    }
+	  break;
+
+	case '5':
+	  if (evex && line[2] == '1' && line[3] == '2')
+	    {
+	      i.tm.opcode_modifier.evex = EVEX512;
+	      line += 4;
+	    }
+	  break;
+	}
+    }
+
+  if (line > end && *line == '.')
+    {
+      /* embedded prefix (VEX.pp, XOP.pp, EVEX.pp).  */
+      switch (line[1])
+	{
+	case 'N':
+	  if (line[2] == 'P')
+	    line += 3;
+	  break;
+
+	case '6':
+	  if (line[2] == '6')
+	    {
+	      i.tm.opcode_modifier.opcodeprefix = PREFIX_0X66;
+	      line += 3;
+	    }
+	  break;
+
+	case 'F': case 'f':
+	  if (line[2] == '3')
+	    {
+	      i.tm.opcode_modifier.opcodeprefix = PREFIX_0XF3;
+	      line += 3;
+	    }
+	  else if (line[2] == '2')
+	    {
+	      i.tm.opcode_modifier.opcodeprefix = PREFIX_0XF2;
+	      line += 3;
+	    }
+	  break;
+	}
+    }
+
+  if (line > end && !xop && *line == '.')
+    {
+      /* Encoding space (VEX.mmmmm, EVEX.mmmm).  */
+      switch (line[1])
+	{
+	case '0':
+	  if (TOUPPER (line[2]) != 'F')
+	    break;
+	  if (line[3] == '.' || is_space_char (line[3]))
+	    {
+	      i.insn_opcode_space = SPACE_0F;
+	      line += 3;
+	    }
+	  else if (line[3] == '3'
+		   && (line[4] == '8' || TOUPPER (line[4]) == 'A')
+		   && (line[5] == '.' || is_space_char (line[5])))
+	    {
+	      i.insn_opcode_space = line[4] == '8' ? SPACE_0F38 : SPACE_0F3A;
+	      line += 5;
+	    }
+	  break;
+
+	case 'M':
+	  if (ISDIGIT (line[2]) && line[2] != '0')
+	    {
+	      char *e;
+	      unsigned long n = strtoul (line + 2, &e, 10);
+
+	      if (n <= (evex ? 15 : 31)
+		  && (*e == '.' || is_space_char (*e)))
+		{
+		  i.insn_opcode_space = n;
+		  line = e;
+		}
+	    }
+	  break;
+	}
+    }
+
+  if (line > end && *line == '.' && line[1] == 'W')
+    {
+      /* VEX.W, XOP.W, EVEX.W  */
+      switch (line[2])
+	{
+	case '0':
+	  i.tm.opcode_modifier.vexw = VEXW0;
+	  break;
+
+	case '1':
+	  i.tm.opcode_modifier.vexw = VEXW1;
+	  break;
+
+	case 'I':
+	  if (line[3] == 'G')
+	    {
+	      i.tm.opcode_modifier.vexw = VEXWIG;
+	      ++line;
+	    }
+	  break;
+	}
+
+      if (i.tm.opcode_modifier.vexw)
+	line += 3;
+    }
+
+  if (line > end && *line && !is_space_char (*line))
+    {
+      /* Improve diagnostic a little.  */
+      if (*line == '.' && line[1] && !is_space_char (line[1]))
+	++line;
+      goto done;
     }
 
   input_line_pointer = line;
@@ -10815,24 +11020,30 @@ s_insn (int dummy ATTRIBUTE_UNUSED)
     }
 
   /* Trim off encoding space.  */
-  if (j > 1 && !i.tm.opcode_space && (val >> ((j - 1) * 8)) == 0x0f)
+  if (j > 1 && !i.insn_opcode_space && (val >> ((j - 1) * 8)) == 0x0f)
     {
       uint8_t byte = val >> ((--j - 1) * 8);
 
-      i.tm.opcode_space = SPACE_0F;
+      i.insn_opcode_space = SPACE_0F;
       switch (byte & -(j > 1))
 	{
 	case 0x38:
-	  i.tm.opcode_space = SPACE_0F38;
+	  i.insn_opcode_space = SPACE_0F38;
 	  --j;
 	  break;
 	case 0x3a:
-	  i.tm.opcode_space = SPACE_0F3A;
+	  i.insn_opcode_space = SPACE_0F3A;
 	  --j;
 	  break;
 	}
+      i.tm.opcode_space = i.insn_opcode_space;
       val &= ((uint64_t)1 << (j * 8)) - 1;
     }
+  if (!i.tm.opcode_space && (vex || evex))
+    /* Arrange for build_vex_prefix() to properly emit 0xC4/0xC5.
+       Also avoid hitting abort() there or in build_evex_prefix().  */
+    i.tm.opcode_space = i.insn_opcode_space == SPACE_0F ? SPACE_0F
+						   : SPACE_0F38;
 
   if (j > 2)
     {
@@ -10842,12 +11053,33 @@ s_insn (int dummy ATTRIBUTE_UNUSED)
   i.opcode_length = j;
   i.tm.base_opcode = val;
 
+  if (vex || xop)
+    {
+      if (!i.tm.opcode_modifier.vex)
+	i.tm.opcode_modifier.vex = VEXScalar; /* LIG */
+
+      build_vex_prefix (NULL);
+      i.rex &= REX_OPCODE;
+    }
+  else if (evex)
+    {
+      if (!i.tm.opcode_modifier.evex)
+	i.tm.opcode_modifier.evex = EVEXLIG;
+
+      build_evex_prefix ();
+      i.rex &= REX_OPCODE;
+    }
+
   output_insn ();
 
+ done:
   *saved_ilp = saved_char;
   input_line_pointer = line;
 
   demand_empty_rest_of_line ();
+
+  /* Make sure dot_insn() won't yield "true" anymore.  */
+  i.tm.mnem_off = 0;
 }
 
 #ifdef TE_PE
--- a/gas/testsuite/gas/i386/insn-32.d
+++ b/gas/testsuite/gas/i386/insn-32.d
@@ -11,4 +11,6 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	f3 90[ 	]+pause
 [ 	]*[a-f0-9]+:	d9 ee[ 	]+fldz
 [ 	]*[a-f0-9]+:	f3 0f 01 e8[ 	]+setssbsy
+[ 	]*[a-f0-9]+:	c5 fc 77[ 	]+vzeroall
+[ 	]*[a-f0-9]+:	c4 e1 7c 77[ 	]+vzeroall
 #pass
--- a/gas/testsuite/gas/i386/insn-32.s
+++ b/gas/testsuite/gas/i386/insn-32.s
@@ -12,3 +12,7 @@ insn:
 
 	# setssbsy
 	.insn 0xf30f01e8
+
+	# vzeroall
+	.insn VEX.256.0F.WIG 0x77
+	.insn {vex3} VEX.L1 0x0f77
--- a/gas/testsuite/gas/i386/insn-64.d
+++ b/gas/testsuite/gas/i386/insn-64.d
@@ -11,4 +11,6 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	f3 90[ 	]+pause
 [ 	]*[a-f0-9]+:	d9 ee[ 	]+fldz
 [ 	]*[a-f0-9]+:	f3 0f 01 e8[ 	]+setssbsy
+[ 	]*[a-f0-9]+:	c5 fc 77[ 	]+vzeroall
+[ 	]*[a-f0-9]+:	c4 e1 7c 77[ 	]+vzeroall
 #pass
--- a/gas/testsuite/gas/i386/insn-64.s
+++ b/gas/testsuite/gas/i386/insn-64.s
@@ -12,3 +12,7 @@ insn:
 
 	# setssbsy
 	.insn 0xf30f01e8
+
+	# vzeroall
+	.insn VEX.256.0F.WIG 0x77
+	.insn {vex3} VEX.L1 0x0f77
--- a/opcodes/i386-opc.h
+++ b/opcodes/i386-opc.h
@@ -643,12 +643,14 @@ enum
 	3: 256bit EVEX prefix.
 	4: Length-ignored (LIG) EVEX prefix.
 	5: Length determined from actual operands.
+	6: L'L = 3 (reserved, .insn only)
    */
 #define EVEX512                1
 #define EVEX128                2
 #define EVEX256                3
 #define EVEXLIG                4
 #define EVEXDYN                5
+#define EVEX_L3                6
   EVex,
 
   /* AVX512 masking support:


  parent reply	other threads:[~2023-03-10 10:19 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-10 10:17 [PATCH v2 00/14] x86: new .insn directive Jan Beulich
2023-03-10 10:19 ` [PATCH v2 01/14] x86: introduce " Jan Beulich
2023-03-10 10:19 ` Jan Beulich [this message]
2023-03-10 10:20 ` [PATCH v2 03/14] x86: parse special opcode modifiers for .insn Jan Beulich
2023-03-10 10:21 ` [PATCH v2 04/14] x86: re-work build_modrm_byte()'s register assignment Jan Beulich
2023-03-10 10:21 ` [PATCH v2 05/14] x86: VexVVVV is now merely a boolean Jan Beulich
2023-03-10 10:22 ` [PATCH v2 06/14] x86: drop "shimm" special case template expansions Jan Beulich
2023-03-10 10:22 ` [PATCH v2 07/14] x86/AT&T: restrict recognition of the "absolute branch" prefix character Jan Beulich
2023-03-10 10:23 ` [PATCH v2 08/14] x86: process instruction operands for .insn Jan Beulich
2023-03-10 10:24 ` [PATCH v2 09/14] x86: handle EVEX Disp8 " Jan Beulich
2023-03-10 10:24 ` [PATCH v2 10/14] x86: allow for multiple immediates in output_disp() Jan Beulich
2023-03-10 10:25 ` [PATCH v2 11/14] x86: handle immediate operands for .insn Jan Beulich
2023-03-10 10:26 ` [PATCH v2 12/14] x86: document .insn Jan Beulich
2023-03-10 10:26 ` [PATCH v2 13/14] x86: convert testcases to use .insn Jan Beulich
2023-04-20  8:56   ` Clément Chigot
2023-04-20  9:01     ` Jan Beulich
2023-04-20  9:09       ` Clément Chigot
2023-04-20  9:19         ` Jan Beulich
2023-04-20  9:22           ` Clément Chigot
2023-03-10 10:27 ` [PATCH RFC v2 14/14] x86: .insn example - VEX-encoded instructions of original Xeon Phi Jan Beulich
2023-03-24  9:51 ` [PATCH v2 00/14] x86: new .insn directive Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8df023f9-58a5-dca7-badd-f3354ed18442@suse.com \
    --to=jbeulich@suse.com \
    --cc=binutils@sourceware.org \
    --cc=haochen.jiang@intel.com \
    --cc=hjl.tools@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).