diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2013-07-26 17:20:25 +0000 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2013-07-26 17:20:25 +0000 |
commit | 43234a1e148a36771f22dab2d8bc126110efd8a9 (patch) | |
tree | 99b3c056bb61cf1473c6265e04e34cc84619f81f /gas/config/tc-i386.c | |
parent | 6f64ef53c0a77b34717741d4a5453760ff2a2cab (diff) | |
download | gdb-43234a1e148a36771f22dab2d8bc126110efd8a9.zip gdb-43234a1e148a36771f22dab2d8bc126110efd8a9.tar.gz gdb-43234a1e148a36771f22dab2d8bc126110efd8a9.tar.bz2 |
Add Intel AVX-512 support
binutils/
2013-07-26 Sergey Guriev <sergey.s.guriev@intel.com>
Alexander Ivchenko <alexander.ivchenko@intel.com>
Maxim Kuznetsov <maxim.kuznetsov@intel.com>
Sergey Lega <sergey.s.lega@intel.com>
Anna Tikhonova <anna.tikhonova@intel.com>
Ilya Tocar <ilya.tocar@intel.com>
Andrey Turetskiy <andrey.turetskiy@intel.com>
Ilya Verbin <ilya.verbin@intel.com>
Kirill Yukhin <kirill.yukhin@intel.com>
Michael Zolotukhin <michael.v.zolotukhin@intel.com>
* dwarf.c (dwarf_regnames_i386): Add k0-k7 registers and
numeration in comments.
(dwarf_regnames_x86_64): Add xmm16-31 and k0-k7 registers to
dwarf table.
gas/
2013-07-26 Sergey Guriev <sergey.s.guriev@intel.com>
Alexander Ivchenko <alexander.ivchenko@intel.com>
Maxim Kuznetsov <maxim.kuznetsov@intel.com>
Sergey Lega <sergey.s.lega@intel.com>
Anna Tikhonova <anna.tikhonova@intel.com>
Ilya Tocar <ilya.tocar@intel.com>
Andrey Turetskiy <andrey.turetskiy@intel.com>
Ilya Verbin <ilya.verbin@intel.com>
Kirill Yukhin <kirill.yukhin@intel.com>
Michael Zolotukhin <michael.v.zolotukhin@intel.com>
* config/tc-i386-intel.c (O_zmmword_ptr): New.
(i386_types): Add zmmword.
(i386_intel_simplify_register): Allow regzmm.
(i386_intel_simplify): Handle zmmwords.
(i386_intel_operand): Handle RC/SAE, vector operations and
zmmwords.
* config/tc-i386.c (ZMMWORD_MNEM_SUFFIX): New.
(struct RC_Operation): New.
(struct Mask_Operation): New.
(struct Broadcast_Operation): New.
(vex_prefix): Size of bytes increased to 4 to support EVEX
encoding.
(enum i386_error): Add new error codes: 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): Add new fields vrex, need_vrex, mask,
rounding, broadcast, memshift.
(struct RC_name): New.
(RC_NamesTable): New.
(evexlig): New.
(evexwig): New.
(extra_symbol_chars): Add '{'.
(cpu_arch): Add AVX512F, AVX512CD, AVX512ER and AVX512PF.
(i386_operand_type): Add regzmm, regmask and vec_disp8.
(match_mem_size): Handle zmmwords.
(operand_type_match): Handle zmm-registers.
(mode_from_disp_size): Handle vec_disp8.
(fits_in_vec_disp8): New.
(md_begin): Handle {} properly.
(type_names): Add "rZMM", "Mask reg" and "Vector d8".
(build_vex_prefix): Handle vrex.
(build_evex_prefix): New.
(process_immext): Adjust to properly handle EVEX.
(md_assemble): Add EVEX encoding support.
(swap_2_operands): Correctly handle operands with masking,
broadcasting or RC/SAE.
(check_VecOperands): Support EVEX features.
(VEX_check_operands): Properly handle 16 upper [xyz]mm registers.
(match_template): Support regzmm and handle new error codes.
(process_suffix): Handle zmmwords and zmm-registers.
(check_byte_reg): Extend to zmm-registers.
(process_operands): Extend to zmm-registers.
(build_modrm_byte): Handle EVEX.
(output_insn): Adjust to properly handle EVEX case.
(disp_size): Handle vec_disp8.
(output_disp): Support compressed disp8*N evex feature.
(output_imm): Handle RC/SAE immediates properly.
(check_VecOperations): New.
(i386_immediate): Handle EVEX features.
(i386_index_check): Handle zmmwords and zmm-registers.
(RC_SAE_immediate): New.
(i386_att_operand): Handle EVEX features.
(parse_real_register): Add a check for ZMM/Mask registers.
(OPTION_MEVEXLIG): New.
(OPTION_MEVEXWIG): New.
(md_longopts): Add mevexlig and mevexwig.
(md_parse_option): Handle mevexlig and mevexwig options.
(md_show_usage): Add description for mevexlig and mevexwig.
* doc/c-i386.texi: Document avx512f/.avx512f, avx512cd/.avx512cd,
avx512er/.avx512er, avx512pf/.avx512pf, mevexlig and mevexwig.
gas/testsuite/
2013-07-26 Sergey Guriev <sergey.s.guriev@intel.com>
Alexander Ivchenko <alexander.ivchenko@intel.com>
Maxim Kuznetsov <maxim.kuznetsov@intel.com>
Sergey Lega <sergey.s.lega@intel.com>
Anna Tikhonova <anna.tikhonova@intel.com>
Ilya Tocar <ilya.tocar@intel.com>
Andrey Turetskiy <andrey.turetskiy@intel.com>
Ilya Verbin <ilya.verbin@intel.com>
Kirill Yukhin <kirill.yukhin@intel.com>
Michael Zolotukhin <michael.v.zolotukhin@intel.com>
* gas/cfi/cfi-i386.s: Add tests for k0-k7.
* gas/cfi/cfi-i386.d: Change to reflect above mentioned changes.
* gas/cfi/cfi-x86_64.s: Add tests for xmm16-31, k0-7.
* gas/cfi/cfi-x86_64.d: Change to reflect above mentioned changes.
* gas/i386/ilp32/cfi/cfi-x86_64.d: Ditto.
* gas/i386/intel-regs.s: Add tests for zmm0 and xmm16 registers.
* gas/i386/intel-regs.d: Change correspondingly.
* gas/i386/prefetch-intel.d: Reflect implementation of prefetchwt1.
* gas/i386/prefetch.d: Ditto.
* gas/i386/x86-64-prefetch-intel.d: Ditto.
* gas/i386/x86-64-prefetch.d: Ditto.
* gas/i386/avx512f-intel.d: New.
* gas/i386/avx512f-nondef.d: New.
* gas/i386/avx512f-nondef.s: New.
* gas/i386/avx512f-opts-intel.d: New.
* gas/i386/avx512f-opts.d: New.
* gas/i386/avx512f-opts.s: New.
* gas/i386/avx512f.d: New.
* gas/i386/avx512f.s: New.
* gas/i386/avx512cd-intel.d: New.
* gas/i386/avx512cd.d: New.
* gas/i386/avx512cd.s: New.
* gas/i386/avx512er-intel.d: New.
* gas/i386/avx512er.d: New.
* gas/i386/avx512er.s: New.
* gas/i386/avx512pf-intel.d: New.
* gas/i386/avx512pf.d: New.
* gas/i386/avx512pf.s: New.
* gas/i386/evex-lig.s: New.
* gas/i386/evex-lig256-intel.d: New.
* gas/i386/evex-lig256.d: New.
* gas/i386/evex-lig512-intel.d: New.
* gas/i386/evex-lig512.d: New.
* gas/i386/evex-wig.s: New.
* gas/i386/evex-wig1-intel.d: New.
* gas/i386/evex-wig1.d: New.
* gas/i386/inval-avx512f.l: New.
* gas/i386/inval-avx512f.s: New.
* gas/i386/x86-64-avx512f-intel.d: New.
* gas/i386/x86-64-avx512f-nondef.d: New.
* gas/i386/x86-64-avx512f-nondef.s: New.
* gas/i386/x86-64-avx512f-opts-intel.d: New.
* gas/i386/x86-64-avx512f-opts.d: New.
* gas/i386/x86-64-avx512f-opts.s: New.
* gas/i386/x86-64-avx512f.d: New.
* gas/i386/x86-64-avx512f.s: New.
* gas/i386/x86-64-avx512cd-intel.d: New.
* gas/i386/x86-64-avx512cd.d: New.
* gas/i386/x86-64-avx512cd.s: New.
* gas/i386/x86-64-avx512er-intel.d: New.
* gas/i386/x86-64-avx512er.d: New.
* gas/i386/x86-64-avx512er.s: New.
* gas/i386/x86-64-avx512pf-intel.d: New.
* gas/i386/x86-64-avx512pf.d: New.
* gas/i386/x86-64-avx512pf.s: New.
* gas/i386/x86-64-evex-lig.s: New.
* gas/i386/x86-64-evex-lig256-intel.d: New.
* gas/i386/x86-64-evex-lig256.d: New.
* gas/i386/x86-64-evex-lig512-intel.d: New.
* gas/i386/x86-64-evex-lig512.d: New.
* gas/i386/x86-64-evex-wig.s: New.
* gas/i386/x86-64-evex-wig1-intel.d: New.
* gas/i386/x86-64-evex-wig1.d: New.
* gas/i386/x86-64-inval-avx512f.l: New.
* gas/i386/x86-64-inval-avx512f.s: New.
* gas/i386/i386.exp: Run new AVX-512 tests.
opcodes/
2013-07-26 Sergey Guriev <sergey.s.guriev@intel.com>
Alexander Ivchenko <alexander.ivchenko@intel.com>
Maxim Kuznetsov <maxim.kuznetsov@intel.com>
Sergey Lega <sergey.s.lega@intel.com>
Anna Tikhonova <anna.tikhonova@intel.com>
Ilya Tocar <ilya.tocar@intel.com>
Andrey Turetskiy <andrey.turetskiy@intel.com>
Ilya Verbin <ilya.verbin@intel.com>
Kirill Yukhin <kirill.yukhin@intel.com>
Michael Zolotukhin <michael.v.zolotukhin@intel.com>
* i386-dis-evex.h: New.
* i386-dis.c (OP_Rounding): New.
(VPCMP_Fixup): New.
(OP_Mask): New.
(Rdq): New.
(XMxmmq): New.
(EXdScalarS): New.
(EXymm): New.
(EXEvexHalfBcstXmmq): New.
(EXxmm_mdq): New.
(EXEvexXGscat): New.
(EXEvexXNoBcst): New.
(VPCMP): New.
(EXxEVexR): New.
(EXxEVexS): New.
(XMask): New.
(MaskG): New.
(MaskE): New.
(MaskR): New.
(MaskVex): New.
(modes enum): Add evex_x_gscat_mode, evex_x_nobcst_mode,
evex_half_bcst_xmmq_mode, xmm_mdq_mode, ymm_mode,
evex_rounding_mode, evex_sae_mode, mask_mode.
(USE_EVEX_TABLE): New.
(EVEX_TABLE): New.
(EVEX enum): New.
(REG enum): Add REG_EVEX_0F72, REG_EVEX_0F73, REG_EVEX_0F38C6,
REG_EVEX_0F38C7.
(MOD enum): Add MOD_EVEX_0F10_PREFIX_1, MOD_EVEX_0F10_PREFIX_3,
MOD_EVEX_0F11_PREFIX_1, MOD_EVEX_0F11_PREFIX_3,
MOD_EVEX_0F12_PREFIX_0, MOD_EVEX_0F16_PREFIX_0, MOD_EVEX_0F38C6_REG_1,
MOD_EVEX_0F38C6_REG_2, MOD_EVEX_0F38C6_REG_5, MOD_EVEX_0F38C6_REG_6,
MOD_EVEX_0F38C7_REG_1, MOD_EVEX_0F38C7_REG_2, MOD_EVEX_0F38C7_REG_5,
MOD_EVEX_0F38C7_REG_6.
(PREFIX enum): Add PREFIX_VEX_0F41, PREFIX_VEX_0F42, PREFIX_VEX_0F44,
PREFIX_VEX_0F45, PREFIX_VEX_0F46, PREFIX_VEX_0F47, PREFIX_VEX_0F4B,
PREFIX_VEX_0F90, PREFIX_VEX_0F91, PREFIX_VEX_0F92, PREFIX_VEX_0F93,
PREFIX_VEX_0F98, PREFIX_VEX_0F3A30, PREFIX_VEX_0F3A32,
PREFIX_VEX_0F3AF0, PREFIX_EVEX_0F10, PREFIX_EVEX_0F11,
PREFIX_EVEX_0F12, PREFIX_EVEX_0F13, PREFIX_EVEX_0F14,
PREFIX_EVEX_0F15, PREFIX_EVEX_0F16, PREFIX_EVEX_0F17,
PREFIX_EVEX_0F28, PREFIX_EVEX_0F29, PREFIX_EVEX_0F2A,
PREFIX_EVEX_0F2B, PREFIX_EVEX_0F2C, PREFIX_EVEX_0F2D,
PREFIX_EVEX_0F2E, PREFIX_EVEX_0F2F, PREFIX_EVEX_0F51,
PREFIX_EVEX_0F58, PREFIX_EVEX_0F59, PREFIX_EVEX_0F5A,
PREFIX_EVEX_0F5B, PREFIX_EVEX_0F5C, PREFIX_EVEX_0F5D,
PREFIX_EVEX_0F5E, PREFIX_EVEX_0F5F, PREFIX_EVEX_0F62,
PREFIX_EVEX_0F66, PREFIX_EVEX_0F6A, PREFIX_EVEX_0F6C,
PREFIX_EVEX_0F6D, PREFIX_EVEX_0F6E, PREFIX_EVEX_0F6F,
PREFIX_EVEX_0F70, PREFIX_EVEX_0F72_REG_0, PREFIX_EVEX_0F72_REG_1,
PREFIX_EVEX_0F72_REG_2, PREFIX_EVEX_0F72_REG_4,
PREFIX_EVEX_0F72_REG_6, PREFIX_EVEX_0F73_REG_2,
PREFIX_EVEX_0F73_REG_6, PREFIX_EVEX_0F76, PREFIX_EVEX_0F78,
PREFIX_EVEX_0F79, PREFIX_EVEX_0F7A, PREFIX_EVEX_0F7B,
PREFIX_EVEX_0F7E, PREFIX_EVEX_0F7F, PREFIX_EVEX_0FC2,
PREFIX_EVEX_0FC6, PREFIX_EVEX_0FD2, PREFIX_EVEX_0FD3,
PREFIX_EVEX_0FD4, PREFIX_EVEX_0FD6, PREFIX_EVEX_0FDB,
PREFIX_EVEX_0FDF, PREFIX_EVEX_0FE2, PREFIX_EVEX_0FE6 PREFIX_EVEX_0FE7,
PREFIX_EVEX_0FEB, PREFIX_EVEX_0FEF, PREFIX_EVEX_0FF2,
PREFIX_EVEX_0FF3, PREFIX_EVEX_0FF4, PREFIX_EVEX_0FFA, PREFIX_EVEX_0FFB,
PREFIX_EVEX_0FFE, PREFIX_EVEX_0F380C, PREFIX_EVEX_0F380D,
PREFIX_EVEX_0F3811, PREFIX_EVEX_0F3812, PREFIX_EVEX_0F3813,
PREFIX_EVEX_0F3814, PREFIX_EVEX_0F3815, PREFIX_EVEX_0F3816,
PREFIX_EVEX_0F3818, PREFIX_EVEX_0F3819, PREFIX_EVEX_0F381A,
PREFIX_EVEX_0F381B, PREFIX_EVEX_0F381E, PREFIX_EVEX_0F381F,
PREFIX_EVEX_0F3821, PREFIX_EVEX_0F3822, PREFIX_EVEX_0F3823,
PREFIX_EVEX_0F3824, PREFIX_EVEX_0F3825, PREFIX_EVEX_0F3827,
PREFIX_EVEX_0F3828, PREFIX_EVEX_0F3829, PREFIX_EVEX_0F382A,
PREFIX_EVEX_0F382C, PREFIX_EVEX_0F382D, PREFIX_EVEX_0F3831,
PREFIX_EVEX_0F3832, PREFIX_EVEX_0F3833, PREFIX_EVEX_0F3834,
PREFIX_EVEX_0F3835, PREFIX_EVEX_0F3836, PREFIX_EVEX_0F3837,
PREFIX_EVEX_0F3839, PREFIX_EVEX_0F383A, PREFIX_EVEX_0F383B,
PREFIX_EVEX_0F383D, PREFIX_EVEX_0F383F, PREFIX_EVEX_0F3840,
PREFIX_EVEX_0F3842, PREFIX_EVEX_0F3843, PREFIX_EVEX_0F3844,
PREFIX_EVEX_0F3845, PREFIX_EVEX_0F3846, PREFIX_EVEX_0F3847,
PREFIX_EVEX_0F384C, PREFIX_EVEX_0F384D, PREFIX_EVEX_0F384E,
PREFIX_EVEX_0F384F, PREFIX_EVEX_0F3858, PREFIX_EVEX_0F3859,
PREFIX_EVEX_0F385A, PREFIX_EVEX_0F385B, PREFIX_EVEX_0F3864,
PREFIX_EVEX_0F3865, PREFIX_EVEX_0F3876, PREFIX_EVEX_0F3877,
PREFIX_EVEX_0F387C, PREFIX_EVEX_0F387E, PREFIX_EVEX_0F387F,
PREFIX_EVEX_0F3888, PREFIX_EVEX_0F3889, PREFIX_EVEX_0F388A,
PREFIX_EVEX_0F388B, PREFIX_EVEX_0F3890, PREFIX_EVEX_0F3891,
PREFIX_EVEX_0F3892, PREFIX_EVEX_0F3893, PREFIX_EVEX_0F3896,
PREFIX_EVEX_0F3897, PREFIX_EVEX_0F3898, PREFIX_EVEX_0F3899,
PREFIX_EVEX_0F389A, PREFIX_EVEX_0F389B, PREFIX_EVEX_0F389C,
PREFIX_EVEX_0F389D, PREFIX_EVEX_0F389E, PREFIX_EVEX_0F389F,
PREFIX_EVEX_0F38A0, PREFIX_EVEX_0F38A1, PREFIX_EVEX_0F38A2,
PREFIX_EVEX_0F38A3, PREFIX_EVEX_0F38A6, PREFIX_EVEX_0F38A7,
PREFIX_EVEX_0F38A8, PREFIX_EVEX_0F38A9, PREFIX_EVEX_0F38AA,
PREFIX_EVEX_0F38AB, PREFIX_EVEX_0F38AC, PREFIX_EVEX_0F38AD,
PREFIX_EVEX_0F38AE, PREFIX_EVEX_0F38AF, PREFIX_EVEX_0F38B6,
PREFIX_EVEX_0F38B7, PREFIX_EVEX_0F38B8, PREFIX_EVEX_0F38B9,
PREFIX_EVEX_0F38BA, PREFIX_EVEX_0F38BB, PREFIX_EVEX_0F38BC,
PREFIX_EVEX_0F38BD, PREFIX_EVEX_0F38BE, PREFIX_EVEX_0F38BF,
PREFIX_EVEX_0F38C4, PREFIX_EVEX_0F38C6_REG_1,
PREFIX_EVEX_0F38C6_REG_2, PREFIX_EVEX_0F38C6_REG_5,
PREFIX_EVEX_0F38C6_REG_6, PREFIX_EVEX_0F38C7_REG_1,
PREFIX_EVEX_0F38C7_REG_2, PREFIX_EVEX_0F38C7_REG_5,
PREFIX_EVEX_0F38C7_REG_6, PREFIX_EVEX_0F38C8, PREFIX_EVEX_0F38CA,
PREFIX_EVEX_0F38CB, PREFIX_EVEX_0F38CC, PREFIX_EVEX_0F38CD,
PREFIX_EVEX_0F3A00, PREFIX_EVEX_0F3A01, PREFIX_EVEX_0F3A03,
PREFIX_EVEX_0F3A04, PREFIX_EVEX_0F3A05, PREFIX_EVEX_0F3A08,
PREFIX_EVEX_0F3A09, PREFIX_EVEX_0F3A0A, PREFIX_EVEX_0F3A0B,
PREFIX_EVEX_0F3A17, PREFIX_EVEX_0F3A18, PREFIX_EVEX_0F3A19,
PREFIX_EVEX_0F3A1A, PREFIX_EVEX_0F3A1B, PREFIX_EVEX_0F3A1D,
PREFIX_EVEX_0F3A1E, PREFIX_EVEX_0F3A1F, PREFIX_EVEX_0F3A21,
PREFIX_EVEX_0F3A23, PREFIX_EVEX_0F3A25, PREFIX_EVEX_0F3A26,
PREFIX_EVEX_0F3A27, PREFIX_EVEX_0F3A38, PREFIX_EVEX_0F3A39,
PREFIX_EVEX_0F3A3A, PREFIX_EVEX_0F3A3B, PREFIX_EVEX_0F3A3E,
PREFIX_EVEX_0F3A3F, PREFIX_EVEX_0F3A43, PREFIX_EVEX_0F3A54,
PREFIX_EVEX_0F3A55.
(VEX_LEN enum): Add VEX_LEN_0F41_P_0, VEX_LEN_0F42_P_0, VEX_LEN_0F44_P_0,
VEX_LEN_0F45_P_0, VEX_LEN_0F46_P_0, VEX_LEN_0F47_P_0,
VEX_LEN_0F4B_P_2, VEX_LEN_0F90_P_0, VEX_LEN_0F91_P_0,
VEX_LEN_0F92_P_0, VEX_LEN_0F93_P_0, VEX_LEN_0F98_P_0,
VEX_LEN_0F3A30_P_2, VEX_LEN_0F3A32_P_2, VEX_W_0F41_P_0_LEN_1,
VEX_W_0F42_P_0_LEN_1, VEX_W_0F44_P_0_LEN_0, VEX_W_0F45_P_0_LEN_1,
VEX_W_0F46_P_0_LEN_1, VEX_W_0F47_P_0_LEN_1, VEX_W_0F4B_P_2_LEN_1,
VEX_W_0F90_P_0_LEN_0, VEX_W_0F91_P_0_LEN_0, VEX_W_0F92_P_0_LEN_0,
VEX_W_0F93_P_0_LEN_0, VEX_W_0F98_P_0_LEN_0, VEX_W_0F3A30_P_2_LEN_0,
VEX_W_0F3A32_P_2_LEN_0.
(VEX_W enum): Add EVEX_W_0F10_P_0, EVEX_W_0F10_P_1_M_0,
EVEX_W_0F10_P_1_M_1, EVEX_W_0F10_P_2, EVEX_W_0F10_P_3_M_0,
EVEX_W_0F10_P_3_M_1, EVEX_W_0F11_P_0, EVEX_W_0F11_P_1_M_0,
EVEX_W_0F11_P_1_M_1, EVEX_W_0F11_P_2, EVEX_W_0F11_P_3_M_0,
EVEX_W_0F11_P_3_M_1, EVEX_W_0F12_P_0_M_0, EVEX_W_0F12_P_0_M_1,
EVEX_W_0F12_P_1, EVEX_W_0F12_P_2, EVEX_W_0F12_P_3, EVEX_W_0F13_P_0,
EVEX_W_0F13_P_2, EVEX_W_0F14_P_0, EVEX_W_0F14_P_2, EVEX_W_0F15_P_0,
EVEX_W_0F15_P_2, EVEX_W_0F16_P_0_M_0, EVEX_W_0F16_P_0_M_1,
EVEX_W_0F16_P_1, EVEX_W_0F16_P_2, EVEX_W_0F17_P_0, EVEX_W_0F17_P_2,
EVEX_W_0F28_P_0, EVEX_W_0F28_P_2, EVEX_W_0F29_P_0, EVEX_W_0F29_P_2,
EVEX_W_0F2A_P_1, EVEX_W_0F2A_P_3, EVEX_W_0F2B_P_0, EVEX_W_0F2B_P_2,
EVEX_W_0F2E_P_0, EVEX_W_0F2E_P_2, EVEX_W_0F2F_P_0, EVEX_W_0F2F_P_2,
EVEX_W_0F51_P_0, EVEX_W_0F51_P_1, EVEX_W_0F51_P_2, EVEX_W_0F51_P_3,
EVEX_W_0F58_P_0, EVEX_W_0F58_P_1, EVEX_W_0F58_P_2, EVEX_W_0F58_P_3,
EVEX_W_0F59_P_0, EVEX_W_0F59_P_1, EVEX_W_0F59_P_2, EVEX_W_0F59_P_3,
EVEX_W_0F5A_P_0, EVEX_W_0F5A_P_1, EVEX_W_0F5A_P_2, EVEX_W_0F5A_P_3,
EVEX_W_0F5B_P_0, EVEX_W_0F5B_P_1, EVEX_W_0F5B_P_2, EVEX_W_0F5C_P_0,
EVEX_W_0F5C_P_1, EVEX_W_0F5C_P_2, EVEX_W_0F5C_P_3, EVEX_W_0F5D_P_0,
EVEX_W_0F5D_P_1, EVEX_W_0F5D_P_2, EVEX_W_0F5D_P_3, EVEX_W_0F5E_P_0,
EVEX_W_0F5E_P_1, EVEX_W_0F5E_P_2, EVEX_W_0F5E_P_3, EVEX_W_0F5F_P_0,
EVEX_W_0F5F_P_1, EVEX_W_0F5F_P_2, EVEX_W_0F5F_P_3, EVEX_W_0F62_P_2,
EVEX_W_0F66_P_2, EVEX_W_0F6A_P_2, EVEX_W_0F6C_P_2, EVEX_W_0F6D_P_2,
EVEX_W_0F6E_P_2, EVEX_W_0F6F_P_1, EVEX_W_0F6F_P_2, EVEX_W_0F70_P_2,
EVEX_W_0F72_R_2_P_2, EVEX_W_0F72_R_6_P_2, EVEX_W_0F73_R_2_P_2,
EVEX_W_0F73_R_6_P_2, EVEX_W_0F76_P_2, EVEX_W_0F78_P_0,
EVEX_W_0F79_P_0, EVEX_W_0F7A_P_1, EVEX_W_0F7A_P_3, EVEX_W_0F7B_P_1,
EVEX_W_0F7B_P_3, EVEX_W_0F7E_P_1, EVEX_W_0F7E_P_2, EVEX_W_0F7F_P_1,
EVEX_W_0F7F_P_2, EVEX_W_0FC2_P_0, EVEX_W_0FC2_P_1, EVEX_W_0FC2_P_2,
EVEX_W_0FC2_P_3, EVEX_W_0FC6_P_0, EVEX_W_0FC6_P_2, EVEX_W_0FD2_P_2,
EVEX_W_0FD3_P_2, EVEX_W_0FD4_P_2, EVEX_W_0FD6_P_2, EVEX_W_0FE6_P_1,
EVEX_W_0FE6_P_2, EVEX_W_0FE6_P_3, EVEX_W_0FE7_P_2, EVEX_W_0FF2_P_2,
EVEX_W_0FF3_P_2, EVEX_W_0FF4_P_2, EVEX_W_0FFA_P_2, EVEX_W_0FFB_P_2,
EVEX_W_0FFE_P_2, EVEX_W_0F380C_P_2, EVEX_W_0F380D_P_2,
EVEX_W_0F3811_P_1, EVEX_W_0F3812_P_1, EVEX_W_0F3813_P_1,
EVEX_W_0F3813_P_2, EVEX_W_0F3814_P_1, EVEX_W_0F3815_P_1,
EVEX_W_0F3818_P_2, EVEX_W_0F3819_P_2, EVEX_W_0F381A_P_2,
EVEX_W_0F381B_P_2, EVEX_W_0F381E_P_2, EVEX_W_0F381F_P_2,
EVEX_W_0F3821_P_1, EVEX_W_0F3822_P_1, EVEX_W_0F3823_P_1,
EVEX_W_0F3824_P_1, EVEX_W_0F3825_P_1, EVEX_W_0F3825_P_2,
EVEX_W_0F3828_P_2, EVEX_W_0F3829_P_2, EVEX_W_0F382A_P_1,
EVEX_W_0F382A_P_2, EVEX_W_0F3831_P_1, EVEX_W_0F3832_P_1,
EVEX_W_0F3833_P_1, EVEX_W_0F3834_P_1, EVEX_W_0F3835_P_1,
EVEX_W_0F3835_P_2, EVEX_W_0F3837_P_2, EVEX_W_0F383A_P_1,
EVEX_W_0F3840_P_2, EVEX_W_0F3858_P_2, EVEX_W_0F3859_P_2,
EVEX_W_0F385A_P_2, EVEX_W_0F385B_P_2, EVEX_W_0F3891_P_2,
EVEX_W_0F3893_P_2, EVEX_W_0F38A1_P_2, EVEX_W_0F38A3_P_2,
EVEX_W_0F38C7_R_1_P_2, EVEX_W_0F38C7_R_2_P_2, EVEX_W_0F38C7_R_5_P_2,
EVEX_W_0F38C7_R_6_P_2, EVEX_W_0F3A00_P_2, EVEX_W_0F3A01_P_2,
EVEX_W_0F3A04_P_2, EVEX_W_0F3A05_P_2, EVEX_W_0F3A08_P_2,
EVEX_W_0F3A09_P_2, EVEX_W_0F3A0A_P_2, EVEX_W_0F3A0B_P_2,
EVEX_W_0F3A18_P_2, EVEX_W_0F3A19_P_2, EVEX_W_0F3A1A_P_2,
EVEX_W_0F3A1B_P_2, EVEX_W_0F3A1D_P_2, EVEX_W_0F3A21_P_2,
EVEX_W_0F3A23_P_2, EVEX_W_0F3A38_P_2, EVEX_W_0F3A39_P_2,
EVEX_W_0F3A3A_P_2, EVEX_W_0F3A3B_P_2, EVEX_W_0F3A43_P_2.
(struct vex): Add fields evex, r, v, mask_register_specifier,
zeroing, ll, b.
(intel_names_xmm): Add upper 16 registers.
(att_names_xmm): Ditto.
(intel_names_ymm): Ditto.
(att_names_ymm): Ditto.
(names_zmm): New.
(intel_names_zmm): Ditto.
(att_names_zmm): Ditto.
(names_mask): Ditto.
(intel_names_mask): Ditto.
(att_names_mask): Ditto.
(names_rounding): Ditto.
(names_broadcast): Ditto.
(x86_64_table): Add escape to evex-table.
(reg_table): Include reg_table evex-entries from
i386-dis-evex.h. Fix prefetchwt1 instruction.
(prefix_table): Add entries for new instructions.
(vex_table): Ditto.
(vex_len_table): Ditto.
(vex_w_table): Ditto.
(mod_table): Ditto.
(get_valid_dis386): Properly handle new instructions.
(print_insn): Handle zmm and mask registers, print mask operand.
(intel_operand_size): Support EVEX, new modes and sizes.
(OP_E_register): Handle new modes.
(OP_E_memory): Ditto.
(OP_G): Ditto.
(OP_XMM): Ditto.
(OP_EX): Ditto.
(OP_VEX): Ditto.
* i386-gen.c (cpu_flag_init): Update CPU_ANY_SSE_FLAGS and
CPU_ANY_AVX_FLAGS. Add CPU_AVX512F_FLAGS, CPU_AVX512CD_FLAGS,
CPU_AVX512ER_FLAGS and CPU_AVX512PF_FLAGS.
(cpu_flags): Add CpuAVX512F, CpuAVX512CD, CpuAVX512ER,
CpuAVX512PF and CpuVREX.
(operand_type_init): Add OPERAND_TYPE_REGZMM,
OPERAND_TYPE_REGMASK and OPERAND_TYPE_VEC_DISP8.
(opcode_modifiers): Add EVex, Masking, VecESize, Broadcast,
StaticRounding, SAE, Disp8MemShift, NoDefMask.
(operand_types): Add RegZMM, RegMask, Vec_Disp8, Zmmword.
* i386-init.h: Regenerate.
* i386-opc.h (CpuAVX512F): New.
(CpuAVX512CD): New.
(CpuAVX512ER): New.
(CpuAVX512PF): New.
(CpuVREX): New.
(i386_cpu_flags): Add cpuavx512f, cpuavx512cd, cpuavx512er,
cpuavx512pf and cpuvrex fields.
(VecSIB): Add VecSIB512.
(EVex): New.
(Masking): New.
(VecESize): New.
(Broadcast): New.
(StaticRounding): New.
(SAE): New.
(Disp8MemShift): New.
(NoDefMask): New.
(i386_opcode_modifier): Add evex, masking, vecesize, broadcast,
staticrounding, sae, disp8memshift and nodefmask.
(RegZMM): New.
(Zmmword): Ditto.
(Vec_Disp8): Ditto.
(i386_operand_type): Add regzmm, regmask, zmmword and vec_disp8
fields.
(RegVRex): New.
* i386-opc.tbl: Add AVX512 instructions.
* i386-reg.tbl: Add 16 upper XMM and YMM registers, 32 new ZMM
registers, mask registers.
* i386-tbl.h: Regenerate.
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 a5e014a..d12ca22 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")); |