Create new working branch for new (Robertson 1977) optimizer.

This doesn't really work yet, which is why it's on a branch!

svn path=/branches/new-optimizer/; revision=1269
0.6.0
Peter Johnson 20 years ago
parent be801e73db
commit 77a535f673
  1. 13
      frontends/yasm/yasm.c
  2. 1
      libyasm.h
  3. 7
      libyasm/Makefile.inc
  4. 8
      libyasm/arch.h
  5. 17
      libyasm/bc-int.h
  6. 268
      libyasm/bytecode.c
  7. 50
      libyasm/bytecode.h
  8. 5
      libyasm/module.h
  9. 10
      libyasm/module.in
  10. 54
      libyasm/optimizer.h
  11. 136
      libyasm/section.c
  12. 20
      libyasm/section.h
  13. 2
      modules/Makefile.inc
  14. 2
      modules/arch/Makefile.inc
  15. 3
      modules/arch/lc3b/lc3barch.c
  16. 3
      modules/arch/x86/x86arch.c
  17. 7
      modules/arch/x86/x86arch.h
  18. 511
      modules/arch/x86/x86bc.c
  19. 112
      modules/arch/x86/x86expr.c
  20. 25
      modules/arch/x86/x86id.re
  21. 2
      modules/dbgfmts/Makefile.inc
  22. 5
      modules/optimizers/Makefile.inc
  23. 5
      modules/optimizers/basic/Makefile.inc
  24. 234
      modules/optimizers/basic/basic-optimizer.c

@ -58,8 +58,6 @@ static int special_options = 0;
/*@null@*/ /*@dependent@*/ static yasm_objfmt *cur_objfmt = NULL;
/*@null@*/ /*@dependent@*/ static const yasm_objfmt_module *
cur_objfmt_module = NULL;
/*@null@*/ /*@dependent@*/ static const yasm_optimizer_module *
cur_optimizer_module = NULL;
/*@null@*/ /*@dependent@*/ static yasm_dbgfmt *cur_dbgfmt = NULL;
/*@null@*/ /*@dependent@*/ static const yasm_dbgfmt_module *
cur_dbgfmt_module = NULL;
@ -478,15 +476,6 @@ main(int argc, char *argv[])
return EXIT_FAILURE;
}
/* Set basic as the optimizer (TODO: user choice) */
cur_optimizer_module = yasm_load_optimizer("basic");
if (!cur_optimizer_module) {
print_error(_("%s: could not load default %s"), _("FATAL"),
_("optimizer"));
return EXIT_FAILURE;
}
/* If list file enabled, make sure we have a list format loaded. */
if (list_filename) {
/* If not already specified, default to nasm as the list format. */
@ -643,7 +632,7 @@ main(int argc, char *argv[])
}
/* Optimize */
cur_optimizer_module->optimize(object);
yasm_object_optimize(object, cur_arch);
if (yasm_get_num_errors(warning_error) > 0) {
yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error,

@ -69,7 +69,6 @@
#include <libyasm/dbgfmt.h>
#include <libyasm/objfmt.h>
#include <libyasm/listfmt.h>
#include <libyasm/optimizer.h>
#include <libyasm/parser.h>
#include <libyasm/preproc.h>

@ -20,6 +20,9 @@ libyasm_a_SOURCES += libyasm/xstrdup.c
libyasm_a_SOURCES += libyasm/strcasecmp.c
libyasm_a_SOURCES += libyasm/mergesort.c
libyasm_a_SOURCES += libyasm/strsep.c
libyasm_a_SOURCES += libyasm/qq.c
libyasm_a_SOURCES += libyasm/stack.c
libyasm_a_SOURCES += libyasm/interval_tree.c
libyasm_a_SOURCES += module.c
module.c: $(top_srcdir)/libyasm/module.in genmodule$(EXEEXT) Makefile
@ -56,7 +59,6 @@ modinclude_HEADERS += libyasm/arch.h
modinclude_HEADERS += libyasm/dbgfmt.h
modinclude_HEADERS += libyasm/objfmt.h
modinclude_HEADERS += libyasm/listfmt.h
modinclude_HEADERS += libyasm/optimizer.h
modinclude_HEADERS += libyasm/parser.h
modinclude_HEADERS += libyasm/preproc.h
modinclude_HEADERS += libyasm/intnum.h
@ -67,6 +69,9 @@ modinclude_HEADERS += libyasm/valparam.h
modinclude_HEADERS += libyasm/compat-queue.h
modinclude_HEADERS += libyasm/assocdat.h
modinclude_HEADERS += libyasm/module.h
modinclude_HEADERS += libyasm/qq.h
modinclude_HEADERS += libyasm/stack.h
modinclude_HEADERS += libyasm/interval_tree.h
EXTRA_DIST += libyasm/tests/Makefile.inc

@ -247,6 +247,12 @@ typedef struct yasm_arch_module {
* #yasm_arch.
*/
unsigned int wordsize;
/** Long/short jump size descriminator. Number of bytes (+/-) a short
* jump can range over. Used to size optimization FIFOs, so don't
* make this extremely large (e.g. >1000).
*/
const unsigned long jmpsize_threshold;
} yasm_arch_module;
#ifdef YASM_LIB_INTERNAL
@ -598,6 +604,8 @@ yasm_effaddr *yasm_arch_ea_create(yasm_arch *arch, /*@keep@*/ yasm_expr *e);
(((yasm_arch_base *)arch)->module->keyword)
#define yasm_arch_wordsize(arch) \
(((yasm_arch_base *)arch)->module->wordsize)
#define yasm_arch_jmpsize_threshold(arch) \
(((yasm_arch_base *)arch)->module->jmpsize_threshold)
#define yasm_arch_create(module, machine, parser, error) \
module->create(machine, parser, error)

@ -59,8 +59,10 @@ typedef struct yasm_bytecode_callback {
void (*destroy) (/*@only@*/ void *contents);
void (*print) (const void *contents, FILE *f, int indent_level);
void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc);
yasm_bc_resolve_flags (*resolve)
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
int (*calc_len) (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
void (*set_long) (yasm_bytecode *bc);
int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -84,9 +86,10 @@ struct yasm_bytecode {
unsigned long line;
/* other assembler state info */
unsigned long offset; /* 0 if unknown */
unsigned long offset; /* ~0UL if unknown */
unsigned long bc_index;
/* storage for optimizer flags */
/* optimizer info */
unsigned long opt_flags;
/* NULL-terminated array of labels that point to this bytecode (as the
@ -122,6 +125,12 @@ void yasm_bc_transform(yasm_bytecode *bc,
*/
void yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc);
/** Common bytecode callback set_long function, for where the bytecode is
* always short (calc_len always returns 0, never 1). Causes an internal
* error if called.
*/
void yasm_bc_set_long_common(yasm_bytecode *bc);
#define yasm_bc__next(x) STAILQ_NEXT(x, link)
#endif

@ -117,24 +117,30 @@ typedef struct bytecode_insn {
static void bc_data_destroy(void *contents);
static void bc_data_print(const void *contents, FILE *f, int indent_level);
static yasm_bc_resolve_flags bc_data_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_data_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_reserve_destroy(void *contents);
static void bc_reserve_print(const void *contents, FILE *f, int indent_level);
static yasm_bc_resolve_flags bc_reserve_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_reserve_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_incbin_destroy(void *contents);
static void bc_incbin_print(const void *contents, FILE *f, int indent_level);
static yasm_bc_resolve_flags bc_incbin_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_incbin_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -142,16 +148,20 @@ static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
static void bc_align_destroy(void *contents);
static void bc_align_print(const void *contents, FILE *f, int indent_level);
static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
static yasm_bc_resolve_flags bc_align_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_align_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_org_destroy(void *contents);
static void bc_org_print(const void *contents, FILE *f, int indent_level);
static yasm_bc_resolve_flags bc_org_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_org_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -159,8 +169,10 @@ static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
static void bc_insn_destroy(void *contents);
static void bc_insn_print(const void *contents, FILE *f, int indent_level);
static void bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
static yasm_bc_resolve_flags bc_insn_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_insn_calc_len
(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
/*@out@*/ long *pos_thres);
static int bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -171,7 +183,8 @@ static const yasm_bytecode_callback bc_data_callback = {
bc_data_destroy,
bc_data_print,
yasm_bc_finalize_common,
bc_data_resolve,
bc_data_calc_len,
yasm_bc_set_long_common,
bc_data_tobytes
};
@ -179,7 +192,8 @@ static const yasm_bytecode_callback bc_reserve_callback = {
bc_reserve_destroy,
bc_reserve_print,
yasm_bc_finalize_common,
bc_reserve_resolve,
bc_reserve_calc_len,
yasm_bc_set_long_common,
bc_reserve_tobytes
};
@ -187,7 +201,8 @@ static const yasm_bytecode_callback bc_incbin_callback = {
bc_incbin_destroy,
bc_incbin_print,
yasm_bc_finalize_common,
bc_incbin_resolve,
bc_incbin_calc_len,
yasm_bc_set_long_common,
bc_incbin_tobytes
};
@ -195,7 +210,8 @@ static const yasm_bytecode_callback bc_align_callback = {
bc_align_destroy,
bc_align_print,
bc_align_finalize,
bc_align_resolve,
bc_align_calc_len,
yasm_bc_set_long_common,
bc_align_tobytes
};
@ -203,7 +219,8 @@ static const yasm_bytecode_callback bc_org_callback = {
bc_org_destroy,
bc_org_print,
yasm_bc_finalize_common,
bc_org_resolve,
bc_org_calc_len,
yasm_bc_set_long_common,
bc_org_tobytes
};
@ -211,7 +228,8 @@ static const yasm_bytecode_callback bc_insn_callback = {
bc_insn_destroy,
bc_insn_print,
bc_insn_finalize,
bc_insn_resolve,
bc_insn_calc_len,
yasm_bc_set_long_common,
bc_insn_tobytes
};
@ -327,6 +345,12 @@ yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc)
{
}
void
yasm_bc_set_long_common(yasm_bytecode *bc)
{
yasm_internal_error(N_("bytecode does not have a long format"));
}
void
yasm_bc_transform(yasm_bytecode *bc, const yasm_bytecode_callback *callback,
void *contents)
@ -352,7 +376,7 @@ yasm_bc_create_common(const yasm_bytecode_callback *callback, void *contents,
bc->line = line;
bc->offset = 0;
bc->offset = ~0UL;
bc->opt_flags = 0;
@ -382,9 +406,9 @@ bc_data_print(const void *contents, FILE *f, int indent_level)
yasm_dvs_print(&bc_data->datahead, f, indent_level+2);
}
static yasm_bc_resolve_flags
bc_data_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
bc_data_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
{
bytecode_data *bc_data = (bytecode_data *)bc->contents;
yasm_dataval *dv;
@ -407,7 +431,7 @@ bc_data_resolve(yasm_bytecode *bc, int save,
}
}
return YASM_BC_RESOLVE_MIN_LEN;
return 0;
}
static int
@ -481,40 +505,30 @@ bc_reserve_print(const void *contents, FILE *f, int indent_level)
(unsigned int)reserve->itemsize);
}
static yasm_bc_resolve_flags
bc_reserve_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
bc_reserve_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
{
bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
/*@null@*/ yasm_expr *temp;
yasm_expr **tempp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
if (save) {
temp = NULL;
tempp = &reserve->numitems;
} else {
temp = yasm_expr_copy(reserve->numitems);
assert(temp != NULL);
tempp = &temp;
}
num = yasm_expr_get_intnum(tempp, calc_bc_dist);
num = yasm_expr_get_intnum(&reserve->numitems, NULL);
if (!num) {
/* For reserve, just say non-constant quantity instead of allowing
* the circular reference error to filter through.
*/
if (temp && yasm_expr__contains(temp, YASM_EXPR_FLOAT))
/* Check for use of floats first. */
if (reserve->numitems &&
yasm_expr__contains(reserve->numitems, YASM_EXPR_FLOAT)) {
yasm__error(bc->line,
N_("expression must not contain floating point value"));
else
yasm__error(bc->line,
N_("attempt to reserve non-constant quantity of space"));
retval = YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
} else
bc->len += yasm_intnum_get_uint(num)*reserve->itemsize;
yasm_expr_destroy(temp);
return retval;
return -1;
}
/* FIXME: Non-constant currently not allowed. */
yasm__error(bc->line,
N_("attempt to reserve non-constant quantity of space"));
return -1;
}
bc->len += yasm_intnum_get_uint(num)*reserve->itemsize;
return 0;
}
static int
@ -571,51 +585,39 @@ bc_incbin_print(const void *contents, FILE *f, int indent_level)
fprintf(f, "\n");
}
static yasm_bc_resolve_flags
bc_incbin_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
bc_incbin_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
{
bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
FILE *f;
/*@null@*/ yasm_expr *temp;
yasm_expr **tempp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen;
/* Try to convert start to integer value */
if (incbin->start) {
if (save) {
temp = NULL;
tempp = &incbin->start;
} else {
temp = yasm_expr_copy(incbin->start);
assert(temp != NULL);
tempp = &temp;
}
num = yasm_expr_get_intnum(tempp, calc_bc_dist);
num = yasm_expr_get_intnum(&incbin->start, NULL);
if (num)
start = yasm_intnum_get_uint(num);
yasm_expr_destroy(temp);
if (!num)
return YASM_BC_RESOLVE_UNKNOWN_LEN;
if (!num) {
/* FIXME */
yasm__error(bc->line,
N_("incbin does not yet understand non-constant"));
return -1;
}
}
/* Try to convert maxlen to integer value */
if (incbin->maxlen) {
if (save) {
temp = NULL;
tempp = &incbin->maxlen;
} else {
temp = yasm_expr_copy(incbin->maxlen);
assert(temp != NULL);
tempp = &temp;
}
num = yasm_expr_get_intnum(tempp, calc_bc_dist);
num = yasm_expr_get_intnum(&incbin->maxlen, NULL);
if (num)
maxlen = yasm_intnum_get_uint(num);
yasm_expr_destroy(temp);
if (!num)
return YASM_BC_RESOLVE_UNKNOWN_LEN;
if (!num) {
/* FIXME */
yasm__error(bc->line,
N_("incbin does not yet understand non-constant"));
return -1;
}
}
/* FIXME: Search include path for filename. Save full path back into
@ -627,29 +629,29 @@ bc_incbin_resolve(yasm_bytecode *bc, int save,
if (!f) {
yasm__error(bc->line, N_("`incbin': unable to open file `%s'"),
incbin->filename);
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
return -1;
}
if (fseek(f, 0L, SEEK_END) < 0) {
yasm__error(bc->line, N_("`incbin': unable to seek on file `%s'"),
incbin->filename);
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
return -1;
}
flen = (unsigned long)ftell(f);
fclose(f);
/* Compute length of incbin from start, maxlen, and len */
if (start > flen) {
yasm__warning(YASM_WARN_GENERAL, bc->line,
N_("`incbin': start past end of file `%s'"),
incbin->filename);
start = flen;
yasm__error(bc->line, N_("`incbin': start past end of file `%s'"),
incbin->filename);
return -1;
}
flen -= start;
if (incbin->maxlen)
if (maxlen < flen)
flen = maxlen;
bc->len += flen;
return YASM_BC_RESOLVE_MIN_LEN;
return 0;
}
static int
@ -751,10 +753,12 @@ bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
yasm__error(bc->line, N_("align maximum skip must be a constant"));
}
static yasm_bc_resolve_flags
bc_align_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
bc_align_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
{
yasm_internal_error(N_("align not yet implemented"));
/*
bytecode_align *align = (bytecode_align *)bc->contents;
unsigned long end;
unsigned long boundary =
@ -778,6 +782,8 @@ bc_align_resolve(yasm_bytecode *bc, int save,
bc->len = 0;
}
return YASM_BC_RESOLVE_MIN_LEN;
*/
return 0;
}
static int
@ -873,10 +879,12 @@ bc_org_print(const void *contents, FILE *f, int indent_level)
fprintf(f, "%*sStart=%lu\n", indent_level, "", org->start);
}
static yasm_bc_resolve_flags
bc_org_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
bc_org_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
{
yasm_internal_error(N_("org not yet implemented"));
#if 0
bytecode_org *org = (bytecode_org *)bc->contents;
/* Check for overrun */
@ -888,6 +896,8 @@ bc_org_resolve(yasm_bytecode *bc, int save,
/* Generate space to start offset */
bc->len = org->start - bc->offset;
return YASM_BC_RESOLVE_MIN_LEN;
#endif
return 0;
}
static int
@ -977,13 +987,13 @@ bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
insn->num_segregs, insn->segregs);
}
static yasm_bc_resolve_flags
bc_insn_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
{
yasm_internal_error(N_("bc_insn_resolve() is not implemented"));
yasm_internal_error(N_("bc_insn_calc_len() is not implemented"));
/*@notreached@*/
return YASM_BC_RESOLVE_ERROR;
return 0;
}
static int
@ -1146,52 +1156,64 @@ yasm_common_calc_bc_dist(/*@null@*/ yasm_bytecode *precbc1,
}
}
yasm_bc_resolve_flags
yasm_bc_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
int
yasm_bc_calc_len(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
{
yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
/*@null@*/ yasm_expr *temp;
yasm_expr **tempp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
int retval = 0;
bc->len = 0; /* start at 0 */
bc->len = 0;
*critical = NULL;
*neg_thres = 0;
*pos_thres = 0;
*long_len = 0;
if (!bc->callback)
yasm_internal_error(N_("got empty bytecode in bc_resolve"));
else
retval = bc->callback->resolve(bc, save, calc_bc_dist);
retval = bc->callback->calc_len(bc, long_len, critical, neg_thres,
pos_thres);
/* Multiply len by number of multiples */
/* Check for multiples */
if (bc->multiple) {
if (save) {
temp = NULL;
tempp = &bc->multiple;
} else {
temp = yasm_expr_copy(bc->multiple);
assert(temp != NULL);
tempp = &temp;
}
num = yasm_expr_get_intnum(tempp, calc_bc_dist);
/*@null@*/ yasm_expr *temp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
num = yasm_expr_get_intnum(&bc->multiple, NULL);
if (!num) {
retval = YASM_BC_RESOLVE_UNKNOWN_LEN;
if (temp && yasm_expr__contains(temp, YASM_EXPR_FLOAT)) {
if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) {
yasm__error(bc->line,
N_("expression must not contain floating point value"));
retval |= YASM_BC_RESOLVE_ERROR;
retval = -1;
} else {
/* FIXME: Non-constant currently not allowed. */
yasm__error(bc->line,
N_("attempt to use non-constant multiple"));
retval = -1;
}
} else
bc->len *= yasm_intnum_get_uint(num);
yasm_expr_destroy(temp);
}
}
/* If we got an error somewhere along the line, clear out any calc len */
if (retval & YASM_BC_RESOLVE_UNKNOWN_LEN)
if (retval < 0) {
bc->len = 0;
*long_len = 0;
}
return retval;
}
void
yasm_bc_set_long(yasm_bytecode *bc, unsigned long long_len)
{
if (!bc->callback)
yasm_internal_error(N_("got empty bytecode in bc_set_long"));
else
bc->callback->set_long(bc);
bc->len = long_len;
}
/*@null@*/ /*@only@*/ unsigned char *
yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
/*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,

@ -47,14 +47,6 @@ typedef struct yasm_datavalhead yasm_datavalhead;
/*@reldef@*/ STAILQ_HEAD(yasm_datavalhead, yasm_dataval);
#endif
/** Return value flags for yasm_bc_resolve(). */
typedef enum {
YASM_BC_RESOLVE_NONE = 0, /**< Ok, but length is not minimum. */
YASM_BC_RESOLVE_ERROR = 1<<0, /**< Error found, output. */
YASM_BC_RESOLVE_MIN_LEN = 1<<1, /**< Length is minimum possible. */
YASM_BC_RESOLVE_UNKNOWN_LEN = 1<<2 /**< Length indeterminate. */
} yasm_bc_resolve_flags;
/** Create an immediate value from an unsigned integer.
* \param int_val unsigned integer
* \param line virtual line (from yasm_linemap)
@ -260,24 +252,32 @@ void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
/*@null@*/ yasm_intnum *yasm_common_calc_bc_dist
(/*@null@*/ yasm_bytecode *precbc1, /*@null@*/ yasm_bytecode *precbc2);
/** Resolve labels in a bytecode, and calculate its length.
* Tries to minimize the length as much as possible.
* \note Sometimes it's impossible to determine if a length is the minimum
* possible. In this case, this function returns that the length is NOT
* the minimum.
/** Resolve EQUs in a bytecode and calculate its possible lengths.
* Tries to minimize the length as much as possible for short_len.
* The short length is set in the bytecode, and the long length is returned
* in long_len (if applicable).
* \param bc bytecode
* \param long_len longer length (returned). 0 returned if no longer
* length is available (must be short).
* \param critical critical expression if bytecode could be longer
* (returned). NULL returned if no critical expression.
* \param neg_thres negative threshold for long/short decision (returned)
* \param pos_thres positive threshold for long/short decision (returned)
* \return 0 if length is minimum (no way it can ever increase), negative if
* there was an error recognized (and output) during execution, and
* positive if the length may increase based on the critical expr.
* \note May store to bytecode updated expressions and the short length.
*/
int yasm_bc_calc_len(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
/*@out@*/ /*@only@*/ yasm_expr **critical,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
/** Mark a bytecode as long. Has no effect if the bytecode does not have
* a long form.
* \param bc bytecode
* \param save when zero, this function does \em not modify bc other
* than the length/size values (i.e. it doesn't keep the
* values returned by calc_bc_dist except temporarily to
* try to minimize the length); when nonzero, all fields
* in bc may be modified by this function
* \param calc_bc_dist function used to determine bytecode distance
* \return Flags indicating whether the length is the minimum possible,
* indeterminate, and if there was an error recognized (and output)
* during execution.
*/
yasm_bc_resolve_flags yasm_bc_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist);
* \param long_len long length (as returned by yasm_bc_calc_len)
*/
void yasm_bc_set_long(yasm_bytecode *bc, unsigned long long_len);
/** Convert a bytecode into its byte representation.
* \param bc bytecode

@ -32,7 +32,6 @@ typedef enum yasm_module_type {
YASM_MODULE_DBGFMT,
YASM_MODULE_OBJFMT,
YASM_MODULE_LISTFMT,
YASM_MODULE_OPTIMIZER,
YASM_MODULE_PARSER,
YASM_MODULE_PREPROC
} yasm_module_type;
@ -48,8 +47,6 @@ typedef enum yasm_module_type {
yasm_load_module(YASM_MODULE_OBJFMT, keyword)
#define yasm_load_listfmt(keyword) \
yasm_load_module(YASM_MODULE_LISTFMT, keyword)
#define yasm_load_optimizer(keyword) \
yasm_load_module(YASM_MODULE_OPTIMIZER, keyword)
#define yasm_load_parser(keyword) \
yasm_load_module(YASM_MODULE_PARSER, keyword)
#define yasm_load_preproc(keyword) \
@ -67,8 +64,6 @@ void yasm_list_modules
yasm_list_modules(YASM_MODULE_OBJFMT, func)
#define yasm_list_listfmt(func) \
yasm_list_modules(YASM_MODULE_LISTFMT, func)
#define yasm_list_optimizer(func) \
yasm_list_modules(YASM_MODULE_OPTIMIZER, func)
#define yasm_list_parser(func) \
yasm_list_modules(YASM_MODULE_PARSER, func)
#define yasm_list_preproc(func) \

@ -53,10 +53,6 @@ static module listfmt_modules[] = {
MODULES_listfmt_
};
static module optimizer_modules[] = {
MODULES_optimizer_
};
static module parser_modules[] = {
MODULES_parser_
};
@ -73,7 +69,6 @@ static struct {
{dbgfmt_modules, sizeof(dbgfmt_modules)/sizeof(module)},
{objfmt_modules, sizeof(objfmt_modules)/sizeof(module)},
{listfmt_modules, sizeof(listfmt_modules)/sizeof(module)},
{optimizer_modules, sizeof(optimizer_modules)/sizeof(module)},
{parser_modules, sizeof(parser_modules)/sizeof(module)},
{preproc_modules, sizeof(preproc_modules)/sizeof(module)},
};
@ -105,7 +100,6 @@ yasm_list_modules(yasm_module_type type,
yasm_dbgfmt_module *dbgfmt;
yasm_objfmt_module *objfmt;
yasm_listfmt_module *listfmt;
yasm_optimizer_module *optimizer;
yasm_parser_module *parser;
yasm_preproc_module *preproc;
@ -128,10 +122,6 @@ yasm_list_modules(yasm_module_type type,
listfmt = modules[i].data;
printfunc(listfmt->name, listfmt->keyword);
break;
case YASM_MODULE_OPTIMIZER:
optimizer = modules[i].data;
printfunc(optimizer->name, optimizer->keyword);
break;
case YASM_MODULE_PARSER:
parser = modules[i].data;
printfunc(parser->name, parser->keyword);

@ -1,54 +0,0 @@
/**
* \file libyasm/optimizer.h
* \brief YASM optimizer module interface.
*
* \rcs
* $Id$
* \endrcs
*
* \license
* Copyright (C) 2001 Peter Johnson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* \endlicense
*/
#ifndef YASM_OPTIMIZER_H
#define YASM_OPTIMIZER_H
/** YASM optimizer module interface. */
typedef struct yasm_optimizer_module {
/** One-line description of the optimizer */
const char *name;
/** Keyword used to select optimizer on the command line */
const char *keyword;
/** Optimize an object. Takes the unoptimized object and optimizes it.
* If successful, the object is ready for output to an object file.
* \param object object
* \note Optimization failures are indicated by this function calling
* yasm__error_at(); see errwarn.h for details.
*/
void (*optimize) (yasm_object *object);
} yasm_optimizer_module;
#endif

@ -1,7 +1,7 @@
/*
* Section utility functions
*
* Copyright (C) 2001 Peter Johnson
* Copyright (C) 2001-2005 Peter Johnson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -31,6 +31,7 @@
#include "coretype.h"
#include "valparam.h"
#include "assocdat.h"
#include "qq.h"
#include "linemgr.h"
#include "errwarn.h"
@ -39,6 +40,7 @@
#include "symrec.h"
#include "bytecode.h"
#include "arch.h"
#include "section.h"
#include "objfmt.h"
@ -211,18 +213,6 @@ yasm_section_is_absolute(yasm_section *sect)
return (sect->type == SECTION_ABSOLUTE);
}
unsigned long
yasm_section_get_opt_flags(const yasm_section *sect)
{
return sect->opt_flags;
}
void
yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags)
{
sect->opt_flags = opt_flags;
}
yasm_object *
yasm_section_get_object(const yasm_section *sect)
{
@ -283,18 +273,22 @@ void
yasm_object_finalize(yasm_object *object)
{
yasm_section *sect;
unsigned long bc_index = 0;
/* Iterate through sections */
STAILQ_FOREACH(sect, &object->sections, link) {
yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prev;
cur->bc_index = bc_index++;
/* Skip our locally created empty bytecode first. */
prev = cur;
cur = STAILQ_NEXT(cur, link);
/* Iterate through the remainder, if any. */
while (cur) {
cur->bc_index = bc_index++;
/* Finalize */
yasm_bc_finalize(cur, prev);
prev = cur;
@ -508,3 +502,119 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level,
}
}
}
/*
* Robertson (1977) optimizer
* Based on the algorithm given in:
* MRC Technical Summary Report # 1779
* CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES
* Edward L. Robertson
* Mathematics Research Center
* University of Wisconsin-Madison
* 610 Walnut Street
* Madison, Wisconsin 53706
* August 1977
*
* Key components of algorithm:
* - start assuming all short forms
* - build spans for short->long transition dependencies
* - if a long form is needed, walk the dependencies and update
* Major differences from Robertson's algorithm:
* - detection of cycles
* - any difference of two locations is allowed
*
* Data structures:
* - Interval tree to store spans and associated data
* - Queue Q
*
* Basic algorithm outline:
*
* 1. Initialization:
* a. Number bytecodes sequentially (done in object_finalize by setting
* bc_index values).
* b. First pass through bytecodes assumes minimum length but builds spans
* if necessary. Also avoids building spans for things that are
* considered "certainly long" such as inter-section references or if
* the # of bytecodes spanned is greater than the long threshold
* (basically treating each bytecode as 1 byte in length).
* c. Iterate over spans; if span exceeds long threshold, add BC for that
* span to Q.
* 2. Main loop:
* While Q not empty:
* Mark BC at head of Q long (and remove from Q).
* For each span that contains BC:
* Increase span length by difference between short and long BC length.
* If span exceeds long threshold, add its BC to tail of Q.
* 3. Final pass over bytecodes to generate offsets.
*/
void
yasm_object_optimize(yasm_object *object, yasm_arch *arch)
{
yasm_section *sect;
int saw_error = 0;
/* Step 1b */
STAILQ_FOREACH(sect, &object->sections, link) {
unsigned long i;
yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prev;
/* Skip our locally created empty bytecode first. */
prev = cur;
cur = STAILQ_NEXT(cur, link);
/* Iterate through the remainder, if any. */
while (cur) {
unsigned long long_len;
/*@only@*/ /*@null@*/ yasm_expr *critical;
long neg_thres;
long pos_thres;
int retval;
switch (yasm_bc_calc_len(cur, &long_len, &critical, &neg_thres,
&pos_thres)) {
case -1:
saw_error = 1;
break;
case 0:
/* No special action required */
break;
case 1:
/* Need to build a span */
yasm_bc_set_long(cur, long_len);
yasm_expr_destroy(critical);
break;
default:
yasm_internal_error(N_("bad return value from bc_calc_len"));
}
prev = cur;
cur = STAILQ_NEXT(cur, link);
}
}
if (saw_error)
return;
/* Step 3 */
STAILQ_FOREACH(sect, &object->sections, link) {
unsigned long offset = 0;
yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prev;
/* Skip our locally created empty bytecode first. */
prev = cur;
cur = STAILQ_NEXT(cur, link);
/* Iterate through the remainder, if any. */
while (cur) {
cur->offset = offset;
offset += cur->len;
prev = cur;
cur = STAILQ_NEXT(cur, link);
}
}
}

@ -132,24 +132,20 @@ int yasm_object_sections_traverse
/*@dependent@*/ yasm_linemap *yasm_object_get_linemap
(const yasm_object *object);
/** Optimize an object. Takes the unoptimized object and optimizes it.
* If successful, the object is ready for output to an object file.
* \param object object
* \note Optimization failures are indicated by this function calling
* yasm__error_at(); see errwarn.h for details.
*/
void yasm_object_optimize(yasm_object *object, yasm_arch *arch);
/** Determine if a section is absolute or general.
* \param sect section
* \return Nonzero if section is absolute.
*/
int yasm_section_is_absolute(yasm_section *sect);
/** Get yasm_optimizer-specific flags. For yasm_optimizer use only.
* \param sect section
* \return Optimizer-specific flags.
*/
unsigned long yasm_section_get_opt_flags(const yasm_section *sect);
/** Set yasm_optimizer-specific flags. For yasm_optimizer use only.
* \param sect section
* \param opt_flags optimizer-specific flags.
*/
void yasm_section_set_opt_flags(yasm_section *sect, unsigned long opt_flags);
/** Get object owner of a section.
* \param sect section
* \return Object this section is a part of.

@ -4,13 +4,11 @@ EXTRA_DIST += modules/arch/Makefile.inc
EXTRA_DIST += modules/listfmts/Makefile.inc
EXTRA_DIST += modules/parsers/Makefile.inc
EXTRA_DIST += modules/preprocs/Makefile.inc
EXTRA_DIST += modules/optimizers/Makefile.inc
EXTRA_DIST += modules/objfmts/Makefile.inc
include modules/arch/Makefile.inc
include modules/listfmts/Makefile.inc
include modules/parsers/Makefile.inc
include modules/preprocs/Makefile.inc
include modules/optimizers/Makefile.inc
include modules/dbgfmts/Makefile.inc
include modules/objfmts/Makefile.inc

@ -4,7 +4,7 @@ EXTRA_DIST += modules/arch/x86/Makefile.inc
EXTRA_DIST += modules/arch/lc3b/Makefile.inc
include modules/arch/x86/Makefile.inc
include modules/arch/lc3b/Makefile.inc
#include modules/arch/lc3b/Makefile.inc
dist_man_MANS += yasm_arch.7

@ -188,5 +188,6 @@ yasm_arch_module yasm_lc3b_LTX_arch = {
lc3b_ea_create_expr,
lc3b_machines,
"lc3b",
2
2,
512
};

@ -383,5 +383,6 @@ yasm_arch_module yasm_x86_LTX_arch = {
yasm_x86__ea_create_expr,
x86_machines,
"x86",
2
2,
128
};

@ -187,7 +187,7 @@ typedef struct x86_insn {
/* Shift opcodes have an immediate form and a ,1 form (with no
* immediate). In the parser, we set this and opcode_len=1, but store
* the ,1 version in the second byte of the opcode array. We then
* the non-,1 version in the second byte of the opcode array. We then
* choose between the two versions once we know the actual value of
* imm (because we don't know it in the parser module).
*
@ -199,7 +199,7 @@ typedef struct x86_insn {
/* Instructions that take a sign-extended imm8 as well as imm values
* (eg, the arith instructions and a subset of the imul instructions)
* should set this and put the imm8 form in the second byte of the
* should set this and put the non-imm8 form in the second byte of the
* opcode.
*/
X86_POSTOP_SIGNEXT_IMM8,
@ -261,8 +261,7 @@ int yasm_x86__expr_checkea
unsigned int nosplit, int address16_op, unsigned char *displen,
unsigned char *modrm, unsigned char *v_modrm, unsigned char *n_modrm,
unsigned char *sib, unsigned char *v_sib, unsigned char *n_sib,
unsigned char *pcrel, unsigned char *rex,
yasm_calc_bc_dist_func calc_bc_dist);
unsigned char *pcrel, unsigned char *rex);
void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid,
unsigned long line);

@ -69,16 +69,20 @@ static void x86_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level);
static void x86_bc_insn_destroy(void *contents);
static void x86_bc_insn_print(const void *contents, FILE *f,
int indent_level);
static yasm_bc_resolve_flags x86_bc_insn_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres,
long *pos_thres);
static void x86_bc_insn_set_long(yasm_bytecode *bc);
static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
void *d, yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void x86_bc_jmp_destroy(void *contents);
static void x86_bc_jmp_print(const void *contents, FILE *f, int indent_level);
static yasm_bc_resolve_flags x86_bc_jmp_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int x86_bc_jmp_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres,
long *pos_thres);
static void x86_bc_jmp_set_long(yasm_bytecode *bc);
static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
void *d, yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
@ -86,8 +90,9 @@ static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
static void x86_bc_jmpfar_destroy(void *contents);
static void x86_bc_jmpfar_print(const void *contents, FILE *f,
int indent_level);
static yasm_bc_resolve_flags x86_bc_jmpfar_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres,
long *pos_thres);
static int x86_bc_jmpfar_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
@ -106,7 +111,8 @@ static const yasm_bytecode_callback x86_bc_callback_insn = {
x86_bc_insn_destroy,
x86_bc_insn_print,
yasm_bc_finalize_common,
x86_bc_insn_resolve,
x86_bc_insn_calc_len,
x86_bc_insn_set_long,
x86_bc_insn_tobytes
};
@ -114,7 +120,8 @@ static const yasm_bytecode_callback x86_bc_callback_jmp = {
x86_bc_jmp_destroy,
x86_bc_jmp_print,
yasm_bc_finalize_common,
x86_bc_jmp_resolve,
x86_bc_jmp_calc_len,
x86_bc_jmp_set_long,
x86_bc_jmp_tobytes
};
@ -122,7 +129,8 @@ static const yasm_bytecode_callback x86_bc_callback_jmpfar = {
x86_bc_jmpfar_destroy,
x86_bc_jmpfar_print,
yasm_bc_finalize_common,
x86_bc_jmpfar_resolve,
x86_bc_jmpfar_calc_len,
yasm_bc_set_long_common,
x86_bc_jmpfar_tobytes
};
@ -477,7 +485,7 @@ x86_bc_jmpfar_print(const void *contents, FILE *f, int indent_level)
}
static unsigned int
x86_common_resolve(const x86_common *common)
x86_common_calc_len(const x86_common *common)
{
unsigned int len = 0;
@ -493,36 +501,27 @@ x86_common_resolve(const x86_common *common)
return len;
}
static yasm_bc_resolve_flags
x86_bc_insn_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
{
x86_insn *insn = (x86_insn *)bc->contents;
/*@null@*/ yasm_expr *temp;
x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
yasm_effaddr *ea = &x86_ea->ea;
yasm_immval *imm = insn->imm;
yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
int retval = 0;
int common_len = 0;
if (ea) {
/* Create temp copy of disp, etc. */
x86_effaddr eat = *x86_ea; /* structure copy */
unsigned char displen = ea->len;
if (ea->disp) {
temp = yasm_expr_copy(ea->disp);
assert(temp != NULL);
/* Handle shortmov special-casing */
if (insn->postop == X86_POSTOP_SHORTMOV &&
insn->common.mode_bits == 64 && insn->common.addrsize == 32 &&
!yasm_expr__contains(temp, YASM_EXPR_REG)) {
yasm_x86__ea_set_disponly((yasm_effaddr *)&eat);
if (save) {
/* Make the short form permanent. */
insn->opcode.opcode[0] = insn->opcode.opcode[1];
}
!yasm_expr__contains(ea->disp, YASM_EXPR_REG)) {
yasm_x86__ea_set_disponly((yasm_effaddr *)x86_ea);
/* Make the short form permanent. */
insn->opcode.opcode[0] = insn->opcode.opcode[1];
}
/* Check validity of effective address and calc R/M bits of
@ -530,71 +529,48 @@ x86_bc_insn_resolve(yasm_bytecode *bc, int save,
* of the Mod/RM byte until we know more about the
* displacement.
*/
switch (yasm_x86__expr_checkea(&temp, &insn->common.addrsize,
if (yasm_x86__expr_checkea(&ea->disp, &insn->common.addrsize,
insn->common.mode_bits, ea->nosplit,
insn->postop == X86_POSTOP_ADDRESS16, &displen, &eat.modrm,
&eat.valid_modrm, &eat.need_modrm, &eat.sib,
&eat.valid_sib, &eat.need_sib, &eat.pcrel, &insn->rex,
calc_bc_dist)) {
case 1:
yasm_expr_destroy(temp);
/* failed, don't bother checking rest of insn */
return YASM_BC_RESOLVE_UNKNOWN_LEN|YASM_BC_RESOLVE_ERROR;
case 2:
yasm_expr_destroy(temp);
/* failed, don't bother checking rest of insn */
return YASM_BC_RESOLVE_UNKNOWN_LEN;
default:
yasm_expr_destroy(temp);
/* okay */
break;
}
if (displen != 1) {
/* Fits into a word/dword, or unknown. */
retval = YASM_BC_RESOLVE_NONE; /* may not be smallest size */
/* Handle unknown case, make displen word-sized */
if (displen == 0xff)
displen = (insn->common.addrsize == 16) ? 2U : 4U;
}
insn->postop == X86_POSTOP_ADDRESS16, &ea->len,
&x86_ea->modrm, &x86_ea->valid_modrm, &x86_ea->need_modrm,
&x86_ea->sib, &x86_ea->valid_sib, &x86_ea->need_sib,
&x86_ea->pcrel, &insn->rex))
/* failed, don't bother checking rest of insn */
return -1;
/* Handle address16 postop case */
if (insn->postop == X86_POSTOP_ADDRESS16)
insn->common.addrsize = 0;
/* If we had forced ea->len but had to override, save it now */
if (ea->len != 0 && ea->len != displen)
ea->len = displen;
if (save) {
*x86_ea = eat; /* structure copy */
ea->len = displen;
if (displen == 0 && ea->disp) {
yasm_expr_destroy(ea->disp);
ea->disp = NULL;
}
}
if (ea->len == 0xff) {
/* Handle unknown case, default to byte-sized and set as
* critical expression.
*/
bc->len += 1;
long_len += (insn->common.addrsize == 16) ? 2U : 4U;
*critical = yasm_expr_copy(ea->disp);
*neg_thres = -128;
*pos_thres = 127;
retval = 1;
} else
bc->len += ea->len;
}
/* Compute length of ea and add to total */
bc->len += eat.need_modrm + (eat.need_sib ? 1:0) + displen;
bc->len += (eat.ea.segreg != 0) ? 1 : 0;
common_len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0);
common_len += (x86_ea->ea.segreg != 0) ? 1 : 0;
}
if (imm) {
const yasm_intnum *num;
unsigned int immlen = imm->len;
int immlen = imm->len;
if (imm->val) {
temp = yasm_expr_copy(imm->val);
assert(temp != NULL);
/* TODO: check imm->len vs. sized len from expr? */
/* Handle signext_imm8 postop special-casing */
if (insn->postop == X86_POSTOP_SIGNEXT_IMM8 && temp &&
(num = yasm_expr_get_intnum(&temp, calc_bc_dist))) {
if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
/*@dependent@*/ /*@null@*/ yasm_intnum *num;
num = yasm_expr_get_intnum(&imm->val, NULL);
if (num) {
int val = yasm_intnum_get_int(num);
if (val >= -128 && val <= 127) {
@ -602,212 +578,175 @@ x86_bc_insn_resolve(yasm_bytecode *bc, int save,
* the immediate length to 1.
*/
immlen = 1;
if (save) {
/* Make the byte form permanent. */
insn->opcode.opcode[0] = insn->opcode.opcode[1];
imm->len = 1;
}
} else {
/* We can't use the ,1. */
insn->opcode.opcode[0] = insn->opcode.opcode[1];
}
}
/* Not really necessary, but saves confusion over it. */
if (save)
insn->postop = X86_POSTOP_NONE;
} else {
/* Unknown; default to byte form and set as critical
* expression.
*/
immlen = 1;
long_len += imm->len;
*critical = yasm_expr_copy(imm->val);
*neg_thres = -128;
*pos_thres = 127;
retval = 1;
}
}
/* Handle shift postop special-casing */
if (insn->postop == X86_POSTOP_SHIFT && temp &&
(num = yasm_expr_get_intnum(&temp, calc_bc_dist))) {
if (num && yasm_intnum_get_uint(num) == 1) {
/* We can use the ,1 form: no immediate (set to 0 len) */
immlen = 0;
if (save) {
/* Make the ,1 form permanent. */
insn->opcode.opcode[0] = insn->opcode.opcode[1];
/* Delete imm, as it's not needed. */
if (insn->postop == X86_POSTOP_SHIFT) {
/*@dependent@*/ /*@null@*/ yasm_intnum *num;
num = yasm_expr_get_intnum(&imm->val, NULL);
if (num) {
if (yasm_intnum_get_uint(num) == 1) {
/* We can use the ,1. */
yasm_expr_destroy(imm->val);
yasm_xfree(imm);
insn->imm = (yasm_immval *)NULL;
insn->imm = NULL;
immlen = 0;
} else {
/* We can't use the ,1. */
insn->opcode.opcode[0] = insn->opcode.opcode[1];
}
} else
retval = YASM_BC_RESOLVE_NONE; /* we could still get ,1 */
/* Not really necessary, but saves confusion over it. */
if (save)
insn->postop = X86_POSTOP_NONE;
} else {
/* Unknown; default to ,1 form and set as critical
* expression.
*/
immlen = 0;
long_len += imm->len;
*critical = yasm_expr_copy(imm->val);
*neg_thres = 1;
*pos_thres = 1;
retval = 1;
}
}
yasm_expr_destroy(temp);
}
bc->len += immlen;
common_len += immlen;
}
bc->len += insn->opcode.len;
bc->len += x86_common_resolve(&insn->common);
bc->len += (insn->special_prefix != 0) ? 1:0;
common_len += insn->opcode.len;
common_len += x86_common_calc_len(&insn->common);
common_len += (insn->special_prefix != 0) ? 1:0;
if (insn->rex != 0xff &&
(insn->rex != 0 ||
(insn->common.mode_bits == 64 && insn->common.opersize == 64 &&
insn->def_opersize_64 != 64)))
bc->len++;
common_len++;
bc->len += common_len;
if (retval > 0)
*long_len += common_len;
return retval;
}
static yasm_bc_resolve_flags
x86_bc_jmp_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static void
x86_bc_insn_set_long(yasm_bytecode *bc)
{
x86_jmp *jmp = (x86_jmp *)bc->contents;
yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
x86_insn *insn = (x86_insn *)bc->contents;
/*@null@*/ yasm_expr *temp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
long rel;
x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
yasm_effaddr *ea = &x86_ea->ea;
yasm_immval *imm = insn->imm;
if (ea && ea->disp) {
/* Change displacement length into word-sized */
if (ea->len == 0xff) {
ea->len = (insn->common.addrsize == 16) ? 2U : 4U;
x86_ea->modrm &= ~0300;
x86_ea->modrm |= 0200;
}
}
if (imm && imm->val) {
/* Handle shift postop special-casing */
if (insn->postop == X86_POSTOP_SHIFT) {
/* We can't use the ,1 form. */
insn->opcode.opcode[0] = insn->opcode.opcode[1];
insn->postop = X86_POSTOP_NONE;
}
}
}
static int
x86_bc_jmp_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
{
x86_jmp *jmp = (x86_jmp *)bc->contents;
int retval = 0;
unsigned int common_len;
unsigned char opersize;
x86_jmp_opcode_sel jrtype = JMP_NONE;
/* As opersize may be 0, figure out its "real" value. */
opersize = (jmp->common.opersize == 0) ?
jmp->common.mode_bits : jmp->common.opersize;
/* We only check to see if forced forms are actually legal if we're in
* save mode. Otherwise we assume that they are legal.
*/
switch (jmp->op_sel) {
case JMP_SHORT_FORCED:
/* 1 byte relative displacement */
jrtype = JMP_SHORT;
if (save) {
temp = yasm_expr_copy(jmp->target);
temp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(temp),
yasm_expr_sym(jmp->origin), bc->line);
num = yasm_expr_get_intnum(&temp, calc_bc_dist);
if (!num) {
yasm__error(bc->line,
N_("short jump target external or out of segment"));
yasm_expr_destroy(temp);
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
} else {
rel = yasm_intnum_get_int(num);
rel -= jmp->shortop.len+1;
yasm_expr_destroy(temp);
/* does a short form exist? */
if (jmp->shortop.len == 0) {
yasm__error(bc->line, N_("short jump does not exist"));
return YASM_BC_RESOLVE_ERROR |
YASM_BC_RESOLVE_UNKNOWN_LEN;
}
/* short displacement must fit in -128 <= rel <= +127 */
if (rel < -128 || rel > 127) {
yasm__error(bc->line, N_("short jump out of range"));
return YASM_BC_RESOLVE_ERROR |
YASM_BC_RESOLVE_UNKNOWN_LEN;
}
}
}
break;
case JMP_NEAR_FORCED:
/* 2/4 byte relative displacement (depending on operand size) */
jrtype = JMP_NEAR;
if (save) {
if (jmp->nearop.len == 0) {
yasm__error(bc->line, N_("near jump does not exist"));
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
}
}
break;
default:
temp = yasm_expr_copy(jmp->target);
if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
if (jmp->shortop.len == 0) {
yasm__error(bc->line, N_("short jump does not exist"));
return -1;
}
/* Try to find shortest displacement based on difference between
* target expr value and our (this bytecode's) offset. Note this
* requires offset to be set BEFORE calling calc_len in order for
* this test to be valid.
*/
temp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(temp),
yasm_expr_sym(jmp->origin), bc->line);
num = yasm_expr_get_intnum(&temp, calc_bc_dist);
if (num) {
rel = yasm_intnum_get_int(num);
rel -= jmp->shortop.len+1;
/* short displacement must fit within -128 <= rel <= +127 */
if (jmp->shortop.len != 0 && rel >= -128 && rel <= 127) {
/* It fits into a short displacement. */
jrtype = JMP_SHORT;
} else if (jmp->nearop.len != 0) {
/* Near for now, but could get shorter in the future if
* there's a short form available.
*/
jrtype = JMP_NEAR;
if (jmp->shortop.len != 0)
retval = YASM_BC_RESOLVE_NONE;
} else {
/* Doesn't fit into short, and there's no near opcode.
* Error out if saving, otherwise just make it a short
* (in the hopes that a short might make it possible for
* it to actually be within short range).
*/
if (save) {
yasm__error(bc->line,
N_("short jump out of range (near jump does not exist)"));
return YASM_BC_RESOLVE_ERROR |
YASM_BC_RESOLVE_UNKNOWN_LEN;
}
jrtype = JMP_SHORT;
}
} else {
/* It's unknown. Thus, assume near displacement. If a near
* opcode is not available, use a short opcode instead.
* If we're saving, error if a near opcode is not available.
*/
if (jmp->nearop.len != 0) {
if (jmp->shortop.len != 0)
retval = YASM_BC_RESOLVE_NONE;
jrtype = JMP_NEAR;
} else {
if (save) {
yasm__error(bc->line,
N_("short jump out of range (near jump does not exist)"));
return YASM_BC_RESOLVE_ERROR |
YASM_BC_RESOLVE_UNKNOWN_LEN;
}
jrtype = JMP_SHORT;
}
}
yasm_expr_destroy(temp);
break;
/* We want to be sure to error if we exceed short length, so still
* put it in as a critical expression, but leave the return value as
* 0.
*/
bc->len += jmp->shortop.len + 1;
*critical = yasm_expr_create(YASM_EXPR_SUB,
yasm_expr_expr(yasm_expr_copy(jmp->target)),
yasm_expr_sym(jmp->origin), bc->line);
*neg_thres = -128;
*pos_thres = 127;
} else if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) {
if (jmp->nearop.len == 0) {
yasm__error(bc->line, N_("near jump does not exist"));
return -1;
}
bc->len += jmp->nearop.len;
bc->len += (opersize == 16) ? 2 : 4;
} else {
/* short length goes into bytecode */
retval = 1;
bc->len += jmp->shortop.len + 1;
*long_len += jmp->nearop.len;
*long_len += (opersize == 16) ? 2 : 4;
*critical = yasm_expr_create(YASM_EXPR_SUB,
yasm_expr_expr(yasm_expr_copy(jmp->target)),
yasm_expr_sym(jmp->origin), bc->line);
*neg_thres = -128;
*pos_thres = 127;
}
switch (jrtype) {
case JMP_SHORT:
if (save)
jmp->op_sel = JMP_SHORT;
if (jmp->shortop.len == 0)
return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */
common_len = x86_common_calc_len(&jmp->common);
bc->len += common_len;
if (retval > 0)
*long_len += common_len;
bc->len += jmp->shortop.len + 1;
break;
case JMP_NEAR:
if (save)
jmp->op_sel = JMP_NEAR;
if (jmp->nearop.len == 0)
return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */
return retval;
}
bc->len += jmp->nearop.len;
bc->len += (opersize == 16) ? 2 : 4;
break;
default:
yasm_internal_error(N_("unknown jump type"));
}
bc->len += x86_common_resolve(&jmp->common);
static void
x86_bc_jmp_set_long(yasm_bytecode *bc)
{
x86_jmp *jmp = (x86_jmp *)bc->contents;
return retval;
if (jmp->nearop.len == 0) {
yasm__error(bc->line,
N_("short jump out of range"));
return;
}
jmp->op_sel = JMP_NEAR;
}
static yasm_bc_resolve_flags
x86_bc_jmpfar_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
x86_bc_jmpfar_calc_len(yasm_bytecode *bc, unsigned long *long_len,
yasm_expr **critical, long *neg_thres, long *pos_thres)
{
x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
unsigned char opersize;
@ -818,9 +757,9 @@ x86_bc_jmpfar_resolve(yasm_bytecode *bc, int save,
bc->len += jmpfar->opcode.len;
bc->len += 2; /* segment */
bc->len += (opersize == 16) ? 2 : 4;
bc->len += x86_common_resolve(&jmpfar->common);
bc->len += x86_common_calc_len(&jmpfar->common);
return YASM_BC_RESOLVE_MIN_LEN;
return 0;
}
static void
@ -895,64 +834,44 @@ x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
}
if (ea->disp) {
x86_effaddr eat = *x86_ea; /* structure copy */
unsigned char displen = ea->len;
unsigned char addrsize = insn->common.addrsize;
eat.valid_modrm = 0; /* force checkea to actually run */
/* Call checkea() to simplify the registers out of the
* displacement. Throw away all of the return values except for
* the modified expr.
*/
if (yasm_x86__expr_checkea(&ea->disp, &addrsize,
insn->common.mode_bits, ea->nosplit,
insn->postop == X86_POSTOP_ADDRESS16,
&displen, &eat.modrm, &eat.valid_modrm,
&eat.need_modrm, &eat.sib,
&eat.valid_sib, &eat.need_sib,
&eat.pcrel, &insn->rex,
yasm_common_calc_bc_dist))
yasm_internal_error(N_("checkea failed"));
if (ea->disp) {
if (eat.pcrel) {
/*@null@*/ yasm_expr *wrt = yasm_expr_extract_wrt(&ea->disp);
/* Simplify expression */
ea->disp = yasm_expr_simplify(ea->disp, yasm_common_calc_bc_dist);
if (x86_ea->pcrel) {
/*@null@*/ yasm_expr *wrt = yasm_expr_extract_wrt(&ea->disp);
ea->disp =
yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(ea->disp),
yasm_expr_sym(x86_ea->origin), bc->line);
if (wrt) {
ea->disp =
yasm_expr_create(YASM_EXPR_SUB,
yasm_expr_create(YASM_EXPR_WRT,
yasm_expr_expr(ea->disp),
yasm_expr_sym(eat.origin), bc->line);
if (wrt) {
ea->disp =
yasm_expr_create(YASM_EXPR_WRT,
yasm_expr_expr(ea->disp),
yasm_expr_expr(wrt), bc->line);
}
if (output_expr(&ea->disp, *bufp, ea->len,
(size_t)(ea->len*8), 0,
(unsigned long)(*bufp-bufp_orig), bc, 1, 1,
d))
return 1;
} else {
if (output_expr(&ea->disp, *bufp, ea->len,
(size_t)(ea->len*8), 0,
(unsigned long)(*bufp-bufp_orig), bc, 0, 1,
d))
return 1;
yasm_expr_expr(wrt), bc->line);
}
*bufp += ea->len;
if (output_expr(&ea->disp, *bufp, ea->len,
(size_t)(ea->len*8), 0,
(unsigned long)(*bufp-bufp_orig), bc, 1, 1,
d))
return 1;
} else {
/* 0 displacement, but we didn't know it before, so we have to
* write out 0 value.
*/
for (i=0; i<ea->len; i++)
YASM_WRITE_8(*bufp, 0);
if (output_expr(&ea->disp, *bufp, ea->len,
(size_t)(ea->len*8), 0,
(unsigned long)(*bufp-bufp_orig), bc, 0, 1,
d))
return 1;
}
*bufp += ea->len;
} else {
/* 0 displacement, but we didn't know it before, so we have to
* write out 0 value.
* FIXME: Is this still needed?
*/
for (i=0; i<ea->len; i++)
YASM_WRITE_8(*bufp, 0);
}
}
/* Immediate (if required) */
if (imm && imm->val) {
if (imm && imm->val && insn->postop != X86_POSTOP_SHIFT) {
if (output_expr(&imm->val, *bufp, imm->len, (size_t)(imm->len*8), 0,
(unsigned long)(*bufp-bufp_orig), bc, 0, 1, d))
return 1;
@ -980,7 +899,7 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
opersize = (jmp->common.opersize == 0) ?
jmp->common.mode_bits : jmp->common.opersize;
/* Check here to see if forced forms are actually legal. */
/* Check here again to see if forms are actually legal. */
switch (jmp->op_sel) {
case JMP_SHORT_FORCED:
case JMP_SHORT:

@ -249,8 +249,7 @@ x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits)
static int
x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
/*@null@*/ int *indexreg, unsigned char *pcrel, unsigned int bits,
void *data, int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d),
yasm_calc_bc_dist_func calc_bc_dist)
void *data, int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d))
{
int i;
int *reg;
@ -260,11 +259,10 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
yasm_expr *e;
/*@-unqualifiedtrans@*/
*ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, calc_bc_dist, NULL,
NULL, NULL);
*ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, NULL, NULL, NULL, NULL);
if (*wrt)
*wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, calc_bc_dist,
NULL, NULL, NULL);
*wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, NULL, NULL, NULL,
NULL);
/*@=unqualifiedtrans@*/
assert(*ep != NULL);
e = *ep;
@ -301,19 +299,13 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
*wrt = yasm_expr_extract_wrt(ep);
if (*wrt)
return x86_expr_checkea_getregusage(ep, wrt, indexreg, pcrel,
bits, data, get_reg,
calc_bc_dist);
bits, data, get_reg);
}
switch (e->op) {
case YASM_EXPR_ADD:
/* Prescan for non-int multipliers against a reg.
* This is because if any of the terms is a more complex
* expr (eg, undetermined value), we don't want to try to
* figure out *any* of the expression, because each register
* lookup overwrites the register with a 0 value! And storing
* the state of this routine from one excution to the next
* would be a major chore.
* This is invalid due to the optimizer structure.
*/
for (i=0; i<e->numterms; i++)
if (e->terms[i].type == YASM_EXPR_EXPR) {
@ -321,10 +313,10 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
if (e->terms[i].data.expn->terms[0].type ==
YASM_EXPR_REG) {
if (e->terms[i].data.expn->numterms > 2)
return 2;
return 1;
if (e->terms[i].data.expn->terms[1].type !=
YASM_EXPR_INT)
return 2;
return 1;
}
}
@ -374,9 +366,9 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
yasm_expr__order_terms(e);
if (e->terms[0].type == YASM_EXPR_REG) {
if (e->numterms > 2)
return 2;
return 1;
if (e->terms[1].type != YASM_EXPR_INT)
return 2;
return 1;
reg = get_reg(&e->terms[0], &regnum, data);
if (!reg)
return 1;
@ -476,25 +468,27 @@ x86_checkea_calc_displen(yasm_expr **ep, unsigned int wordsize, int noreg,
* unknown displacement, including none.
*/
*displen = 0xff;
}
intn = yasm_expr_get_intnum(ep, NULL);
if (!intn) {
/* expr still has unknown values: assume 16/32-bit disp */
*displen = wordsize;
*modrm |= 0200;
*modrm |= 0100;
*v_modrm = 1;
return 0;
}
}
/* don't try to find out what size displacement we have if
* displen is known.
/* At this point there's 3 possibilities for the displacement:
* - None (if =0)
* - signed 8 bit (if in -128 to 127 range)
* - 16/32 bit (word size)
* For now, check intnum value right now; if it's not 0,
* assume 8 bit and set up for allowing 16 bit later.
* FIXME: this should really set up two thresholds, one for 8-bit
* expansion and one for 16-bit expansion. The complex expression
* equaling zero is probably a rare case, so we ignore it for now.
*/
if (*displen != 0 && *displen != 0xff) {
if (*displen == 1)
*modrm |= 0100;
else
*modrm |= 0200;
intn = yasm_expr_get_intnum(ep, NULL);
if (!intn) {
/* expr still has unknown values: treat like BP/EBP above */
*displen = 0xff;
*modrm |= 0100;
*v_modrm = 1;
return 0;
}
@ -502,15 +496,12 @@ x86_checkea_calc_displen(yasm_expr **ep, unsigned int wordsize, int noreg,
dispval = yasm_intnum_get_int(intn);
/* Figure out what size displacement we will have. */
if (*displen != 0xff && dispval == 0) {
if (dispval == 0) {
/* if we know that the displacement is 0 right now,
* go ahead and delete the expr (making it so no
* displacement value is included in the output).
* The Mod bits of ModRM are set to 0 above, and
* we're done with the ModRM byte!
*
* Don't do this if we came from dispreq check above, so
* check *displen.
*/
yasm_expr_destroy(e);
*ep = (yasm_expr *)NULL;
@ -562,8 +553,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
unsigned char *modrm, unsigned char *v_modrm,
unsigned char *n_modrm, unsigned char *sib,
unsigned char *v_sib, unsigned char *n_sib,
unsigned char *pcrel, unsigned char *rex,
yasm_calc_bc_dist_func calc_bc_dist)
unsigned char *pcrel, unsigned char *rex)
{
yasm_expr *e, *wrt;
int retval;
@ -658,23 +648,13 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
reg3264_data.regs = reg3264mult;
reg3264_data.bits = bits;
reg3264_data.addrsize = *addrsize;
switch (x86_expr_checkea_getregusage(ep, &wrt, &indexreg, pcrel, bits,
&reg3264_data,
x86_expr_checkea_get_reg3264,
calc_bc_dist)) {
case 1:
e = *ep;
yasm__error(e->line, N_("invalid effective address"));
return 1;
case 2:
if (wrt)
*ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
(*ep)->line);
return 2;
default:
e = *ep;
break;
if (x86_expr_checkea_getregusage(ep, &wrt, &indexreg, pcrel, bits,
&reg3264_data,
x86_expr_checkea_get_reg3264)) {
yasm__error((*ep)->line, N_("invalid effective address"));
return 1;
}
e = *ep;
/* If indexreg mult is 0, discard it.
* This is possible because of the way indexreg is found in
@ -909,23 +889,13 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
*v_sib = 0;
*n_sib = 0;
switch (x86_expr_checkea_getregusage(ep, &wrt, (int *)NULL, pcrel,
bits, &reg16mult,
x86_expr_checkea_get_reg16,
calc_bc_dist)) {
case 1:
e = *ep;
yasm__error(e->line, N_("invalid effective address"));
return 1;
case 2:
if (wrt)
*ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
(*ep)->line);
return 2;
default:
e = *ep;
break;
if (x86_expr_checkea_getregusage(ep, &wrt, NULL, pcrel, bits,
&reg16mult,
x86_expr_checkea_get_reg16)) {
yasm__error((*ep)->line, N_("invalid effective address"));
return 1;
}
e = *ep;
/* reg multipliers not 0 or 1 are illegal. */
if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 ||

@ -1025,23 +1025,23 @@ static const x86_insn_info imul_insn[] = {
{ CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x6B, 0, 0}, 0, 2,
{OPT_Reg|OPS_64|OPA_SpareEA, OPT_Imm|OPS_8|OPA_SImm, 0} },
{ CPU_186, MOD_GasSufW, 16, 0, 0, 1, {0x69, 0x6B, 0}, 0, 3,
{ CPU_186, MOD_GasSufW, 16, 0, 0, 1, {0x6B, 0x69, 0}, 0, 3,
{OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA,
OPT_Imm|OPS_16|OPS_Relaxed|OPA_SImm|OPAP_SImm8Avail} },
{ CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x69, 0x6B, 0}, 0, 3,
{ CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x6B, 0x69, 0}, 0, 3,
{OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA,
OPT_Imm|OPS_32|OPS_Relaxed|OPA_SImm|OPAP_SImm8Avail} },
{ CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x69, 0x6B, 0}, 0, 3,
{ CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x6B, 0x69, 0}, 0, 3,
{OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA,
OPT_Imm|OPS_32|OPS_Relaxed|OPA_SImm|OPAP_SImm8Avail} },
{ CPU_186, MOD_GasSufW, 16, 0, 0, 1, {0x69, 0x6B, 0}, 0, 2,
{ CPU_186, MOD_GasSufW, 16, 0, 0, 1, {0x6B, 0x69, 0}, 0, 2,
{OPT_Reg|OPS_16|OPA_SpareEA,
OPT_Imm|OPS_16|OPS_Relaxed|OPA_SImm|OPAP_SImm8Avail, 0} },
{ CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x69, 0x6B, 0}, 0, 2,
{ CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x6B, 0x69, 0}, 0, 2,
{OPT_Reg|OPS_32|OPA_SpareEA,
OPT_Imm|OPS_32|OPS_Relaxed|OPA_SImm|OPAP_SImm8Avail, 0} },
{ CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x69, 0x6B, 0}, 0, 2,
{ CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x6B, 0x69, 0}, 0, 2,
{OPT_Reg|OPS_64|OPA_SpareEA,
OPT_Imm|OPS_32|OPS_Relaxed|OPA_SImm|OPAP_SImm8Avail, 0} }
};
@ -1054,22 +1054,27 @@ static const x86_insn_info shift_insn[] = {
* ,1 form, so it has to be marked as Any. We need to store the active
* CPU flags somewhere to pass that parse-time info down the line.
*/
{ CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xC0, 0xD0, 0}, 0, 2,
{ CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0xC0, 0}, 0, 2,
{OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
0} },
{ CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD3, 0, 0}, 0, 2,
{OPT_RM|OPS_16|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
{ CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xC1, 0xD1, 0}, 0, 2,
{ CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2,
{OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
0} },
{ CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD3, 0, 0}, 0, 2,
{OPT_RM|OPS_32|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
{ CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xC1, 0xD1, 0}, 0, 2,
{ CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2,
{OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
0} },
{ CPU_Hammer|CPU_64, MOD_SpAdd, 64, 0, 0, 1, {0xD3, 0, 0}, 0, 2,
{OPT_RM|OPS_64|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
{ CPU_Hammer|CPU_64, MOD_SpAdd, 64, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2,
{OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
0} },
{ CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD3, 0, 0}, 0,
2, {OPT_RM|OPS_64|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
{ CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xC1, 0xD1, 0},
{ CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD1, 0xC1, 0},
0, 2, {OPT_RM|OPS_64|OPA_EA,
OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp, 0} },
/* In GAS mode, single operands are equivalent to shifting by 1 forms */

@ -4,4 +4,4 @@ EXTRA_DIST += modules/dbgfmts/null/Makefile.inc
EXTRA_DIST += modules/dbgfmts/stabs/Makefile.inc
include modules/dbgfmts/null/Makefile.inc
include modules/dbgfmts/stabs/Makefile.inc
#include modules/dbgfmts/stabs/Makefile.inc

@ -1,5 +0,0 @@
# $Id$
EXTRA_DIST += modules/optimizers/basic/Makefile.inc
include modules/optimizers/basic/Makefile.inc

@ -1,5 +0,0 @@
# $Id$
libyasm_a_SOURCES += modules/optimizers/basic/basic-optimizer.c
YASM_MODULES += optimizer_basic

@ -1,234 +0,0 @@
/*
* Basic optimizer (equivalent to the NASM 2-pass 'no optimizer' design)
*
* Copyright (C) 2001 Peter Johnson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <util.h>
/*@unused@*/ RCSID("$Id$");
#define YASM_LIB_INTERNAL
#define YASM_BC_INTERNAL
#include <libyasm.h>
#define SECTFLAG_NONE 0UL
#define SECTFLAG_INPROGRESS (1UL<<0)
#define SECTFLAG_DONE (1UL<<1)
#define BCFLAG_NONE 0UL
#define BCFLAG_INPROGRESS (1UL<<0)
#define BCFLAG_DONE (1UL<<1)
static int basic_optimize_section_1(yasm_section *sect,
/*@unused@*/ /*@null@*/ void *d);
static /*@null@*/ yasm_intnum *
basic_optimize_calc_bc_dist_1(yasm_bytecode *precbc1, yasm_bytecode *precbc2)
{
unsigned int dist;
yasm_intnum *intn;
if (precbc1->section != precbc2->section)
yasm_internal_error(N_("Trying to calc_bc_dist between sections"));
if (yasm_section_get_opt_flags(precbc1->section) == SECTFLAG_NONE) {
/* Section not started. Optimize it (recursively). */
basic_optimize_section_1(precbc1->section, NULL);
}
/* If a section is done, the following will always succeed. If it's in-
* progress, this will fail if the bytecode comes AFTER the current one.
*/
if (precbc2 != yasm_section_bcs_first(precbc2->section)) {
if (precbc2->opt_flags == BCFLAG_DONE) {
dist = precbc2->offset + precbc2->len;
if (precbc1 != yasm_section_bcs_first(precbc1->section)) {
if (precbc1->opt_flags == BCFLAG_DONE) {
if (dist < precbc1->offset + precbc1->len) {
intn = yasm_intnum_create_uint(precbc1->offset +
precbc1->len - dist);
yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL,
precbc1->line);
return intn;
}
dist -= precbc1->offset + precbc1->len;
} else {
return NULL;
}
}
return yasm_intnum_create_uint(dist);
} else {
return NULL;
}
} else {
if (precbc1 != yasm_section_bcs_first(precbc1->section)) {
if (precbc1->opt_flags == BCFLAG_DONE) {
intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len);
yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
return intn;
} else {
return NULL;
}
} else {
return yasm_intnum_create_uint(0);
}
}
}
typedef struct basic_optimize_data {
/*@observer@*/ yasm_bytecode *precbc;
int saw_unknown;
} basic_optimize_data;
static int
basic_optimize_bytecode_1(/*@observer@*/ yasm_bytecode *bc, void *d)
{
basic_optimize_data *data = (basic_optimize_data *)d;
yasm_bc_resolve_flags bcr_retval;
/* Don't even bother if we're in-progress or done. */
if (bc->opt_flags == BCFLAG_INPROGRESS)
return 1;
if (bc->opt_flags == BCFLAG_DONE)
return 0;
bc->opt_flags = BCFLAG_INPROGRESS;
bc->offset = data->precbc->offset + data->precbc->len;
data->precbc = bc;
/* We're doing just a single pass, so essentially ignore whether the size
* is minimum or not, and just check for indeterminate length (indicative
* of circular reference).
*/
bcr_retval = yasm_bc_resolve(bc, 0, basic_optimize_calc_bc_dist_1);
if (bcr_retval & YASM_BC_RESOLVE_UNKNOWN_LEN) {
if (!(bcr_retval & YASM_BC_RESOLVE_ERROR))
yasm__error(bc->line, N_("circular reference detected."));
data->saw_unknown = -1;
return 0;
}
bc->opt_flags = BCFLAG_DONE;
return 0;
}
static int
basic_optimize_section_1(yasm_section *sect, /*@null@*/ void *d)
{
/*@null@*/ int *saw_unknown = (int *)d;
basic_optimize_data data;
unsigned long flags;
int retval;
data.precbc = yasm_section_bcs_first(sect);
data.saw_unknown = 0;
/* Don't even bother if we're in-progress or done. */
flags = yasm_section_get_opt_flags(sect);
if (flags == SECTFLAG_INPROGRESS)
return 1;
if (flags == SECTFLAG_DONE)
return 0;
yasm_section_set_opt_flags(sect, SECTFLAG_INPROGRESS);
retval = yasm_section_bcs_traverse(sect, &data, basic_optimize_bytecode_1);
if (retval != 0)
return retval;
if (data.saw_unknown != 0 && saw_unknown)
*saw_unknown = data.saw_unknown;
yasm_section_set_opt_flags(sect, SECTFLAG_DONE);
return 0;
}
static int
basic_optimize_bytecode_2(/*@observer@*/ yasm_bytecode *bc, /*@null@*/ void *d)
{
basic_optimize_data *data = (basic_optimize_data *)d;
assert(data != NULL);
if (bc->opt_flags != BCFLAG_DONE)
yasm_internal_error(N_("Optimizer pass 1 missed a bytecode!"));
bc->offset = data->precbc->offset + data->precbc->len;
data->precbc = bc;
if (yasm_bc_resolve(bc, 1, yasm_common_calc_bc_dist)
& YASM_BC_RESOLVE_ERROR)
return -1;
return 0;
}
static int
basic_optimize_section_2(yasm_section *sect, /*@unused@*/ /*@null@*/ void *d)
{
basic_optimize_data data;
data.precbc = yasm_section_bcs_first(sect);
if (yasm_section_get_opt_flags(sect) != SECTFLAG_DONE)
yasm_internal_error(N_("Optimizer pass 1 missed a section!"));
return yasm_section_bcs_traverse(sect, &data, basic_optimize_bytecode_2);
}
static void
basic_optimize(yasm_object *object)
{
int saw_unknown = 0;
/* Optimization process: (essentially NASM's pass 1)
* Determine the size of all bytecodes.
* Forward references are /not/ resolved (only backward references are
* computed and sized).
* Check "critical" expressions (must be computable on the first pass,
* i.e. depend only on symbols before it).
* Differences from NASM:
* - right-hand side of EQU is /not/ a critical expr (as the entire file
* has already been parsed, we know all their values at this point).
* - not strictly top->bottom scanning; we scan through a section and
* hop to other sections as necessary.
*/
if (yasm_object_sections_traverse(object, &saw_unknown,
basic_optimize_section_1) < 0 ||
saw_unknown != 0)
return;
/* Check completion of all sections and save bytecode changes */
yasm_object_sections_traverse(object, NULL, basic_optimize_section_2);
}
/* Define optimizer structure -- see optimizer.h for details */
yasm_optimizer_module yasm_basic_LTX_optimizer = {
"Only the most basic optimizations",
"basic",
basic_optimize
};
Loading…
Cancel
Save