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 01/14] x86: introduce .insn directive
Date: Fri, 10 Mar 2023 11:19:22 +0100	[thread overview]
Message-ID: <97d9240d-2d1a-d7a4-35e4-7cec1f418f38@suse.com> (raw)
In-Reply-To: <b3625235-faf6-00ad-69c2-82583531fe43@suse.com>

For starters this deals with only very basic constructs.
---
Subsequently a dot_insn() predicate will be introduced. If deemed better
than parse_insn()'s new parameter, its introduction could be pulled
ahead into here, and the predicate then be used there instead.

--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -137,6 +137,7 @@ typedef struct
 arch_entry;
 
 static void update_code_flag (int, int);
+static void s_insn (int);
 static void set_code_flag (int);
 static void set_16bit_gcc_code_flag (int);
 static void set_intel_syntax (int);
@@ -159,7 +160,7 @@ static int i386_intel_operand (char *, i
 static int i386_intel_simplify (expressionS *);
 static int i386_intel_parse_name (const char *, expressionS *);
 static const reg_entry *parse_register (char *, char **);
-static const char *parse_insn (const char *, char *);
+static const char *parse_insn (const char *, char *, bool);
 static char *parse_operands (char *, const char *);
 static void swap_operands (void);
 static void swap_2_operands (unsigned int, unsigned int);
@@ -1198,6 +1199,7 @@ const pseudo_typeS md_pseudo_table[] =
   {"bfloat16", float_cons, 'b'},
   {"value", cons, 2},
   {"slong", signed_cons, 4},
+  {"insn", s_insn, 0},
   {"noopt", s_ignore, 0},
   {"optim", s_ignore, 0},
   {"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT},
@@ -4856,6 +4858,20 @@ insert_lfence_before (void)
     }
 }
 
+/* Shared helper for md_assemble() and s_insn().  */
+static void init_globals (void)
+{
+  unsigned int j;
+
+  memset (&i, '\0', sizeof (i));
+  i.rounding.type = rc_none;
+  for (j = 0; j < MAX_OPERANDS; j++)
+    i.reloc[j] = NO_RELOC;
+  memset (disp_expressions, '\0', sizeof (disp_expressions));
+  memset (im_expressions, '\0', sizeof (im_expressions));
+  save_stack_p = save_stack;
+}
+
 /* Helper for md_assemble() to decide whether to prepare for a possible 2nd
    parsing pass. Instead of introducing a rarely use new insn attribute this
    utilizes a common pattern between affected templates. It is deemed
@@ -4888,19 +4904,13 @@ md_assemble (char *line)
   /* Initialize globals.  */
   current_templates = NULL;
  retry:
-  memset (&i, '\0', sizeof (i));
-  i.rounding.type = rc_none;
-  for (j = 0; j < MAX_OPERANDS; j++)
-    i.reloc[j] = NO_RELOC;
-  memset (disp_expressions, '\0', sizeof (disp_expressions));
-  memset (im_expressions, '\0', sizeof (im_expressions));
-  save_stack_p = save_stack;
+  init_globals ();
 
   /* First parse an instruction mnemonic & call i386_operand for the operands.
      We assume that the scrubber has arranged it so that line[0] is the valid
      start of a (possibly prefixed) mnemonic.  */
 
-  end = parse_insn (line, mnemonic);
+  end = parse_insn (line, mnemonic, false);
   if (end == NULL)
     {
       if (pass1_mnem != NULL)
@@ -5439,7 +5449,7 @@ static INLINE bool q_suffix_allowed(cons
 }
 
 static const char *
-parse_insn (const char *line, char *mnemonic)
+parse_insn (const char *line, char *mnemonic, bool prefix_only)
 {
   const char *l = line, *token_start = l;
   char *mnem_p;
@@ -5469,6 +5479,8 @@ parse_insn (const char *line, char *mnem
 	      || (*l != PREFIX_SEPARATOR
 		  && *l != ',')))
 	{
+	  if (prefix_only)
+	    break;
 	  as_bad (_("invalid character %s in mnemonic"),
 		  output_invalid (*l));
 	  return NULL;
@@ -5590,6 +5602,9 @@ parse_insn (const char *line, char *mnem
 	break;
     }
 
+  if (prefix_only)
+    return token_start;
+
   if (!current_templates)
     {
       /* Deprecated functionality (new code should use pseudo-prefixes instead):
@@ -10705,6 +10720,136 @@ signed_cons (int size)
   cons_sign = -1;
 }
 
+static void
+s_insn (int dummy ATTRIBUTE_UNUSED)
+{
+  char mnemonic[MAX_MNEM_SIZE], *line = input_line_pointer;
+  char *saved_ilp = find_end_of_line (line, false), saved_char;
+  const char *end;
+  unsigned int j;
+  valueT val;
+  bool vex = false, xop = false, evex = false;
+  static const templates tt = { &i.tm, &i.tm + 1 };
+
+  init_globals ();
+
+  saved_char = *saved_ilp;
+  *saved_ilp = 0;
+
+  end = parse_insn (line, mnemonic, true);
+  if (end == NULL)
+    {
+  bad:
+      *saved_ilp = saved_char;
+      ignore_rest_of_line ();
+      return;
+    }
+  line += end - line;
+
+  current_templates = &tt;
+  i.tm.mnem_off = MN__insn;
+
+  if (startswith (line, "VEX")
+      && (line[3] == '.' || is_space_char (line[3])))
+    {
+      vex = true;
+      line += 3;
+    }
+  else if (startswith (line, "XOP") && ISDIGIT (line[3]))
+    {
+      char *e;
+      unsigned long n = strtoul (line + 3, &e, 16);
+
+      if (e == line + 5 && n >= 0x08 && n <= 0x1f
+	  && (*e == '.' || is_space_char (*e)))
+	{
+	  xop = true;
+	  line = e;
+	}
+    }
+  else if (startswith (line, "EVEX")
+	   && (line[4] == '.' || is_space_char (line[4])))
+    {
+      evex = true;
+      line += 4;
+    }
+
+  if (vex || xop
+      ? i.vec_encoding == vex_encoding_evex
+      : evex
+	? i.vec_encoding == vex_encoding_vex
+	  || i.vec_encoding == vex_encoding_vex3
+	: i.vec_encoding != vex_encoding_default)
+    {
+      as_bad (_("pseudo-prefix conflicts with encoding specifier"));
+      goto bad;
+    }
+
+  if (line > end && *line == '.')
+    {
+    }
+
+  input_line_pointer = line;
+  val = get_absolute_expression ();
+  line = input_line_pointer;
+
+  for (j = 1; j < sizeof(val); ++j)
+    if (!(val >> (j * 8)))
+      break;
+
+  /* Trim off a prefix if present.  */
+  if (j > 1 && !vex && !xop && !evex)
+    {
+      uint8_t byte = val >> ((j - 1) * 8);
+
+      switch (byte)
+	{
+	case DATA_PREFIX_OPCODE:
+	case REPE_PREFIX_OPCODE:
+	case REPNE_PREFIX_OPCODE:
+	  if (!add_prefix (byte))
+	    goto bad;
+	  val &= ((uint64_t)1 << (--j * 8)) - 1;
+	  break;
+	}
+    }
+
+  /* Trim off encoding space.  */
+  if (j > 1 && !i.tm.opcode_space && (val >> ((j - 1) * 8)) == 0x0f)
+    {
+      uint8_t byte = val >> ((--j - 1) * 8);
+
+      i.tm.opcode_space = SPACE_0F;
+      switch (byte & -(j > 1))
+	{
+	case 0x38:
+	  i.tm.opcode_space = SPACE_0F38;
+	  --j;
+	  break;
+	case 0x3a:
+	  i.tm.opcode_space = SPACE_0F3A;
+	  --j;
+	  break;
+	}
+      val &= ((uint64_t)1 << (j * 8)) - 1;
+    }
+
+  if (j > 2)
+    {
+      as_bad (_("opcode residual (%#"PRIx64") too wide"), val);
+      goto bad;
+    }
+  i.opcode_length = j;
+  i.tm.base_opcode = val;
+
+  output_insn ();
+
+  *saved_ilp = saved_char;
+  input_line_pointer = line;
+
+  demand_empty_rest_of_line ();
+}
+
 #ifdef TE_PE
 static void
 pe_directive_secrel (int dummy ATTRIBUTE_UNUSED)
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -68,6 +68,7 @@ if [gas_32_check] then {
     run_dump_test "intelok"
     run_dump_test "prefix"
     run_list_test "prefix32" "-al"
+    run_dump_test "insn-32"
     run_dump_test "lea"
     run_dump_test "lea16"
     run_dump_test "amd"
@@ -873,6 +874,7 @@ if [gas_64_check] then {
     run_dump_test "x86-64-sysenter-mixed"
     run_dump_test "x86-64-sysenter-amd"
     run_list_test "x86-64-sysenter-amd" "-mamd64"
+    run_dump_test "insn-64"
     run_dump_test "noreg64"
     run_list_test "noreg64"
     run_dump_test "noreg64-data16"
--- /dev/null
+++ b/gas/testsuite/gas/i386/insn-32.d
@@ -0,0 +1,14 @@
+#objdump: -dw
+#name: .insn (32-bit code)
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+ <insn>:
+[ 	]*[a-f0-9]+:	90[ 	]+nop
+[ 	]*[a-f0-9]+:	f3 90[ 	]+pause
+[ 	]*[a-f0-9]+:	f3 90[ 	]+pause
+[ 	]*[a-f0-9]+:	d9 ee[ 	]+fldz
+[ 	]*[a-f0-9]+:	f3 0f 01 e8[ 	]+setssbsy
+#pass
--- /dev/null
+++ b/gas/testsuite/gas/i386/insn-32.s
@@ -0,0 +1,14 @@
+	.text
+insn:
+	# nop
+	.insn 0x90
+
+	# pause
+	.insn 0xf390
+	.insn repe 0x90
+
+	# fldz
+	.insn 0xd9ee
+
+	# setssbsy
+	.insn 0xf30f01e8
--- /dev/null
+++ b/gas/testsuite/gas/i386/insn-64.d
@@ -0,0 +1,14 @@
+#objdump: -dw
+#name: .insn (64-bit code)
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+ <insn>:
+[ 	]*[a-f0-9]+:	90[ 	]+nop
+[ 	]*[a-f0-9]+:	f3 90[ 	]+pause
+[ 	]*[a-f0-9]+:	f3 90[ 	]+pause
+[ 	]*[a-f0-9]+:	d9 ee[ 	]+fldz
+[ 	]*[a-f0-9]+:	f3 0f 01 e8[ 	]+setssbsy
+#pass
--- /dev/null
+++ b/gas/testsuite/gas/i386/insn-64.s
@@ -0,0 +1,14 @@
+	.text
+insn:
+	# nop
+	.insn 0x90
+
+	# pause
+	.insn 0xf390
+	.insn repe 0x90
+
+	# fldz
+	.insn 0xd9ee
+
+	# setssbsy
+	.insn 0xf30f01e8
--- a/opcodes/i386-gen.c
+++ b/opcodes/i386-gen.c
@@ -1814,6 +1814,9 @@ process_i386_opcodes (FILE *table)
       l = l1;
     }
 
+  fprintf (table, "  \"\\0\"\".insn\"\n");
+  fprintf (fp, "#define MN__insn %#x\n", offs + 1);
+
   fprintf (table, ";\n");
 
   fclose (fp);
--- a/opcodes/i386-mnem.h
+++ b/opcodes/i386-mnem.h
@@ -2339,3 +2339,4 @@ extern const char i386_mnemonics[];
 #define MN__rex_ 0x469c
 #define MN__evex_ 0x46a2
 #define MN__vex_ 0x46a9
+#define MN__insn 0x46af
--- a/opcodes/i386-tbl.h
+++ b/opcodes/i386-tbl.h
@@ -60199,6 +60199,7 @@ const char i386_mnemonics[] =
   "\0""{rex}"
   "\0""{evex}"
   "\0""{vex}"
+  "\0"".insn"
 ;
 
 /* i386 register table.  */


  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 " Jan Beulich
2023-03-10 10:19 ` Jan Beulich [this message]
2023-03-10 10:19 ` [PATCH v2 02/14] x86: parse VEX and alike specifiers for .insn Jan Beulich
2023-03-10 10:20 ` [PATCH v2 03/14] x86: parse special opcode modifiers " 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=97d9240d-2d1a-d7a4-35e4-7cec1f418f38@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).