Shrink the size of the x86_insn_info structure, particularly on 64-bit

systems, by combining operand lists into a single array (and trying to find
overlaps where possible).  This saves about 4K even on a 32-bit system.

Also shrink the generated gperf code by outputting the number of info
structures directly rather than using NELEMS().

svn path=/trunk/yasm/; revision=1943
multiarch^2
Peter Johnson 18 years ago
parent cfcad025c5
commit a7f73e3a6c
  1. 48
      modules/arch/x86/gen_x86_insn.py
  2. 49
      modules/arch/x86/x86id.c
  3. 2452
      x86insn_gas.gperf
  4. 1492
      x86insn_nasm.gperf
  5. 1734
      x86insns.c

@ -122,6 +122,22 @@ class Operand(object):
return '|'.join(op_str)
def __eq__(self, other):
return (self.type == other.type and
self.size == other.size and
self.relaxed == other.relaxed and
self.dest == other.dest and
self.tmod == other.tmod and
self.opt == other.opt)
def __ne__(self, other):
return (self.type != other.type or
self.size != other.size or
self.relaxed != other.relaxed or
self.dest != other.dest or
self.tmod != other.tmod or
self.opt != other.opt)
class GroupForm(object):
def __init__(self, **kwargs):
# Parsers
@ -235,11 +251,6 @@ class GroupForm(object):
opcodes_str.extend(["0", "0", "0"])
opcodes_str = "{" + ', '.join(opcodes_str[0:3]) + "}"
operands_str = [str(x) for x in self.operands]
# Ensure operands initializer string is 3 long
operands_str.extend(["0", "0", "0"])
operands_str = "{" + ', '.join(operands_str[0:3]) + "}"
cpus_str = "|".join("CPU_%s" % x for x in sorted(self.cpu))
if len(self.modifiers) > 3:
@ -281,7 +292,7 @@ class GroupForm(object):
opcodes_str,
"%d" % (self.spare or 0),
"%d" % len(self.operands),
operands_str]) + " }"
"%d" % self.all_operands_index]) + " }"
groups = {}
groupnames_ordered = []
@ -395,8 +406,8 @@ class Insn(object):
modifier_str = "0"
return ",\t".join(["%s_insn" % self.groupname,
"(%sUL<<8)|NELEMS(%s_insn)" % \
(modifier_str, self.groupname),
"(%sUL<<8)|%d" % \
(modifier_str, len(groups[self.groupname])),
cpu_str or "CPU_Any",
suffix_str])
@ -491,6 +502,27 @@ def output_nasm_insns(f):
output_insns(f, "nasm", nasm_insns)
def output_groups(f):
# Merge all operand lists into single list
# Sort by number of operands to shorten output
all_operands = []
for form in sorted((form for g in groups.itervalues() for form in g),
key=lambda x:len(x.operands), reverse=True):
num_operands = len(form.operands)
for i in xrange(len(all_operands)):
if all_operands[i:i+num_operands] == form.operands:
form.all_operands_index = i
break
else:
form.all_operands_index = len(all_operands)
all_operands.extend(form.operands)
# Output operands list
print >>f, "static const unsigned long insn_operands[] = {"
print >>f, " ",
print >>f, ",\n ".join(str(x) for x in all_operands)
print >>f, "};\n"
# Output groups
seen = set()
for name in groupnames_ordered:
if name in seen:

@ -270,10 +270,12 @@ typedef struct x86_insn_info {
unsigned char spare;
/* The number of operands this form of the instruction takes */
unsigned char num_operands;
unsigned int num_operands:4;
/* The types of each operand, see above */
unsigned long operands[3];
/* The index into the insn_operands array which contains the type of each
* operand, see above
*/
unsigned int operands_index:12;
} x86_insn_info;
typedef struct x86_id_insn {
@ -320,18 +322,14 @@ static const yasm_bytecode_callback x86_id_insn_callback = {
/* Empty instruction */
static const x86_insn_info empty_insn[] = {
{ CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, {0, 0, 0} }
{ CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0 }
};
/* Placeholder for instructions invalid in 64-bit mode */
static const x86_insn_info not64_insn[] = {
{ CPU_Not64, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, {0, 0, 0} }
{ CPU_Not64, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0 }
};
static const unsigned long insertq_4operands[] =
{OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA,
OPT_Imm|OPS_8|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm};
#include "x86insns.c"
static void
@ -446,7 +444,7 @@ x86_finalize_jmp(yasm_bytecode *bc, yasm_bytecode *prev_bc,
jmp->target.jump_target = 1;
/* See if the user explicitly specified short/near/far. */
switch ((int)(jinfo->operands[0] & OPTM_MASK)) {
switch ((int)(insn_operands[jinfo->operands_index+0] & OPTM_MASK)) {
case OPTM_Short:
jmp->op_sel = JMP_SHORT_FORCED;
break;
@ -459,9 +457,10 @@ x86_finalize_jmp(yasm_bytecode *bc, yasm_bytecode *prev_bc,
/* Check for address size setting in second operand, if present */
if (jinfo->num_operands > 1 &&
(jinfo->operands[1] & OPA_MASK) == OPA_AdSizeR)
(insn_operands[jinfo->operands_index+1] & OPA_MASK) == OPA_AdSizeR)
jmp->common.addrsize = (unsigned char)
size_lookup[(jinfo->operands[1] & OPS_MASK)>>OPS_SHIFT];
size_lookup[(insn_operands[jinfo->operands_index+1]
& OPS_MASK)>>OPS_SHIFT];
/* Check for address size override */
if (jinfo->modifiers & MOD_AdSizeR)
@ -488,13 +487,13 @@ x86_finalize_jmp(yasm_bytecode *bc, yasm_bytecode *prev_bc,
if (info->num_operands == 0)
continue;
if ((info->operands[0] & OPA_MASK) != OPA_JmpRel)
if ((insn_operands[info->operands_index+0] & OPA_MASK) != OPA_JmpRel)
continue;
if (info->opersize != jmp->common.opersize)
continue;
switch ((int)(info->operands[0] & OPTM_MASK)) {
switch ((int)(insn_operands[info->operands_index+0] & OPTM_MASK)) {
case OPTM_Short:
x86_finalize_opcode(&jmp->shortop, info);
if (info->modifiers & MOD_Op0Add)
@ -547,7 +546,7 @@ x86_find_match(x86_id_insn *id_insn, yasm_insn_operand **ops,
*/
for (; num_info>0 && !found; num_info--, info++) {
yasm_insn_operand *op, **use_ops;
const unsigned long *info_ops = info->operands;
const unsigned long *info_ops = &insn_operands[info->operands_index];
unsigned long icpu;
unsigned int size;
int mismatch = 0;
@ -593,10 +592,6 @@ x86_find_match(x86_id_insn *id_insn, yasm_insn_operand **ops,
break;
}
/* 4-operand special case for insertq */
if (info->num_operands > 3)
info_ops = insertq_4operands;
/* Match each operand type and size */
for (i = 0, op = use_ops[0]; op && i<info->num_operands && !mismatch;
op = use_ops[++i]) {
@ -969,11 +964,9 @@ x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
yasm_insn_finalize(&id_insn->insn);
/* Build local array of operands from list, since we know we have a max
* of 3 operands.
* of 4 operands.
*/
if (id_insn->insn.num_operands == 4 && info == insertq_insn)
;
else if (id_insn->insn.num_operands > 3) {
if (id_insn->insn.num_operands > 4) {
yasm_error_set(YASM_ERROR_TYPE, N_("too many operands"));
return;
}
@ -999,7 +992,7 @@ x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
* operands and adjust for dereferences / lack thereof.
*/
if (id_insn->parser == X86_PARSER_GAS
&& (info->operands[0] & OPA_MASK) == OPA_JmpRel) {
&& (insn_operands[info->operands_index+0] & OPA_MASK) == OPA_JmpRel) {
for (i = 0, op = ops[0]; op; op = ops[++i]) {
if (!op->deref && (op->type == YASM_INSN__OPERAND_REG
|| (op->type == YASM_INSN__OPERAND_MEMORY
@ -1032,7 +1025,7 @@ x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
}
if (id_insn->insn.num_operands > 0) {
switch (info->operands[0] & OPA_MASK) {
switch (insn_operands[info->operands_index+0] & OPA_MASK) {
case OPA_JmpRel:
/* Shortcut to JmpRel */
x86_finalize_jmp(bc, prev_bc, info);
@ -1114,17 +1107,13 @@ x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
/* Go through operands and assign */
if (id_insn->insn.num_operands > 0) {
yasm_insn_operand **use_ops = ops;
const unsigned long *info_ops = info->operands;
const unsigned long *info_ops = &insn_operands[info->operands_index];
/* Use reversed operands in GAS mode if not otherwise specified */
if (id_insn->parser == X86_PARSER_GAS
&& !(info->modifiers & MOD_GasNoRev))
use_ops = rev_ops;
/* 4-operand special case for insertq */
if (info->num_operands > 3)
info_ops = insertq_4operands;
for (i = 0, op = use_ops[0]; op && i<info->num_operands;
op = use_ops[++i]) {
switch ((int)(info_ops[i] & OPA_MASK)) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save