From: Peter Johnson Date: Mon, 12 Jun 2006 07:53:49 +0000 (-0000) Subject: Move towards building interval tree by splitting dependent value into X-Git-Tag: v0.6.0~172^2~16 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1d3f2ded2377fbb4f0754087064e84d954be456a;p=yasm Move towards building interval tree by splitting dependent value into sym-sym terms. Starting to get some code duplication that should get refactored somehow, but the first priority is getting it working. svn path=/branches/new-optimizer/; revision=1575 --- diff --git a/libyasm/expr-int.h b/libyasm/expr-int.h index 456da9ca..0a1bc5a9 100644 --- a/libyasm/expr-int.h +++ b/libyasm/expr-int.h @@ -32,10 +32,11 @@ typedef enum { YASM_EXPR_NONE = 0, YASM_EXPR_REG = 1<<0, YASM_EXPR_INT = 1<<1, - YASM_EXPR_FLOAT = 1<<2, - YASM_EXPR_SYM = 1<<3, - YASM_EXPR_SYMEXP = 1<<4, /* post-expanded sym (due to absolute expansion) */ - YASM_EXPR_EXPR = 1<<5 + YASM_EXPR_SUBST = 1<<2, + YASM_EXPR_FLOAT = 1<<3, + YASM_EXPR_SYM = 1<<4, + YASM_EXPR_SYMEXP = 1<<5, /* post-expanded sym (due to absolute expansion) */ + YASM_EXPR_EXPR = 1<<6 } yasm_expr__type; struct yasm_expr__item { @@ -46,6 +47,7 @@ struct yasm_expr__item { yasm_intnum *intn; yasm_floatnum *flt; unsigned long reg; + unsigned int subst; } data; }; @@ -85,4 +87,28 @@ yasm_expr *yasm_expr__copy_except(const yasm_expr *e, int except); int yasm_expr__contains(const yasm_expr *e, yasm_expr__type t); +/** Transform symrec-symrec terms in expression into YASM_EXPR_SUBST items. + * Calls the callback function for each symrec-symrec term. + * \param ep expression (pointer to) + * \param cbd callback data passed to callback function + * \param callback callback function: given subst index for bytecode + * pair, bytecode pair (bc2-bc1), and cbd (callback data) + * \return Number of transformations made. + */ +int yasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd, + void (*callback) (unsigned int subst, + yasm_bytecode *precbc, + yasm_bytecode *precbc2, + void *cbd)); + +/** Substitute items into expr YASM_EXPR_SUBST items (by index). Items are + * copied, so caller is responsible for freeing array of items. + * \param e expression + * \param num_items number of items in items array + * \param items items array + * \return 1 on error (index out of range). + */ +int yasm_expr__subst(yasm_expr *e, unsigned int num_items, + const yasm_expr__item *items); + #endif diff --git a/libyasm/expr.c b/libyasm/expr.c index 95522b37..5332f6b7 100644 --- a/libyasm/expr.c +++ b/libyasm/expr.c @@ -183,11 +183,17 @@ yasm_expr_reg(unsigned long reg) return e; } -/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into integers if - * possible. Uses a simple n^2 algorithm because n is usually quite small. +/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into single + * expritems if possible. Uses a simple n^2 algorithm because n is usually + * quite small. */ static /*@only@*/ yasm_expr * -expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e) +expr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e, + /*@null@*/ void *cbd, + int (*callback) (yasm_expr__item *ei, + yasm_bytecode *precbc, + yasm_bytecode *precbc2, + void *cbd)) { int i; /*@dependent@*/ yasm_section *sect; @@ -243,10 +249,7 @@ expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e) yasm_symrec_get_label(e->terms[j].data.sym, &precbc2) && (sect = yasm_bc_get_section(precbc2)) && sect == sect2 && - (dist = yasm_calc_bc_dist(precbc, precbc2))) { - /* Change the symrec term to an integer */ - e->terms[j].type = YASM_EXPR_INT; - e->terms[j].data.intn = dist; + callback(&e->terms[j], precbc, precbc2, cbd)) { /* Delete the matching (-1*symrec) term */ yasm_expr_destroy(sube); e->terms[i].type = YASM_EXPR_NONE; @@ -272,6 +275,65 @@ expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e) return e; } +static int +expr_xform_bc_dist_cb(yasm_expr__item *ei, yasm_bytecode *precbc, + yasm_bytecode *precbc2, /*@null@*/ void *d) +{ + yasm_intnum *dist = yasm_calc_bc_dist(precbc, precbc2); + if (!dist) + return 0; + /* Change the term to an integer */ + ei->type = YASM_EXPR_INT; + ei->data.intn = dist; + return 1; +} + +/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into integers if + * possible. + */ +static /*@only@*/ yasm_expr * +expr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e) +{ + return expr_xform_bc_dist_base(e, NULL, expr_xform_bc_dist_cb); +} + +typedef struct bc_dist_subst_cbd { + void (*callback) (unsigned int subst, yasm_bytecode *precbc, + yasm_bytecode *precbc2, void *cbd); + void *cbd; + unsigned int subst; +} bc_dist_subst_cbd; + +static int +expr_bc_dist_subst_cb(yasm_expr__item *ei, yasm_bytecode *precbc, + yasm_bytecode *precbc2, /*@null@*/ void *d) +{ + bc_dist_subst_cbd *my_cbd = d; + assert(my_cbd != NULL); + /* Call higher-level callback */ + my_cbd->callback(my_cbd->subst, precbc, precbc2, my_cbd->cbd); + /* Change the term to an subst */ + ei->type = YASM_EXPR_SUBST; + ei->data.subst = my_cbd->subst; + my_cbd->subst++; + return 1; +} + +int +yasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd, + void (*callback) (unsigned int subst, + yasm_bytecode *precbc, + yasm_bytecode *precbc2, + void *cbd)) +{ + bc_dist_subst_cbd my_cbd; /* callback info for low-level callback */ + my_cbd.callback = callback; + my_cbd.cbd = cbd; + my_cbd.subst = 0; + *ep = expr_xform_bc_dist_base(*ep, &my_cbd, expr_bc_dist_subst_cb); + return my_cbd.subst; +} + /* Negate just a single ExprItem by building a -1*ei subexpression */ static void expr_xform_neg_item(yasm_expr *e, yasm_expr__item *ei) @@ -892,6 +954,36 @@ yasm_expr__order_terms(yasm_expr *e) } } +static void +expr_item_copy(yasm_expr__item *dest, const yasm_expr__item *src) +{ + dest->type = src->type; + switch (src->type) { + case YASM_EXPR_SYM: + case YASM_EXPR_SYMEXP: + /* Symbols don't need to be copied */ + dest->data.sym = src->data.sym; + break; + case YASM_EXPR_EXPR: + dest->data.expn = yasm_expr__copy_except(src->data.expn, -1); + break; + case YASM_EXPR_INT: + dest->data.intn = yasm_intnum_copy(src->data.intn); + break; + case YASM_EXPR_FLOAT: + dest->data.flt = yasm_floatnum_copy(src->data.flt); + break; + case YASM_EXPR_REG: + dest->data.reg = src->data.reg; + break; + case YASM_EXPR_SUBST: + dest->data.subst = src->data.subst; + break; + default: + break; + } +} + /* Copy entire expression EXCEPT for index "except" at *top level only*. */ yasm_expr * yasm_expr__copy_except(const yasm_expr *e, int except) @@ -906,34 +998,8 @@ yasm_expr__copy_except(const yasm_expr *e, int except) n->line = e->line; n->numterms = e->numterms; for (i=0; inumterms; i++) { - yasm_expr__item *dest = &n->terms[i]; - const yasm_expr__item *src = &e->terms[i]; - - if (i != except) { - dest->type = src->type; - switch (src->type) { - case YASM_EXPR_SYM: - case YASM_EXPR_SYMEXP: - /* Symbols don't need to be copied */ - dest->data.sym = src->data.sym; - break; - case YASM_EXPR_EXPR: - dest->data.expn = - yasm_expr__copy_except(src->data.expn, -1); - break; - case YASM_EXPR_INT: - dest->data.intn = yasm_intnum_copy(src->data.intn); - break; - case YASM_EXPR_FLOAT: - dest->data.flt = yasm_floatnum_copy(src->data.flt); - break; - case YASM_EXPR_REG: - dest->data.reg = src->data.reg; - break; - default: - break; - } - } + if (i != except) + expr_item_copy(&n->terms[i], &e->terms[i]); } return n; @@ -992,6 +1058,33 @@ yasm_expr__contains(const yasm_expr *e, yasm_expr__type t) return yasm_expr__traverse_leaves_in_const(e, &t, expr_contains_callback); } +typedef struct subst_cbd { + unsigned int num_items; + const yasm_expr__item *items; +} subst_cbd; + +static int +expr_subst_callback(yasm_expr__item *ei, void *d) +{ + subst_cbd *cbd = d; + if (ei->type != YASM_EXPR_SUBST) + return 0; + if (ei->data.subst >= cbd->num_items) + return 1; /* error */ + expr_item_copy(ei, &cbd->items[ei->data.subst]); + return 0; +} + +int +yasm_expr__subst(yasm_expr *e, unsigned int num_items, + const yasm_expr__item *items) +{ + subst_cbd cbd; + cbd.num_items = num_items; + cbd.items = items; + return yasm_expr__traverse_leaves_in(e, &cbd, expr_subst_callback); +} + /* Traverse over expression tree, calling func for each operation AFTER the * branches (if expressions) have been traversed (eg, postorder * traversal). The data pointer d is passed to each func call. @@ -1308,6 +1401,9 @@ yasm_expr_print(const yasm_expr *e, FILE *f) /* FIXME */ /*yasm_arch_reg_print(arch, e->terms[i].data.reg, f);*/ break; + case YASM_EXPR_SUBST: + fprintf(f, "[%u]", e->terms[i].data.subst); + break; case YASM_EXPR_NONE: break; } diff --git a/libyasm/section.c b/libyasm/section.c index e5547284..c8bedbfd 100644 --- a/libyasm/section.c +++ b/libyasm/section.c @@ -46,6 +46,7 @@ #include "section.h" #include "objfmt.h" +#include "expr-int.h" #include "bc-int.h" @@ -697,7 +698,16 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level, * 3. Final pass over bytecodes to generate final offsets. */ -typedef struct yasm_span { +typedef struct yasm_span yasm_span; + +typedef struct yasm_span_term { + yasm_bytecode *precbc, *precbc2; + yasm_span *span; /* span this term is a member of */ + long cur_val, new_val; + unsigned int subst; +} yasm_span_term; + +struct yasm_span { /*@reldef@*/ STAILQ_ENTRY(yasm_span) link; /* for allocation tracking */ /*@reldef@*/ STAILQ_ENTRY(yasm_span) linkq; /* for Q */ @@ -705,6 +715,13 @@ typedef struct yasm_span { yasm_value depval; + /* span term for relative portion of value */ + yasm_span_term *rel_term; + /* span terms in absolute portion of value */ + yasm_span_term *terms; + yasm_expr__item *items; + unsigned int num_terms; + /* Special handling: see descriptions above */ enum { NOT_SPECIAL = 0, @@ -721,10 +738,11 @@ typedef struct yasm_span { int id; int active; -} yasm_span; +}; typedef struct optimize_data { - /*@reldef@*/ STAILQ_HEAD(yasm_spanhead, yasm_span) spans; + /*@reldef@*/ STAILQ_HEAD(, yasm_span) spans; + /*@reldef@*/ STAILQ_HEAD(, yasm_span) Q; } optimize_data; static void @@ -736,6 +754,10 @@ optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id, span->bc = bc; yasm_value_init_copy(&span->depval, value); + span->rel_term = NULL; + span->terms = NULL; + span->items = NULL; + span->num_terms = 0; span->special = NOT_SPECIAL; span->cur_val = 0; span->new_val = 0; @@ -747,26 +769,114 @@ optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id, STAILQ_INSERT_TAIL(&optd->spans, span, link); } -/* Recalculate span value based on current bytecode offsets. +static void +add_span_term(unsigned int subst, yasm_bytecode *precbc, + yasm_bytecode *precbc2, void *d) +{ + yasm_span *span = d; + yasm_intnum *intn; + + if (subst >= span->num_terms) { + /* Linear expansion since total number is essentially always small */ + span->num_terms = subst+1; + span->terms = yasm_xrealloc(span->terms, + span->num_terms*sizeof(yasm_span_term)); + } + span->terms[subst].precbc = precbc; + span->terms[subst].precbc2 = precbc2; + span->terms[subst].span = span; + span->terms[subst].subst = subst; + + intn = yasm_calc_bc_dist(precbc, precbc2); + if (!intn) + yasm_internal_error(N_("could not calculate bc distance")); + span->terms[subst].cur_val = 0; + span->terms[subst].new_val = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); +} + +static void +span_create_terms(yasm_span *span) +{ + unsigned int i; + yasm_intnum *intn; + + /* Split out sym-sym terms in absolute portion of dependent value */ + if (span->depval.abs) { + span->num_terms = yasm_expr__bc_dist_subst(&span->depval.abs, span, + add_span_term); + if (span->num_terms > 0) { + span->items = yasm_xmalloc(span->num_terms*sizeof(yasm_expr__item)); + for (i=0; inum_terms; i++) { + /* Create items with dummy value */ + span->items[i].type = YASM_EXPR_INT; + span->items[i].data.intn = yasm_intnum_create_int(0); + } + } + } + + /* Create term for relative portion of dependent value */ + if (span->depval.rel) { + yasm_bytecode *rel_precbc; + int sym_local; + + sym_local = yasm_symrec_get_label(span->depval.rel, &rel_precbc); + if (span->depval.wrt || span->depval.seg_of || span->depval.section_rel + || !sym_local) + return; /* we can't handle SEG, WRT, or external symbols */ + if (rel_precbc->section != span->bc->section) + return; /* not in this section */ + if (!span->depval.curpos_rel) + return; /* not PC-relative */ + + span->rel_term = yasm_xmalloc(sizeof(yasm_span_term)); + span->rel_term->precbc = rel_precbc; + span->rel_term->precbc2 = NULL; + span->rel_term->span = span; + span->rel_term->subst = ~0U; + + span->rel_term->cur_val = 0; + span->rel_term->new_val = + rel_precbc->offset + rel_precbc->len - span->bc->offset; + } +} + +/* Recalculate span value based on current span replacement values. * Returns 1 if span exceeded thresholds. */ static int recalc_normal_span(yasm_span *span) { - yasm_value val; - /*@null@*/ /*@only@*/ yasm_intnum *num; - - 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 longest form */ - span->new_val = LONG_MAX; - span->active = 0; + span->new_val = 0; + + if (span->depval.abs) { + yasm_expr *abs_copy = yasm_expr_copy(span->depval.abs); + /*@null@*/ /*@dependent@*/ yasm_intnum *num; + + /* Update sym-sym terms and substitute back into expr */ + unsigned int i; + for (i=0; inum_terms; i++) + yasm_intnum_set_int(span->items[i].data.intn, + span->terms[i].new_val); + yasm_expr__subst(abs_copy, span->num_terms, span->items); + num = yasm_expr_get_intnum(&abs_copy, 0); + if (num) + span->new_val = yasm_intnum_get_int(num); + else + span->new_val = LONG_MAX; /* too complex; force to longest form */ + yasm_expr_destroy(abs_copy); + } + + if (span->depval.rel && span->new_val != LONG_MAX) { + if (span->rel_term) { + span->new_val += span->rel_term->new_val >> span->depval.rshift; + } else + span->new_val = LONG_MAX; /* too complex; force to longest form */ } - yasm_value_delete(&val); + + if (span->new_val == LONG_MAX) + span->active = 0; + return (span->new_val < span->neg_thres || span->new_val > span->pos_thres); } @@ -823,7 +933,7 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch, yasm_span *span; long neg_thres, pos_thres; int retval; - /*@reldef@*/ STAILQ_HEAD(yasm_spanhead, yasm_span) Q; + unsigned int i; STAILQ_INIT(&optd.spans); @@ -855,6 +965,10 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch, span->bc = bc; yasm_value_initialize(&span->depval, NULL, 0); + span->rel_term = NULL; + span->terms = NULL; + span->items = NULL; + span->num_terms = 0; span->special = SPECIAL_BC_OFFSET; span->cur_val = (long)bc->offset; span->new_val = 0; @@ -890,6 +1004,7 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch, STAILQ_FOREACH(span, &optd.spans, link) { if (!span->active) continue; + span_create_terms(span); switch (span->special) { case NOT_SPECIAL: if (recalc_normal_span(span)) { @@ -930,24 +1045,43 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch, return; /* Step 1d */ - STAILQ_INIT(&Q); + STAILQ_INIT(&optd.Q); STAILQ_FOREACH(span, &optd.spans, link) { + yasm_intnum *intn; + if (!span->active) continue; + + /* Update span terms based on new bc offsets */ + for (i=0; inum_terms; i++) { + intn = yasm_calc_bc_dist(span->terms[i].precbc, + span->terms[i].precbc2); + if (!intn) + yasm_internal_error(N_("could not calculate bc distance")); + span->terms[i].cur_val = span->terms[i].new_val; + span->terms[i].new_val = yasm_intnum_get_int(intn); + yasm_intnum_destroy(intn); + } + if (span->rel_term) { + span->rel_term->cur_val = span->rel_term->new_val; + span->rel_term->new_val = span->rel_term->precbc->offset + + span->rel_term->precbc->len - span->bc->offset; + } + switch (span->special) { case NOT_SPECIAL: /* Add to interval tree */ if (recalc_normal_span(span)) { /* Exceeded threshold, add span to Q */ - STAILQ_INSERT_TAIL(&Q, span, linkq); + STAILQ_INSERT_TAIL(&optd.Q, span, linkq); } break; case SPECIAL_BC_OFFSET: /* Add to interval tree */ /* It's impossible to exceed any threshold here (as we just - * adjusted this when updating the BC offsets, so just update + * adjusted this when updating the BC offsets), so just update * span values and thresholds. */ span->new_val = (long)span->bc->offset; @@ -960,10 +1094,26 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch, } /* Step 2 */ - while (!STAILQ_EMPTY(&Q)) { + while (!STAILQ_EMPTY(&optd.Q)) { yasm_internal_error(N_("second optimization phase not implemented")); + span = STAILQ_FIRST(&optd.Q); + STAILQ_REMOVE_HEAD(&optd.Q, linkq); + 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) { + span->neg_thres = neg_thres; + span->pos_thres = pos_thres; + } else + span->active = 0; + } + if (saw_error) + return; + /* Step 3 */ update_all_bc_offsets(object, errwarns); }