/* tc-i386.c -- Assemble code for the Intel 80386
- Copyright (C) 1989-2016 Free Software Foundation, Inc.
+ Copyright (C) 1989-2017 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
/* Compressed disp8*N attribute. */
unsigned int memshift;
- /* Swap operand in encoding. */
- unsigned int swap_operand;
+ /* Prefer load or store in encoding. */
+ enum
+ {
+ dir_encoding_default = 0,
+ dir_encoding_load,
+ dir_encoding_store
+ } dir_encoding;
/* Prefer 8bit or 32bit displacement in encoding. */
enum
disp_encoding_32bit
} disp_encoding;
+ /* How to encode vector instructions. */
+ enum
+ {
+ vex_encoding_default = 0,
+ vex_encoding_vex2,
+ vex_encoding_vex3,
+ vex_encoding_evex
+ } vec_encoding;
+
/* REP prefix. */
const char *rep_prefix;
/* Have BND prefix. */
const char *bnd_prefix;
- /* Need VREX to support upper 16 registers. */
- int need_vrex;
+ /* Have NOTRACK prefix. */
+ const char *notrack_prefix;
/* Error message. */
enum i386_error error;
/* List of chars besides those in app.c:symbol_chars that can start an
operand. Used to prevent the scrubber eating vital white-space. */
-const char extra_symbol_chars[] = "*%-([{"
+const char extra_symbol_chars[] = "*%-([{}"
#ifdef LEX_AT
"@"
#endif
/* 1 if register prefix % not required. */
static int allow_naked_reg = 0;
-/* 1 if the assembler should add BND prefix for all control-tranferring
+/* 1 if the assembler should add BND prefix for all control-transferring
instructions supporting it, even if this prefix wasn't specified
explicitly. */
static int add_bnd_prefix = 0;
CPU_AVX512_4FMAPS_FLAGS, 0 },
{ STRING_COMMA_LEN (".avx512_4vnniw"), PROCESSOR_UNKNOWN,
CPU_AVX512_4VNNIW_FLAGS, 0 },
+ { STRING_COMMA_LEN (".avx512_vpopcntdq"), PROCESSOR_UNKNOWN,
+ CPU_AVX512_VPOPCNTDQ_FLAGS, 0 },
+ { STRING_COMMA_LEN (".avx512_vbmi2"), PROCESSOR_UNKNOWN,
+ CPU_AVX512_VBMI2_FLAGS, 0 },
{ STRING_COMMA_LEN (".clzero"), PROCESSOR_UNKNOWN,
CPU_CLZERO_FLAGS, 0 },
{ STRING_COMMA_LEN (".mwaitx"), PROCESSOR_UNKNOWN,
CPU_RDPID_FLAGS, 0 },
{ STRING_COMMA_LEN (".ptwrite"), PROCESSOR_UNKNOWN,
CPU_PTWRITE_FLAGS, 0 },
+ { STRING_COMMA_LEN (".cet"), PROCESSOR_UNKNOWN,
+ CPU_CET_FLAGS, 0 },
+ { STRING_COMMA_LEN (".gfni"), PROCESSOR_UNKNOWN,
+ CPU_GFNI_FLAGS, 0 },
};
static const noarch_entry cpu_noarch[] =
{ STRING_COMMA_LEN ("noavx512vbmi"), CPU_ANY_AVX512VBMI_FLAGS },
{ STRING_COMMA_LEN ("noavx512_4fmaps"), CPU_ANY_AVX512_4FMAPS_FLAGS },
{ STRING_COMMA_LEN ("noavx512_4vnniw"), CPU_ANY_AVX512_4VNNIW_FLAGS },
+ { STRING_COMMA_LEN ("noavx512_vpopcntdq"), CPU_ANY_AVX512_VPOPCNTDQ_FLAGS },
+ { STRING_COMMA_LEN ("noavx512_vbmi2"), CPU_ANY_AVX512_VBMI2_FLAGS },
};
#ifdef I386COFF
{
switch (ARRAY_SIZE(x->array))
{
+ case 4:
+ if (x->array[3])
+ return 0;
+ /* Fall through. */
case 3:
if (x->array[2])
return 0;
{
switch (ARRAY_SIZE(x->array))
{
+ case 4:
+ if (x->array[3] != y->array[3])
+ return 0;
+ /* Fall through. */
case 3:
if (x->array[2] != y->array[2])
return 0;
{
switch (ARRAY_SIZE (x.array))
{
+ case 4:
+ x.array [3] &= y.array [3];
+ /* Fall through. */
case 3:
x.array [2] &= y.array [2];
/* Fall through. */
{
switch (ARRAY_SIZE (x.array))
{
+ case 4:
+ x.array [3] |= y.array [3];
+ /* Fall through. */
case 3:
x.array [2] |= y.array [2];
/* Fall through. */
{
switch (ARRAY_SIZE (x.array))
{
+ case 4:
+ x.array [3] &= ~y.array [3];
+ /* Fall through. */
case 3:
x.array [2] &= ~y.array [2];
/* Fall through. */
PREFIX_EXIST = 0,
PREFIX_LOCK,
PREFIX_REP,
+ PREFIX_DS,
PREFIX_OTHER
};
same class already exists.
b. PREFIX_LOCK if lock prefix is added.
c. PREFIX_REP if rep/repne prefix is added.
- d. PREFIX_OTHER if other prefix is added.
+ d. PREFIX_DS if ds prefix is added.
+ e. PREFIX_OTHER if other prefix is added.
*/
static enum PREFIX_GROUP
default:
abort ();
- case CS_PREFIX_OPCODE:
case DS_PREFIX_OPCODE:
+ ret = PREFIX_DS;
+ /* Fall through. */
+ case CS_PREFIX_OPCODE:
case ES_PREFIX_OPCODE:
case FS_PREFIX_OPCODE:
case GS_PREFIX_OPCODE:
if (*string == '.' && j >= ARRAY_SIZE (cpu_arch))
{
- /* Disable an ISA entension. */
+ /* Disable an ISA extension. */
for (j = 0; j < ARRAY_SIZE (cpu_noarch); j++)
if (strcmp (string + 1, cpu_noarch [j].name) == 0)
{
{
const char *hash_err;
+ /* Support pseudo prefixes like {disp32}. */
+ lex_type ['{'] = LEX_BEGIN_NAME;
+
/* Initialize op_hash hash table. */
op_hash = hash_new ();
operand_chars[c] = c;
}
else if (c == '{' || c == '}')
- operand_chars[c] = c;
+ {
+ mnemonic_chars[c] = c;
+ operand_chars[c] = c;
+ }
if (ISALPHA (c) || ISDIGIT (c))
identifier_chars[c] = c;
else
register_specifier = 0xf;
- /* Use 2-byte VEX prefix by swappping destination and source
+ /* Use 2-byte VEX prefix by swapping destination and source
operand. */
- if (!i.swap_operand
+ if (i.vec_encoding != vex_encoding_vex3
+ && i.dir_encoding == dir_encoding_default
&& i.operands == i.reg_operands
&& i.tm.opcode_modifier.vexopcode == VEX0F
- && i.tm.opcode_modifier.s
+ && i.tm.opcode_modifier.load
&& i.rex == REX_B)
{
unsigned int xchg = i.operands - 1;
}
/* Use 2-byte VEX prefix if possible. */
- if (i.tm.opcode_modifier.vexopcode == VEX0F
+ if (i.vec_encoding != vex_encoding_vex3
+ && i.tm.opcode_modifier.vexopcode == VEX0F
&& i.tm.opcode_modifier.vexw != VEXW1
&& (i.rex & (REX_W | REX_X | REX_B)) == 0)
{
if (i.bnd_prefix && !i.tm.opcode_modifier.bndprefixok)
as_bad (_("expecting valid branch instruction after `bnd'"));
+ /* Check NOTRACK prefix. */
+ if (i.notrack_prefix && !i.tm.opcode_modifier.notrackprefixok)
+ as_bad (_("expecting indirect branch instruction after `notrack'"));
+
if (i.tm.cpu_flags.bitfield.cpumpx)
{
if (flag_code == CODE_64BIT && i.prefix[ADDR_PREFIX])
current_templates->start->name);
return NULL;
}
- /* Add prefix, checking for repeated prefixes. */
- switch (add_prefix (current_templates->start->base_opcode))
+ if (current_templates->start->opcode_length == 0)
{
- case PREFIX_EXIST:
- return NULL;
- case PREFIX_REP:
- if (current_templates->start->cpu_flags.bitfield.cpuhle)
- i.hle_prefix = current_templates->start->name;
- else if (current_templates->start->cpu_flags.bitfield.cpumpx)
- i.bnd_prefix = current_templates->start->name;
- else
- i.rep_prefix = current_templates->start->name;
- break;
- default:
- break;
+ /* Handle pseudo prefixes. */
+ switch (current_templates->start->base_opcode)
+ {
+ case 0x0:
+ /* {disp8} */
+ i.disp_encoding = disp_encoding_8bit;
+ break;
+ case 0x1:
+ /* {disp32} */
+ i.disp_encoding = disp_encoding_32bit;
+ break;
+ case 0x2:
+ /* {load} */
+ i.dir_encoding = dir_encoding_load;
+ break;
+ case 0x3:
+ /* {store} */
+ i.dir_encoding = dir_encoding_store;
+ break;
+ case 0x4:
+ /* {vex2} */
+ i.vec_encoding = vex_encoding_vex2;
+ break;
+ case 0x5:
+ /* {vex3} */
+ i.vec_encoding = vex_encoding_vex3;
+ break;
+ case 0x6:
+ /* {evex} */
+ i.vec_encoding = vex_encoding_evex;
+ break;
+ default:
+ abort ();
+ }
+ }
+ else
+ {
+ /* Add prefix, checking for repeated prefixes. */
+ switch (add_prefix (current_templates->start->base_opcode))
+ {
+ case PREFIX_EXIST:
+ return NULL;
+ case PREFIX_DS:
+ if (current_templates->start->cpu_flags.bitfield.cpucet)
+ i.notrack_prefix = current_templates->start->name;
+ break;
+ case PREFIX_REP:
+ if (current_templates->start->cpu_flags.bitfield.cpuhle)
+ i.hle_prefix = current_templates->start->name;
+ else if (current_templates->start->cpu_flags.bitfield.cpumpx)
+ i.bnd_prefix = current_templates->start->name;
+ else
+ i.rep_prefix = current_templates->start->name;
+ break;
+ default:
+ break;
+ }
}
/* Skip past PREFIX_SEPARATOR and reset token_start. */
token_start = ++l;
/* Check if we should swap operand or force 32bit displacement in
encoding. */
if (mnem_p - 2 == dot_p && dot_p[1] == 's')
- i.swap_operand = 1;
+ i.dir_encoding = dir_encoding_store;
else if (mnem_p - 3 == dot_p
&& dot_p[1] == 'd'
&& dot_p[2] == '8')
{ /* Yes, we've read in another operand. */
unsigned int operand_ok;
this_operand = i.operands++;
- i.types[this_operand].bitfield.unspecified = 1;
if (i.operands > MAX_OPERANDS)
{
as_bad (_("spurious operands; (%d operands/instruction max)"),
MAX_OPERANDS);
return NULL;
}
+ i.types[this_operand].bitfield.unspecified = 1;
/* Now parse operand adding info to 'i' as we go along. */
END_STRING_AND_SAVE (l);
static int
VEX_check_operands (const insn_template *t)
{
- /* VREX is only valid with EVEX prefix. */
- if (i.need_vrex && !t->opcode_modifier.evex)
+ if (i.vec_encoding == vex_encoding_evex)
{
- i.error = invalid_register_operand;
- return 1;
+ /* This instruction must be encoded with EVEX prefix. */
+ if (!t->opcode_modifier.evex)
+ {
+ i.error = unsupported;
+ return 1;
+ }
+ return 0;
}
if (!t->opcode_modifier.vex)
- return 0;
+ {
+ /* This instruction template doesn't have VEX prefix. */
+ if (i.vec_encoding != vex_encoding_default)
+ {
+ i.error = unsupported;
+ return 1;
+ }
+ return 0;
+ }
/* Only check VEX_Imm4, which must be the first operand. */
if (t->operand_types[0].bitfield.vec_imm4)
continue;
break;
case 2:
- /* xchg %eax, %eax is a special case. It is an aliase for nop
+ /* xchg %eax, %eax is a special case. It is an alias for nop
only in 32bit mode and we can use opcode 0x90. In 64bit
mode, we can't use 0x90 for xchg %eax, %eax since it should
zero-extend %eax to %rax. */
&& operand_type_equal (&i.types [0], &acc32)
&& operand_type_equal (&i.types [1], &acc32))
continue;
- if (i.swap_operand)
- {
- /* If we swap operand in encoding, we either match
- the next one or reverse direction of operands. */
- if (t->opcode_modifier.s)
- continue;
- else if (t->opcode_modifier.d)
- goto check_reverse;
- }
+ /* If we want store form, we reverse direction of operands. */
+ if (i.dir_encoding == dir_encoding_store
+ && t->opcode_modifier.d)
+ goto check_reverse;
/* Fall through. */
case 3:
- /* If we swap operand in encoding, we match the next one. */
- if (i.swap_operand && t->opcode_modifier.s)
+ /* If we want store form, we skip the current load. */
+ if (i.dir_encoding == dir_encoding_store
+ && i.mem_operands == 0
+ && t->opcode_modifier.load)
continue;
/* Fall through. */
case 4:
if (i.tm.opcode_modifier.immext)
{
- /* When ImmExt is set, the immdiate byte is the last
+ /* When ImmExt is set, the immediate byte is the last
operand. */
imm_slot = i.operands - 1;
source--;
{
case BFD_RELOC_386_PLT32:
case BFD_RELOC_X86_64_PLT32:
- /* Symbol with PLT relocatin may be preempted. */
+ /* Symbol with PLT relocation may be preempted. */
return 0;
default:
abort ();
mode. */
if ((r->reg_flags & RegVRex))
{
+ if (i.vec_encoding == vex_encoding_default)
+ i.vec_encoding = vex_encoding_evex;
+
if (!cpu_arch_flags.bitfield.cpuvrex
+ || i.vec_encoding != vex_encoding_evex
|| flag_code != CODE_64BIT)
return (const reg_entry *) NULL;
-
- i.need_vrex = 1;
}
if (((r->reg_flags & (RegRex64 | RegRex))
&& (valueT) e->X_add_number < i386_regtab_size);
r = i386_regtab + e->X_add_number;
if ((r->reg_flags & RegVRex))
- i.need_vrex = 1;
+ i.vec_encoding = vex_encoding_evex;
*end_op = input_line_pointer;
}
*input_line_pointer = c;
else if (*cpu_arch [j].name == '.'
&& strcmp (arch, cpu_arch [j].name + 1) == 0)
{
- /* ISA entension. */
+ /* ISA extension. */
i386_cpu_flags flags;
flags = cpu_flags_or (cpu_arch_flags,
if (j >= ARRAY_SIZE (cpu_arch))
{
- /* Disable an ISA entension. */
+ /* Disable an ISA extension. */
for (j = 0; j < ARRAY_SIZE (cpu_noarch); j++)
if (strcmp (arch, cpu_noarch [j].name) == 0)
{