#include "xed-decode.h"
#include "xed-error-enum.h"
#include "xed-decoded-inst.h"
#include "xed-operand-storage.h"
#include "xed-tables-extern.h"
#include "xed-internal-header.h"
#include "xed-isa-set.h"
#include "xed-ild-private.h"
#include "xed3-static-decode.h"
#include "xed3-dynamic-decode.h"
#include "xed3-dynamic-part1-capture.h"
#include "xed-chip-features.h"
#include "xed-chip-features-private.h"
#include "xed-chip-modes.h"
#include "xed-reg-class.h"
#if defined(XED_AVX)
static xed_uint_t reg_id_avx2(xed_reg_enum_t r) {
xed_reg_class_enum_t reg_class = xed_reg_class(r);
if (reg_class == XED_REG_CLASS_YMM)
return r - XED_REG_YMM0;
return r - XED_REG_XMM0;
}
static void check_avx2_gathers(xed_decoded_inst_t* xds) {
xed_uint_t indx_id = reg_id_avx2(xed3_operand_get_index(xds));
xed_uint_t dest_id = reg_id_avx2(xed3_operand_get_reg0(xds));
xed_uint_t mask_id = reg_id_avx2(xed3_operand_get_reg1(xds));
if (indx_id == mask_id ||
indx_id == dest_id ||
mask_id == dest_id )
{
xed3_operand_set_error(xds,XED_ERROR_GATHER_REGS);
}
}
# if defined(XED_SUPPORTS_AVX512)
static xed_uint_t reg_id_avx512(xed_reg_enum_t r) {
xed_reg_class_enum_t reg_class = xed_reg_class(r);
if (reg_class == XED_REG_CLASS_ZMM)
return r - XED_REG_ZMM0;
if (reg_class == XED_REG_CLASS_YMM)
return r - XED_REG_YMM0;
return r - XED_REG_XMM0;
}
static void check_avx512_gathers(xed_decoded_inst_t* xds) {
xed_uint_t indx_id = reg_id_avx512(xed3_operand_get_index(xds));
xed_uint_t dest_id = reg_id_avx512(xed3_operand_get_reg0(xds));
if (indx_id == dest_id)
xed3_operand_set_error(xds,XED_ERROR_GATHER_REGS);
}
# endif
#endif
#if defined(XED_ATTRIBUTE_NO_SRC_DEST_MATCH_DEFINED)
static void check_src2_dest_match(xed_decoded_inst_t* xds) {
xed_reg_enum_t srcx;
xed_reg_enum_t dest = xed3_operand_get_reg0(xds);
xed_reg_enum_t srcy = xed3_operand_get_reg2(xds);
if (xed_decoded_inst_get_attribute(xds, XED_ATTRIBUTE_MASKOP_EVEX))
srcx = xed3_operand_get_reg3(xds);
else
srcx = xed3_operand_get_reg1(xds);
if (dest == srcx || dest == srcy)
xed3_operand_set_error(xds,XED_ERROR_BAD_REG_MATCH);
}
#endif
#if defined(XED_ATTRIBUTE_NO_SRC_DEST_MATCH_DEFINED)
static XED_INLINE void check_all_regs_match(xed_decoded_inst_t* xds) {
xed_reg_enum_t reg1;
xed_reg_enum_t reg0 = xed3_operand_get_reg0(xds);
xed_reg_enum_t reg2 = xed3_operand_get_reg2(xds);
if (xed_decoded_inst_get_attribute(xds, XED_ATTRIBUTE_MASKOP_EVEX))
reg1 = xed3_operand_get_reg3(xds);
else
reg1 = xed3_operand_get_reg1(xds);
if (reg0 == reg1 || reg1 == reg2 || reg0 == reg2)
xed3_operand_set_error(xds,XED_ERROR_BAD_REG_MATCH);
}
#endif
static XED_INLINE void
xed_decode_finalize_operand_storage_fields(xed_decoded_inst_t* xds)
{
if ( xed3_operand_get_lock(xds) &&
!xed_decoded_inst_get_attribute(xds,XED_ATTRIBUTE_LOCKED)) {
xed3_operand_set_error(xds,XED_ERROR_BAD_LOCK_PREFIX);
return;
}
#if 0#endif
#if defined(XED_ATTRIBUTE_NO_SRC_DEST_MATCH_DEFINED)
if (xed_decoded_inst_get_attribute(xds, XED_ATTRIBUTE_NO_SRC_DEST_MATCH)) {
check_src2_dest_match(xds);
}
#endif
#if defined(XED_ATTRIBUTE_NO_REG_MATCH_DEFINED)
if (xed_decoded_inst_get_attribute(xds, XED_ATTRIBUTE_NO_REG_MATCH)) {
check_all_regs_match(xds);
}
#endif
#if defined(XED_AVX)
if (xed_decoded_inst_get_attribute(xds, XED_ATTRIBUTE_GATHER))
{
if (xed_decoded_inst_get_extension(xds) == XED_EXTENSION_AVX2GATHER)
check_avx2_gathers(xds);
# if defined(XED_SUPPORTS_AVX512)
else if (xed_decoded_inst_get_attribute(xds, XED_ATTRIBUTE_MASKOP_EVEX))
check_avx512_gathers(xds);
# endif }
#endif
#if defined(XED_MPX)
if (xed_decoded_inst_get_attribute(xds, XED_ATTRIBUTE_NO_RIP_REL))
if (xed3_operand_get_rm(xds) == 5 && xed3_operand_get_mod(xds) == 0)
if (xed3_operand_get_mode(xds)==2) xed3_operand_set_error(xds,XED_ERROR_GENERAL_ERROR);
#endif
}
xed_error_enum_t
xed_decode_with_features(xed_decoded_inst_t* xedd,
const xed_uint8_t* itext,
const unsigned int bytes,
xed_chip_features_t* features)
{
xed_error_enum_t error;
unsigned int tbytes = bytes;
xed_chip_enum_t chip = xed_decoded_inst_get_input_chip(xedd);
set_chip_modes(xedd, chip, features);
xedd->_byte_array._dec = itext;
if (tbytes > XED_MAX_INSTRUCTION_BYTES)
tbytes = XED_MAX_INSTRUCTION_BYTES;
xed3_operand_set_max_bytes(xedd, tbytes);
xed_instruction_length_decode(xedd);
if (xed3_operand_get_error(xedd))
return xed3_operand_get_error(xedd);
xed3_dynamic_decode_part1(xedd);
if (xed3_operand_get_error(xedd))
return xed3_operand_get_error(xedd);
xed3_static_decode(xedd);
if (xed_decoded_inst_get_iform_enum(xedd) == XED_IFORM_INVALID)
return XED_ERROR_GENERAL_ERROR;
xed3_dynamic_decode_part2(xedd);
if (xed3_operand_get_error(xedd))
return xed3_operand_get_error(xedd);
xed3_decode_operands(xedd);
if (xed3_operand_get_error(xedd))
return xed3_operand_get_error(xedd);
xed_decode_finalize_operand_storage_fields(xedd);
error = xed3_operand_get_error(xedd);
if (error == XED_ERROR_NONE) {
if (chip != XED_CHIP_INVALID) {
if (!xed_decoded_inst_valid_for_chip(xedd, chip)) {
return XED_ERROR_INVALID_FOR_CHIP;
}
#if defined(XED_APX)
if (!chip_supports_apx(xedd) && xed_classify_apx(xedd)){
return XED_ERROR_INVALID_FOR_CHIP;
}
#endif
}
if (features) {
const xed_isa_set_enum_t isa_set = xed_decoded_inst_get_isa_set(xedd);
if (!xed_test_chip_features(features, isa_set)) {
return XED_ERROR_INVALID_FOR_CHIP;
}
}
}
return error;
}
xed_error_enum_t
xed_decode(xed_decoded_inst_t* xedd,
const xed_uint8_t* itext,
const unsigned int bytes)
{
return xed_decode_with_features(xedd, itext, bytes, 0);
}