x86: consistently convert to byte registers for TEST w/ imm optimization
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index 41a6a0817a832c76e57685b49876abc3b92a04dd..efa43650928ab70f5fd8c6f02fee8a1031277478 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-i386.c -- Assemble code for the Intel 80386
-   Copyright (C) 1989-2019 Free Software Foundation, Inc.
+   Copyright (C) 1989-2020 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -182,6 +182,7 @@ static char *parse_insn (char *, char *);
 static char *parse_operands (char *, const char *);
 static void swap_operands (void);
 static void swap_2_operands (int, int);
+static enum flag_code i386_addressing_mode (void);
 static void optimize_imm (void);
 static void optimize_disp (void);
 static const insn_template *match_template (char);
@@ -4008,18 +4009,16 @@ optimize_encoding (void)
          i.types[1].bitfield.byte = 1;
          /* Ignore the suffix.  */
          i.suffix = 0;
-         if (base_regnum >= 4
-             && !(i.op[1].regs->reg_flags & RegRex))
-           {
-             /* Handle SP, BP, SI and DI registers.  */
-             if (i.types[1].bitfield.word)
-               j = 16;
-             else if (i.types[1].bitfield.dword)
-               j = 32;
-             else
-               j = 48;
-             i.op[1].regs -= j;
-           }
+         /* Convert to byte registers.  */
+         if (i.types[1].bitfield.word)
+           j = 16;
+         else if (i.types[1].bitfield.dword)
+           j = 32;
+         else
+           j = 48;
+         if (!(i.op[1].regs->reg_flags & RegRex) && base_regnum < 4)
+           j += 8;
+         i.op[1].regs -= j;
        }
     }
   else if (flag_code == CODE_64BIT
@@ -5884,51 +5883,50 @@ match_template (char mnem_suffix)
            break;
        }
 
-      /* Address size prefix will turn Disp64/Disp32/Disp16 operand
-        into Disp32/Disp16/Disp32 operand.  */
-      if (i.prefix[ADDR_PREFIX] != 0)
-         {
-           /* There should be only one Disp operand.  */
-           switch (flag_code)
-           {
-           case CODE_16BIT:
-             for (j = 0; j < MAX_OPERANDS; j++)
-               {
-                 if (operand_types[j].bitfield.disp16)
-                   {
-                     addr_prefix_disp = j;
-                     operand_types[j].bitfield.disp32 = 1;
-                     operand_types[j].bitfield.disp16 = 0;
-                     break;
-                   }
-               }
+      if (!t->opcode_modifier.jump
+         || t->opcode_modifier.jump == JUMP_ABSOLUTE)
+       {
+         /* There should be only one Disp operand.  */
+         for (j = 0; j < MAX_OPERANDS; j++)
+           if (operand_type_check (operand_types[j], disp))
              break;
-           case CODE_32BIT:
-             for (j = 0; j < MAX_OPERANDS; j++)
+         if (j < MAX_OPERANDS)
+           {
+             bfd_boolean override = (i.prefix[ADDR_PREFIX] != 0);
+
+             addr_prefix_disp = j;
+
+             /* Address size prefix will turn Disp64/Disp32S/Disp32/Disp16
+                operand into Disp32/Disp32/Disp16/Disp32 operand.  */
+             switch (flag_code)
                {
-                 if (operand_types[j].bitfield.disp32)
+               case CODE_16BIT:
+                 override = !override;
+                 /* Fall through.  */
+               case CODE_32BIT:
+                 if (operand_types[j].bitfield.disp32
+                     && operand_types[j].bitfield.disp16)
                    {
-                     addr_prefix_disp = j;
-                     operand_types[j].bitfield.disp32 = 0;
-                     operand_types[j].bitfield.disp16 = 1;
-                     break;
+                     operand_types[j].bitfield.disp16 = override;
+                     operand_types[j].bitfield.disp32 = !override;
                    }
-               }
-             break;
-           case CODE_64BIT:
-             for (j = 0; j < MAX_OPERANDS; j++)
-               {
-                 if (operand_types[j].bitfield.disp64)
+                 operand_types[j].bitfield.disp32s = 0;
+                 operand_types[j].bitfield.disp64 = 0;
+                 break;
+
+               case CODE_64BIT:
+                 if (operand_types[j].bitfield.disp32s
+                     || operand_types[j].bitfield.disp64)
                    {
-                     addr_prefix_disp = j;
-                     operand_types[j].bitfield.disp64 = 0;
-                     operand_types[j].bitfield.disp32 = 1;
-                     break;
+                     operand_types[j].bitfield.disp64 &= !override;
+                     operand_types[j].bitfield.disp32s &= !override;
+                     operand_types[j].bitfield.disp32 = override;
                    }
+                 operand_types[j].bitfield.disp16 = 0;
+                 break;
                }
-             break;
            }
-         }
+       }
 
       /* Force 0x8b encoding for "mov foo@GOT, %eax".  */
       if (i.reloc[0] == BFD_RELOC_386_GOT32 && t->base_opcode == 0xa0)
@@ -7862,6 +7860,18 @@ build_modrm_byte (void)
   return default_seg;
 }
 
+static unsigned int
+flip_code16 (unsigned int code16)
+{
+  gas_assert (i.tm.operands == 1);
+
+  return !(i.prefix[REX_PREFIX] & REX_W)
+        && (code16 ? i.tm.operand_types[0].bitfield.disp32
+                     || i.tm.operand_types[0].bitfield.disp32s
+                   : i.tm.operand_types[0].bitfield.disp16)
+        ? CODE16 : 0;
+}
+
 static void
 output_branch (void)
 {
@@ -7881,7 +7891,7 @@ output_branch (void)
     {
       prefix = 1;
       i.prefixes -= 1;
-      code16 ^= CODE16;
+      code16 ^= flip_code16(code16);
     }
   /* Pentium4 branch hints.  */
   if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */
@@ -7899,12 +7909,12 @@ output_branch (void)
   /* BND prefixed jump.  */
   if (i.prefix[BND_PREFIX] != 0)
     {
-      FRAG_APPEND_1_CHAR (i.prefix[BND_PREFIX]);
-      i.prefixes -= 1;
+      prefix++;
+      i.prefixes--;
     }
 
-  if (i.prefixes != 0 && !intel_syntax)
-    as_warn (_("skipping prefixes on this instruction"));
+  if (i.prefixes != 0)
+    as_warn (_("skipping prefixes on `%s'"), i.tm.name);
 
   /* It's always a symbol;  End frag & setup for relax.
      Make sure there is enough room in this frag for the largest
@@ -7919,6 +7929,8 @@ output_branch (void)
   if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE
       || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE)
     *p++ = i.prefix[SEG_PREFIX];
+  if (i.prefix[BND_PREFIX] != 0)
+    *p++ = BND_PREFIX_OPCODE;
   if (i.prefix[REX_PREFIX] != 0)
     *p++ = i.prefix[REX_PREFIX];
   *p = i.tm.base_opcode;
@@ -8023,7 +8035,7 @@ output_jump (void)
        {
          FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
          i.prefixes -= 1;
-         code16 ^= CODE16;
+         code16 ^= flip_code16(code16);
        }
 
       size = 4;
@@ -8031,21 +8043,21 @@ output_jump (void)
        size = 2;
     }
 
-  if (i.prefix[REX_PREFIX] != 0)
+  /* BND prefixed jump.  */
+  if (i.prefix[BND_PREFIX] != 0)
     {
-      FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]);
+      FRAG_APPEND_1_CHAR (i.prefix[BND_PREFIX]);
       i.prefixes -= 1;
     }
 
-  /* BND prefixed jump.  */
-  if (i.prefix[BND_PREFIX] != 0)
+  if (i.prefix[REX_PREFIX] != 0)
     {
-      FRAG_APPEND_1_CHAR (i.prefix[BND_PREFIX]);
+      FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]);
       i.prefixes -= 1;
     }
 
-  if (i.prefixes != 0 && !intel_syntax)
-    as_warn (_("skipping prefixes on this instruction"));
+  if (i.prefixes != 0)
+    as_warn (_("skipping prefixes on `%s'"), i.tm.name);
 
   p = frag_more (i.tm.opcode_length + size);
   switch (i.tm.opcode_length)
@@ -8098,18 +8110,15 @@ output_interseg_jump (void)
       i.prefixes -= 1;
       code16 ^= CODE16;
     }
-  if (i.prefix[REX_PREFIX] != 0)
-    {
-      prefix++;
-      i.prefixes -= 1;
-    }
+
+  gas_assert (!i.prefix[REX_PREFIX]);
 
   size = 4;
   if (code16)
     size = 2;
 
-  if (i.prefixes != 0 && !intel_syntax)
-    as_warn (_("skipping prefixes on this instruction"));
+  if (i.prefixes != 0)
+    as_warn (_("skipping prefixes on `%s'"), i.tm.name);
 
   /* 1 opcode; 2 segment; offset  */
   p = frag_more (prefix + 1 + 2 + size);
@@ -9938,10 +9947,11 @@ i386_displacement (char *disp_start, char *disp_end)
 
   operand_type_set (&bigdisp, 0);
   if (i.jumpabsolute
+      || i.types[this_operand].bitfield.baseindex
       || (current_templates->start->opcode_modifier.jump != JUMP
          && current_templates->start->opcode_modifier.jump != JUMP_DWORD))
     {
-      bigdisp.bitfield.disp32 = 1;
+      i386_addressing_mode ();
       override = (i.prefix[ADDR_PREFIX] != 0);
       if (flag_code == CODE_64BIT)
        {
@@ -9950,27 +9960,47 @@ i386_displacement (char *disp_start, char *disp_end)
              bigdisp.bitfield.disp32s = 1;
              bigdisp.bitfield.disp64 = 1;
            }
+         else
+           bigdisp.bitfield.disp32 = 1;
        }
       else if ((flag_code == CODE_16BIT) ^ override)
-       {
-         bigdisp.bitfield.disp32 = 0;
          bigdisp.bitfield.disp16 = 1;
-       }
+      else
+         bigdisp.bitfield.disp32 = 1;
     }
   else
     {
-      /* For PC-relative branches, the width of the displacement
-        is dependent upon data size, not address size.  */
+      /* For PC-relative branches, the width of the displacement may be
+        dependent upon data size, but is never dependent upon address size.
+        Also make sure to not unintentionally match against a non-PC-relative
+        branch template.  */
+      static templates aux_templates;
+      const insn_template *t = current_templates->start;
+      bfd_boolean has_intel64 = FALSE;
+
+      aux_templates.start = t;
+      while (++t < current_templates->end)
+       {
+         if (t->opcode_modifier.jump
+             != current_templates->start->opcode_modifier.jump)
+           break;
+         if (t->opcode_modifier.intel64)
+           has_intel64 = TRUE;
+       }
+      if (t < current_templates->end)
+       {
+         aux_templates.end = t;
+         current_templates = &aux_templates;
+       }
+
       override = (i.prefix[DATA_PREFIX] != 0);
       if (flag_code == CODE_64BIT)
        {
-         if (override || i.suffix == WORD_MNEM_SUFFIX)
+         if ((override || i.suffix == WORD_MNEM_SUFFIX)
+             && (!intel64 || !has_intel64))
            bigdisp.bitfield.disp16 = 1;
          else
-           {
-             bigdisp.bitfield.disp32 = 1;
-             bigdisp.bitfield.disp32s = 1;
-           }
+           bigdisp.bitfield.disp32s = 1;
        }
       else
        {
@@ -10143,6 +10173,11 @@ i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
     }
 #endif
 
+  if (current_templates->start->opcode_modifier.jump == JUMP_BYTE
+      /* Constants get taken care of by optimize_disp().  */
+      && exp->X_op != O_constant)
+    i.types[this_operand].bitfield.disp8 = 1;
+
   /* Check if this is a displacement only operand.  */
   bigdisp = i.types[this_operand];
   bigdisp.bitfield.disp8 = 0;
@@ -12000,6 +12035,7 @@ const char *md_shortopts = "qnO::";
 #define OPTION_MALIGN_BRANCH_BOUNDARY (OPTION_MD_BASE + 27)
 #define OPTION_MALIGN_BRANCH_PREFIX_SIZE (OPTION_MD_BASE + 28)
 #define OPTION_MALIGN_BRANCH (OPTION_MD_BASE + 29)
+#define OPTION_MBRANCHES_WITH_32B_BOUNDARIES (OPTION_MD_BASE + 30)
 
 struct option md_longopts[] =
 {
@@ -12038,6 +12074,7 @@ struct option md_longopts[] =
   {"malign-branch-boundary", required_argument, NULL, OPTION_MALIGN_BRANCH_BOUNDARY},
   {"malign-branch-prefix-size", required_argument, NULL, OPTION_MALIGN_BRANCH_PREFIX_SIZE},
   {"malign-branch", required_argument, NULL, OPTION_MALIGN_BRANCH},
+  {"mbranches-within-32B-boundaries", no_argument, NULL, OPTION_MBRANCHES_WITH_32B_BOUNDARIES},
   {"mamd64", no_argument, NULL, OPTION_MAMD64},
   {"mintel64", no_argument, NULL, OPTION_MINTEL64},
   {NULL, no_argument, NULL, 0}
@@ -12500,6 +12537,14 @@ md_parse_option (int c, const char *arg)
       free (saved);
       break;
 
+    case OPTION_MBRANCHES_WITH_32B_BOUNDARIES:
+      align_branch_power = 5;
+      align_branch_prefix_size = 5;
+      align_branch = (align_branch_jcc_bit
+                     | align_branch_fused_bit
+                     | align_branch_jmp_bit);
+      break;
+
     case OPTION_MAMD64:
       intel64 = 0;
       break;
@@ -12763,6 +12808,9 @@ md_show_usage (FILE *stream)
   -malign-branch-prefix-size=NUM (default: 5)\n\
                           align branches with NUM prefixes per instruction\n"));
   fprintf (stream, _("\
+  -mbranches-within-32B-boundaries\n\
+                          align branches within 32 byte boundary\n"));
+  fprintf (stream, _("\
   -mamd64                 accept only AMD64 ISA [default]\n"));
   fprintf (stream, _("\
   -mintel64               accept only Intel64 ISA\n"));
This page took 0.030739 seconds and 4 git commands to generate.