Rewrote i386_index_check
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 7 Mar 2013 21:40:06 +0000 (21:40 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Thu, 7 Mar 2013 21:40:06 +0000 (21:40 +0000)
* config/tc-i386.c (flag_code_names): Removed.
(i386_index_check): Rewrote.

gas/ChangeLog
gas/config/tc-i386.c

index 31cb2af..40276f4 100644 (file)
@@ -1,3 +1,8 @@
+2013-03-07  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * config/tc-i386.c (flag_code_names): Removed.
+       (i386_index_check): Rewrote.
+
 2013-03-05  Yufeng Zhang  <yufeng.zhang@arm.com>
 
        * config/tc-aarch64.c (aarch64_imm_float_p): Rename 'e' to 'pattern';
index 04640d2..f7d488c 100644 (file)
@@ -425,14 +425,6 @@ enum x86_elf_abi
 static enum x86_elf_abi x86_elf_abi = I386_ABI;
 #endif
 
-/* The names used to print error messages.  */
-static const char *flag_code_names[] =
-  {
-    "32",
-    "16",
-    "64"
-  };
-
 /* 1 for intel syntax,
    0 if att syntax.  */
 static int intel_syntax = 0;
@@ -7420,14 +7412,55 @@ i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
 static int
 i386_index_check (const char *operand_string)
 {
-  int ok;
   const char *kind = "base/index";
+  enum flag_code addr_mode;
+
+  if (i.prefix[ADDR_PREFIX])
+    addr_mode = flag_code == CODE_32BIT ? CODE_16BIT : CODE_32BIT;
+  else
+    {
+      addr_mode = flag_code;
+
 #if INFER_ADDR_PREFIX
-  int fudged = 0;
+      if (i.mem_operands == 0)
+       {
+         /* Infer address prefix from the first memory operand.  */
+         const reg_entry *addr_reg = i.base_reg;
+
+         if (addr_reg == NULL)
+           addr_reg = i.index_reg;
 
- tryprefix:
+         if (addr_reg)
+           {
+             if (addr_reg->reg_num == RegEip
+                 || addr_reg->reg_num == RegEiz
+                 || addr_reg->reg_type.bitfield.reg32)
+               addr_mode = CODE_32BIT;
+             else if (flag_code != CODE_64BIT
+                      && addr_reg->reg_type.bitfield.reg16)
+               addr_mode = CODE_16BIT;
+
+             if (addr_mode != flag_code)
+               {
+                 i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
+                 i.prefixes += 1;
+                 /* Change the size of any displacement too.  At most one
+                    of Disp16 or Disp32 is set.
+                    FIXME.  There doesn't seem to be any real need for
+                    separate Disp16 and Disp32 flags.  The same goes for
+                    Imm16 and Imm32.  Removing them would probably clean
+                    up the code quite a lot.  */
+                 if (flag_code != CODE_64BIT
+                     && (i.types[this_operand].bitfield.disp16
+                         || i.types[this_operand].bitfield.disp32))
+                   i.types[this_operand]
+                     = operand_type_xor (i.types[this_operand], disp16_32);
+               }
+           }
+       }
 #endif
-  ok = 1;
+    }
+
   if (current_templates->start->opcode_modifier.isstring
       && !current_templates->start->opcode_modifier.immext
       && (current_templates->end[-1].opcode_modifier.isstring
@@ -7435,7 +7468,14 @@ i386_index_check (const char *operand_string)
     {
       /* Memory operands of string insns are special in that they only allow
         a single register (rDI, rSI, or rBX) as their memory address.  */
-      unsigned int expected;
+      const reg_entry *expected_reg;
+      static const char *di_si[][2] =
+       {
+         { "esi", "edi" },
+         { "si", "di" },
+         { "rsi", "rdi" }
+       };
+      static const char *bx[] = { "ebx", "bx", "rbx" };
 
       kind = "string address";
 
@@ -7448,77 +7488,70 @@ i386_index_check (const char *operand_string)
                  && current_templates->end[-1].operand_types[1]
                     .bitfield.baseindex))
            type = current_templates->end[-1].operand_types[1];
-         expected = type.bitfield.esseg ? 7 /* rDI */ : 6 /* rSI */;
+         expected_reg = hash_find (reg_hash,
+                                   di_si[addr_mode][type.bitfield.esseg]);
+
        }
       else
-       expected = 3 /* rBX */;
+       expected_reg = hash_find (reg_hash, bx[addr_mode]);
 
-      if (!i.base_reg || i.index_reg
+      if (i.base_reg != expected_reg
+         || i.index_reg
          || operand_type_check (i.types[this_operand], disp))
-       ok = -1;
-      else if (!(flag_code == CODE_64BIT
-                ? i.prefix[ADDR_PREFIX]
-                  ? i.base_reg->reg_type.bitfield.reg32
-                  : i.base_reg->reg_type.bitfield.reg64
-                : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX]
-                  ? i.base_reg->reg_type.bitfield.reg32
-                  : i.base_reg->reg_type.bitfield.reg16))
-       ok = 0;
-      else if (register_number (i.base_reg) != expected)
-       ok = -1;
-
-      if (ok < 0)
-       {
-         unsigned int j;
-
-         for (j = 0; j < i386_regtab_size; ++j)
-           if ((flag_code == CODE_64BIT
-                ? i.prefix[ADDR_PREFIX]
-                  ? i386_regtab[j].reg_type.bitfield.reg32
-                  : i386_regtab[j].reg_type.bitfield.reg64
-                : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX]
-                  ? i386_regtab[j].reg_type.bitfield.reg32
-                  : i386_regtab[j].reg_type.bitfield.reg16)
-               && register_number(i386_regtab + j) == expected)
-             break;
-         gas_assert (j < i386_regtab_size);
+       {
+         /* The second memory operand must have the same size as
+            the first one.  */
+         if (i.mem_operands
+             && i.base_reg
+             && !((addr_mode == CODE_64BIT
+                   && i.base_reg->reg_type.bitfield.reg64)
+                  || (addr_mode == CODE_32BIT
+                      ? i.base_reg->reg_type.bitfield.reg32
+                      : i.base_reg->reg_type.bitfield.reg16)))
+           goto bad_address;
+
          as_warn (_("`%s' is not valid here (expected `%c%s%s%c')"),
                   operand_string,
                   intel_syntax ? '[' : '(',
                   register_prefix,
-                  i386_regtab[j].reg_name,
+                  expected_reg->reg_name,
                   intel_syntax ? ']' : ')');
-         ok = 1;
-       }
-    }
-  else if (flag_code == CODE_64BIT)
-    {
-      if ((i.base_reg
-          && ((i.prefix[ADDR_PREFIX] == 0
-               && !i.base_reg->reg_type.bitfield.reg64)
-              || (i.prefix[ADDR_PREFIX]
-                  && !i.base_reg->reg_type.bitfield.reg32))
-          && (i.index_reg
-              || i.base_reg->reg_num !=
-                 (i.prefix[ADDR_PREFIX] == 0 ? RegRip : RegEip)))
-         || (i.index_reg
-             && !(i.index_reg->reg_type.bitfield.regxmm
-                  || i.index_reg->reg_type.bitfield.regymm)
-             && (!i.index_reg->reg_type.bitfield.baseindex
-                 || (i.prefix[ADDR_PREFIX] == 0
-                     && i.index_reg->reg_num != RegRiz
-                     && !i.index_reg->reg_type.bitfield.reg64
-                     )
-                 || (i.prefix[ADDR_PREFIX]
-                     && i.index_reg->reg_num != RegEiz
-                     && !i.index_reg->reg_type.bitfield.reg32))))
-       ok = 0;
+         return 1;
+       }
+      else
+       return 1;
+
+bad_address:
+      as_bad (_("`%s' is not a valid %s expression"),
+             operand_string, kind);
+      return 0;
     }
   else
     {
-      if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
+      if (addr_mode != CODE_16BIT)
+       {
+         /* 32-bit/64-bit checks.  */
+         if ((i.base_reg
+              && (addr_mode == CODE_64BIT
+                  ? !i.base_reg->reg_type.bitfield.reg64
+                  : !i.base_reg->reg_type.bitfield.reg32)
+              && (i.index_reg
+                  || (i.base_reg->reg_num
+                      != (addr_mode == CODE_64BIT ? RegRip : RegEip))))
+             || (i.index_reg
+                 && !i.index_reg->reg_type.bitfield.regxmm
+                 && !i.index_reg->reg_type.bitfield.regymm
+                 && ((addr_mode == CODE_64BIT
+                      ? !(i.index_reg->reg_type.bitfield.reg64
+                          || i.index_reg->reg_num == RegRiz)
+                      : !(i.index_reg->reg_type.bitfield.reg32
+                          || i.index_reg->reg_num == RegEiz))
+                     || !i.index_reg->reg_type.bitfield.baseindex)))
+           goto bad_address;
+       }
+      else
        {
-         /* 16bit checks.  */
+         /* 16-bit checks.  */
          if ((i.base_reg
               && (!i.base_reg->reg_type.bitfield.reg16
                   || !i.base_reg->reg_type.bitfield.baseindex))
@@ -7529,58 +7562,10 @@ i386_index_check (const char *operand_string)
                           && i.base_reg->reg_num < 6
                           && i.index_reg->reg_num >= 6
                           && i.log2_scale_factor == 0))))
-           ok = 0;
-       }
-      else
-       {
-         /* 32bit checks.  */
-         if ((i.base_reg
-              && !i.base_reg->reg_type.bitfield.reg32)
-             || (i.index_reg
-                 && !i.index_reg->reg_type.bitfield.regxmm
-                 && !i.index_reg->reg_type.bitfield.regymm
-                 && ((!i.index_reg->reg_type.bitfield.reg32
-                      && i.index_reg->reg_num != RegEiz)
-                     || !i.index_reg->reg_type.bitfield.baseindex)))
-           ok = 0;
+           goto bad_address;
        }
     }
-  if (!ok)
-    {
-#if INFER_ADDR_PREFIX
-      if (!i.mem_operands && !i.prefix[ADDR_PREFIX])
-       {
-         i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
-         i.prefixes += 1;
-         /* Change the size of any displacement too.  At most one of
-            Disp16 or Disp32 is set.
-            FIXME.  There doesn't seem to be any real need for separate
-            Disp16 and Disp32 flags.  The same goes for Imm16 and Imm32.
-            Removing them would probably clean up the code quite a lot.  */
-         if (flag_code != CODE_64BIT
-             && (i.types[this_operand].bitfield.disp16
-                 || i.types[this_operand].bitfield.disp32))
-           i.types[this_operand]
-             = operand_type_xor (i.types[this_operand], disp16_32);
-         fudged = 1;
-         goto tryprefix;
-       }
-      if (fudged)
-       as_bad (_("`%s' is not a valid %s expression"),
-               operand_string,
-               kind);
-      else
-#endif
-       as_bad (_("`%s' is not a valid %s-bit %s expression"),
-               operand_string,
-               flag_code_names[i.prefix[ADDR_PREFIX]
-                                        ? flag_code == CODE_32BIT
-                                          ? CODE_16BIT
-                                          : CODE_32BIT
-                                        : flag_code],
-               kind);
-    }
-  return ok;
+  return 1;
 }
 
 /* Parse OPERAND_STRING into the i386_insn structure I.  Returns zero