#endif
#endif
-#ifndef REGISTER_WARNINGS
-#define REGISTER_WARNINGS 1
-#endif
-
#ifndef INFER_ADDR_PREFIX
#define INFER_ADDR_PREFIX 1
#endif
unsigned int prefixes;
unsigned char prefix[MAX_PREFIXES];
+ /* Register is in low 3 bits of opcode. */
+ bfd_boolean short_form;
+
/* The operand to a branch insn indicates an absolute branch. */
bfd_boolean jumpabsolute;
0 if att syntax. */
static int intel_syntax = 0;
-/* 1 for Intel64 ISA,
- 0 if AMD64 ISA. */
-static int intel64;
+static enum x86_64_isa
+{
+ amd64 = 1, /* AMD64 ISA. */
+ intel64 /* Intel64 ISA. */
+} isa64;
/* 1 for intel mnemonic,
0 if att mnemonic. */
{ STRING_COMMA_LEN ("nossse3"), CPU_ANY_SSSE3_FLAGS },
{ STRING_COMMA_LEN ("nosse4.1"), CPU_ANY_SSE4_1_FLAGS },
{ STRING_COMMA_LEN ("nosse4.2"), CPU_ANY_SSE4_2_FLAGS },
- { STRING_COMMA_LEN ("nosse4"), CPU_ANY_SSE4_1_FLAGS },
+ { STRING_COMMA_LEN ("nosse4"), CPU_ANY_SSE4_FLAGS },
{ STRING_COMMA_LEN ("noavx"), CPU_ANY_AVX_FLAGS },
{ STRING_COMMA_LEN ("noavx2"), CPU_ANY_AVX2_FLAGS },
{ STRING_COMMA_LEN ("noavx512f"), CPU_ANY_AVX512F_FLAGS },
return x;
}
+static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
+
#define CPU_FLAGS_ARCH_MATCH 0x1
#define CPU_FLAGS_64BIT_MATCH 0x2
/* If given types g0 and g1 are registers they must be of the same type
unless the expected operand type register overlap is null.
- Memory operand size of certain SIMD instructions is also being checked
- here. */
+ Some Intel syntax memory operand size checking also happens here. */
static INLINE int
operand_type_register_match (i386_operand_type g0,
&& g0.bitfield.class != RegSIMD
&& (!operand_type_check (g0, anymem)
|| g0.bitfield.unspecified
- || t0.bitfield.class != RegSIMD))
+ || (t0.bitfield.class != Reg
+ && t0.bitfield.class != RegSIMD)))
return 1;
if (g1.bitfield.class != Reg
&& g1.bitfield.class != RegSIMD
&& (!operand_type_check (g1, anymem)
|| g1.bitfield.unspecified
- || t1.bitfield.class != RegSIMD))
+ || (t1.bitfield.class != Reg
+ && t1.bitfield.class != RegSIMD)))
return 1;
if (g0.bitfield.byte == g1.bitfield.byte
i.tm.base_opcode = 0xb8;
i.tm.extension_opcode = None;
i.tm.opcode_modifier.w = 0;
- i.tm.opcode_modifier.shortform = 1;
i.tm.opcode_modifier.modrm = 0;
}
}
{
unsigned int op;
i386_cpu_flags cpu;
- static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
/* Templates allowing for ZMMword as well as YMMword and/or XMMword for
any one operand are implicity requiring AVX512VL support if the actual
if (intel_mnemonic && t->opcode_modifier.attmnemonic)
continue;
- /* Check AT&T/Intel syntax and Intel64/AMD64 ISA. */
+ /* Check AT&T/Intel syntax. */
i.error = unsupported_syntax;
if ((intel_syntax && t->opcode_modifier.attsyntax)
- || (!intel_syntax && t->opcode_modifier.intelsyntax)
- || (intel64 && t->opcode_modifier.amd64)
- || (!intel64 && t->opcode_modifier.intel64))
+ || (!intel_syntax && t->opcode_modifier.intelsyntax))
continue;
+ /* Check Intel64/AMD64 ISA. */
+ switch (isa64)
+ {
+ default:
+ /* Default: Don't accept Intel64. */
+ if (t->opcode_modifier.isa64 == INTEL64)
+ continue;
+ break;
+ case amd64:
+ /* -mamd64: Don't accept Intel64 and Intel64 only. */
+ if (t->opcode_modifier.isa64 >= INTEL64)
+ continue;
+ break;
+ case intel64:
+ /* -mintel64: Don't accept AMD64. */
+ if (t->opcode_modifier.isa64 == AMD64 && flag_code == CODE_64BIT)
+ continue;
+ break;
+ }
+
/* Check the suffix. */
i.error = invalid_instruction_suffix;
if ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf)
else
abort ();
}
- else if (i.tm.opcode_modifier.defaultsize
- && !i.suffix
- /* exclude fldenv/frstor/fsave/fstenv */
- && i.tm.opcode_modifier.no_ssuf)
+ else if (i.tm.opcode_modifier.defaultsize && !i.suffix)
{
i.suffix = stackop_size;
if (stackop_size == LONG_MNEM_SUFFIX)
}
if (!i.suffix
- && !i.tm.opcode_modifier.defaultsize
- && !i.tm.opcode_modifier.ignoresize)
+ && (!i.tm.opcode_modifier.defaultsize
+ /* Also cover lret/retf/iret in 64-bit mode. */
+ || (flag_code == CODE_64BIT
+ && !i.tm.opcode_modifier.no_lsuf
+ && !i.tm.opcode_modifier.no_qsuf))
+ && !i.tm.opcode_modifier.ignoresize
+ /* Accept FLDENV et al without suffix. */
+ && (i.tm.opcode_modifier.no_ssuf || i.tm.opcode_modifier.floatmf))
{
- unsigned int suffixes;
+ unsigned int suffixes, evex = 0;
suffixes = !i.tm.opcode_modifier.no_bsuf;
if (!i.tm.opcode_modifier.no_wsuf)
if (flag_code == CODE_64BIT && !i.tm.opcode_modifier.no_qsuf)
suffixes |= 1 << 5;
- /* Are multiple suffixes allowed? */
+ /* For [XYZ]MMWORD operands inspect operand sizes. While generally
+ also suitable for AT&T syntax mode, it was requested that this be
+ restricted to just Intel syntax. */
+ if (intel_syntax)
+ {
+ i386_cpu_flags cpu = cpu_flags_and (i.tm.cpu_flags, avx512);
+
+ if (!cpu_flags_all_zero (&cpu) && !i.broadcast)
+ {
+ unsigned int op;
+
+ for (op = 0; op < i.tm.operands; ++op)
+ {
+ if (!cpu_arch_flags.bitfield.cpuavx512vl)
+ {
+ if (i.tm.operand_types[op].bitfield.ymmword)
+ i.tm.operand_types[op].bitfield.xmmword = 0;
+ if (i.tm.operand_types[op].bitfield.zmmword)
+ i.tm.operand_types[op].bitfield.ymmword = 0;
+ if (!i.tm.opcode_modifier.evex
+ || i.tm.opcode_modifier.evex == EVEXDYN)
+ i.tm.opcode_modifier.evex = EVEX512;
+ }
+
+ if (i.tm.operand_types[op].bitfield.xmmword
+ + i.tm.operand_types[op].bitfield.ymmword
+ + i.tm.operand_types[op].bitfield.zmmword < 2)
+ continue;
+
+ /* Any properly sized operand disambiguates the insn. */
+ if (i.types[op].bitfield.xmmword
+ || i.types[op].bitfield.ymmword
+ || i.types[op].bitfield.zmmword)
+ {
+ suffixes &= ~(7 << 6);
+ evex = 0;
+ break;
+ }
+
+ if ((i.flags[op] & Operand_Mem)
+ && i.tm.operand_types[op].bitfield.unspecified)
+ {
+ if (i.tm.operand_types[op].bitfield.xmmword)
+ suffixes |= 1 << 6;
+ if (i.tm.operand_types[op].bitfield.ymmword)
+ suffixes |= 1 << 7;
+ if (i.tm.operand_types[op].bitfield.zmmword)
+ suffixes |= 1 << 8;
+ evex = EVEX512;
+ }
+ }
+ }
+ }
+
+ /* Are multiple suffixes / operand sizes allowed? */
if (suffixes & (suffixes - 1))
{
- if (intel_syntax)
+ if (intel_syntax
+ && (!i.tm.opcode_modifier.defaultsize
+ || operand_check == check_error))
{
as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
return 0;
return 0;
}
if (operand_check == check_warning)
- as_warn (_("no instruction mnemonic suffix given and "
- "no register operands; using default for `%s'"),
- i.tm.name);
+ as_warn (_("%s; using default for `%s'"),
+ intel_syntax
+ ? _("ambiguous operand size")
+ : _("no instruction mnemonic suffix given and "
+ "no register operands"),
+ i.tm.name);
if (i.tm.opcode_modifier.floatmf)
i.suffix = SHORT_MNEM_SUFFIX;
+ else if (evex)
+ i.tm.opcode_modifier.evex = evex;
else if (flag_code == CODE_16BIT)
i.suffix = WORD_MNEM_SUFFIX;
else if (!i.tm.opcode_modifier.no_lsuf)
}
}
+ if (!i.tm.opcode_modifier.modrm && i.reg_operands && i.tm.operands < 3)
+ i.short_form = (i.tm.operand_types[0].bitfield.class == Reg)
+ != (i.tm.operand_types[1].bitfield.class == Reg);
+
/* Change the opcode based on the operand size given by i.suffix. */
switch (i.suffix)
{
/* It's not a byte, select word/dword operation. */
if (i.tm.opcode_modifier.w)
{
- if (i.tm.opcode_modifier.shortform)
+ if (i.short_form)
i.tm.base_opcode |= 8;
else
i.tm.base_opcode |= 1;
&& i.tm.operand_types[op].bitfield.word)
continue;
- /* crc32 doesn't generate this warning. */
- if (i.tm.base_opcode == 0xf20f38f0)
+ /* crc32 only wants its source operand checked here. */
+ if (i.tm.base_opcode == 0xf20f38f0 && op)
continue;
- if ((i.types[op].bitfield.word
- || i.types[op].bitfield.dword
- || i.types[op].bitfield.qword)
- && i.op[op].regs->reg_num < 4
- /* Prohibit these changes in 64bit mode, since the lowering
- would be more complicated. */
- && flag_code != CODE_64BIT)
- {
-#if REGISTER_WARNINGS
- if (!quiet_warnings)
- as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
- register_prefix,
- (i.op[op].regs + (i.types[op].bitfield.word
- ? REGNAM_AL - REGNAM_AX
- : REGNAM_AL - REGNAM_EAX))->reg_name,
- register_prefix,
- i.op[op].regs->reg_name,
- i.suffix);
-#endif
- continue;
- }
/* Any other register is bad. */
if (i.types[op].bitfield.class == Reg
|| i.types[op].bitfield.class == RegMMX
i.suffix);
return 0;
}
- /* Warn if the e prefix on a general reg is missing. */
- else if ((!quiet_warnings || flag_code == CODE_64BIT)
- && i.types[op].bitfield.word
+ /* Error if the e prefix on a general reg is missing. */
+ else if (i.types[op].bitfield.word
&& (i.tm.operand_types[op].bitfield.class == Reg
|| i.tm.operand_types[op].bitfield.instance == Accum)
&& i.tm.operand_types[op].bitfield.dword)
{
- /* Prohibit these changes in the 64bit mode, since the
- lowering is more complicated. */
- if (flag_code == CODE_64BIT)
- {
- as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
- register_prefix, i.op[op].regs->reg_name,
- i.suffix);
- return 0;
- }
-#if REGISTER_WARNINGS
- as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
- register_prefix,
- (i.op[op].regs + REGNAM_EAX - REGNAM_AX)->reg_name,
- register_prefix, i.op[op].regs->reg_name, i.suffix);
-#endif
+ as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
+ register_prefix, i.op[op].regs->reg_name,
+ i.suffix);
+ return 0;
}
/* Warn if the r prefix on a general reg is present. */
else if (i.types[op].bitfield.qword
&& i.tm.operand_types[op].bitfield.dword)
{
if (intel_syntax
- && i.tm.opcode_modifier.toqword
+ && (i.tm.opcode_modifier.toqword
+ /* Also convert to QWORD for MOVSXD. */
+ || i.tm.base_opcode == 0x63)
&& i.types[0].bitfield.class != RegSIMD)
{
/* Convert to QWORD. We want REX byte. */
i.suffix);
return 0;
}
- /* Warn if the e or r prefix on a general reg is present. */
- else if ((!quiet_warnings || flag_code == CODE_64BIT)
- && (i.types[op].bitfield.dword
+ /* Error if the e or r prefix on a general reg is present. */
+ else if ((i.types[op].bitfield.dword
|| i.types[op].bitfield.qword)
&& (i.tm.operand_types[op].bitfield.class == Reg
|| i.tm.operand_types[op].bitfield.instance == Accum)
&& i.tm.operand_types[op].bitfield.word)
{
- /* Prohibit these changes in the 64bit mode, since the
- lowering is more complicated. */
- if (flag_code == CODE_64BIT)
- {
- as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
- register_prefix, i.op[op].regs->reg_name,
- i.suffix);
- return 0;
- }
-#if REGISTER_WARNINGS
- as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
- register_prefix,
- (i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name,
- register_prefix, i.op[op].regs->reg_name, i.suffix);
-#endif
+ as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
+ register_prefix, i.op[op].regs->reg_name,
+ i.suffix);
+ return 0;
}
return 1;
}
on one of their operands, the default segment is ds. */
default_seg = &ds;
}
- else if (i.tm.opcode_modifier.shortform)
+ else if (i.short_form)
{
/* The register or float register operand is in operand
0 or 1. */
&& i.rm.regmem == 5))
&& (i.rm.mode == 2
|| (i.rm.mode == 0 && i.rm.regmem == 5))
+ && !is_any_vex_encoding(&i.tm)
&& ((i.operands == 1
&& i.tm.base_opcode == 0xff
&& (i.rm.reg == 2 || i.rm.reg == 4))
|| (i.operands == 2
&& (i.tm.base_opcode == 0x8b
|| i.tm.base_opcode == 0x85
- || (i.tm.base_opcode & 0xc7) == 0x03))))
+ || (i.tm.base_opcode & ~0x38) == 0x03))))
{
if (object_64bit)
{
if (t->opcode_modifier.jump
!= current_templates->start->opcode_modifier.jump)
break;
- if (t->opcode_modifier.intel64)
+ if ((t->opcode_modifier.isa64 >= INTEL64))
has_intel64 = TRUE;
}
if (t < current_templates->end)
break;
case OPTION_MAMD64:
- intel64 = 0;
+ isa64 = amd64;
break;
case OPTION_MINTEL64:
- intel64 = 1;
+ isa64 = intel64;
break;
case 'O':