diff options
Diffstat (limited to 'gas/config/tc-i386.c')
-rw-r--r-- | gas/config/tc-i386.c | 1017 |
1 files changed, 960 insertions, 57 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index a5e014af5e..d12ca22ef7 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -86,6 +86,7 @@ #define QWORD_MNEM_SUFFIX 'q' #define XMMWORD_MNEM_SUFFIX 'x' #define YMMWORD_MNEM_SUFFIX 'y' +#define ZMMWORD_MNEM_SUFFIX 'z' /* Intel Syntax. Use a non-ascii letter since since it never appears in instructions. */ #define LONG_DOUBLE_MNEM_SUFFIX '\1' @@ -189,11 +190,53 @@ static void handle_large_common (int small ATTRIBUTE_UNUSED); static const char *default_arch = DEFAULT_ARCH; +/* This struct describes rounding control and SAE in the instruction. */ +struct RC_Operation +{ + enum rc_type + { + rne = 0, + rd, + ru, + rz, + saeonly + } type; + int operand; +}; + +static struct RC_Operation rc_op; + +/* The struct describes masking, applied to OPERAND in the instruction. + MASK is a pointer to the corresponding mask register. ZEROING tells + whether merging or zeroing mask is used. */ +struct Mask_Operation +{ + const reg_entry *mask; + unsigned int zeroing; + /* The operand where this operation is associated. */ + int operand; +}; + +static struct Mask_Operation mask_op; + +/* The struct describes broadcasting, applied to OPERAND. FACTOR is + broadcast factor. */ +struct Broadcast_Operation +{ + /* Type of broadcast: no broadcast, {1to8}, or {1to16}. */ + int type; + + /* Index of broadcasted operand. */ + int operand; +}; + +static struct Broadcast_Operation broadcast_op; + /* VEX prefix. */ typedef struct { - /* VEX prefix is either 2 byte or 3 byte. */ - unsigned char bytes[3]; + /* VEX prefix is either 2 byte or 3 byte. EVEX is 4 byte. */ + unsigned char bytes[4]; unsigned int length; /* Destination or source register specifier. */ const reg_entry *register_specifier; @@ -223,7 +266,17 @@ enum i386_error unsupported, invalid_vsib_address, invalid_vector_register_set, - unsupported_vector_index_register + unsupported_vector_index_register, + unsupported_broadcast, + broadcast_not_on_src_operand, + broadcast_needed, + unsupported_masking, + mask_not_on_destination, + no_default_mask, + unsupported_rc_sae, + rc_sae_operand_not_last_imm, + invalid_register_operand, + try_vector_disp8 }; struct _i386_insn @@ -277,9 +330,22 @@ struct _i386_insn addressing modes of this insn are encoded. */ modrm_byte rm; rex_byte rex; + rex_byte vrex; sib_byte sib; vex_prefix vex; + /* Masking attributes. */ + struct Mask_Operation *mask; + + /* Rounding control and SAE attributes. */ + struct RC_Operation *rounding; + + /* Broadcasting attributes. */ + struct Broadcast_Operation *broadcast; + + /* Compressed disp8*N attribute. */ + unsigned int memshift; + /* Swap operand in encoding. */ unsigned int swap_operand; @@ -300,15 +366,36 @@ struct _i386_insn /* Have BND prefix. */ const char *bnd_prefix; + /* Need VREX to support upper 16 registers. */ + int need_vrex; + /* Error message. */ enum i386_error error; }; typedef struct _i386_insn i386_insn; +/* Link RC type with corresponding string, that'll be looked for in + asm. */ +struct RC_name +{ + enum rc_type type; + const char *name; + unsigned int len; +}; + +static const struct RC_name RC_NamesTable[] = +{ + { rne, STRING_COMMA_LEN ("rn-sae") }, + { rd, STRING_COMMA_LEN ("rd-sae") }, + { ru, STRING_COMMA_LEN ("ru-sae") }, + { rz, STRING_COMMA_LEN ("rz-sae") }, + { saeonly, STRING_COMMA_LEN ("sae") }, +}; + /* 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 @@ -512,6 +599,21 @@ static enum vex256 } avxscalar; +/* Encode scalar EVEX LIG instructions with specific vector length. */ +static enum + { + evexl128 = 0, + evexl256, + evexl512 + } evexlig; + +/* Encode EVEX WIG instructions with specific evex.w. */ +static enum + { + evexw0 = 0, + evexw1 + } evexwig; + /* Pre-defined "_GLOBAL_OFFSET_TABLE_". */ static symbolS *GOT_symbol; @@ -706,6 +808,14 @@ static const arch_entry cpu_arch[] = CPU_AVX_FLAGS, 0, 0 }, { STRING_COMMA_LEN (".avx2"), PROCESSOR_UNKNOWN, CPU_AVX2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".avx512f"), PROCESSOR_UNKNOWN, + CPU_AVX512F_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".avx512cd"), PROCESSOR_UNKNOWN, + CPU_AVX512CD_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".avx512er"), PROCESSOR_UNKNOWN, + CPU_AVX512ER_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".avx512pf"), PROCESSOR_UNKNOWN, + CPU_AVX512PF_FLAGS, 0, 0 }, { STRING_COMMA_LEN (".noavx"), PROCESSOR_UNKNOWN, CPU_ANY_AVX_FLAGS, 0, 1 }, { STRING_COMMA_LEN (".vmx"), PROCESSOR_UNKNOWN, @@ -1543,6 +1653,8 @@ static const i386_operand_type anydisp = OPERAND_TYPE_ANYDISP; static const i386_operand_type regxmm = OPERAND_TYPE_REGXMM; static const i386_operand_type regymm = OPERAND_TYPE_REGYMM; +static const i386_operand_type regzmm = OPERAND_TYPE_REGZMM; +static const i386_operand_type regmask = OPERAND_TYPE_REGMASK; static const i386_operand_type imm8 = OPERAND_TYPE_IMM8; static const i386_operand_type imm8s = OPERAND_TYPE_IMM8S; static const i386_operand_type imm16 = OPERAND_TYPE_IMM16; @@ -1554,6 +1666,7 @@ static const i386_operand_type imm16_32s = OPERAND_TYPE_IMM16_32S; static const i386_operand_type imm16_32_32s = OPERAND_TYPE_IMM16_32_32S; static const i386_operand_type vec_imm4 = OPERAND_TYPE_VEC_IMM4; static const i386_operand_type regbnd = OPERAND_TYPE_REGBND; +static const i386_operand_type vec_disp8 = OPERAND_TYPE_VEC_DISP8; enum operand_type { @@ -1636,7 +1749,9 @@ match_mem_size (const insn_template *t, unsigned int j) || (i.types[j].bitfield.xmmword && !t->operand_types[j].bitfield.xmmword) || (i.types[j].bitfield.ymmword - && !t->operand_types[j].bitfield.ymmword))); + && !t->operand_types[j].bitfield.ymmword) + || (i.types[j].bitfield.zmmword + && !t->operand_types[j].bitfield.zmmword))); } /* Return 1 if there is no size conflict on any operands for @@ -1717,6 +1832,7 @@ operand_type_match (i386_operand_type overlap, temp.bitfield.tbyte = 0; temp.bitfield.xmmword = 0; temp.bitfield.ymmword = 0; + temp.bitfield.zmmword = 0; if (operand_type_all_zero (&temp)) goto mismatch; @@ -1794,7 +1910,7 @@ register_number (const reg_entry *r) static INLINE unsigned int mode_from_disp_size (i386_operand_type t) { - if (t.bitfield.disp8) + if (t.bitfield.disp8 || t.bitfield.vec_disp8) return 1; else if (t.bitfield.disp16 || t.bitfield.disp32 @@ -1850,6 +1966,25 @@ fits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED) } /* fits_in_unsigned_long() */ static INLINE int +fits_in_vec_disp8 (offsetT num) +{ + int shift = i.memshift; + unsigned int mask; + + if (shift == -1) + abort (); + + mask = (1 << shift) - 1; + + /* Return 0 if NUM isn't properly aligned. */ + if ((num & mask)) + return 0; + + /* Check if NUM will fit in 8bit after shift. */ + return fits_in_signed_byte (num >> shift); +} + +static INLINE int fits_in_imm4 (offsetT num) { return (num & 0xf) == num; @@ -2440,6 +2575,8 @@ md_begin (void) register_chars[c] = mnemonic_chars[c]; operand_chars[c] = c; } + else if (c == '{' || c == '}') + operand_chars[c] = c; if (ISALPHA (c) || ISDIGIT (c)) identifier_chars[c] = c; @@ -2532,6 +2669,7 @@ pi (char *line, i386_insn *x) || x->types[j].bitfield.regmmx || x->types[j].bitfield.regxmm || x->types[j].bitfield.regymm + || x->types[j].bitfield.regzmm || x->types[j].bitfield.sreg2 || x->types[j].bitfield.sreg3 || x->types[j].bitfield.control @@ -2619,6 +2757,7 @@ const type_names[] = { OPERAND_TYPE_DISP32, "d32" }, { OPERAND_TYPE_DISP32S, "d32s" }, { OPERAND_TYPE_DISP64, "d64" }, + { OPERAND_TYPE_VEC_DISP8, "Vector d8" }, { OPERAND_TYPE_INOUTPORTREG, "InOutPortReg" }, { OPERAND_TYPE_SHIFTCOUNT, "ShiftCount" }, { OPERAND_TYPE_CONTROL, "control reg" }, @@ -2633,6 +2772,8 @@ const type_names[] = { OPERAND_TYPE_REGMMX, "rMMX" }, { OPERAND_TYPE_REGXMM, "rXMM" }, { OPERAND_TYPE_REGYMM, "rYMM" }, + { OPERAND_TYPE_REGZMM, "rZMM" }, + { OPERAND_TYPE_REGMASK, "Mask reg" }, { OPERAND_TYPE_ESSEG, "es" }, }; @@ -2882,7 +3023,11 @@ build_vex_prefix (const insn_template *t) /* Check register specifier. */ if (i.vex.register_specifier) - register_specifier = ~register_number (i.vex.register_specifier) & 0xf; + { + register_specifier = + ~register_number (i.vex.register_specifier) & 0xf; + gas_assert ((i.vex.register_specifier->reg_flags & RegVRex) == 0); + } else register_specifier = 0xf; @@ -3016,6 +3161,175 @@ build_vex_prefix (const insn_template *t) } } +/* Build the EVEX prefix. */ + +static void +build_evex_prefix (void) +{ + unsigned int register_specifier; + unsigned int implied_prefix; + unsigned int m, w; + rex_byte vrex_used = 0; + + /* Check register specifier. */ + if (i.vex.register_specifier) + { + gas_assert ((i.vrex & REX_X) == 0); + + register_specifier = i.vex.register_specifier->reg_num; + if ((i.vex.register_specifier->reg_flags & RegRex)) + register_specifier += 8; + /* The upper 16 registers are encoded in the fourth byte of the + EVEX prefix. */ + if (!(i.vex.register_specifier->reg_flags & RegVRex)) + i.vex.bytes[3] = 0x8; + register_specifier = ~register_specifier & 0xf; + } + else + { + register_specifier = 0xf; + + /* Encode upper 16 vector index register in the fourth byte of + the EVEX prefix. */ + if (!(i.vrex & REX_X)) + i.vex.bytes[3] = 0x8; + else + vrex_used |= REX_X; + } + + switch ((i.tm.base_opcode >> 8) & 0xff) + { + case 0: + implied_prefix = 0; + break; + case DATA_PREFIX_OPCODE: + implied_prefix = 1; + break; + case REPE_PREFIX_OPCODE: + implied_prefix = 2; + break; + case REPNE_PREFIX_OPCODE: + implied_prefix = 3; + break; + default: + abort (); + } + + /* 4 byte EVEX prefix. */ + i.vex.length = 4; + i.vex.bytes[0] = 0x62; + + /* mmmm bits. */ + switch (i.tm.opcode_modifier.vexopcode) + { + case VEX0F: + m = 1; + break; + case VEX0F38: + m = 2; + break; + case VEX0F3A: + m = 3; + break; + default: + abort (); + break; + } + + /* The high 3 bits of the second EVEX byte are 1's compliment of RXB + bits from REX. */ + i.vex.bytes[1] = (~i.rex & 0x7) << 5 | m; + + /* The fifth bit of the second EVEX byte is 1's compliment of the + REX_R bit in VREX. */ + if (!(i.vrex & REX_R)) + i.vex.bytes[1] |= 0x10; + else + vrex_used |= REX_R; + + if ((i.reg_operands + i.imm_operands) == i.operands) + { + /* When all operands are registers, the REX_X bit in REX is not + used. We reuse it to encode the upper 16 registers, which is + indicated by the REX_B bit in VREX. The REX_X bit is encoded + as 1's compliment. */ + if ((i.vrex & REX_B)) + { + vrex_used |= REX_B; + i.vex.bytes[1] &= ~0x40; + } + } + + /* EVEX instructions shouldn't need the REX prefix. */ + i.vrex &= ~vrex_used; + gas_assert (i.vrex == 0); + + /* Check the REX.W bit. */ + w = (i.rex & REX_W) ? 1 : 0; + if (i.tm.opcode_modifier.vexw) + { + if (i.tm.opcode_modifier.vexw == VEXW1) + w = 1; + } + /* If w is not set it means we are dealing with WIG instruction. */ + else if (!w) + { + if (evexwig == evexw1) + w = 1; + } + + /* Encode the U bit. */ + implied_prefix |= 0x4; + + /* The third byte of the EVEX prefix. */ + i.vex.bytes[2] = (w << 7 | register_specifier << 3 | implied_prefix); + + /* The fourth byte of the EVEX prefix. */ + /* The zeroing-masking bit. */ + if (i.mask && i.mask->zeroing) + i.vex.bytes[3] |= 0x80; + + /* Don't always set the broadcast bit if there is no RC. */ + if (!i.rounding) + { + /* Encode the vector length. */ + unsigned int vec_length; + + switch (i.tm.opcode_modifier.evex) + { + case EVEXLIG: /* LL' is ignored */ + vec_length = evexlig << 5; + break; + case EVEX128: + vec_length = 0 << 5; + break; + case EVEX256: + vec_length = 1 << 5; + break; + case EVEX512: + vec_length = 2 << 5; + break; + default: + abort (); + break; + } + i.vex.bytes[3] |= vec_length; + /* Encode the broadcast bit. */ + if (i.broadcast) + i.vex.bytes[3] |= 0x10; + } + else + { + if (i.rounding->type != saeonly) + i.vex.bytes[3] |= 0x10 | (i.rounding->type << 5); + else + i.vex.bytes[3] |= 0x10; + } + + if (i.mask && i.mask->mask) + i.vex.bytes[3] |= i.mask->mask->reg_num; +} + static void process_immext (void) { @@ -3047,9 +3361,10 @@ process_immext (void) AVX instructions also use this encoding, for some of 3 argument instructions. */ - gas_assert (i.imm_operands == 0 + gas_assert (i.imm_operands <= 1 && (i.operands <= 2 - || (i.tm.opcode_modifier.vex + || ((i.tm.opcode_modifier.vex + || i.tm.opcode_modifier.evex) && i.operands <= 4))); exp = &im_expressions[i.imm_operands++]; @@ -3296,6 +3611,9 @@ md_assemble (char *line) if (i.tm.opcode_modifier.vex) build_vex_prefix (t); + if (i.tm.opcode_modifier.evex) + build_evex_prefix (); + /* Handle conversion of 'int $3' --> special int3 insn. XOP or FMA4 instructions may define INT_OPCODE as well, so avoid this corner case for those instructions that use MODRM. */ @@ -3735,6 +4053,28 @@ swap_2_operands (int xchg1, int xchg2) temp_reloc = i.reloc[xchg2]; i.reloc[xchg2] = i.reloc[xchg1]; i.reloc[xchg1] = temp_reloc; + + if (i.mask) + { + if (i.mask->operand == xchg1) + i.mask->operand = xchg2; + else if (i.mask->operand == xchg2) + i.mask->operand = xchg1; + } + if (i.broadcast) + { + if (i.broadcast->operand == xchg1) + i.broadcast->operand = xchg2; + else if (i.broadcast->operand == xchg2) + i.broadcast->operand = xchg1; + } + if (i.rounding) + { + if (i.rounding->operand == xchg1) + i.rounding->operand = xchg2; + else if (i.rounding->operand == xchg2) + i.rounding->operand = xchg1; + } } static void @@ -3990,11 +4330,14 @@ optimize_disp (void) static int check_VecOperands (const insn_template *t) { + unsigned int op; + /* Without VSIB byte, we can't have a vector register for index. */ if (!t->opcode_modifier.vecsib && i.index_reg && (i.index_reg->reg_type.bitfield.regxmm - || i.index_reg->reg_type.bitfield.regymm)) + || i.index_reg->reg_type.bitfield.regymm + || i.index_reg->reg_type.bitfield.regzmm)) { i.error = unsupported_vector_index_register; return 1; @@ -4008,31 +4351,188 @@ check_VecOperands (const insn_template *t) || !((t->opcode_modifier.vecsib == VecSIB128 && i.index_reg->reg_type.bitfield.regxmm) || (t->opcode_modifier.vecsib == VecSIB256 - && i.index_reg->reg_type.bitfield.regymm))) + && i.index_reg->reg_type.bitfield.regymm) + || (t->opcode_modifier.vecsib == VecSIB512 + && i.index_reg->reg_type.bitfield.regzmm))) { i.error = invalid_vsib_address; return 1; } - gas_assert (i.reg_operands == 2); - gas_assert (i.types[0].bitfield.regxmm - || i.types[0].bitfield.regymm); - gas_assert (i.types[2].bitfield.regxmm - || i.types[2].bitfield.regymm); + gas_assert (i.reg_operands == 2 || i.mask); + if (i.reg_operands == 2 && !i.mask) + { + gas_assert (i.types[0].bitfield.regxmm + || i.types[0].bitfield.regymm + || i.types[0].bitfield.regzmm); + gas_assert (i.types[2].bitfield.regxmm + || i.types[2].bitfield.regymm + || i.types[2].bitfield.regzmm); + if (operand_check == check_none) + return 0; + if (register_number (i.op[0].regs) + != register_number (i.index_reg) + && register_number (i.op[2].regs) + != register_number (i.index_reg) + && register_number (i.op[0].regs) + != register_number (i.op[2].regs)) + return 0; + if (operand_check == check_error) + { + i.error = invalid_vector_register_set; + return 1; + } + as_warn (_("mask, index, and destination registers should be distinct")); + } + } + + /* Check if broadcast is supported by the instruction and is applied + to the memory operand. */ + if (i.broadcast) + { + int broadcasted_opnd_size; + + /* Check if specified broadcast is supported in this instruction, + and it's applied to memory operand of DWORD or QWORD type, + depending on VecESize. */ + if (i.broadcast->type != t->opcode_modifier.broadcast + || !i.types[i.broadcast->operand].bitfield.mem + || (t->opcode_modifier.vecesize == 0 + && !i.types[i.broadcast->operand].bitfield.dword + && !i.types[i.broadcast->operand].bitfield.unspecified) + || (t->opcode_modifier.vecesize == 1 + && !i.types[i.broadcast->operand].bitfield.qword + && !i.types[i.broadcast->operand].bitfield.unspecified)) + goto bad_broadcast; + + broadcasted_opnd_size = t->opcode_modifier.vecesize ? 64 : 32; + if (i.broadcast->type == BROADCAST_1TO16) + broadcasted_opnd_size <<= 4; /* Broadcast 1to16. */ + else if (i.broadcast->type == BROADCAST_1TO8) + broadcasted_opnd_size <<= 3; /* Broadcast 1to8. */ + else + goto bad_broadcast; - if (operand_check == check_none) - return 0; - if (register_number (i.op[0].regs) != register_number (i.index_reg) - && register_number (i.op[2].regs) != register_number (i.index_reg) - && register_number (i.op[0].regs) != register_number (i.op[2].regs)) - return 0; - if (operand_check == check_error) + if ((broadcasted_opnd_size == 256 + && !t->operand_types[i.broadcast->operand].bitfield.ymmword) + || (broadcasted_opnd_size == 512 + && !t->operand_types[i.broadcast->operand].bitfield.zmmword)) + { + bad_broadcast: + i.error = unsupported_broadcast; + return 1; + } + } + /* If broadcast is supported in this instruction, we need to check if + operand of one-element size isn't specified without broadcast. */ + else if (t->opcode_modifier.broadcast && i.mem_operands) + { + /* Find memory operand. */ + for (op = 0; op < i.operands; op++) + if (operand_type_check (i.types[op], anymem)) + break; + gas_assert (op < i.operands); + /* Check size of the memory operand. */ + if ((t->opcode_modifier.vecesize == 0 + && i.types[op].bitfield.dword) + || (t->opcode_modifier.vecesize == 1 + && i.types[op].bitfield.qword)) + { + i.error = broadcast_needed; + return 1; + } + } + + /* Check if requested masking is supported. */ + if (i.mask + && (!t->opcode_modifier.masking + || (i.mask->zeroing + && t->opcode_modifier.masking == MERGING_MASKING))) + { + i.error = unsupported_masking; + return 1; + } + + /* Check if masking is applied to dest operand. */ + if (i.mask && (i.mask->operand != (int) (i.operands - 1))) + { + i.error = mask_not_on_destination; + return 1; + } + + /* Check if default mask is allowed. */ + if (t->opcode_modifier.nodefmask + && (!i.mask || i.mask->mask->reg_num == 0)) + { + i.error = no_default_mask; + return 1; + } + + /* Check RC/SAE. */ + if (i.rounding) + { + if ((i.rounding->type != saeonly + && !t->opcode_modifier.staticrounding) + || (i.rounding->type == saeonly + && (t->opcode_modifier.staticrounding + || !t->opcode_modifier.sae))) { - i.error = invalid_vector_register_set; + i.error = unsupported_rc_sae; return 1; } - as_warn (_("mask, index, and destination registers should be distinct")); + /* If the instruction has several immediate operands and one of + them is rounding, the rounding operand should be the last + immediate operand. */ + if (i.imm_operands > 1 + && i.rounding->operand != (int) (i.imm_operands - 1)) + { + i.error = rc_sae_operand_not_last_imm; + return 1; + } + } + + /* Check vector Disp8 operand. */ + if (t->opcode_modifier.disp8memshift) + { + if (i.broadcast) + i.memshift = t->opcode_modifier.vecesize ? 3 : 2; + else + i.memshift = t->opcode_modifier.disp8memshift; + + for (op = 0; op < i.operands; op++) + if (operand_type_check (i.types[op], disp) + && i.op[op].disps->X_op == O_constant) + { + offsetT value = i.op[op].disps->X_add_number; + int vec_disp8_ok = fits_in_vec_disp8 (value); + if (t->operand_types [op].bitfield.vec_disp8) + { + if (vec_disp8_ok) + i.types[op].bitfield.vec_disp8 = 1; + else + { + /* Vector insn can only have Vec_Disp8/Disp32 in + 32/64bit modes, and Vec_Disp8/Disp16 in 16bit + mode. */ + i.types[op].bitfield.disp8 = 0; + if (flag_code != CODE_16BIT) + i.types[op].bitfield.disp16 = 0; + } + } + else if (flag_code != CODE_16BIT) + { + /* One form of this instruction supports vector Disp8. + Try vector Disp8 if we need to use Disp32. */ + if (vec_disp8_ok && !fits_in_signed_byte (value)) + { + i.error = try_vector_disp8; + return 1; + } + } + } } + else + i.memshift = -1; return 0; } @@ -4043,6 +4543,13 @@ check_VecOperands (const insn_template *t) static int VEX_check_operands (const insn_template *t) { + /* VREX is only valid with EVEX prefix. */ + if (i.need_vrex && !t->opcode_modifier.evex) + { + i.error = invalid_register_operand; + return 1; + } + if (!t->opcode_modifier.vex) return 0; @@ -4159,10 +4666,12 @@ match_template (void) : intel_float_operand (t->name) != 2) && ((!operand_types[0].bitfield.regmmx && !operand_types[0].bitfield.regxmm - && !operand_types[0].bitfield.regymm) + && !operand_types[0].bitfield.regymm + && !operand_types[0].bitfield.regzmm) || (!operand_types[t->operands > 1].bitfield.regmmx && !!operand_types[t->operands > 1].bitfield.regxmm - && !!operand_types[t->operands > 1].bitfield.regymm)) + && !!operand_types[t->operands > 1].bitfield.regymm + && !!operand_types[t->operands > 1].bitfield.regzmm)) && (t->base_opcode != 0x0fc7 || t->extension_opcode != 1 /* cmpxchg8b */)) continue; @@ -4433,6 +4942,36 @@ check_reverse: case unsupported_vector_index_register: err_msg = _("unsupported vector index register"); break; + case unsupported_broadcast: + err_msg = _("unsupported broadcast"); + break; + case broadcast_not_on_src_operand: + err_msg = _("broadcast not on source memory operand"); + break; + case broadcast_needed: + err_msg = _("broadcast is needed for operand of such type"); + break; + case unsupported_masking: + err_msg = _("unsupported masking"); + break; + case mask_not_on_destination: + err_msg = _("mask not on destination operand"); + break; + case no_default_mask: + err_msg = _("default mask isn't allowed"); + break; + case unsupported_rc_sae: + err_msg = _("unsupported static rounding/sae"); + break; + case rc_sae_operand_not_last_imm: + if (intel_syntax) + err_msg = _("RC/SAE operand must precede immediate operands"); + else + err_msg = _("RC/SAE operand must follow immediate operands"); + break; + case invalid_register_operand: + err_msg = _("invalid register operand"); + break; } as_bad (_("%s for `%s'"), err_msg, current_templates->start->name); @@ -4625,9 +5164,10 @@ process_suffix (void) return 0; } else if (i.suffix == XMMWORD_MNEM_SUFFIX - || i.suffix == YMMWORD_MNEM_SUFFIX) + || i.suffix == YMMWORD_MNEM_SUFFIX + || i.suffix == ZMMWORD_MNEM_SUFFIX) { - /* Skip if the instruction has x/y suffix. match_template + /* Skip if the instruction has x/y/z suffix. match_template should check if it is a valid suffix. */ } else if (intel_syntax && i.tm.opcode_modifier.ignoresize) @@ -4715,7 +5255,8 @@ process_suffix (void) if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX && i.suffix != XMMWORD_MNEM_SUFFIX - && i.suffix != YMMWORD_MNEM_SUFFIX) + && i.suffix != YMMWORD_MNEM_SUFFIX + && i.suffix != ZMMWORD_MNEM_SUFFIX) { /* It's not a byte, select word/dword operation. */ if (i.tm.opcode_modifier.w) @@ -4835,6 +5376,7 @@ check_byte_reg (void) || i.types[op].bitfield.regmmx || i.types[op].bitfield.regxmm || i.types[op].bitfield.regymm + || i.types[op].bitfield.regzmm || i.types[op].bitfield.sreg2 || i.types[op].bitfield.sreg3 || i.types[op].bitfield.control @@ -5206,10 +5748,11 @@ duplicate: { unsigned int j; - /* The first operand is implicit and must be xmm0/ymm0. */ + /* The first operand is implicit and must be xmm0/ymm0/zmm0. */ gas_assert (i.reg_operands && (operand_type_equal (&i.types[0], ®xmm) - || operand_type_equal (&i.types[0], ®ymm))); + || operand_type_equal (&i.types[0], ®ymm) + || operand_type_equal (&i.types[0], ®zmm))); if (register_number (i.op[0].regs) != 0) return bad_implicit_operand (i.types[0].bitfield.regxmm); @@ -5363,8 +5906,8 @@ build_modrm_byte (void) /* There are 2 kinds of instructions: 1. 5 operands: 4 register operands or 3 register operands plus 1 memory operand plus one Vec_Imm4 operand, VexXDS, and - VexW0 or VexW1. The destination must be either XMM or YMM - register. + VexW0 or VexW1. The destination must be either XMM, YMM or + ZMM register. 2. 4 operands: 4 register operands or 3 register operands plus 1 memory operand, VexXDS, and VexImmExt */ gas_assert ((i.reg_operands == 4 @@ -5376,7 +5919,8 @@ build_modrm_byte (void) && (i.tm.opcode_modifier.vexw == VEXW0 || i.tm.opcode_modifier.vexw == VEXW1) && (operand_type_equal (&i.tm.operand_types[dest], ®xmm) - || operand_type_equal (&i.tm.operand_types[dest], ®ymm))))); + || operand_type_equal (&i.tm.operand_types[dest], ®ymm) + || operand_type_equal (&i.tm.operand_types[dest], ®zmm))))); if (i.imm_operands == 0) { @@ -5411,10 +5955,13 @@ build_modrm_byte (void) gas_assert (operand_type_equal (&i.tm.operand_types[reg_slot], ®xmm) || operand_type_equal (&i.tm.operand_types[reg_slot], - ®ymm)); + ®ymm) + || operand_type_equal (&i.tm.operand_types[reg_slot], + ®zmm)); exp->X_op = O_constant; exp->X_add_number = register_number (i.op[reg_slot].regs) << 4; - } + gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0); + } else { unsigned int imm_slot; @@ -5455,14 +6002,19 @@ build_modrm_byte (void) gas_assert (operand_type_equal (&i.tm.operand_types[reg_slot], ®xmm) || operand_type_equal (&i.tm.operand_types[reg_slot], - ®ymm)); + ®ymm) + || operand_type_equal (&i.tm.operand_types[reg_slot], + ®zmm)); i.op[imm_slot].imms->X_add_number |= register_number (i.op[reg_slot].regs) << 4; + gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0); } gas_assert (operand_type_equal (&i.tm.operand_types[nds], ®xmm) || operand_type_equal (&i.tm.operand_types[nds], - ®ymm)); + ®ymm) + || operand_type_equal (&i.tm.operand_types[nds], + ®zmm)); i.vex.register_specifier = i.op[nds].regs; } else @@ -5515,7 +6067,8 @@ build_modrm_byte (void) || (i.tm.opcode_modifier.vexvvvv == VEXXDS && i.imm_operands == 1 && (i.types[0].bitfield.imm8 - || i.types[i.operands - 1].bitfield.imm8))); + || i.types[i.operands - 1].bitfield.imm8 + || i.rounding))); if (i.imm_operands == 2) source = 2; else @@ -5527,6 +6080,23 @@ build_modrm_byte (void) } break; case 5: + if (i.tm.opcode_modifier.evex) + { + /* For EVEX instructions, when there are 5 operands, the + first one must be immediate operand. If the second one + is immediate operand, the source operand is the 3th + one. If the last one is immediate operand, the source + operand is the 2nd one. */ + gas_assert (i.imm_operands == 2 + && i.tm.opcode_modifier.sae + && operand_type_check (i.types[0], imm)); + if (operand_type_check (i.types[1], imm)) + source = 2; + else if (operand_type_check (i.types[4], imm)) + source = 1; + else + abort (); + } break; default: abort (); @@ -5536,13 +6106,18 @@ build_modrm_byte (void) { dest = source + 1; + /* RC/SAE operand could be between DEST and SRC. That happens + when one operand is GPR and the other one is XMM/YMM/ZMM + register. */ + if (i.rounding && i.rounding->operand == (int) dest) + dest++; + if (i.tm.opcode_modifier.vexvvvv == VEXXDS) { - /* For instructions with VexNDS, the register-only - source operand must be 32/64bit integer, XMM or - YMM register. It is encoded in VEX prefix. We - need to clear RegMem bit before calling - operand_type_equal. */ + /* For instructions with VexNDS, the register-only source + operand must be 32/64bit integer, XMM, YMM or ZMM + register. It is encoded in VEX prefix. We need to + clear RegMem bit before calling operand_type_equal. */ i386_operand_type op; unsigned int vvvv; @@ -5564,7 +6139,9 @@ build_modrm_byte (void) || (op.bitfield.reg32 != 1 && !op.bitfield.reg64 != 1 && !operand_type_equal (&op, ®xmm) - && !operand_type_equal (&op, ®ymm))) + && !operand_type_equal (&op, ®ymm) + && !operand_type_equal (&op, ®zmm) + && !operand_type_equal (&op, ®mask))) abort (); i.vex.register_specifier = i.op[vvvv].regs; dest++; @@ -5585,8 +6162,12 @@ build_modrm_byte (void) i.rm.regmem = i.op[source].regs->reg_num; if ((i.op[dest].regs->reg_flags & RegRex) != 0) i.rex |= REX_R; + if ((i.op[dest].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_R; if ((i.op[source].regs->reg_flags & RegRex) != 0) i.rex |= REX_B; + if ((i.op[source].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_B; } else { @@ -5594,8 +6175,12 @@ build_modrm_byte (void) i.rm.regmem = i.op[dest].regs->reg_num; if ((i.op[dest].regs->reg_flags & RegRex) != 0) i.rex |= REX_B; + if ((i.op[dest].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_B; if ((i.op[source].regs->reg_flags & RegRex) != 0) i.rex |= REX_R; + if ((i.op[source].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_R; } if (flag_code != CODE_64BIT && (i.rex & (REX_R | REX_B))) { @@ -5631,6 +6216,8 @@ build_modrm_byte (void) { i.sib.base = NO_BASE_REGISTER; i.sib.scale = i.log2_scale_factor; + /* No Vec_Disp8 if there is no base. */ + i.types[op].bitfield.vec_disp8 = 0; i.types[op].bitfield.disp8 = 0; i.types[op].bitfield.disp16 = 0; i.types[op].bitfield.disp64 = 0; @@ -5649,6 +6236,8 @@ build_modrm_byte (void) i.sib.index = i.index_reg->reg_num; if ((i.index_reg->reg_flags & RegRex) != 0) i.rex |= REX_X; + if ((i.index_reg->reg_flags & RegVRex) != 0) + i.vrex |= REX_X; } default_seg = &ds; @@ -5703,6 +6292,8 @@ build_modrm_byte (void) i.sib.base = NO_BASE_REGISTER; i.sib.scale = i.log2_scale_factor; i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + /* No Vec_Disp8 if there is no base. */ + i.types[op].bitfield.vec_disp8 = 0; i.types[op].bitfield.disp8 = 0; i.types[op].bitfield.disp16 = 0; i.types[op].bitfield.disp64 = 0; @@ -5732,6 +6323,7 @@ build_modrm_byte (void) i.types[op].bitfield.disp32 = 0; i.types[op].bitfield.disp32s = 1; i.types[op].bitfield.disp64 = 0; + i.types[op].bitfield.vec_disp8 = 0; i.flags[op] |= Operand_PCrel; if (! i.disp_operands) fake_zero_displacement = 1; @@ -5755,7 +6347,10 @@ build_modrm_byte (void) if (operand_type_check (i.types[op], disp) == 0) { /* fake (%bp) into 0(%bp) */ - i.types[op].bitfield.disp8 = 1; + if (i.tm.operand_types[op].bitfield.vec_disp8) + i.types[op].bitfield.vec_disp8 = 1; + else + i.types[op].bitfield.disp8 = 1; fake_zero_displacement = 1; } } @@ -5775,6 +6370,8 @@ build_modrm_byte (void) i386_operand_type temp; operand_type_set (&temp, 0); temp.bitfield.disp8 = i.types[op].bitfield.disp8; + temp.bitfield.vec_disp8 + = i.types[op].bitfield.vec_disp8; i.types[op] = temp; if (i.prefix[ADDR_PREFIX] == 0) i.types[op].bitfield.disp32s = 1; @@ -5796,7 +6393,10 @@ build_modrm_byte (void) if (i.base_reg->reg_num == 5 && i.disp_operands == 0) { fake_zero_displacement = 1; - i.types[op].bitfield.disp8 = 1; + if (i.tm.operand_types [op].bitfield.vec_disp8) + i.types[op].bitfield.vec_disp8 = 1; + else + i.types[op].bitfield.disp8 = 1; } i.sib.scale = i.log2_scale_factor; if (i.index_reg == 0) @@ -5924,6 +6524,8 @@ build_modrm_byte (void) || i.types[op].bitfield.regxmm || i.types[op].bitfield.regymm || i.types[op].bitfield.regbnd + || i.types[op].bitfield.regzmm + || i.types[op].bitfield.regmask || i.types[op].bitfield.sreg2 || i.types[op].bitfield.sreg3 || i.types[op].bitfield.control @@ -5990,7 +6592,9 @@ build_modrm_byte (void) if (type->bitfield.reg32 != 1 && type->bitfield.reg64 != 1 && !operand_type_equal (type, ®xmm) - && !operand_type_equal (type, ®ymm)) + && !operand_type_equal (type, ®ymm) + && !operand_type_equal (type, ®zmm) + && !operand_type_equal (type, ®mask)) abort (); i.vex.register_specifier = i.op[vex_reg].regs; @@ -6006,12 +6610,16 @@ build_modrm_byte (void) i.rm.regmem = i.op[op].regs->reg_num; if ((i.op[op].regs->reg_flags & RegRex) != 0) i.rex |= REX_B; + if ((i.op[op].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_B; } else { i.rm.reg = i.op[op].regs->reg_num; if ((i.op[op].regs->reg_flags & RegRex) != 0) i.rex |= REX_R; + if ((i.op[op].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_R; } } @@ -6290,9 +6898,9 @@ output_insn (void) unsigned int j; unsigned int prefix; - /* Since the VEX prefix contains the implicit prefix, we don't - need the explicit prefix. */ - if (!i.tm.opcode_modifier.vex) + /* Since the VEX/EVEX prefix contains the implicit prefix, we + don't need the explicit prefix. */ + if (!i.tm.opcode_modifier.vex && !i.tm.opcode_modifier.evex) { switch (i.tm.opcode_length) { @@ -6349,6 +6957,11 @@ check_prefix: abort (); } + /* For EVEX instructions i.vrex should become 0 after + build_evex_prefix. For VEX instructions upper 16 registers + aren't available, so VREX should be 0. */ + if (i.vrex) + abort (); /* Now the VEX prefix. */ p = frag_more (i.vex.length); for (j = 0; j < i.vex.length; j++) @@ -6364,6 +6977,11 @@ check_prefix: { switch (i.tm.opcode_length) { + case 4: + p = frag_more (4); + *p++ = (i.tm.base_opcode >> 24) & 0xff; + *p++ = (i.tm.base_opcode >> 16) & 0xff; + break; case 3: p = frag_more (3); *p++ = (i.tm.base_opcode >> 16) & 0xff; @@ -6420,7 +7038,11 @@ static int disp_size (unsigned int n) { int size = 4; - if (i.types[n].bitfield.disp64) + + /* Vec_Disp8 has to be 8bit. */ + if (i.types[n].bitfield.vec_disp8) + size = 1; + else if (i.types[n].bitfield.disp64) size = 8; else if (i.types[n].bitfield.disp8) size = 1; @@ -6452,15 +7074,17 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off) for (n = 0; n < i.operands; n++) { - if (operand_type_check (i.types[n], disp)) + if (i.types[n].bitfield.vec_disp8 + || operand_type_check (i.types[n], disp)) { if (i.op[n].disps->X_op == O_constant) { int size = disp_size (n); - offsetT val; + offsetT val = i.op[n].disps->X_add_number; - val = offset_in_range (i.op[n].disps->X_add_number, - size); + if (i.types[n].bitfield.vec_disp8) + val >>= i.memshift; + val = offset_in_range (val, size); p = frag_more (size); md_number_to_chars (p, val, size); } @@ -6553,6 +7177,10 @@ output_imm (fragS *insn_start_frag, offsetT insn_start_off) for (n = 0; n < i.operands; n++) { + /* Skip SAE/RC Imm operand in EVEX. They are already handled. */ + if (i.rounding && (int) n == i.rounding->operand) + continue; + if (operand_type_check (i.types[n], imm)) { if (i.op[n].imms->X_op == O_constant) @@ -7052,6 +7680,140 @@ pe_directive_secrel (int dummy ATTRIBUTE_UNUSED) } #endif +/* Handle Vector operations. */ + +static char * +check_VecOperations (char *op_string, char *op_end) +{ + const reg_entry *mask; + const char *saved; + char *end_op; + + while (*op_string + && (op_end == NULL || op_string < op_end)) + { + saved = op_string; + if (*op_string == '{') + { + op_string++; + + /* Check broadcasts. */ + if (strncmp (op_string, "1to", 3) == 0) + { + int bcst_type; + + if (i.broadcast) + goto duplicated_vec_op; + + op_string += 3; + if (*op_string == '8') + bcst_type = BROADCAST_1TO8; + else if (*op_string == '1' + && *(op_string+1) == '6') + { + bcst_type = BROADCAST_1TO16; + op_string++; + } + else + { + as_bad (_("Unsupported broadcast: `%s'"), saved); + return NULL; + } + op_string++; + + broadcast_op.type = bcst_type; + broadcast_op.operand = this_operand; + i.broadcast = &broadcast_op; + } + /* Check masking operation. */ + else if ((mask = parse_register (op_string, &end_op)) != NULL) + { + /* k0 can't be used for write mask. */ + if (mask->reg_num == 0) + { + as_bad (_("`%s' can't be used for write mask"), + op_string); + return NULL; + } + + if (!i.mask) + { + mask_op.mask = mask; + mask_op.zeroing = 0; + mask_op.operand = this_operand; + i.mask = &mask_op; + } + else + { + if (i.mask->mask) + goto duplicated_vec_op; + + i.mask->mask = mask; + + /* Only "{z}" is allowed here. No need to check + zeroing mask explicitly. */ + if (i.mask->operand != this_operand) + { + as_bad (_("invalid write mask `%s'"), saved); + return NULL; + } + } + + op_string = end_op; + } + /* Check zeroing-flag for masking operation. */ + else if (*op_string == 'z') + { + if (!i.mask) + { + mask_op.mask = NULL; + mask_op.zeroing = 1; + mask_op.operand = this_operand; + i.mask = &mask_op; + } + else + { + if (i.mask->zeroing) + { + duplicated_vec_op: + as_bad (_("duplicated `%s'"), saved); + return NULL; + } + + i.mask->zeroing = 1; + + /* Only "{%k}" is allowed here. No need to check mask + register explicitly. */ + if (i.mask->operand != this_operand) + { + as_bad (_("invalid zeroing-masking `%s'"), + saved); + return NULL; + } + } + + op_string++; + } + else + goto unknown_vec_op; + + if (*op_string != '}') + { + as_bad (_("missing `}' in `%s'"), saved); + return NULL; + } + op_string++; + continue; + } + unknown_vec_op: + /* We don't know this one. */ + as_bad (_("unknown vector operation: `%s'"), saved); + return NULL; + } + + return op_string; +} + static int i386_immediate (char *imm_start) { @@ -7086,6 +7848,16 @@ i386_immediate (char *imm_start) exp_seg = expression (exp); SKIP_WHITESPACE (); + + /* Handle vector operations. */ + if (*input_line_pointer == '{') + { + input_line_pointer = check_VecOperations (input_line_pointer, + NULL); + if (input_line_pointer == NULL) + return 0; + } + if (*input_line_pointer) as_bad (_("junk `%s' after expression"), input_line_pointer); @@ -7578,6 +8350,7 @@ bad_address: || (i.index_reg && !i.index_reg->reg_type.bitfield.regxmm && !i.index_reg->reg_type.bitfield.regymm + && !i.index_reg->reg_type.bitfield.regzmm && ((addr_mode == CODE_64BIT ? !(i.index_reg->reg_type.bitfield.reg64 || i.index_reg->reg_num == RegRiz) @@ -7605,6 +8378,67 @@ bad_address: return 1; } +/* Handle vector immediates. */ + +static int +RC_SAE_immediate (const char *imm_start) +{ + unsigned int match_found, j; + const char *pstr = imm_start; + expressionS *exp; + + if (*pstr != '{') + return 0; + + pstr++; + match_found = 0; + for (j = 0; j < ARRAY_SIZE (RC_NamesTable); j++) + { + if (!strncmp (pstr, RC_NamesTable[j].name, RC_NamesTable[j].len)) + { + if (!i.rounding) + { + rc_op.type = RC_NamesTable[j].type; + rc_op.operand = this_operand; + i.rounding = &rc_op; + } + else + { + as_bad (_("duplicated `%s'"), imm_start); + return 0; + } + pstr += RC_NamesTable[j].len; + match_found = 1; + break; + } + } + if (!match_found) + return 0; + + if (*pstr++ != '}') + { + as_bad (_("Missing '}': '%s'"), imm_start); + return 0; + } + /* RC/SAE immediate string should contain nothing more. */; + if (*pstr != 0) + { + as_bad (_("Junk after '}': '%s'"), imm_start); + return 0; + } + + exp = &im_expressions[i.imm_operands++]; + i.op[this_operand].imms = exp; + + exp->X_op = O_constant; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_op_symbol = (symbolS *) 0; + + i.types[this_operand].bitfield.imm8 = 1; + return 1; +} + /* Parse OPERAND_STRING into the i386_insn structure I. Returns zero on error. */ @@ -7687,6 +8521,15 @@ i386_att_operand (char *operand_string) } goto do_memory_reference; } + + /* Handle vector operations. */ + if (*op_string == '{') + { + op_string = check_VecOperations (op_string, NULL); + if (op_string == NULL) + return 0; + } + if (*op_string) { as_bad (_("junk `%s' after register"), op_string); @@ -7716,6 +8559,11 @@ i386_att_operand (char *operand_string) if (!i386_immediate (op_string)) return 0; } + else if (RC_SAE_immediate (operand_string)) + { + /* If it is a RC or SAE immediate, do nothing. */ + ; + } else if (is_digit_char (*op_string) || is_identifier_char (*op_string) || *op_string == '(') @@ -7726,6 +8574,7 @@ i386_att_operand (char *operand_string) /* Start and end of displacement string expression (if found). */ char *displacement_string_start; char *displacement_string_end; + char *vop_start; do_memory_reference: if ((i.mem_operands == 1 @@ -7743,6 +8592,15 @@ i386_att_operand (char *operand_string) after the '('. */ base_string = op_string + strlen (op_string); + /* Handle vector operations. */ + vop_start = strchr (op_string, '{'); + if (vop_start && vop_start < base_string) + { + if (check_VecOperations (vop_start, base_string) == NULL) + return 0; + base_string = vop_start; + } + --base_string; if (is_space_char (*base_string)) --base_string; @@ -8446,11 +9304,26 @@ parse_real_register (char *reg_string, char **end_op) if (r->reg_type.bitfield.regymm && !cpu_arch_flags.bitfield.cpuavx) return (const reg_entry *) NULL; + if ((r->reg_type.bitfield.regzmm || r->reg_type.bitfield.regmask) + && !cpu_arch_flags.bitfield.cpuavx512f) + return (const reg_entry *) NULL; + /* Don't allow fake index register unless allow_index_reg isn't 0. */ if (!allow_index_reg && (r->reg_num == RegEiz || r->reg_num == RegRiz)) return (const reg_entry *) NULL; + /* Upper 16 vector register is only available with VREX in 64bit + mode. */ + if ((r->reg_flags & RegVRex)) + { + if (!cpu_arch_flags.bitfield.cpuvrex + || flag_code != CODE_64BIT) + return (const reg_entry *) NULL; + + i.need_vrex = 1; + } + if (((r->reg_flags & (RegRex64 | RegRex)) || r->reg_type.bitfield.reg64) && (!cpu_arch_flags.bitfield.cpulm @@ -8583,6 +9456,8 @@ const char *md_shortopts = "qn"; #define OPTION_MAVXSCALAR (OPTION_MD_BASE + 13) #define OPTION_X32 (OPTION_MD_BASE + 14) #define OPTION_MADD_BND_PREFIX (OPTION_MD_BASE + 15) +#define OPTION_MEVEXLIG (OPTION_MD_BASE + 16) +#define OPTION_MEVEXWIG (OPTION_MD_BASE + 17) struct option md_longopts[] = { @@ -8607,6 +9482,8 @@ struct option md_longopts[] = {"moperand-check", required_argument, NULL, OPTION_MOPERAND_CHECK}, {"mavxscalar", required_argument, NULL, OPTION_MAVXSCALAR}, {"madd-bnd-prefix", no_argument, NULL, OPTION_MADD_BND_PREFIX}, + {"mevexlig", required_argument, NULL, OPTION_MEVEXLIG}, + {"mevexwig", required_argument, NULL, OPTION_MEVEXWIG}, {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); @@ -8868,6 +9745,26 @@ md_parse_option (int c, char *arg) add_bnd_prefix = 1; break; + case OPTION_MEVEXLIG: + if (strcmp (arg, "128") == 0) + evexlig = evexl128; + else if (strcmp (arg, "256") == 0) + evexlig = evexl256; + else if (strcmp (arg, "512") == 0) + evexlig = evexl512; + else + as_fatal (_("invalid -mevexlig= option: `%s'"), arg); + break; + + case OPTION_MEVEXWIG: + if (strcmp (arg, "0") == 0) + evexwig = evexw0; + else if (strcmp (arg, "1") == 0) + evexwig = evexw1; + else + as_fatal (_("invalid -mevexwig= option: `%s'"), arg); + break; + default: return 0; } @@ -9003,6 +9900,12 @@ md_show_usage (FILE *stream) -mavxscalar=[128|256] encode scalar AVX instructions with specific vector\n\ length\n")); fprintf (stream, _("\ + -mevexlig=[128|256|512] encode scalar EVEX instructions with specific vector\n\ + length\n")); + fprintf (stream, _("\ + -mevexwig=[0|1] encode EVEX instructions with specific EVEX.W value\n\ + for EVEX.W bit ignored instructions\n")); + fprintf (stream, _("\ -mmnemonic=[att|intel] use AT&T/Intel mnemonic\n")); fprintf (stream, _("\ -msyntax=[att|intel] use AT&T/Intel syntax\n")); |