[1/6] x86: allow opcode templates to be templated

Message ID c6886c82-2d96-650a-4123-a774a18748ac@suse.com
State New
Headers show
Series
  • x86: introduce "templated" insn templates
Related show

Commit Message

Jan Beulich March 6, 2020, 8:11 a.m.
In order to reduce redundancy as well as the chance of things going out
of sync (see a later patch for an example), make the opcode table
generator capable of recognizing and expanding templated templates. Use
the new capability for compacting the general purpose conditional insns.

opcodes/
2020-03-XX  Jan Beulich  <jbeulich@suse.com>

	* i386-gen.c (struct template_arg, struct template_instance,
	struct template_param, struct template, templates,
	parse_template, expand_templates): New.
	(process_i386_opcodes): Various local variables moved to
	expand_templates. Call parse_template and expand_templates.
	* i386-opc.tbl (cc): New. Use it for Jcc, SETcc, and CMOVcc.
	* i386-tbl.h: Re-generate.
---
The set* templates lack No_bSuf - is there an expectation that in AT&T
mode a 'b' suffix may be used on them? Otherwise this should be added
imo, as being yet another omission of commit dc2be329b950 ("i386: Only
check suffix in instruction mnemonic").

Comments

H.J. Lu March 6, 2020, 2:42 p.m. | #1
On Fri, Mar 6, 2020 at 12:11 AM Jan Beulich <jbeulich@suse.com> wrote:
>

> In order to reduce redundancy as well as the chance of things going out

> of sync (see a later patch for an example), make the opcode table

> generator capable of recognizing and expanding templated templates. Use

> the new capability for compacting the general purpose conditional insns.

>

> opcodes/

> 2020-03-XX  Jan Beulich  <jbeulich@suse.com>

>

>         * i386-gen.c (struct template_arg, struct template_instance,

>         struct template_param, struct template, templates,

>         parse_template, expand_templates): New.

>         (process_i386_opcodes): Various local variables moved to

>         expand_templates. Call parse_template and expand_templates.

>         * i386-opc.tbl (cc): New. Use it for Jcc, SETcc, and CMOVcc.

>         * i386-tbl.h: Re-generate.


OK.  Thanks.

> ---

> The set* templates lack No_bSuf - is there an expectation that in AT&T

> mode a 'b' suffix may be used on them? Otherwise this should be added


What does setb do?

> imo, as being yet another omission of commit dc2be329b950 ("i386: Only

> check suffix in instruction mnemonic").

>


-- 
H.J.
Jan Beulich March 6, 2020, 2:51 p.m. | #2
On 06.03.2020 15:42, H.J. Lu wrote:
> On Fri, Mar 6, 2020 at 12:11 AM Jan Beulich <jbeulich@suse.com> wrote:

>>

>> In order to reduce redundancy as well as the chance of things going out

>> of sync (see a later patch for an example), make the opcode table

>> generator capable of recognizing and expanding templated templates. Use

>> the new capability for compacting the general purpose conditional insns.

>>

>> opcodes/

>> 2020-03-XX  Jan Beulich  <jbeulich@suse.com>

>>

>>         * i386-gen.c (struct template_arg, struct template_instance,

>>         struct template_param, struct template, templates,

>>         parse_template, expand_templates): New.

>>         (process_i386_opcodes): Various local variables moved to

>>         expand_templates. Call parse_template and expand_templates.

>>         * i386-opc.tbl (cc): New. Use it for Jcc, SETcc, and CMOVcc.

>>         * i386-tbl.h: Re-generate.

> 

> OK.  Thanks.

> 

>> ---

>> The set* templates lack No_bSuf - is there an expectation that in AT&T

>> mode a 'b' suffix may be used on them? Otherwise this should be added

> 

> What does setb do?


setb is just a normal mnemonic. I'm wondering about setbb or setnzb or
alike.

Jan
H.J. Lu March 6, 2020, 3:37 p.m. | #3
On Fri, Mar 6, 2020 at 6:51 AM Jan Beulich <jbeulich@suse.com> wrote:
>

> On 06.03.2020 15:42, H.J. Lu wrote:

> > On Fri, Mar 6, 2020 at 12:11 AM Jan Beulich <jbeulich@suse.com> wrote:

> >>

> >> In order to reduce redundancy as well as the chance of things going out

> >> of sync (see a later patch for an example), make the opcode table

> >> generator capable of recognizing and expanding templated templates. Use

> >> the new capability for compacting the general purpose conditional insns.

> >>

> >> opcodes/

> >> 2020-03-XX  Jan Beulich  <jbeulich@suse.com>

> >>

> >>         * i386-gen.c (struct template_arg, struct template_instance,

> >>         struct template_param, struct template, templates,

> >>         parse_template, expand_templates): New.

> >>         (process_i386_opcodes): Various local variables moved to

> >>         expand_templates. Call parse_template and expand_templates.

> >>         * i386-opc.tbl (cc): New. Use it for Jcc, SETcc, and CMOVcc.

> >>         * i386-tbl.h: Re-generate.

> >

> > OK.  Thanks.

> >

> >> ---

> >> The set* templates lack No_bSuf - is there an expectation that in AT&T

> >> mode a 'b' suffix may be used on them? Otherwise this should be added

> >

> > What does setb do?

>

> setb is just a normal mnemonic. I'm wondering about setbb or setnzb or

> alike.

>


setXX takes a byte operand.  'b' suffix is appropriate.

-- 
H.J.
Jan Beulich March 9, 2020, 9:19 a.m. | #4
On 06.03.2020 15:42, H.J. Lu wrote:
> On Fri, Mar 6, 2020 at 12:11 AM Jan Beulich <jbeulich@suse.com> wrote:

>>

>> In order to reduce redundancy as well as the chance of things going out

>> of sync (see a later patch for an example), make the opcode table

>> generator capable of recognizing and expanding templated templates. Use

>> the new capability for compacting the general purpose conditional insns.

>>

>> opcodes/

>> 2020-03-XX  Jan Beulich  <jbeulich@suse.com>

>>

>>         * i386-gen.c (struct template_arg, struct template_instance,

>>         struct template_param, struct template, templates,

>>         parse_template, expand_templates): New.

>>         (process_i386_opcodes): Various local variables moved to

>>         expand_templates. Call parse_template and expand_templates.

>>         * i386-opc.tbl (cc): New. Use it for Jcc, SETcc, and CMOVcc.

>>         * i386-tbl.h: Re-generate.

> 

> OK.  Thanks.


Now that this is in, a question I have is how far we want to go with
using this templating. There are certainly more groups of insns which
are sufficiently similar, but I guess using templates for just two or
three insns wouldn't be helpful readability wise. An example of where
I'm on the edge are the {,V}PCLMUL pseudos. Do you have any thoughts
on the general question, or is it entirely up to me to decide where
else to use this new functionality?

Jan
H.J. Lu March 9, 2020, 12:15 p.m. | #5
On Mon, Mar 9, 2020 at 2:19 AM Jan Beulich <jbeulich@suse.com> wrote:
>

> On 06.03.2020 15:42, H.J. Lu wrote:

> > On Fri, Mar 6, 2020 at 12:11 AM Jan Beulich <jbeulich@suse.com> wrote:

> >>

> >> In order to reduce redundancy as well as the chance of things going out

> >> of sync (see a later patch for an example), make the opcode table

> >> generator capable of recognizing and expanding templated templates. Use

> >> the new capability for compacting the general purpose conditional insns.

> >>

> >> opcodes/

> >> 2020-03-XX  Jan Beulich  <jbeulich@suse.com>

> >>

> >>         * i386-gen.c (struct template_arg, struct template_instance,

> >>         struct template_param, struct template, templates,

> >>         parse_template, expand_templates): New.

> >>         (process_i386_opcodes): Various local variables moved to

> >>         expand_templates. Call parse_template and expand_templates.

> >>         * i386-opc.tbl (cc): New. Use it for Jcc, SETcc, and CMOVcc.

> >>         * i386-tbl.h: Re-generate.

> >

> > OK.  Thanks.

>

> Now that this is in, a question I have is how far we want to go with

> using this templating. There are certainly more groups of insns which

> are sufficiently similar, but I guess using templates for just two or

> three insns wouldn't be helpful readability wise. An example of where

> I'm on the edge are the {,V}PCLMUL pseudos. Do you have any thoughts

> on the general question, or is it entirely up to me to decide where

> else to use this new functionality?

>


I will leave it entirely up to you.  Thanks for your great work.

-- 
H.J.

Patch

--- a/opcodes/i386-gen.c
+++ b/opcodes/i386-gen.c
@@ -740,6 +740,31 @@  static const char *filename;
 static i386_cpu_flags active_cpu_flags;
 static int active_isstring;
 
+struct template_arg {
+  const struct template_arg *next;
+  const char *val;
+};
+
+struct template_instance {
+  const struct template_instance *next;
+  const char *name;
+  const struct template_arg *args;
+};
+
+struct template_param {
+  const struct template_param *next;
+  const char *name;
+};
+
+struct template {
+  const struct template *next;
+  const char *name;
+  const struct template_instance *instances;
+  const struct template_param *params;
+};
+
+static const struct template *templates;
+
 static int
 compare (const void *x, const void *y)
 {
@@ -1374,25 +1399,254 @@  opcode_hash_eq (const void *p, const voi
 }
 
 static void
+parse_template (char *buf, int lineno)
+{
+  char sep, *end, *name;
+  struct template *tmpl = xmalloc (sizeof (*tmpl));
+  struct template_instance *last_inst = NULL;
+
+  buf = remove_leading_whitespaces (buf + 1);
+  end = strchr (buf, ':');
+  if (end == NULL)
+    fail ("%s: %d: missing ':'\n", filename, lineno);
+  *end++ = '\0';
+  remove_trailing_whitespaces (buf);
+
+  if (*buf == '\0')
+    fail ("%s: %d: missing template identifier\n", filename, lineno);
+  tmpl->name = xstrdup (buf);
+
+  tmpl->params = NULL;
+  do {
+      struct template_param *param;
+
+      buf = remove_leading_whitespaces (end);
+      end = strpbrk (buf, ":,");
+      if (end == NULL)
+        fail ("%s: %d: missing ':' or ','\n", filename, lineno);
+
+      sep = *end;
+      *end++ = '\0';
+      remove_trailing_whitespaces (buf);
+
+      param = xmalloc (sizeof (*param));
+      param->name = xstrdup (buf);
+      param->next = tmpl->params;
+      tmpl->params = param;
+  } while (sep == ':');
+
+  tmpl->instances = NULL;
+  do {
+      struct template_instance *inst;
+      char *cur, *next;
+      const struct template_param *param;
+
+      buf = remove_leading_whitespaces (end);
+      end = strpbrk (buf, ",>");
+      if (end == NULL)
+        fail ("%s: %d: missing ',' or '>'\n", filename, lineno);
+
+      sep = *end;
+      *end++ = '\0';
+
+      inst = xmalloc (sizeof (*inst));
+
+      cur = next_field (buf, ':', &next, end);
+      inst->name = xstrdup (cur);
+
+      for (param = tmpl->params; param; param = param->next)
+	{
+	  struct template_arg *arg = xmalloc (sizeof (*arg));
+
+	  cur = next_field (next, ':', &next, end);
+	  if (next > end)
+	    fail ("%s: %d: missing argument for '%s'\n", filename, lineno, param->name);
+	  arg->val = xstrdup (cur);
+	  arg->next = inst->args;
+	  inst->args = arg;
+	}
+
+      if (tmpl->instances)
+	last_inst->next = inst;
+      else
+	tmpl->instances = inst;
+      last_inst = inst;
+  } while (sep == ',');
+
+  buf = remove_leading_whitespaces (end);
+  if (*buf)
+    fprintf(stderr, "%s: %d: excess characters '%s'\n",
+	    filename, lineno, buf);
+
+  tmpl->next = templates;
+  templates = tmpl;
+}
+
+static unsigned int
+expand_templates (char *name, const char *str, htab_t opcode_hash_table,
+		  struct opcode_hash_entry ***opcode_array_p, int lineno)
+{
+  static unsigned int idx, opcode_array_size;
+  struct opcode_hash_entry **opcode_array = *opcode_array_p;
+  struct opcode_hash_entry **hash_slot, **entry;
+  char *ptr1 = strchr(name, '<'), *ptr2;
+
+  if (ptr1 == NULL)
+    {
+      /* Get the slot in hash table.  */
+      hash_slot = (struct opcode_hash_entry **)
+	htab_find_slot_with_hash (opcode_hash_table, name,
+				  htab_hash_string (name),
+				  INSERT);
+
+      if (*hash_slot == NULL)
+	{
+	  /* It is the new one.  Put it on opcode array.  */
+	  if (idx >= opcode_array_size)
+	    {
+	      /* Grow the opcode array when needed.  */
+	      opcode_array_size += 1024;
+	      opcode_array = (struct opcode_hash_entry **)
+		xrealloc (opcode_array,
+			  sizeof (*opcode_array) * opcode_array_size);
+		*opcode_array_p = opcode_array;
+	    }
+
+	  opcode_array[idx] = (struct opcode_hash_entry *)
+	    xmalloc (sizeof (struct opcode_hash_entry));
+	  opcode_array[idx]->next = NULL;
+	  opcode_array[idx]->name = xstrdup (name);
+	  opcode_array[idx]->opcode = xstrdup (str);
+	  opcode_array[idx]->lineno = lineno;
+	  *hash_slot = opcode_array[idx];
+	  idx++;
+	}
+      else
+	{
+	  /* Append it to the existing one.  */
+	  entry = hash_slot;
+	  while ((*entry) != NULL)
+	    entry = &(*entry)->next;
+	  *entry = (struct opcode_hash_entry *)
+	    xmalloc (sizeof (struct opcode_hash_entry));
+	  (*entry)->next = NULL;
+	  (*entry)->name = (*hash_slot)->name;
+	  (*entry)->opcode = xstrdup (str);
+	  (*entry)->lineno = lineno;
+	}
+    }
+  else if ((ptr2 = strchr(ptr1 + 1, '>')) == NULL)
+    fail ("%s: %d: missing '>'\n", filename, lineno);
+  else
+    {
+      const struct template *tmpl;
+      const struct template_instance *inst;
+
+      *ptr1 = '\0';
+      ptr1 = remove_leading_whitespaces (ptr1 + 1);
+      remove_trailing_whitespaces (ptr1);
+
+      *ptr2++ = '\0';
+
+      for ( tmpl = templates; tmpl; tmpl = tmpl->next )
+	if (!strcmp(ptr1, tmpl->name))
+	  break;
+      if (!tmpl)
+	fail ("reference to unknown template '%s'\n", ptr1);
+
+      for (inst = tmpl->instances; inst; inst = inst->next)
+	{
+	  char *name2 = xmalloc(strlen(name) + strlen(inst->name) + strlen(ptr2) + 1);
+	  char *str2 = xmalloc(2 * strlen(str));
+	  const char *src;
+
+	  strcpy (name2, name);
+	  strcat (name2, inst->name);
+	  strcat (name2, ptr2);
+
+	  for (ptr1 = str2, src = str; *src; )
+	    {
+	      const char *ident = tmpl->name, *end;
+	      const struct template_param *param;
+	      const struct template_arg *arg;
+
+	      if ((*ptr1 = *src++) != '<')
+		{
+		  ++ptr1;
+		  continue;
+		}
+	      while (ISSPACE(*src))
+		++src;
+	      while (*ident && *src == *ident)
+		++src, ++ident;
+	      while (ISSPACE(*src))
+		++src;
+	      if (*src != ':' || *ident != '\0')
+		{
+		  memcpy (++ptr1, tmpl->name, ident - tmpl->name);
+		  ptr1 += ident - tmpl->name;
+		  continue;
+		}
+	      while (ISSPACE(*++src))
+		;
+
+	      end = src;
+	      while (*end != '\0' && !ISSPACE(*end) && *end != '>')
+		++end;
+
+	      for (param = tmpl->params, arg = inst->args; param;
+		   param = param->next, arg = arg->next)
+		{
+		  if (end - src == strlen (param->name)
+		      && !memcmp (src, param->name, end - src))
+		    {
+		      src = end;
+		      break;
+		    }
+		}
+
+	      if (param == NULL)
+		fail ("template '%s' has no parameter '%.*s'\n",
+		      tmpl->name, (int)(end - src), src);
+
+	      while (ISSPACE(*src))
+		++src;
+	      if (*src != '>')
+		fail ("%s: %d: missing '>'\n", filename, lineno);
+
+	      memcpy(ptr1, arg->val, strlen(arg->val));
+	      ptr1 += strlen(arg->val);
+	      ++src;
+	    }
+
+	  *ptr1 = '\0';
+
+	  expand_templates (name2, str2, opcode_hash_table, opcode_array_p,
+			    lineno);
+
+	  free (str2);
+	  free (name2);
+	}
+    }
+
+  return idx;
+}
+
+static void
 process_i386_opcodes (FILE *table)
 {
   FILE *fp;
   char buf[2048];
   unsigned int i, j;
   char *str, *p, *last, *name;
-  struct opcode_hash_entry **hash_slot, **entry, *next;
   htab_t opcode_hash_table;
-  struct opcode_hash_entry **opcode_array;
-  unsigned int opcode_array_size = 1024;
+  struct opcode_hash_entry **opcode_array = NULL;
   int lineno = 0, marker = 0;
 
   filename = "i386-opc.tbl";
   fp = stdin;
 
   i = 0;
-  opcode_array = (struct opcode_hash_entry **)
-    xmalloc (sizeof (*opcode_array) * opcode_array_size);
-
   opcode_hash_table = htab_create_alloc (16, opcode_hash_hash,
 					 opcode_hash_eq, NULL,
 					 xcalloc, free);
@@ -1444,6 +1698,9 @@  process_i386_opcodes (FILE *table)
 	case '\0':
 	  continue;
 	  break;
+	case '<':
+	  parse_template (p, lineno);
+	  continue;
 	default:
 	  if (!marker)
 	    continue;
@@ -1455,51 +1712,15 @@  process_i386_opcodes (FILE *table)
       /* Find name.  */
       name = next_field (p, ',', &str, last);
 
-      /* Get the slot in hash table.  */
-      hash_slot = (struct opcode_hash_entry **)
-	htab_find_slot_with_hash (opcode_hash_table, name,
-				  htab_hash_string (name),
-				  INSERT);
-
-      if (*hash_slot == NULL)
-	{
-	  /* It is the new one.  Put it on opcode array.  */
-	  if (i >= opcode_array_size)
-	    {
-	      /* Grow the opcode array when needed.  */
-	      opcode_array_size += 1024;
-	      opcode_array = (struct opcode_hash_entry **)
-		xrealloc (opcode_array,
-			  sizeof (*opcode_array) * opcode_array_size);
-	    }
-
-	  opcode_array[i] = (struct opcode_hash_entry *)
-	    xmalloc (sizeof (struct opcode_hash_entry));
-	  opcode_array[i]->next = NULL;
-	  opcode_array[i]->name = xstrdup (name);
-	  opcode_array[i]->opcode = xstrdup (str);
-	  opcode_array[i]->lineno = lineno;
-	  *hash_slot = opcode_array[i];
-	  i++;
-	}
-      else
-	{
-	  /* Append it to the existing one.  */
-	  entry = hash_slot;
-	  while ((*entry) != NULL)
-	    entry = &(*entry)->next;
-	  *entry = (struct opcode_hash_entry *)
-	    xmalloc (sizeof (struct opcode_hash_entry));
-	  (*entry)->next = NULL;
-	  (*entry)->name = (*hash_slot)->name;
-	  (*entry)->opcode = xstrdup (str);
-	  (*entry)->lineno = lineno;
-	}
+      i = expand_templates (name, str, opcode_hash_table, &opcode_array,
+			    lineno);
     }
 
   /* Process opcode array.  */
   for (j = 0; j < i; j++)
     {
+      struct opcode_hash_entry *next;
+
       for (next = opcode_array[j]; next; next = next->next)
 	{
 	  name = next->name;
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -420,37 +420,11 @@  enter, 2, 0xc8, None, 1, Cpu64, DefaultS
 leave, 0, 0xc9, None, 1, Cpu186|CpuNo64, DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { 0 }
 leave, 0, 0xc9, None, 1, Cpu64, DefaultSize|No_bSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64, { 0 }
 
+<cc:opc, o:0, no:1, b:2, c:2, nae:2, nb:3, nc:3, ae:3, e:4, z:4, ne:5, nz:5, be:6, na:6, nbe:7, a:7, \
+         s:8, ns:9, p:a, pe:a, np:b, po:b, l:c, nge:c, nl:d, ge:d, le:e, ng:e, nle:f, g:f>
+
 // Conditional jumps.
-jo, 1, 0x70, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jno, 1, 0x71, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jb, 1, 0x72, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jc, 1, 0x72, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jnae, 1, 0x72, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jnb, 1, 0x73, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jnc, 1, 0x73, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jae, 1, 0x73, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-je, 1, 0x74, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jz, 1, 0x74, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jne, 1, 0x75, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jnz, 1, 0x75, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jbe, 1, 0x76, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jna, 1, 0x76, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jnbe, 1, 0x77, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-ja, 1, 0x77, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-js, 1, 0x78, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jns, 1, 0x79, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jp, 1, 0x7a, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jpe, 1, 0x7a, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jnp, 1, 0x7b, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jpo, 1, 0x7b, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jl, 1, 0x7c, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jnge, 1, 0x7c, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jnl, 1, 0x7d, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jge, 1, 0x7d, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jle, 1, 0x7e, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jng, 1, 0x7e, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jnle, 1, 0x7f, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
-jg, 1, 0x7f, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
+j<cc>, 1, 0x7<cc:opc>, None, 1, 0, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32|Disp32S }
 
 // jcxz vs. jecxz is chosen on the basis of the address size prefix.
 jcxz, 1, 0xe3, None, 1, CpuNo64, JumpByte|Size16|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Disp8 }
@@ -473,36 +447,7 @@  loopne, 1, 0xe0, None, 1, CpuNo64, JumpB
 loopne, 1, 0xe0, None, 1, Cpu64, JumpByte|No_bSuf|No_wSuf|No_sSuf|No_ldSuf|NoRex64, { Disp8 }
 
 // Set byte on flag instructions.
-seto, 1, 0xf90, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setno, 1, 0xf91, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setb, 1, 0xf92, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setc, 1, 0xf92, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setnae, 1, 0xf92, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setnb, 1, 0xf93, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setnc, 1, 0xf93, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setae, 1, 0xf93, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-sete, 1, 0xf94, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setz, 1, 0xf94, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setne, 1, 0xf95, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setnz, 1, 0xf95, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setbe, 1, 0xf96, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setna, 1, 0xf96, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setnbe, 1, 0xf97, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-seta, 1, 0xf97, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-sets, 1, 0xf98, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setns, 1, 0xf99, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setp, 1, 0xf9a, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setpe, 1, 0xf9a, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setnp, 1, 0xf9b, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setpo, 1, 0xf9b, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setl, 1, 0xf9c, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setnge, 1, 0xf9c, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setnl, 1, 0xf9d, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setge, 1, 0xf9d, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setle, 1, 0xf9e, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setng, 1, 0xf9e, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setnle, 1, 0xf9f, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
-setg, 1, 0xf9f, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
+set<cc>, 1, 0xf9<cc:opc>, 0x0, 2, Cpu386, Modrm|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Reg8|Byte|Unspecified|BaseIndex }
 
 // String manipulation.
 cmps, 0, 0xa6, None, 1, 0, W|No_sSuf|No_ldSuf|IsString|RepPrefixOk, { 0 }
@@ -934,36 +879,7 @@  ud2b, 2, 0xfb9, None, 2, Cpu186, Modrm|N
 // 3rd official undefined instr (older CPUs don't take a ModR/M byte)
 ud0, 2, 0xfff, None, 2, Cpu186, Modrm|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
 
-cmovo, 2, 0xf40, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovno, 2, 0xf41, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovb, 2, 0xf42, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovc, 2, 0xf42, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovnae, 2, 0xf42, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovae, 2, 0xf43, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovnc, 2, 0xf43, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovnb, 2, 0xf43, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmove, 2, 0xf44, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovz, 2, 0xf44, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovne, 2, 0xf45, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovnz, 2, 0xf45, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovbe, 2, 0xf46, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovna, 2, 0xf46, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmova, 2, 0xf47, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovnbe, 2, 0xf47, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovs, 2, 0xf48, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovns, 2, 0xf49, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovp, 2, 0xf4a, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovnp, 2, 0xf4b, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovl, 2, 0xf4c, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovnge, 2, 0xf4c, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovge, 2, 0xf4d, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovnl, 2, 0xf4d, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovle, 2, 0xf4e, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovng, 2, 0xf4e, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovg, 2, 0xf4f, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovnle, 2, 0xf4f, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovpe, 2, 0xf4a, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
-cmovpo, 2, 0xf4b, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
+cmov<cc>, 2, 0xf4<cc:opc>, None, 2, CpuCMOV, Modrm|CheckRegSize|No_bSuf|No_sSuf|No_ldSuf, { Reg16|Reg32|Reg64|Word|Dword|Qword|Unspecified|BaseIndex, Reg16|Reg32|Reg64 }
 
 fcmovb, 2, 0xdac0, None, 2, Cpu687, No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { FloatReg, FloatAcc }
 fcmovnae, 2, 0xdac0, None, 2, Cpu687, No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { FloatReg, FloatAcc }