Implement first phase of align and org.

svn path=/branches/new-optimizer/; revision=1567
This commit is contained in:
Peter Johnson 2006-06-11 06:57:03 +00:00
parent 53d9be8757
commit 114cee8b06
10 changed files with 218 additions and 162 deletions

View file

@ -71,7 +71,7 @@ static const yasm_bytecode_callback bc_align_callback = {
bc_align_calc_len,
bc_align_expand,
bc_align_tobytes,
0
YASM_BC_SPECIAL_OFFSET
};
@ -121,31 +121,13 @@ static int
bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
yasm_internal_error(N_("align not yet implemented"));
#if 0
bytecode_align *align = (bytecode_align *)bc->contents;
unsigned long end;
unsigned long boundary =
yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, NULL));
long neg_thres = 0;
long pos_thres = 0;
if (boundary == 0) {
bc->len = 0;
return YASM_BC_RESOLVE_MIN_LEN;
}
if (bc_align_expand(bc, 0, 0, (long)bc->offset, &neg_thres,
&pos_thres) < 0)
return -1;
end = bc->offset;
if (bc->offset & (boundary-1))
end = (bc->offset & ~(boundary-1)) + boundary;
bc->len = end - bc->offset;
if (align->maxskip) {
unsigned long maxskip =
yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, NULL));
if ((end - bc->offset) > maxskip)
bc->len = 0;
}
#endif
return 0;
}
@ -153,8 +135,31 @@ static int
bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
{
yasm_internal_error(N_("align not yet implemented"));
return 0;
bytecode_align *align = (bytecode_align *)bc->contents;
unsigned long end;
unsigned long boundary =
yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0));
if (boundary == 0) {
bc->len = 0;
*pos_thres = 0;
return 0;
}
end = new_val;
if (new_val & (boundary-1))
end = (new_val & ~(boundary-1)) + boundary;
*pos_thres = end;
bc->len = end - new_val;
if (align->maxskip) {
unsigned long maxskip =
yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0));
if ((end - new_val) > maxskip)
bc->len = 0;
}
return 1;
}
static int

View file

@ -38,7 +38,11 @@ typedef struct yasm_bytecode_callback {
int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
int reserve; /* Reserve space instead of outputting data */
enum {
YASM_BC_SPECIAL_NONE = 0,
YASM_BC_SPECIAL_RESERVE,/* Reserves space instead of outputting data */
YASM_BC_SPECIAL_OFFSET /* Adjusts offset instead of calculating len */
} special;
} yasm_bytecode_callback;
struct yasm_bytecode {

View file

@ -64,7 +64,7 @@ static const yasm_bytecode_callback bc_org_callback = {
bc_org_calc_len,
bc_org_expand,
bc_org_tobytes,
0
YASM_BC_SPECIAL_OFFSET
};
@ -91,20 +91,13 @@ static int
bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
void *add_span_data)
{
yasm_internal_error(N_("org not yet implemented"));
#if 0
bytecode_org *org = (bytecode_org *)bc->contents;
long neg_thres = 0;
long pos_thres = org->start;
/* Check for overrun */
if (bc->offset > org->start) {
yasm_error_set(YASM_ERROR_GENERAL,
N_("ORG overlap with already existing data"));
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
}
if (bc_org_expand(bc, 0, 0, (long)bc->offset, &neg_thres, &pos_thres) < 0)
return -1;
/* Generate space to start offset */
bc->len = org->start - bc->offset;
#endif
return 0;
}
@ -112,8 +105,18 @@ static int
bc_org_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
{
yasm_internal_error(N_("org not yet implemented"));
return 0;
bytecode_org *org = (bytecode_org *)bc->contents;
/* Check for overrun */
if ((unsigned long)new_val > org->start) {
yasm_error_set(YASM_ERROR_GENERAL,
N_("ORG overlap with already existing data"));
return -1;
}
/* Generate space to start offset */
bc->len = org->start - new_val;
return 1;
}
static int

View file

@ -63,7 +63,7 @@ static const yasm_bytecode_callback bc_reserve_callback = {
bc_reserve_calc_len,
yasm_bc_expand_common,
bc_reserve_tobytes,
1
YASM_BC_SPECIAL_RESERVE
};

View file

@ -83,20 +83,13 @@ yasm_bc_create_common(const yasm_bytecode_callback *callback, void *contents,
yasm_bytecode *bc = yasm_xmalloc(sizeof(yasm_bytecode));
bc->callback = callback;
bc->section = NULL;
bc->multiple = (yasm_expr *)NULL;
bc->len = 0;
bc->line = line;
bc->offset = ~0UL; /* obviously incorrect / uninitialized value */
bc->opt_flags = 0;
bc->symrecs = NULL;
bc->contents = contents;
return bc;
@ -206,29 +199,31 @@ yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
bc->len = 0;
if (!bc->callback)
yasm_internal_error(N_("got empty bytecode in bc_resolve"));
yasm_internal_error(N_("got empty bytecode in yasm_bc_calc_len"));
else
retval = bc->callback->calc_len(bc, add_span, add_span_data);
#if 0
/* Check for multiples */
if (bc->multiple) {
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
num = yasm_expr_get_intnum(&bc->multiple, NULL);
if (!num) {
num = yasm_expr_get_intnum(&bc->multiple, 0);
if (num)
bc->len *= yasm_intnum_get_uint(num);
else {
if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) {
yasm_error_set(YASM_ERROR_VALUE,
N_("expression must not contain floating point value"));
retval = -1;
} else {
/* FIXME: Non-constant currently not allowed. */
yasm__error(bc->line,
N_("attempt to use non-constant multiple"));
yasm_error_set(YASM_ERROR_VALUE,
N_("attempt to use non-constant multiple"));
retval = -1;
}
}
}
#endif
/* If we got an error somewhere along the line, clear out any calc len */
if (retval < 0)
bc->len = 0;
@ -241,7 +236,7 @@ yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
/*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
{
if (!bc->callback) {
yasm_internal_error(N_("got empty bytecode in bc_set_long"));
yasm_internal_error(N_("got empty bytecode in yasm_bc_expand"));
/*@unreached@*/
return 0;
} else
@ -267,7 +262,7 @@ yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
}
/* special case for reserve bytecodes */
if (bc->callback->reserve) {
if (bc->callback->special == YASM_BC_SPECIAL_RESERVE) {
*bufsize = bc->len;
*gap = 1;
return NULL; /* we didn't allocate a buffer */

View file

@ -317,7 +317,7 @@ void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
* \param pos_thres positive threshold for long/short decision
*/
typedef void (*yasm_bc_add_span_func)
(void *add_span_data, yasm_bytecode *bc, int id, yasm_value *value,
(void *add_span_data, yasm_bytecode *bc, int id, const yasm_value *value,
long neg_thres, long pos_thres);
/** Resolve EQUs in a bytecode and calculate its minimum size.

View file

@ -648,20 +648,19 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level,
* Some portions are critical values that must not depend on any bytecode
* offset (either relative or absolute).
*
* ALIGN: 0 length (always). Bump offset to alignment. Span from 0 to
* align bytecode, update on any change. If span length
* increases past alignment, increase offset by alignment and update
* dependent spans. Alignment is critical value.
* ORG: Same as align, but if span's length exceeds org value, error.
* ORG value is critical value.
* ALIGN/ORG/other offset-based bytecodes: Length set to bump offset to
* alignment. Span from 0 to bytecode, update on any change. Can
* update to new offset for things like align, which gets propagated
* to update dependent spans. Alignment/ORG value is critical value.
* Cannot be combined with TIMES.
*
* How times is handled:
*
* TIMES: Handled separately from bytecode "raw" size. If not span-dependent,
* trivial (just multiplied in at any bytecode size increase). Span
* dependent times update on any change (span ID 0). If the resultant
* next bytecode offset would be less than the old next bytecode offset,
* error. Otherwise increase offset and update dependent spans.
* trivial (just multiplied in at any bytecode size increase). Span
* dependent times update on any change (span ID 0). If the resultant
* next bytecode offset would be less than the old next bytecode offset,
* error. Otherwise increase offset and update dependent spans.
*
* To reduce interval tree size, a first expansion pass is performed
* before the spans are added to the tree.
@ -673,9 +672,8 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level,
* of all bytecodes assuming minimum length, building a list of all
* dependent spans as we go.
* "minimum" here means absolute minimum:
* - align 0 length, but bumps offset
* - align/org (offset-based) bumps offset as normal
* - times values (with span-dependent values) assumed to be 0
* - org 0 length, but bumps offset
* b. Iterate over spans. Set span length based on bytecode offsets
* determined in 1a. If span is "certainly" long because the span
* is an absolute reference to another section (or external) or the
@ -707,13 +705,12 @@ typedef struct yasm_span {
/*@dependent@*/ yasm_bytecode *bc;
yasm_value *depval;
yasm_value depval;
/* Special handling: see descriptions above */
enum {
NOT_SPECIAL = 0,
SPECIAL_ALIGN,
SPECIAL_ORG,
SPECIAL_BC_OFFSET,
SPECIAL_TIMES
} special;
@ -734,13 +731,13 @@ typedef struct optimize_data {
static void
optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id,
yasm_value *value, long neg_thres, long pos_thres)
const yasm_value *value, long neg_thres, long pos_thres)
{
optimize_data *optd = (optimize_data *)add_span_data;
yasm_span *span = yasm_xmalloc(sizeof(yasm_span));
span->bc = bc;
span->depval = value;
yasm_value_init_copy(&span->depval, value);
span->special = NOT_SPECIAL;
span->cur_val = 0;
span->new_val = 0;
@ -752,29 +749,42 @@ optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id,
STAILQ_INSERT_TAIL(&optd->spans, span, link);
}
static void
update_all_bc_offsets(yasm_object *object)
static int
update_all_bc_offsets(yasm_object *object, yasm_errwarns *errwarns)
{
yasm_section *sect;
int saw_error = 0;
STAILQ_FOREACH(sect, &object->sections, link) {
unsigned long offset = 0;
yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prev;
yasm_bytecode *bc = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prevbc;
/* Skip our locally created empty bytecode first. */
prev = cur;
cur = STAILQ_NEXT(cur, link);
prevbc = bc;
bc = STAILQ_NEXT(bc, link);
/* Iterate through the remainder, if any. */
while (cur) {
cur->offset = offset;
offset += cur->len;
prev = cur;
cur = STAILQ_NEXT(cur, link);
while (bc) {
if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) {
/* Recalculate/adjust len of offset-based bytecodes here */
long neg_thres = 0;
long pos_thres = bc->offset+bc->len;
int retval = yasm_bc_expand(bc, 0, 0,
(long)(prevbc->offset+prevbc->len),
&neg_thres, &pos_thres);
yasm_errwarn_propagate(errwarns, bc->line);
if (retval < 0)
saw_error = 1;
}
bc->offset = offset;
offset += bc->len;
prevbc = bc;
bc = STAILQ_NEXT(bc, link);
}
}
return saw_error;
}
void
@ -797,31 +807,55 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch,
STAILQ_FOREACH(sect, &object->sections, link) {
unsigned long offset = 0;
yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prev;
yasm_bytecode *bc = STAILQ_FIRST(&sect->bcs);
yasm_bytecode *prevbc;
cur->bc_index = bc_index++;
bc->bc_index = bc_index++;
/* Skip our locally created empty bytecode first. */
prev = cur;
cur = STAILQ_NEXT(cur, link);
prevbc = bc;
bc = STAILQ_NEXT(bc, link);
/* Iterate through the remainder, if any. */
while (cur) {
cur->bc_index = bc_index++;
while (bc) {
bc->bc_index = bc_index++;
bc->offset = offset;
if (yasm_bc_calc_len(cur, optimize_add_span, &optd))
retval = yasm_bc_calc_len(bc, optimize_add_span, &optd);
yasm_errwarn_propagate(errwarns, bc->line);
if (retval)
saw_error = 1;
yasm_errwarn_propagate(errwarns, cur->line);
else {
if (bc->callback->special == YASM_BC_SPECIAL_OFFSET) {
span = yasm_xmalloc(sizeof(yasm_span));
/* TODO: times */
if (cur->multiple)
yasm_internal_error("multiple not yet supported");
span->bc = bc;
yasm_value_initialize(&span->depval, NULL, 0);
span->special = SPECIAL_BC_OFFSET;
span->cur_val = (long)(prevbc->offset+prevbc->len);
span->new_val = 0;
span->neg_thres = 0;
span->pos_thres = (long)(bc->offset+bc->len);
span->id = 0;
span->active = 1;
cur->offset = offset;
offset += cur->len;
prev = cur;
cur = STAILQ_NEXT(cur, link);
STAILQ_INSERT_TAIL(&optd.spans, span, link);
if (bc->multiple) {
yasm_error_set(YASM_ERROR_VALUE,
N_("cannot combine multiples and setting assembly position"));
yasm_errwarn_propagate(errwarns, span->bc->line);
saw_error = 1;
}
}
/* TODO: times */
if (bc->len != 0 && bc->multiple) {
yasm_internal_error("multiple not yet supported");
}
offset += bc->len;
}
prevbc = bc;
bc = STAILQ_NEXT(bc, link);
}
}
@ -832,47 +866,61 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch,
STAILQ_FOREACH(span, &optd.spans, link) {
if (!span->active)
continue;
yasm_value_init_copy(&val, span->depval);
num = yasm_value_get_intnum(&val, span->bc, 1);
if (num) {
span->new_val = yasm_intnum_get_int(num);
yasm_intnum_destroy(num);
} else {
/* external or too complex; force to longer form */
span->new_val = LONG_MAX;
span->active = 0;
}
yasm_value_delete(&val);
if ((span->id == 0 && span->new_val != span->cur_val) ||
(span->new_val < span->neg_thres
|| span->new_val > span->pos_thres)) {
retval = yasm_bc_expand(span->bc, span->id, span->cur_val,
span->new_val, &neg_thres, &pos_thres);
yasm_errwarn_propagate(errwarns, span->bc->line);
if (retval < 0)
saw_error = 1;
else if (retval > 0) {
if (!span->active) {
yasm_error_set(YASM_ERROR_VALUE,
N_("secondary expansion of an external/complex value"));
yasm_errwarn_propagate(errwarns, span->bc->line);
saw_error = 1;
switch (span->special) {
case NOT_SPECIAL:
yasm_value_init_copy(&val, &span->depval);
num = yasm_value_get_intnum(&val, span->bc, 1);
if (num) {
span->new_val = yasm_intnum_get_int(num);
yasm_intnum_destroy(num);
} else {
span->neg_thres = neg_thres;
span->pos_thres = pos_thres;
/* external or too complex; force to longest form */
span->new_val = LONG_MAX;
span->active = 0;
}
} else
span->active = 0;
yasm_value_delete(&val);
if ((span->id == 0 && span->new_val != span->cur_val) ||
(span->new_val < span->neg_thres
|| span->new_val > span->pos_thres)) {
retval = yasm_bc_expand(span->bc, span->id, span->cur_val,
span->new_val, &neg_thres,
&pos_thres);
yasm_errwarn_propagate(errwarns, span->bc->line);
if (retval < 0)
saw_error = 1;
else if (retval > 0) {
if (!span->active) {
yasm_error_set(YASM_ERROR_VALUE,
N_("secondary expansion of an external/complex value"));
yasm_errwarn_propagate(errwarns, span->bc->line);
saw_error = 1;
} else {
span->neg_thres = neg_thres;
span->pos_thres = pos_thres;
}
} else
span->active = 0;
}
span->cur_val = span->new_val;
if (span->active) {
/* Add to interval tree */
}
break;
case SPECIAL_BC_OFFSET:
/* Add to interval tree; nothing else to do here */
break;
case SPECIAL_TIMES:
break;
}
span->cur_val = span->new_val;
}
if (saw_error)
return;
/* Step 1c */
update_all_bc_offsets(object);
if (update_all_bc_offsets(object, errwarns))
return;
/* Step 1d */
STAILQ_FOREACH(span, &optd.spans, link) {
@ -883,5 +931,5 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch,
/* Step 2 */
/* Step 3 */
update_all_bc_offsets(object);
update_all_bc_offsets(object, errwarns);
}

View file

@ -494,31 +494,33 @@ yasm_value_get_intnum(yasm_value *value, yasm_bytecode *bc, int calc_bc_dist)
}
if (value->rel) {
/* If relative portion is not in bc section, return NULL.
* Otherwise get the relative portion's offset.
*/
/* Get the relative portion's offset. */
/*@dependent@*/ yasm_bytecode *rel_prevbc;
unsigned long dist;
if (!bc)
return NULL; /* Can't calculate relative value */
if (!calc_bc_dist)
return NULL; /* Don't calculate BC distance */
sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
if (value->wrt || value->seg_of || value->section_rel || !sym_local)
return NULL; /* we can't handle SEG, WRT, or external symbols */
if (rel_prevbc->section != bc->section)
return NULL; /* not in this section */
if (!value->curpos_rel)
return NULL; /* not PC-relative */
/* Calculate value relative to current assembly position */
/* Calculate relative value as integer */
dist = rel_prevbc->offset + rel_prevbc->len;
if (dist < bc->offset) {
outval = yasm_intnum_create_uint(bc->offset - dist);
yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
} else {
dist -= bc->offset;
outval = yasm_intnum_create_uint(dist);
if (value->curpos_rel) {
/* PC-relative */
if (!bc)
return NULL; /* Can't calculate PC-relative value */
if (rel_prevbc->section != bc->section)
return NULL; /* not in this section */
if (dist < bc->offset) {
outval = yasm_intnum_create_uint(bc->offset - dist);
yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
} else {
dist -= bc->offset;
outval = yasm_intnum_create_uint(dist);
}
}
if (value->rshift > 0) {

View file

@ -100,15 +100,15 @@ int yasm_value_finalize_expr(/*@out@*/ yasm_value *value,
/*@null@*/ /*@kept@*/ yasm_expr *e,
unsigned int size);
/** Get value if absolute or PC-relative section-local relative. Returns NULL
* otherwise.
/** Get value if absolute, pure relative, or PC-relative section-local
* relative. Returns NULL otherwise.
* \param value value
* \param bc current bytecode (for PC-relative calculation); if
* NULL, NULL is returned for PC-relative values.
* \param calc_bc_dist if nonzero, calculates bytecode distances in absolute
* portion of value
* \note Adds in value.rel (correctly) if PC-relative and in the same section
* as bc (and there is no WRT or SEG).
* as bc (and there is no WRT or SEG), or if value is pure-relative.
* \return Intnum if can be resolved to integer value, otherwise NULL.
*/
/*@null@*/ /*@only@*/ yasm_intnum *yasm_value_get_intnum

View file

@ -47,12 +47,6 @@ cdef extern from "libyasm/bytecode.h":
cdef struct yasm_dataval
cdef struct yasm_datavalhead
cdef enum yasm_bc_resolve_flags:
YASM_BC_RESOLVE_NONE
YASM_BC_RESOLVE_ERROR
YASM_BC_RESOLVE_MIN_LEN
YASM_BC_RESOLVE_UNKNOWN_LEN
cdef yasm_immval* yasm_imm_create_expr(yasm_expr *e)
cdef yasm_expr* yasm_ea_get_disp(yasm_effaddr *ea)
cdef void yasm_ea_set_len(yasm_effaddr *ea, unsigned int len)
@ -118,6 +112,11 @@ cdef extern from "libyasm/bytecode.h":
int indent_level)
cdef extern from "libyasm/bc-int.h":
cdef enum yasm_bc_special:
YASM_BC_SPECIAL_NONE
YASM_BC_SPECIAL_RESERVE
YASM_BC_SPECIAL_OFFSET
cdef struct yasm_bytecode_callback:
void (*destroy) (void *contents)
void (*c_print "print") (void *contents, FILE *f, int indent_level)
@ -129,7 +128,7 @@ cdef extern from "libyasm/bc-int.h":
int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_value_func output_value,
yasm_output_reloc_func output_reloc)
int reserve
yasm_bc_special special
cdef struct yasm_bytecode:
yasm_bytecode_callback *callback