Index: third_party/yasm/patched-yasm/modules/arch/x86/x86id.c |
=================================================================== |
--- third_party/yasm/patched-yasm/modules/arch/x86/x86id.c (revision 71129) |
+++ third_party/yasm/patched-yasm/modules/arch/x86/x86id.c (working copy) |
@@ -26,7 +26,7 @@ |
*/ |
#include <ctype.h> |
#include <util.h> |
-RCSID("$Id: x86id.c 2130 2008-10-07 05:38:11Z peter $"); |
+RCSID("$Id: x86id.c 2279 2010-01-19 07:57:43Z peter $"); |
#include <libyasm.h> |
#include <libyasm/phash.h> |
@@ -53,21 +53,18 @@ |
/* GAS suffix flags for instructions */ |
enum x86_gas_suffix_flags { |
- NONE = 0, |
- SUF_B = 1<<0, |
- SUF_W = 1<<1, |
- SUF_L = 1<<2, |
- SUF_Q = 1<<3, |
- SUF_S = 1<<4, |
- SUF_MASK = SUF_B|SUF_W|SUF_L|SUF_Q|SUF_S, |
+ SUF_Z = 1<<0, /* no suffix */ |
+ SUF_B = 1<<1, |
+ SUF_W = 1<<2, |
+ SUF_L = 1<<3, |
+ SUF_Q = 1<<4, |
+ SUF_S = 1<<5, |
+ SUF_MASK = SUF_Z|SUF_B|SUF_W|SUF_L|SUF_Q|SUF_S, |
/* Flags only used in x86_insn_info */ |
- GAS_ONLY = 1<<5, /* Only available in GAS mode */ |
- GAS_ILLEGAL = 1<<6, /* Illegal in GAS mode */ |
- GAS_NO_REV = 1<<7, /* Don't reverse operands in GAS mode */ |
- |
- /* Flags only used in insnprefix_parse_data */ |
- WEAK = 1<<5 /* Relaxed operand mode for GAS */ |
+ GAS_ONLY = 1<<6, /* Only available in GAS mode */ |
+ GAS_ILLEGAL = 1<<7, /* Illegal in GAS mode */ |
+ GAS_NO_REV = 1<<8 /* Don't reverse operands in GAS mode */ |
}; |
/* Miscellaneous flag tests for instructions */ |
@@ -114,9 +111,7 @@ |
*/ |
OPT_MemrAX = 25, |
/* EAX memory operand only (EA) [special case for SVM skinit opcode] */ |
- OPT_MemEAX = 26, |
- /* SIMDReg with value equal to operand 0 SIMDReg */ |
- OPT_SIMDRegMatch0 = 27 |
+ OPT_MemEAX = 26 |
}; |
enum x86_operand_size { |
@@ -164,18 +159,17 @@ |
OPA_JmpFar = 10, |
/* ea operand only sets address size (no actual ea field) */ |
OPA_AdSizeEA = 11, |
- OPA_DREX = 12, /* operand data goes into DREX "dest" field */ |
- OPA_VEX = 13, /* operand data goes into VEX "vvvv" field */ |
- /* operand data goes into BOTH VEX "vvvv" field and ea field */ |
- OPA_EAVEX = 14, |
- /* operand data goes into BOTH VEX "vvvv" field and spare field */ |
- OPA_SpareVEX = 15, |
+ OPA_VEX = 12, /* operand data goes into VEX/XOP "vvvv" field */ |
+ /* operand data goes into BOTH VEX/XOP "vvvv" field and ea field */ |
+ OPA_EAVEX = 13, |
+ /* operand data goes into BOTH VEX/XOP "vvvv" field and spare field */ |
+ OPA_SpareVEX = 14, |
/* operand data goes into upper 4 bits of immediate byte (VEX is4 field) */ |
- OPA_VEXImmSrc = 16, |
+ OPA_VEXImmSrc = 15, |
/* operand data goes into bottom 4 bits of immediate byte |
* (currently only VEX imz2 field) |
*/ |
- OPA_VEXImm = 17 |
+ OPA_VEXImm = 16 |
}; |
enum x86_operand_post_action { |
@@ -236,10 +230,10 @@ |
typedef struct x86_insn_info { |
/* GAS suffix flags */ |
- unsigned int gas_flags:8; /* Enabled for these GAS suffixes */ |
+ unsigned int gas_flags:9; /* Enabled for these GAS suffixes */ |
- /* Tests against BITS==64 and AVX */ |
- unsigned int misc_flags:6; |
+ /* Tests against BITS==64, AVX, and XOP */ |
+ unsigned int misc_flags:5; |
/* The CPU feature flags needed to execute this instruction. This is OR'ed |
* with arch-specific data[2]. This combined value is compared with |
@@ -277,17 +271,11 @@ |
* 01: 66 |
* 10: F3 |
* 11: F2 |
+ * 0x80 - 0x8F indicate a XOP prefix, with the four LSBs holding "WLpp": |
+ * same meanings as VEX prefix. |
*/ |
unsigned char special_prefix; |
- /* The DREX base byte value (almost). The only bit kept from this |
- * value is the OC0 bit (0x08). The MSB (0x80) of this value indicates |
- * if the DREX byte needs to be present in the instruction. |
- */ |
-#define NEED_DREX_MASK 0x80 |
-#define DREX_OC0_MASK 0x08 |
- unsigned char drex_oc0; |
- |
/* The length of the basic opcode */ |
unsigned char opcode_len; |
@@ -327,10 +315,10 @@ |
unsigned int mode_bits:8; |
/* Suffix flags */ |
- unsigned int suffix:8; |
+ unsigned int suffix:9; |
/* Tests against BITS==64 and AVX */ |
- unsigned int misc_flags:6; |
+ unsigned int misc_flags:5; |
/* Parser enabled at the time of parsing the instruction */ |
unsigned int parser:2; |
@@ -394,9 +382,11 @@ |
const x86_insn_info *info) |
{ |
x86_id_insn *id_insn = (x86_id_insn *)bc->contents; |
+ unsigned char *mod_data = id_insn->mod_data; |
unsigned int mode_bits = id_insn->mode_bits; |
x86_jmpfar *jmpfar; |
yasm_insn_operand *op; |
+ unsigned int i; |
jmpfar = yasm_xmalloc(sizeof(x86_jmpfar)); |
x86_finalize_common(&jmpfar->common, info, mode_bits); |
@@ -422,9 +412,44 @@ |
|| yasm_value_finalize_expr(&jmpfar->segment, e, prev_bc, 16)) |
yasm_error_set(YASM_ERROR_TOO_COMPLEX, |
N_("jump target expression too complex")); |
+ } else if (yasm_insn_op_next(op)) { |
+ /* Two operand form (gas) */ |
+ yasm_insn_operand *op2 = yasm_insn_op_next(op); |
+ if (yasm_value_finalize_expr(&jmpfar->segment, op->data.val, prev_bc, |
+ 16)) |
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX, |
+ N_("jump target segment too complex")); |
+ if (yasm_value_finalize_expr(&jmpfar->offset, op2->data.val, prev_bc, |
+ 0)) |
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX, |
+ N_("jump target offset too complex")); |
+ if (op2->size == OPS_BITS) |
+ jmpfar->common.opersize = (unsigned char)mode_bits; |
} else |
yasm_internal_error(N_("didn't get FAR expression in jmpfar")); |
+ /* Apply modifiers */ |
+ for (i=0; i<NELEMS(info->modifiers); i++) { |
+ switch (info->modifiers[i]) { |
+ case MOD_Gap: |
+ break; |
+ case MOD_Op0Add: |
+ jmpfar->opcode.opcode[0] += mod_data[i]; |
+ break; |
+ case MOD_Op1Add: |
+ jmpfar->opcode.opcode[1] += mod_data[i]; |
+ break; |
+ case MOD_Op2Add: |
+ jmpfar->opcode.opcode[2] += mod_data[i]; |
+ break; |
+ case MOD_Op1AddSp: |
+ jmpfar->opcode.opcode[1] += mod_data[i]<<3; |
+ break; |
+ default: |
+ break; |
+ } |
+ } |
+ |
yasm_x86__bc_apply_prefixes((x86_common *)jmpfar, NULL, |
info->def_opersize_64, |
id_insn->insn.num_prefixes, |
@@ -614,7 +639,7 @@ |
continue; |
/* Match suffix (if required) */ |
- if (suffix != 0 && suffix != WEAK |
+ if (id_insn->parser == X86_PARSER_GAS |
&& ((suffix & SUF_MASK) & (gas_flags & SUF_MASK)) == 0) |
continue; |
@@ -667,7 +692,6 @@ |
if (op->type == YASM_INSN__OPERAND_MEMORY) |
break; |
/*@fallthrough@*/ |
- case OPT_SIMDRegMatch0: |
case OPT_SIMDReg: |
if (op->type != YASM_INSN__OPERAND_REG) |
mismatch = 1; |
@@ -682,9 +706,6 @@ |
break; |
} |
} |
- if (!mismatch && info_ops[i].type == OPT_SIMDRegMatch0 && |
- bypass != 7 && op->data.reg != use_ops[0]->data.reg) |
- mismatch = 1; |
break; |
case OPT_SegReg: |
if (op->type != YASM_INSN__OPERAND_SEGREG) |
@@ -839,7 +860,7 @@ |
/* Check operand size */ |
size = size_lookup[info_ops[i].size]; |
- if (suffix != 0) { |
+ if (id_insn->parser == X86_PARSER_GAS) { |
/* Require relaxed operands for GAS mode (don't allow |
* per-operand sizing). |
*/ |
@@ -881,7 +902,8 @@ |
break; |
/* Check for 64-bit effective address size in NASM mode */ |
- if (suffix == 0 && op->type == YASM_INSN__OPERAND_MEMORY) { |
+ if (id_insn->parser != X86_PARSER_GAS && |
+ op->type == YASM_INSN__OPERAND_MEMORY) { |
if (info_ops[i].eas64) { |
if (op->data.ea->disp.size != 64) |
mismatch = 1; |
@@ -1005,8 +1027,6 @@ |
unsigned char im_len; |
unsigned char im_sign; |
unsigned char spare; |
- unsigned char drex; |
- unsigned char *pdrex; |
unsigned char vexdata, vexreg; |
unsigned int i; |
unsigned int size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 256, 0}; |
@@ -1099,19 +1119,18 @@ |
insn->def_opersize_64 = info->def_opersize_64; |
insn->special_prefix = info->special_prefix; |
spare = info->spare; |
- drex = info->drex_oc0 & DREX_OC0_MASK; |
vexdata = 0; |
vexreg = 0; |
im_len = 0; |
im_sign = 0; |
insn->postop = X86_POSTOP_NONE; |
insn->rex = 0; |
- pdrex = (info->drex_oc0 & NEED_DREX_MASK) ? &drex : NULL; |
- /* Move VEX data (stored in special prefix) to separate location to |
+ /* Move VEX/XOP data (stored in special prefix) to separate location to |
* allow overriding of special prefix by modifiers. |
*/ |
- if ((insn->special_prefix & 0xF0) == 0xC0) { |
+ if ((insn->special_prefix & 0xF0) == 0xC0 || |
+ (insn->special_prefix & 0xF0) == 0x80) { |
vexdata = insn->special_prefix; |
insn->special_prefix = 0; |
} |
@@ -1199,7 +1218,7 @@ |
insn->x86_ea = |
yasm_x86__ea_create_reg(insn->x86_ea, |
(unsigned long)op->data.reg, &insn->rex, |
- pdrex, mode_bits); |
+ mode_bits); |
break; |
case YASM_INSN__OPERAND_SEGREG: |
yasm_internal_error( |
@@ -1236,8 +1255,7 @@ |
yasm_internal_error(N_("invalid operand conversion")); |
insn->x86_ea = |
yasm_x86__ea_create_reg(insn->x86_ea, |
- (unsigned long)op->data.reg, &insn->rex, pdrex, |
- mode_bits); |
+ (unsigned long)op->data.reg, &insn->rex, mode_bits); |
vexreg = op->data.reg & 0xF; |
break; |
case OPA_Imm: |
@@ -1265,8 +1283,8 @@ |
if (op->type == YASM_INSN__OPERAND_SEGREG) |
spare = (unsigned char)(op->data.reg&7); |
else if (op->type == YASM_INSN__OPERAND_REG) { |
- if (yasm_x86__set_rex_from_reg(&insn->rex, pdrex, |
- &spare, op->data.reg, mode_bits, X86_REX_R)) |
+ if (yasm_x86__set_rex_from_reg(&insn->rex, &spare, |
+ op->data.reg, mode_bits, X86_REX_R)) |
return; |
} else |
yasm_internal_error(N_("invalid operand conversion")); |
@@ -1274,16 +1292,16 @@ |
case OPA_SpareVEX: |
if (op->type != YASM_INSN__OPERAND_REG) |
yasm_internal_error(N_("invalid operand conversion")); |
- if (yasm_x86__set_rex_from_reg(&insn->rex, pdrex, |
- &spare, op->data.reg, mode_bits, X86_REX_R)) |
+ if (yasm_x86__set_rex_from_reg(&insn->rex, &spare, |
+ op->data.reg, mode_bits, X86_REX_R)) |
return; |
vexreg = op->data.reg & 0xF; |
break; |
case OPA_Op0Add: |
if (op->type == YASM_INSN__OPERAND_REG) { |
unsigned char opadd; |
- if (yasm_x86__set_rex_from_reg(&insn->rex, pdrex, |
- &opadd, op->data.reg, mode_bits, X86_REX_B)) |
+ if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd, |
+ op->data.reg, mode_bits, X86_REX_B)) |
return; |
insn->opcode.opcode[0] += opadd; |
} else |
@@ -1292,8 +1310,8 @@ |
case OPA_Op1Add: |
if (op->type == YASM_INSN__OPERAND_REG) { |
unsigned char opadd; |
- if (yasm_x86__set_rex_from_reg(&insn->rex, pdrex, |
- &opadd, op->data.reg, mode_bits, X86_REX_B)) |
+ if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd, |
+ op->data.reg, mode_bits, X86_REX_B)) |
return; |
insn->opcode.opcode[1] += opadd; |
} else |
@@ -1304,10 +1322,10 @@ |
insn->x86_ea = |
yasm_x86__ea_create_reg(insn->x86_ea, |
(unsigned long)op->data.reg, &insn->rex, |
- pdrex, mode_bits); |
+ mode_bits); |
if (!insn->x86_ea || |
- yasm_x86__set_rex_from_reg(&insn->rex, pdrex, |
- &spare, op->data.reg, mode_bits, X86_REX_R)) { |
+ yasm_x86__set_rex_from_reg(&insn->rex, &spare, |
+ op->data.reg, mode_bits, X86_REX_R)) { |
if (insn->x86_ea) |
yasm_xfree(insn->x86_ea); |
yasm_xfree(insn); |
@@ -1340,13 +1358,6 @@ |
yasm_x86__ea_destroy(op->data.ea); |
break; |
} |
- case OPA_DREX: |
- if (op->type == YASM_INSN__OPERAND_REG) { |
- drex &= 0x0F; |
- drex |= (op->data.reg << 4) & 0xF0; |
- } else |
- yasm_internal_error(N_("invalid operand conversion")); |
- break; |
case OPA_VEX: |
if (op->type != YASM_INSN__OPERAND_REG) |
yasm_internal_error(N_("invalid operand conversion")); |
@@ -1441,9 +1452,7 @@ |
} |
if (insn->x86_ea) { |
- yasm_x86__ea_init(insn->x86_ea, spare, drex, |
- (unsigned int)(info->drex_oc0 & NEED_DREX_MASK), |
- prev_bc); |
+ yasm_x86__ea_init(insn->x86_ea, spare, prev_bc); |
for (i=0; i<id_insn->insn.num_segregs; i++) |
yasm_ea_set_segreg(&insn->x86_ea->ea, id_insn->insn.segregs[i]); |
} else if (id_insn->insn.num_segregs > 0 && insn->special_prefix == 0) { |
@@ -1513,8 +1522,7 @@ |
* opcode 0 being a mov instruction! |
*/ |
insn->x86_ea = yasm_x86__ea_create_reg(insn->x86_ea, |
- (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp, |
- NULL, 64); |
+ (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp, 64); |
/* Make the imm32s form permanent. */ |
insn->opcode.opcode[0] = insn->opcode.opcode[1]; |
@@ -1526,31 +1534,46 @@ |
break; |
} |
- /* Convert to VEX prefixes if requested. |
- * To save space in the insn structure, the VEX prefix is written into |
+ /* Convert to VEX/XOP prefixes if requested. |
+ * To save space in the insn structure, the VEX/XOP prefix is written into |
* special_prefix and the first 2 bytes of the instruction are set to |
- * the second two VEX bytes. During calc_len() it may be shortened to |
- * one VEX byte (this can only be done after knowledge of REX value). |
+ * the second two VEX/XOP bytes. During calc_len() it may be shortened to |
+ * one VEX byte (this can only be done after knowledge of REX value); this |
+ * further optimization is not possible for XOP. |
*/ |
if (vexdata) { |
+ int xop = ((vexdata & 0xF0) == 0x80); |
unsigned char vex1 = 0xE0; /* R=X=B=1, mmmmm=0 */ |
unsigned char vex2; |
- /* Look at the first bytes of the opcode to see what leading bytes |
- * to encode in the VEX mmmmm field. Leave R=X=B=1 for now. |
- */ |
- if (insn->opcode.opcode[0] != 0x0F) |
- yasm_internal_error(N_("first opcode byte of VEX must be 0x0F")); |
- if (insn->opcode.opcode[1] == 0x38) |
- vex1 |= 0x02; /* implied 0x0F 0x38 */ |
- else if (insn->opcode.opcode[1] == 0x3A) |
- vex1 |= 0x03; /* implied 0x0F 0x3A */ |
- else { |
- /* Originally a 0F-only opcode; move opcode byte back one position |
- * to make room for VEX prefix. |
+ if (xop) { |
+ /* Look at the first bytes of the opcode for the XOP mmmmm field. |
+ * Leave R=X=B=1 for now. |
*/ |
+ if (insn->opcode.opcode[0] != 0x08 && |
+ insn->opcode.opcode[0] != 0x09) |
+ yasm_internal_error(N_("first opcode byte of XOP must be 0x08 or 0x09")); |
+ vex1 |= insn->opcode.opcode[0]; |
+ /* Move opcode byte back one byte to make room for XOP prefix. */ |
insn->opcode.opcode[2] = insn->opcode.opcode[1]; |
- vex1 |= 0x01; /* implied 0x0F */ |
+ } else { |
+ /* Look at the first bytes of the opcode to see what leading bytes |
+ * to encode in the VEX mmmmm field. Leave R=X=B=1 for now. |
+ */ |
+ if (insn->opcode.opcode[0] != 0x0F) |
+ yasm_internal_error(N_("first opcode byte of VEX must be 0x0F")); |
+ |
+ if (insn->opcode.opcode[1] == 0x38) |
+ vex1 |= 0x02; /* implied 0x0F 0x38 */ |
+ else if (insn->opcode.opcode[1] == 0x3A) |
+ vex1 |= 0x03; /* implied 0x0F 0x3A */ |
+ else { |
+ /* Originally a 0F-only opcode; move opcode byte back one |
+ * position to make room for VEX prefix. |
+ */ |
+ insn->opcode.opcode[2] = insn->opcode.opcode[1]; |
+ vex1 |= 0x01; /* implied 0x0F */ |
+ } |
} |
/* Check for update of special prefix by modifiers */ |
@@ -1580,7 +1603,7 @@ |
(vexdata & 0x7)); /* Lpp */ |
/* Save to special_prefix and opcode */ |
- insn->special_prefix = 0xC4; /* VEX prefix */ |
+ insn->special_prefix = xop ? 0x8F : 0xC4; /* VEX/XOP prefix */ |
insn->opcode.opcode[0] = vex1; |
insn->opcode.opcode[1] = vex2; |
insn->opcode.len = 3; /* two prefix bytes and 1 opcode byte */ |
@@ -1730,7 +1753,7 @@ |
lcaseid[i] = tolower(id[i]); |
lcaseid[id_len] = '\0'; |
- switch (arch_x86->parser) { |
+ switch (PARSER(arch_x86)) { |
case X86_PARSER_NASM: |
pdata = insnprefix_nasm_find(lcaseid, id_len); |
break; |
@@ -1770,7 +1793,8 @@ |
id_insn->mode_bits = arch_x86->mode_bits; |
id_insn->suffix = 0; |
id_insn->misc_flags = 0; |
- id_insn->parser = arch_x86->parser; |
+ id_insn->parser = PARSER(arch_x86); |
+ |
id_insn->force_strict = arch_x86->force_strict != 0; |
id_insn->default_rel = arch_x86->default_rel != 0; |
*bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); |
@@ -1801,7 +1825,7 @@ |
id_insn->mode_bits = arch_x86->mode_bits; |
id_insn->suffix = pdata->flags; |
id_insn->misc_flags = pdata->misc_flags; |
- id_insn->parser = arch_x86->parser; |
+ id_insn->parser = PARSER(arch_x86); |
id_insn->force_strict = arch_x86->force_strict != 0; |
id_insn->default_rel = arch_x86->default_rel != 0; |
*bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); |
@@ -1862,9 +1886,9 @@ |
id_insn->mod_data[2] = 0; |
id_insn->num_info = NELEMS(empty_insn); |
id_insn->mode_bits = arch_x86->mode_bits; |
- id_insn->suffix = 0; |
+ id_insn->suffix = (PARSER(arch_x86) == X86_PARSER_GAS) ? SUF_Z : 0; |
id_insn->misc_flags = 0; |
- id_insn->parser = arch_x86->parser; |
+ id_insn->parser = PARSER(arch_x86); |
id_insn->force_strict = arch_x86->force_strict != 0; |
id_insn->default_rel = arch_x86->default_rel != 0; |