[03/13] x86: introduce operand type "class"

Message ID d1b961c2-484f-52cb-bdb4-d0f34cb61a65@suse.com
State New
Headers show
Series
  • x86: further insn template compaction
Related show

Commit Message

Jan Beulich Oct. 30, 2019, 8:24 a.m.
Many operand types, in particular the various kinds of registers, can't
be combined with one another (neither in templates nor in register
entries), and hence it is not a good use of resources (memory as well as
execution time) to represent them as individual bits of a bit field.

gas/
2019-10-XX  Jan Beulich  <jbeulich@suse.com>

	* config/tc-i386.c (operand_type_set, operand_type_and,
	operand_type_and_not, operand_type_or, operand_type_xor): Handle
	"class" field specially.
	(anyimm): New.
	(operand_type_check, operand_size_match,
	operand_type_register_match, pi, md_assemble, is_short_form,
	process_suffix, check_byte_reg, check_long_reg, check_qword_reg,
	check_word_reg, process_operands, build_modrm_byte): Use "class"
	instead of "reg" field.
	(optimize_imm): Likewise. Reduce redundancy. Adjust calculation
	of "allowed".

opcodes/
2019-10-XX  Jan Beulich  <jbeulich@suse.com>

	* i386-gen.c (operand_type_init): Add Class=. New
	OPERAND_TYPE_ANYIMM entry.
	(operand_classes): New.
	(operand_types): Drop Reg entry.
	(output_operand_type): New parameter "class". Process it.
	(process_i386_operand_type): New local variable "class".
	(main): Adjust static assertions.
	* i386-opc.h (CLASS_WIDTH): Define.
	(enum operand_class): New.
	(Reg): Replace by Class. Adjust comment.
	(union i386_operand_type): Replace reg by class.
	* i386-opc.tbl (Reg8, Reg16, Reg32, Reg64, FloatReg): Add
	Class=.
	* i386-reg.tbl: Replace Reg by Class=Reg.
	* i386-init.h: Re-generate.

Comments

H.J. Lu Oct. 31, 2019, 7:25 p.m. | #1
On Wed, Oct 30, 2019 at 1:24 AM Jan Beulich <jbeulich@suse.com> wrote:
>

> Many operand types, in particular the various kinds of registers, can't

> be combined with one another (neither in templates nor in register

> entries), and hence it is not a good use of resources (memory as well as

> execution time) to represent them as individual bits of a bit field.

>

> gas/

> 2019-10-XX  Jan Beulich  <jbeulich@suse.com>

>

>         * config/tc-i386.c (operand_type_set, operand_type_and,

>         operand_type_and_not, operand_type_or, operand_type_xor): Handle

>         "class" field specially.

>         (anyimm): New.

>         (operand_type_check, operand_size_match,

>         operand_type_register_match, pi, md_assemble, is_short_form,

>         process_suffix, check_byte_reg, check_long_reg, check_qword_reg,

>         check_word_reg, process_operands, build_modrm_byte): Use "class"

>         instead of "reg" field.

>         (optimize_imm): Likewise. Reduce redundancy. Adjust calculation

>         of "allowed".

>

> opcodes/

> 2019-10-XX  Jan Beulich  <jbeulich@suse.com>

>

>         * i386-gen.c (operand_type_init): Add Class=. New

>         OPERAND_TYPE_ANYIMM entry.

>         (operand_classes): New.

>         (operand_types): Drop Reg entry.

>         (output_operand_type): New parameter "class". Process it.

>         (process_i386_operand_type): New local variable "class".

>         (main): Adjust static assertions.

>         * i386-opc.h (CLASS_WIDTH): Define.

>         (enum operand_class): New.

>         (Reg): Replace by Class. Adjust comment.

>         (union i386_operand_type): Replace reg by class.

>         * i386-opc.tbl (Reg8, Reg16, Reg32, Reg64, FloatReg): Add

>         Class=.

>         * i386-reg.tbl: Replace Reg by Class=Reg.

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

>


OK.

Thanks.


-- 
H.J.

Patch

--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -1607,6 +1607,8 @@  operand_type_set (union i386_operand_typ
     default:
       abort ();
     }
+
+  x->bitfield.class = ClassNone;
 }
 
 static INLINE int
@@ -1823,6 +1825,9 @@  cpu_flags_match (const insn_template *t)
 static INLINE i386_operand_type
 operand_type_and (i386_operand_type x, i386_operand_type y)
 {
+  if (x.bitfield.class != y.bitfield.class)
+    x.bitfield.class = ClassNone;
+
   switch (ARRAY_SIZE (x.array))
     {
     case 3:
@@ -1843,6 +1848,8 @@  operand_type_and (i386_operand_type x, i
 static INLINE i386_operand_type
 operand_type_and_not (i386_operand_type x, i386_operand_type y)
 {
+  gas_assert (y.bitfield.class == ClassNone);
+
   switch (ARRAY_SIZE (x.array))
     {
     case 3:
@@ -1863,6 +1870,10 @@  operand_type_and_not (i386_operand_type
 static INLINE i386_operand_type
 operand_type_or (i386_operand_type x, i386_operand_type y)
 {
+  gas_assert (x.bitfield.class == ClassNone ||
+              y.bitfield.class == ClassNone ||
+              x.bitfield.class == y.bitfield.class);
+
   switch (ARRAY_SIZE (x.array))
     {
     case 3:
@@ -1883,6 +1894,8 @@  operand_type_or (i386_operand_type x, i3
 static INLINE i386_operand_type
 operand_type_xor (i386_operand_type x, i386_operand_type y)
 {
+  gas_assert (y.bitfield.class == ClassNone);
+
   switch (ARRAY_SIZE (x.array))
     {
     case 3:
@@ -1904,8 +1917,8 @@  static const i386_operand_type disp16 =
 static const i386_operand_type disp32 = OPERAND_TYPE_DISP32;
 static const i386_operand_type disp32s = OPERAND_TYPE_DISP32S;
 static const i386_operand_type disp16_32 = OPERAND_TYPE_DISP16_32;
-static const i386_operand_type anydisp
-  = OPERAND_TYPE_ANYDISP;
+static const i386_operand_type anydisp = OPERAND_TYPE_ANYDISP;
+static const i386_operand_type anyimm = OPERAND_TYPE_ANYIMM;
 static const i386_operand_type regxmm = OPERAND_TYPE_REGXMM;
 static const i386_operand_type regmask = OPERAND_TYPE_REGMASK;
 static const i386_operand_type imm8 = OPERAND_TYPE_IMM8;
@@ -1932,7 +1945,7 @@  operand_type_check (i386_operand_type t,
   switch (c)
     {
     case reg:
-      return t.bitfield.reg;
+      return t.bitfield.class == Reg;
 
     case imm:
       return (t.bitfield.imm8
@@ -2050,11 +2063,11 @@  operand_size_match (const insn_template
   /* Check memory and accumulator operand size.  */
   for (j = 0; j < i.operands; j++)
     {
-      if (!i.types[j].bitfield.reg && !i.types[j].bitfield.regsimd
+      if (i.types[j].bitfield.class != Reg && !i.types[j].bitfield.regsimd
 	  && t->operand_types[j].bitfield.anysize)
 	continue;
 
-      if (t->operand_types[j].bitfield.reg
+      if (t->operand_types[j].bitfield.class == Reg
 	  && !match_operand_size (t, j, j))
 	{
 	  match = 0;
@@ -2097,7 +2110,7 @@  mismatch:
     {
       unsigned int given = i.operands - j - 1;
 
-      if (t->operand_types[j].bitfield.reg
+      if (t->operand_types[j].bitfield.class == Reg
 	  && !match_operand_size (t, j, given))
 	goto mismatch;
 
@@ -2157,14 +2170,14 @@  operand_type_register_match (i386_operan
 			     i386_operand_type g1,
 			     i386_operand_type t1)
 {
-  if (!g0.bitfield.reg
+  if (g0.bitfield.class != Reg
       && !g0.bitfield.regsimd
       && (!operand_type_check (g0, anymem)
 	  || g0.bitfield.unspecified
 	  || !t0.bitfield.regsimd))
     return 1;
 
-  if (!g1.bitfield.reg
+  if (g1.bitfield.class != Reg
       && !g1.bitfield.regsimd
       && (!operand_type_check (g1, anymem)
 	  || g1.bitfield.unspecified
@@ -3030,7 +3044,7 @@  pi (const char *line, i386_insn *x)
       fprintf (stdout, "    #%d:  ", j + 1);
       pt (x->types[j]);
       fprintf (stdout, "\n");
-      if (x->types[j].bitfield.reg
+      if (x->types[j].bitfield.class == Reg
 	  || x->types[j].bitfield.regmmx
 	  || x->types[j].bitfield.regsimd
 	  || x->types[j].bitfield.sreg
@@ -4489,12 +4503,12 @@  md_assemble (char *line)
      instruction already has a prefix, we need to convert old
      registers to new ones.  */
 
-  if ((i.types[0].bitfield.reg && i.types[0].bitfield.byte
+  if ((i.types[0].bitfield.class == Reg && i.types[0].bitfield.byte
        && (i.op[0].regs->reg_flags & RegRex64) != 0)
-      || (i.types[1].bitfield.reg && i.types[1].bitfield.byte
+      || (i.types[1].bitfield.class == Reg && i.types[1].bitfield.byte
 	  && (i.op[1].regs->reg_flags & RegRex64) != 0)
-      || (((i.types[0].bitfield.reg && i.types[0].bitfield.byte)
-	   || (i.types[1].bitfield.reg && i.types[1].bitfield.byte))
+      || (((i.types[0].bitfield.class == Reg && i.types[0].bitfield.byte)
+	   || (i.types[1].bitfield.class == Reg && i.types[1].bitfield.byte))
 	  && i.rex != 0))
     {
       int x;
@@ -4503,7 +4517,7 @@  md_assemble (char *line)
       for (x = 0; x < 2; x++)
 	{
 	  /* Look for 8 bit operand that uses old registers.  */
-	  if (i.types[x].bitfield.reg && i.types[x].bitfield.byte
+	  if (i.types[x].bitfield.class == Reg && i.types[x].bitfield.byte
 	      && (i.op[x].regs->reg_flags & RegRex64) == 0)
 	    {
 	      /* In case it is "hi" register, give up.  */
@@ -4528,7 +4542,7 @@  md_assemble (char *line)
 	 the REX_OPCODE byte.  */
       int x;
       for (x = 0; x < 2; x++)
-	if (i.types[x].bitfield.reg
+	if (i.types[x].bitfield.class == Reg
 	    && i.types[x].bitfield.byte
 	    && (i.op[x].regs->reg_flags & RegRex64) == 0
 	    && i.op[x].regs->reg_num > 3)
@@ -5049,22 +5063,24 @@  optimize_imm (void)
 	 but the following works for instructions with immediates.
 	 In any case, we can't set i.suffix yet.  */
       for (op = i.operands; --op >= 0;)
-	if (i.types[op].bitfield.reg && i.types[op].bitfield.byte)
+	if (i.types[op].bitfield.class != Reg)
+	  continue;
+	else if (i.types[op].bitfield.byte)
 	  {
 	    guess_suffix = BYTE_MNEM_SUFFIX;
 	    break;
 	  }
-	else if (i.types[op].bitfield.reg && i.types[op].bitfield.word)
+	else if (i.types[op].bitfield.word)
 	  {
 	    guess_suffix = WORD_MNEM_SUFFIX;
 	    break;
 	  }
-	else if (i.types[op].bitfield.reg && i.types[op].bitfield.dword)
+	else if (i.types[op].bitfield.dword)
 	  {
 	    guess_suffix = LONG_MNEM_SUFFIX;
 	    break;
 	  }
-	else if (i.types[op].bitfield.reg && i.types[op].bitfield.qword)
+	else if (i.types[op].bitfield.qword)
 	  {
 	    guess_suffix = QWORD_MNEM_SUFFIX;
 	    break;
@@ -5153,8 +5169,10 @@  optimize_imm (void)
 	      for (t = current_templates->start;
 		   t < current_templates->end;
 		   ++t)
-		allowed = operand_type_or (allowed,
-					   t->operand_types[op]);
+		{
+		  allowed = operand_type_or (allowed, t->operand_types[op]);
+		  allowed = operand_type_and (allowed, anyimm);
+		}
 	      switch (guess_suffix)
 		{
 		case QWORD_MNEM_SUFFIX:
@@ -6218,7 +6236,7 @@  is_short_form (const insn_template *t)
     return FALSE;
 
   for (num_reg = op = 0; op < t->operands; ++op)
-    if (t->operand_types[op].bitfield.reg)
+    if (t->operand_types[op].bitfield.class == Reg)
       ++num_reg;
 
   return num_reg == 1;
@@ -6260,7 +6278,7 @@  process_suffix (void)
 	    if (!i.tm.operand_types[op].bitfield.inoutportreg
 		&& !i.tm.operand_types[op].bitfield.shiftcount)
 	      {
-		if (!i.types[op].bitfield.reg)
+		if (i.types[op].bitfield.class != Reg)
 		  continue;
 		if (i.types[op].bitfield.byte)
 		  i.suffix = BYTE_MNEM_SUFFIX;
@@ -6538,7 +6556,7 @@  process_suffix (void)
 	 size prefix, except for instructions that will ignore this
 	 prefix anyway.  */
       if (i.reg_operands > 0
-	  && i.types[0].bitfield.reg
+	  && i.types[0].bitfield.class == Reg
 	  && i.tm.opcode_modifier.addrprefixopreg
 	  && (i.tm.opcode_modifier.immext
 	      || i.operands == 1))
@@ -6606,7 +6624,7 @@  process_suffix (void)
 	}
 
       for (op = 0; op < i.operands; op++)
-	if (i.types[op].bitfield.reg
+	if (i.types[op].bitfield.class == Reg
 	    && ((need == need_word
 		 && !i.op[op].regs->reg_type.bitfield.word)
 		|| (need == need_dword
@@ -6631,7 +6649,7 @@  check_byte_reg (void)
   for (op = i.operands; --op >= 0;)
     {
       /* Skip non-register operands. */
-      if (!i.types[op].bitfield.reg)
+      if (i.types[op].bitfield.class != Reg)
 	continue;
 
       /* If this is an eight bit register, it's OK.  If it's the 16 or
@@ -6670,7 +6688,7 @@  check_byte_reg (void)
 	  continue;
 	}
       /* Any other register is bad.  */
-      if (i.types[op].bitfield.reg
+      if (i.types[op].bitfield.class == Reg
 	  || i.types[op].bitfield.regmmx
 	  || i.types[op].bitfield.regsimd
 	  || i.types[op].bitfield.sreg
@@ -6696,12 +6714,12 @@  check_long_reg (void)
 
   for (op = i.operands; --op >= 0;)
     /* Skip non-register operands. */
-    if (!i.types[op].bitfield.reg)
+    if (i.types[op].bitfield.class != Reg)
       continue;
     /* Reject eight bit registers, except where the template requires
        them. (eg. movzb)  */
     else if (i.types[op].bitfield.byte
-	     && (i.tm.operand_types[op].bitfield.reg
+	     && (i.tm.operand_types[op].bitfield.class == Reg
 		 || i.tm.operand_types[op].bitfield.acc)
 	     && (i.tm.operand_types[op].bitfield.word
 		 || i.tm.operand_types[op].bitfield.dword))
@@ -6716,7 +6734,7 @@  check_long_reg (void)
     /* Warn if the e prefix on a general reg is missing.  */
     else if ((!quiet_warnings || flag_code == CODE_64BIT)
 	     && i.types[op].bitfield.word
-	     && (i.tm.operand_types[op].bitfield.reg
+	     && (i.tm.operand_types[op].bitfield.class == Reg
 		 || i.tm.operand_types[op].bitfield.acc)
 	     && i.tm.operand_types[op].bitfield.dword)
       {
@@ -6738,7 +6756,7 @@  check_long_reg (void)
       }
     /* Warn if the r prefix on a general reg is present.  */
     else if (i.types[op].bitfield.qword
-	     && (i.tm.operand_types[op].bitfield.reg
+	     && (i.tm.operand_types[op].bitfield.class == Reg
 		 || i.tm.operand_types[op].bitfield.acc)
 	     && i.tm.operand_types[op].bitfield.dword)
       {
@@ -6767,12 +6785,12 @@  check_qword_reg (void)
 
   for (op = i.operands; --op >= 0; )
     /* Skip non-register operands. */
-    if (!i.types[op].bitfield.reg)
+    if (i.types[op].bitfield.class != Reg)
       continue;
     /* Reject eight bit registers, except where the template requires
        them. (eg. movzb)  */
     else if (i.types[op].bitfield.byte
-	     && (i.tm.operand_types[op].bitfield.reg
+	     && (i.tm.operand_types[op].bitfield.class == Reg
 		 || i.tm.operand_types[op].bitfield.acc)
 	     && (i.tm.operand_types[op].bitfield.word
 		 || i.tm.operand_types[op].bitfield.dword))
@@ -6787,7 +6805,7 @@  check_qword_reg (void)
     /* Warn if the r prefix on a general reg is missing.  */
     else if ((i.types[op].bitfield.word
 	      || i.types[op].bitfield.dword)
-	     && (i.tm.operand_types[op].bitfield.reg
+	     && (i.tm.operand_types[op].bitfield.class == Reg
 		 || i.tm.operand_types[op].bitfield.acc)
 	     && i.tm.operand_types[op].bitfield.qword)
       {
@@ -6817,12 +6835,12 @@  check_word_reg (void)
   int op;
   for (op = i.operands; --op >= 0;)
     /* Skip non-register operands. */
-    if (!i.types[op].bitfield.reg)
+    if (i.types[op].bitfield.class != Reg)
       continue;
     /* Reject eight bit registers, except where the template requires
        them. (eg. movzb)  */
     else if (i.types[op].bitfield.byte
-	     && (i.tm.operand_types[op].bitfield.reg
+	     && (i.tm.operand_types[op].bitfield.class == Reg
 		 || i.tm.operand_types[op].bitfield.acc)
 	     && (i.tm.operand_types[op].bitfield.word
 		 || i.tm.operand_types[op].bitfield.dword))
@@ -6838,7 +6856,7 @@  check_word_reg (void)
     else if ((!quiet_warnings || flag_code == CODE_64BIT)
 	     && (i.types[op].bitfield.dword
 		 || i.types[op].bitfield.qword)
-	     && (i.tm.operand_types[op].bitfield.reg
+	     && (i.tm.operand_types[op].bitfield.class == Reg
 		 || i.tm.operand_types[op].bitfield.acc)
 	     && i.tm.operand_types[op].bitfield.word)
       {
@@ -7136,7 +7154,7 @@  duplicate:
     {
       /* The register or float register operand is in operand
 	 0 or 1.  */
-      unsigned int op = !i.tm.operand_types[0].bitfield.reg;
+      unsigned int op = i.tm.operand_types[0].bitfield.class != Reg;
 
       /* Register goes in low 3 bits of opcode.  */
       i.tm.base_opcode |= i.op[op].regs->reg_num;
@@ -7371,7 +7389,7 @@  build_modrm_byte (void)
 
 	      op = i.tm.operand_types[vvvv];
 	      if ((dest + 1) >= i.operands
-		  || ((!op.bitfield.reg
+		  || ((op.bitfield.class != Reg
 		       || (!op.bitfield.dword && !op.bitfield.qword))
 		      && !op.bitfield.regsimd
 		      && !operand_type_equal (&op, &regmask)))
@@ -7748,7 +7766,7 @@  build_modrm_byte (void)
 
 	  for (op = 0; op < i.operands; op++)
 	    {
-	      if (i.types[op].bitfield.reg
+	      if (i.types[op].bitfield.class == Reg
 		  || i.types[op].bitfield.regbnd
 		  || i.types[op].bitfield.regmask
 		  || i.types[op].bitfield.sreg
@@ -7830,7 +7848,7 @@  build_modrm_byte (void)
 	    {
 	      i386_operand_type *type = &i.tm.operand_types[vex_reg];
 
-	      if ((!type->bitfield.reg
+	      if ((type->bitfield.class != Reg
 		   || (!type->bitfield.dword && !type->bitfield.qword))
 		  && !type->bitfield.regsimd
 		  && !operand_type_equal (type, &regmask))
--- a/opcodes/i386-gen.c
+++ b/opcodes/i386-gen.c
@@ -384,13 +384,13 @@  static initializer operand_type_init[] =
   { "OPERAND_TYPE_NONE",
     "0" },
   { "OPERAND_TYPE_REG8",
-    "Reg|Byte" },
+    "Class=Reg|Byte" },
   { "OPERAND_TYPE_REG16",
-    "Reg|Word" },
+    "Class=Reg|Word" },
   { "OPERAND_TYPE_REG32",
-    "Reg|Dword" },
+    "Class=Reg|Dword" },
   { "OPERAND_TYPE_REG64",
-    "Reg|Qword" },
+    "Class=Reg|Qword" },
   { "OPERAND_TYPE_IMM1",
     "Imm1" },
   { "OPERAND_TYPE_IMM8",
@@ -428,7 +428,7 @@  static initializer operand_type_init[] =
   { "OPERAND_TYPE_DEBUG",
     "Debug" },
   { "OPERAND_TYPE_FLOATREG",
-    "Reg|Tbyte" },
+    "Class=Reg|Tbyte" },
   { "OPERAND_TYPE_FLOATACC",
     "Acc|Tbyte" },
   { "OPERAND_TYPE_SREG",
@@ -475,6 +475,8 @@  static initializer operand_type_init[] =
     "Imm32|Imm32S|Imm64|Disp32" },
   { "OPERAND_TYPE_IMM32_32S_64_DISP32_64",
     "Imm32|Imm32S|Imm64|Disp32|Disp64" },
+  { "OPERAND_TYPE_ANYIMM",
+    "Imm1|Imm8|Imm8S|Imm16|Imm32|Imm32S|Imm64" },
   { "OPERAND_TYPE_REGBND",
     "RegBND" },
 };
@@ -667,9 +669,19 @@  static bitfield opcode_modifiers[] =
   BITFIELD (Intel64),
 };
 
+#define CLASS(n) #n, n
+
+static const struct {
+  const char *name;
+  enum operand_class value;
+} operand_classes[] = {
+  CLASS (Reg),
+};
+
+#undef CLASS
+
 static bitfield operand_types[] =
 {
-  BITFIELD (Reg),
   BITFIELD (RegMMX),
   BITFIELD (RegSIMD),
   BITFIELD (RegMask),
@@ -1127,20 +1139,21 @@  enum stage {
 };
 
 static void
-output_operand_type (FILE *table, bitfield *types, unsigned int size,
+output_operand_type (FILE *table, enum operand_class class,
+		     const bitfield *types, unsigned int size,
 		     enum stage stage, const char *indent)
 {
   unsigned int i;
 
-  fprintf (table, "{ { ");
+  fprintf (table, "{ { %d, ", class);
 
   for (i = 0; i < size - 1; i++)
     {
-      if (((i + 1) % 20) != 0)
+      if (((i + 2) % 20) != 0)
 	fprintf (table, "%d, ", types[i].value);
       else
 	fprintf (table, "%d,", types[i].value);
-      if (((i + 1) % 20) == 0)
+      if (((i + 2) % 20) == 0)
 	{
 	  /* We need \\ for macro.  */
 	  if (stage == stage_macros)
@@ -1158,6 +1171,7 @@  process_i386_operand_type (FILE *table,
 			   const char *indent, int lineno)
 {
   char *str, *next, *last;
+  enum operand_class class = ClassNone;
   bitfield types [ARRAY_SIZE (operand_types)];
 
   /* Copy the default operand type.  */
@@ -1173,6 +1187,21 @@  process_i386_operand_type (FILE *table,
 	  str = next_field (next, '|', &next, last);
 	  if (str)
 	    {
+	      unsigned int i;
+
+	      if (!strncmp(str, "Class=", 6))
+		{
+		  for (i = 0; i < ARRAY_SIZE(operand_classes); ++i)
+		    if (!strcmp(str + 6, operand_classes[i].name))
+		      {
+			class = operand_classes[i].value;
+			str = NULL;
+			break;
+		      }
+		}
+	    }
+	  if (str)
+	    {
 	      set_bitfield (str, types, 1, ARRAY_SIZE (types), lineno);
 	      if (strcasecmp(str, "BaseIndex") == 0)
 		baseindex = 1;
@@ -1190,7 +1219,7 @@  process_i386_operand_type (FILE *table,
 	    set_bitfield("Disp32S", types, 1, ARRAY_SIZE (types), lineno);
 	}
     }
-  output_operand_type (table, types, ARRAY_SIZE (types), stage,
+  output_operand_type (table, class, types, ARRAY_SIZE (types), stage,
 		       indent);
 }
 
@@ -1681,9 +1710,9 @@  main (int argc, char **argv)
 
   /* Check the unused bitfield in i386_operand_type.  */
 #ifdef OTUnused
-  static_assert (ARRAY_SIZE (operand_types) == OTNum + 1);
+  static_assert (ARRAY_SIZE (operand_types) + CLASS_WIDTH == OTNum + 1);
 #else
-  static_assert (ARRAY_SIZE (operand_types) == OTNum);
+  static_assert (ARRAY_SIZE (operand_types) + CLASS_WIDTH == OTNum);
 
   c = OTNumOfBits - OTMax - 1;
   if (c)
--- a/opcodes/i386-opc.h
+++ b/opcodes/i386-opc.h
@@ -693,12 +693,21 @@  typedef struct i386_opcode_modifier
   unsigned int intel64:1;
 } i386_opcode_modifier;
 
+/* Operand classes.  */
+
+#define CLASS_WIDTH 4
+enum operand_class
+{
+  ClassNone,
+  Reg, /* GPRs and FP regs, distinguished by operand size */
+};
+
 /* Position of operand_type bits.  */
 
 enum
 {
-  /* Register (qualified by Byte, Word, etc) */
-  Reg = 0,
+  /* Class */
+  Class = CLASS_WIDTH - 1,
   /* MMX register */
   RegMMX,
   /* Vector registers */
@@ -782,7 +791,7 @@  enum
   /* Bound register.  */
   RegBND,
 
-  /* The number of bitfields in i386_operand_type.  */
+  /* The number of bits in i386_operand_type.  */
   OTNum
 };
 
@@ -799,7 +808,7 @@  typedef union i386_operand_type
 {
   struct
     {
-      unsigned int reg:1;
+      unsigned int class:CLASS_WIDTH;
       unsigned int regmmx:1;
       unsigned int regsimd:1;
       unsigned int regmask:1;
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -22,13 +22,13 @@ 
 #include "i386-opc.h"
 #undef None
 
-#define Reg8  Reg|Byte
-#define Reg16 Reg|Word
-#define Reg32 Reg|Dword
-#define Reg64 Reg|Qword
+#define Reg8  Class=Reg|Byte
+#define Reg16 Class=Reg|Word
+#define Reg32 Class=Reg|Dword
+#define Reg64 Class=Reg|Qword
 
 #define FloatAcc Acc|Tbyte
-#define FloatReg Reg|Tbyte
+#define FloatReg Class=Reg|Tbyte
 
 #define RegXMM RegSIMD|Xmmword
 #define RegYMM RegSIMD|Ymmword
--- a/opcodes/i386-reg.tbl
+++ b/opcodes/i386-reg.tbl
@@ -19,82 +19,82 @@ 
 // 02110-1301, USA.
 
 // Make %st first as we test for it.
-st, Reg|Acc|Tbyte, 0, 0, 11, 33
+st, Class=Reg|Acc|Tbyte, 0, 0, 11, 33
 // 8 bit regs
-al, Reg|Acc|Byte, 0, 0, Dw2Inval, Dw2Inval
-cl, Reg|Byte|ShiftCount, 0, 1, Dw2Inval, Dw2Inval
-dl, Reg|Byte, 0, 2, Dw2Inval, Dw2Inval
-bl, Reg|Byte, 0, 3, Dw2Inval, Dw2Inval
-ah, Reg|Byte, 0, 4, Dw2Inval, Dw2Inval
-ch, Reg|Byte, 0, 5, Dw2Inval, Dw2Inval
-dh, Reg|Byte, 0, 6, Dw2Inval, Dw2Inval
-bh, Reg|Byte, 0, 7, Dw2Inval, Dw2Inval
-axl, Reg|Byte, RegRex64, 0, Dw2Inval, Dw2Inval
-cxl, Reg|Byte, RegRex64, 1, Dw2Inval, Dw2Inval
-dxl, Reg|Byte, RegRex64, 2, Dw2Inval, Dw2Inval
-bxl, Reg|Byte, RegRex64, 3, Dw2Inval, Dw2Inval
-spl, Reg|Byte, RegRex64, 4, Dw2Inval, Dw2Inval
-bpl, Reg|Byte, RegRex64, 5, Dw2Inval, Dw2Inval
-sil, Reg|Byte, RegRex64, 6, Dw2Inval, Dw2Inval
-dil, Reg|Byte, RegRex64, 7, Dw2Inval, Dw2Inval
-r8b, Reg|Byte, RegRex|RegRex64, 0, Dw2Inval, Dw2Inval
-r9b, Reg|Byte, RegRex|RegRex64, 1, Dw2Inval, Dw2Inval
-r10b, Reg|Byte, RegRex|RegRex64, 2, Dw2Inval, Dw2Inval
-r11b, Reg|Byte, RegRex|RegRex64, 3, Dw2Inval, Dw2Inval
-r12b, Reg|Byte, RegRex|RegRex64, 4, Dw2Inval, Dw2Inval
-r13b, Reg|Byte, RegRex|RegRex64, 5, Dw2Inval, Dw2Inval
-r14b, Reg|Byte, RegRex|RegRex64, 6, Dw2Inval, Dw2Inval
-r15b, Reg|Byte, RegRex|RegRex64, 7, Dw2Inval, Dw2Inval
+al, Class=Reg|Acc|Byte, 0, 0, Dw2Inval, Dw2Inval
+cl, Class=Reg|Byte|ShiftCount, 0, 1, Dw2Inval, Dw2Inval
+dl, Class=Reg|Byte, 0, 2, Dw2Inval, Dw2Inval
+bl, Class=Reg|Byte, 0, 3, Dw2Inval, Dw2Inval
+ah, Class=Reg|Byte, 0, 4, Dw2Inval, Dw2Inval
+ch, Class=Reg|Byte, 0, 5, Dw2Inval, Dw2Inval
+dh, Class=Reg|Byte, 0, 6, Dw2Inval, Dw2Inval
+bh, Class=Reg|Byte, 0, 7, Dw2Inval, Dw2Inval
+axl, Class=Reg|Byte, RegRex64, 0, Dw2Inval, Dw2Inval
+cxl, Class=Reg|Byte, RegRex64, 1, Dw2Inval, Dw2Inval
+dxl, Class=Reg|Byte, RegRex64, 2, Dw2Inval, Dw2Inval
+bxl, Class=Reg|Byte, RegRex64, 3, Dw2Inval, Dw2Inval
+spl, Class=Reg|Byte, RegRex64, 4, Dw2Inval, Dw2Inval
+bpl, Class=Reg|Byte, RegRex64, 5, Dw2Inval, Dw2Inval
+sil, Class=Reg|Byte, RegRex64, 6, Dw2Inval, Dw2Inval
+dil, Class=Reg|Byte, RegRex64, 7, Dw2Inval, Dw2Inval
+r8b, Class=Reg|Byte, RegRex|RegRex64, 0, Dw2Inval, Dw2Inval
+r9b, Class=Reg|Byte, RegRex|RegRex64, 1, Dw2Inval, Dw2Inval
+r10b, Class=Reg|Byte, RegRex|RegRex64, 2, Dw2Inval, Dw2Inval
+r11b, Class=Reg|Byte, RegRex|RegRex64, 3, Dw2Inval, Dw2Inval
+r12b, Class=Reg|Byte, RegRex|RegRex64, 4, Dw2Inval, Dw2Inval
+r13b, Class=Reg|Byte, RegRex|RegRex64, 5, Dw2Inval, Dw2Inval
+r14b, Class=Reg|Byte, RegRex|RegRex64, 6, Dw2Inval, Dw2Inval
+r15b, Class=Reg|Byte, RegRex|RegRex64, 7, Dw2Inval, Dw2Inval
 // 16 bit regs
-ax, Reg|Acc|Word, 0, 0, Dw2Inval, Dw2Inval
-cx, Reg|Word, 0, 1, Dw2Inval, Dw2Inval
-dx, Reg|Word|InOutPortReg, 0, 2, Dw2Inval, Dw2Inval
-bx, Reg|Word|BaseIndex, 0, 3, Dw2Inval, Dw2Inval
-sp, Reg|Word, 0, 4, Dw2Inval, Dw2Inval
-bp, Reg|Word|BaseIndex, 0, 5, Dw2Inval, Dw2Inval
-si, Reg|Word|BaseIndex, 0, 6, Dw2Inval, Dw2Inval
-di, Reg|Word|BaseIndex, 0, 7, Dw2Inval, Dw2Inval
-r8w, Reg|Word, RegRex, 0, Dw2Inval, Dw2Inval
-r9w, Reg|Word, RegRex, 1, Dw2Inval, Dw2Inval
-r10w, Reg|Word, RegRex, 2, Dw2Inval, Dw2Inval
-r11w, Reg|Word, RegRex, 3, Dw2Inval, Dw2Inval
-r12w, Reg|Word, RegRex, 4, Dw2Inval, Dw2Inval
-r13w, Reg|Word, RegRex, 5, Dw2Inval, Dw2Inval
-r14w, Reg|Word, RegRex, 6, Dw2Inval, Dw2Inval
-r15w, Reg|Word, RegRex, 7, Dw2Inval, Dw2Inval
+ax, Class=Reg|Acc|Word, 0, 0, Dw2Inval, Dw2Inval
+cx, Class=Reg|Word, 0, 1, Dw2Inval, Dw2Inval
+dx, Class=Reg|Word|InOutPortReg, 0, 2, Dw2Inval, Dw2Inval
+bx, Class=Reg|Word|BaseIndex, 0, 3, Dw2Inval, Dw2Inval
+sp, Class=Reg|Word, 0, 4, Dw2Inval, Dw2Inval
+bp, Class=Reg|Word|BaseIndex, 0, 5, Dw2Inval, Dw2Inval
+si, Class=Reg|Word|BaseIndex, 0, 6, Dw2Inval, Dw2Inval
+di, Class=Reg|Word|BaseIndex, 0, 7, Dw2Inval, Dw2Inval
+r8w, Class=Reg|Word, RegRex, 0, Dw2Inval, Dw2Inval
+r9w, Class=Reg|Word, RegRex, 1, Dw2Inval, Dw2Inval
+r10w, Class=Reg|Word, RegRex, 2, Dw2Inval, Dw2Inval
+r11w, Class=Reg|Word, RegRex, 3, Dw2Inval, Dw2Inval
+r12w, Class=Reg|Word, RegRex, 4, Dw2Inval, Dw2Inval
+r13w, Class=Reg|Word, RegRex, 5, Dw2Inval, Dw2Inval
+r14w, Class=Reg|Word, RegRex, 6, Dw2Inval, Dw2Inval
+r15w, Class=Reg|Word, RegRex, 7, Dw2Inval, Dw2Inval
 // 32 bit regs
-eax, Reg|Acc|Dword|BaseIndex, 0, 0, 0, Dw2Inval
-ecx, Reg|Dword|BaseIndex, 0, 1, 1, Dw2Inval
-edx, Reg|Dword|BaseIndex, 0, 2, 2, Dw2Inval
-ebx, Reg|Dword|BaseIndex, 0, 3, 3, Dw2Inval
-esp, Reg|Dword, 0, 4, 4, Dw2Inval
-ebp, Reg|Dword|BaseIndex, 0, 5, 5, Dw2Inval
-esi, Reg|Dword|BaseIndex, 0, 6, 6, Dw2Inval
-edi, Reg|Dword|BaseIndex, 0, 7, 7, Dw2Inval
-r8d, Reg|Dword|BaseIndex, RegRex, 0, Dw2Inval, Dw2Inval
-r9d, Reg|Dword|BaseIndex, RegRex, 1, Dw2Inval, Dw2Inval
-r10d, Reg|Dword|BaseIndex, RegRex, 2, Dw2Inval, Dw2Inval
-r11d, Reg|Dword|BaseIndex, RegRex, 3, Dw2Inval, Dw2Inval
-r12d, Reg|Dword|BaseIndex, RegRex, 4, Dw2Inval, Dw2Inval
-r13d, Reg|Dword|BaseIndex, RegRex, 5, Dw2Inval, Dw2Inval
-r14d, Reg|Dword|BaseIndex, RegRex, 6, Dw2Inval, Dw2Inval
-r15d, Reg|Dword|BaseIndex, RegRex, 7, Dw2Inval, Dw2Inval
-rax, Reg|Acc|Qword|BaseIndex, 0, 0, Dw2Inval, 0
-rcx, Reg|Qword|BaseIndex, 0, 1, Dw2Inval, 2
-rdx, Reg|Qword|BaseIndex, 0, 2, Dw2Inval, 1
-rbx, Reg|Qword|BaseIndex, 0, 3, Dw2Inval, 3
-rsp, Reg|Qword, 0, 4, Dw2Inval, 7
-rbp, Reg|Qword|BaseIndex, 0, 5, Dw2Inval, 6
-rsi, Reg|Qword|BaseIndex, 0, 6, Dw2Inval, 4
-rdi, Reg|Qword|BaseIndex, 0, 7, Dw2Inval, 5
-r8, Reg|Qword|BaseIndex, RegRex, 0, Dw2Inval, 8
-r9, Reg|Qword|BaseIndex, RegRex, 1, Dw2Inval, 9
-r10, Reg|Qword|BaseIndex, RegRex, 2, Dw2Inval, 10
-r11, Reg|Qword|BaseIndex, RegRex, 3, Dw2Inval, 11
-r12, Reg|Qword|BaseIndex, RegRex, 4, Dw2Inval, 12
-r13, Reg|Qword|BaseIndex, RegRex, 5, Dw2Inval, 13
-r14, Reg|Qword|BaseIndex, RegRex, 6, Dw2Inval, 14
-r15, Reg|Qword|BaseIndex, RegRex, 7, Dw2Inval, 15
+eax, Class=Reg|Acc|Dword|BaseIndex, 0, 0, 0, Dw2Inval
+ecx, Class=Reg|Dword|BaseIndex, 0, 1, 1, Dw2Inval
+edx, Class=Reg|Dword|BaseIndex, 0, 2, 2, Dw2Inval
+ebx, Class=Reg|Dword|BaseIndex, 0, 3, 3, Dw2Inval
+esp, Class=Reg|Dword, 0, 4, 4, Dw2Inval
+ebp, Class=Reg|Dword|BaseIndex, 0, 5, 5, Dw2Inval
+esi, Class=Reg|Dword|BaseIndex, 0, 6, 6, Dw2Inval
+edi, Class=Reg|Dword|BaseIndex, 0, 7, 7, Dw2Inval
+r8d, Class=Reg|Dword|BaseIndex, RegRex, 0, Dw2Inval, Dw2Inval
+r9d, Class=Reg|Dword|BaseIndex, RegRex, 1, Dw2Inval, Dw2Inval
+r10d, Class=Reg|Dword|BaseIndex, RegRex, 2, Dw2Inval, Dw2Inval
+r11d, Class=Reg|Dword|BaseIndex, RegRex, 3, Dw2Inval, Dw2Inval
+r12d, Class=Reg|Dword|BaseIndex, RegRex, 4, Dw2Inval, Dw2Inval
+r13d, Class=Reg|Dword|BaseIndex, RegRex, 5, Dw2Inval, Dw2Inval
+r14d, Class=Reg|Dword|BaseIndex, RegRex, 6, Dw2Inval, Dw2Inval
+r15d, Class=Reg|Dword|BaseIndex, RegRex, 7, Dw2Inval, Dw2Inval
+rax, Class=Reg|Acc|Qword|BaseIndex, 0, 0, Dw2Inval, 0
+rcx, Class=Reg|Qword|BaseIndex, 0, 1, Dw2Inval, 2
+rdx, Class=Reg|Qword|BaseIndex, 0, 2, Dw2Inval, 1
+rbx, Class=Reg|Qword|BaseIndex, 0, 3, Dw2Inval, 3
+rsp, Class=Reg|Qword, 0, 4, Dw2Inval, 7
+rbp, Class=Reg|Qword|BaseIndex, 0, 5, Dw2Inval, 6
+rsi, Class=Reg|Qword|BaseIndex, 0, 6, Dw2Inval, 4
+rdi, Class=Reg|Qword|BaseIndex, 0, 7, Dw2Inval, 5
+r8, Class=Reg|Qword|BaseIndex, RegRex, 0, Dw2Inval, 8
+r9, Class=Reg|Qword|BaseIndex, RegRex, 1, Dw2Inval, 9
+r10, Class=Reg|Qword|BaseIndex, RegRex, 2, Dw2Inval, 10
+r11, Class=Reg|Qword|BaseIndex, RegRex, 3, Dw2Inval, 11
+r12, Class=Reg|Qword|BaseIndex, RegRex, 4, Dw2Inval, 12
+r13, Class=Reg|Qword|BaseIndex, RegRex, 5, Dw2Inval, 13
+r14, Class=Reg|Qword|BaseIndex, RegRex, 6, Dw2Inval, 14
+r15, Class=Reg|Qword|BaseIndex, RegRex, 7, Dw2Inval, 15
 // Vector mask registers.
 k0, RegMask, 0, 0, 93, 118
 k1, RegMask, 0, 1, 94, 119
@@ -283,23 +283,23 @@  bnd0, RegBND, 0, 0, Dw2Inval, Dw2Inval
 bnd1, RegBND, 0, 1, Dw2Inval, Dw2Inval
 bnd2, RegBND, 0, 2, Dw2Inval, Dw2Inval
 bnd3, RegBND, 0, 3, Dw2Inval, Dw2Inval
-// No Reg will make these registers rejected for all purposes except
+// No Class=Reg will make these registers rejected for all purposes except
 // for addressing.  This saves creating one extra type for RIP/EIP.
 rip, Qword, RegRex64, RegIP, Dw2Inval, 16
 eip, Dword, RegRex64, RegIP, 8, Dw2Inval
-// No Reg will make these registers rejected for all purposes except
+// No Class=Reg will make these registers rejected for all purposes except
 // for addressing.
 riz, Qword|BaseIndex, RegRex64, RegIZ, Dw2Inval, Dw2Inval
 eiz, Dword|BaseIndex, 0, RegIZ, Dw2Inval, Dw2Inval
 // fp regs.
-st(0), Reg|Acc|Tbyte, 0, 0, 11, 33
-st(1), Reg|Tbyte, 0, 1, 12, 34
-st(2), Reg|Tbyte, 0, 2, 13, 35
-st(3), Reg|Tbyte, 0, 3, 14, 36
-st(4), Reg|Tbyte, 0, 4, 15, 37
-st(5), Reg|Tbyte, 0, 5, 16, 38
-st(6), Reg|Tbyte, 0, 6, 17, 39
-st(7), Reg|Tbyte, 0, 7, 18, 40
+st(0), Class=Reg|Acc|Tbyte, 0, 0, 11, 33
+st(1), Class=Reg|Tbyte, 0, 1, 12, 34
+st(2), Class=Reg|Tbyte, 0, 2, 13, 35
+st(3), Class=Reg|Tbyte, 0, 3, 14, 36
+st(4), Class=Reg|Tbyte, 0, 4, 15, 37
+st(5), Class=Reg|Tbyte, 0, 5, 16, 38
+st(6), Class=Reg|Tbyte, 0, 6, 17, 39
+st(7), Class=Reg|Tbyte, 0, 7, 18, 40
 // Pseudo-register names only used in .cfi_* directives
 eflags, 0, 0, 0, 9, 49
 rflags, 0, 0, 0, Dw2Inval, 49