diff options
author | Jannis Harder <jix@jixco.de> | 2012-08-03 17:30:15 +0200 |
---|---|---|
committer | Jannis Harder <jix@jixco.de> | 2012-08-03 17:30:15 +0200 |
commit | 0341b793112d739810c48f5179306547c3424e72 (patch) | |
tree | 058751ca0ab5679cac5a51f6f561e3dc874000e4 | |
parent | c02c6c72d0eba5552b8dfe0365934cfbcf4619df (diff) | |
download | yasm-0341b793112d739810c48f5179306547c3424e72.tar.gz |
Better optimization of expr with segoffs
Lift all segoffs to the root of the tree. Combine identical segment
values while doing this.
-rw-r--r-- | libyasm/coretype.h | 1 | ||||
-rw-r--r-- | libyasm/expr.c | 61 |
2 files changed, 62 insertions, 0 deletions
diff --git a/libyasm/coretype.h b/libyasm/coretype.h index 624e3c44..c4b82cce 100644 --- a/libyasm/coretype.h +++ b/libyasm/coretype.h @@ -233,6 +233,7 @@ typedef enum yasm_expr_op { YASM_EXPR_NOR, /**< Bitwise NOR. */ YASM_EXPR_SHL, /**< Shift left (logical). */ YASM_EXPR_SHR, /**< Shift right (logical). */ + YASM_EXPR_LOGIC, /**< Start of logic operations (not an op). */ YASM_EXPR_LOR, /**< Logical OR. */ YASM_EXPR_LAND, /**< Logical AND. */ YASM_EXPR_LNOT, /**< Logical negation. */ diff --git a/libyasm/expr.c b/libyasm/expr.c index fa817ebd..1aad79df 100644 --- a/libyasm/expr.c +++ b/libyasm/expr.c @@ -909,12 +909,65 @@ expr_simplify_seg(yasm_expr *e) } static yasm_expr * +expr_lift_segoff(yasm_expr *e, int calc_bc_dist) +{ + yasm_expr *retval = NULL; + int i; + + if (e->op < YASM_EXPR_LOGIC || e->op == YASM_EXPR_SEGOFF) { + i = e->op == YASM_EXPR_SEGOFF ? 1 : 0; + for (; i<e->numterms; i++) { + if (e->terms[i].type == YASM_EXPR_EXPR && + e->terms[i].data.expn->op == YASM_EXPR_SEGOFF) { + yasm_expr *sub = e->terms[i].data.expn; + e->terms[i] = sub->terms[1]; + retval = sub; + retval->op = YASM_EXPR_SEGOFF; + retval->line = e->line; + retval->numterms = 2; + break; + } + } + } + + if (retval != NULL && e->op == YASM_EXPR_SEGOFF) { + yasm_intnum *diff; + yasm_expr *helper; + e->op = YASM_EXPR_IDENT; + e->numterms = 1; + retval->op = YASM_EXPR_IDENT; + retval->numterms = 1; + helper = yasm_xmalloc(sizeof(yasm_expr)); + helper->op = YASM_EXPR_SUB; + helper->numterms = 2; + helper->terms[0].type = YASM_EXPR_EXPR; + helper->terms[0].data.expn = yasm_expr_copy(e); + helper->terms[1].type = YASM_EXPR_EXPR; + helper->terms[1].data.expn = yasm_expr_copy(retval); + diff = yasm_expr_get_intnum(&helper, calc_bc_dist); + if (diff != NULL && yasm_intnum_is_zero(diff)) { + yasm_expr_destroy(retval); + retval = NULL; + } else { + retval->op = YASM_EXPR_SEGOFF; + retval->numterms = 2; + } + yasm_expr_destroy(helper); + e->op = YASM_EXPR_SEGOFF; + e->numterms = 2; + } + + return retval; +} + +static yasm_expr * expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident, int simplify_reg_mul, int calc_bc_dist, yasm_expr_xform_func expr_xform_extra, void *expr_xform_extra_data) { int i; + yasm_expr *seg; e = expr_xform_neg(e); e = expr_simplify_seg(e); @@ -931,6 +984,9 @@ expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident, /* do callback */ e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul); + seg = expr_lift_segoff(e, calc_bc_dist); + if (seg) + e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul); if (calc_bc_dist || expr_xform_extra) { if (calc_bc_dist) e = expr_xform_bc_dist(e); @@ -939,6 +995,11 @@ expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident, e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul, 0, NULL, NULL); } + if (seg) { + seg->terms[1].type = YASM_EXPR_EXPR; + seg->terms[1].data.expn = e; + e = seg; + } return e; } |