New wrt optimization and improved seg optimization

- Improve seg optimization to handle deep segoffs
- Add wrt optimization that handles deep segoffs
This commit is contained in:
Jannis Harder 2012-07-27 03:18:21 +02:00
parent 90a8e215d6
commit 662fa69efc

View file

@ -846,6 +846,68 @@ expr_expand_equ(yasm_expr *e, yasm__exprhead *eh)
return e;
}
static yasm_expr *
expr_simplify_seg(yasm_expr *e)
{
yasm_expr *sube, *seg;
if (e->op != YASM_EXPR_SEG && e->op != YASM_EXPR_WRT)
return e;
if (e->terms[0].type != YASM_EXPR_EXPR)
return e;
sube = e->terms[0].data.expn;
seg = yasm_expr_extract_deep_segoff(&sube);
if (!seg)
return e;
if (e->op == YASM_EXPR_SEG) {
e->op = YASM_EXPR_IDENT;
yasm_expr_destroy(sube);
e->terms[0].data.expn = seg;
} else if (e->op == YASM_EXPR_WRT) {
yasm_expr *old_base, *new_base;
yasm_expr *wrt, *off;
unsigned long line = e->line;
off = e;
wrt = yasm_expr_extract_wrt(&off);
assert(wrt != NULL);
old_base = yasm_xmalloc(sizeof(yasm_expr));
old_base->op = YASM_EXPR_MUL;
old_base->line = line;
old_base->numterms = 2;
old_base->terms[0].type = YASM_EXPR_INT;
old_base->terms[0].data.intn = yasm_intnum_create_int(16);
old_base->terms[1].type = YASM_EXPR_EXPR;
old_base->terms[1].data.expn = seg;
new_base = yasm_xmalloc(sizeof(yasm_expr));
new_base->op = YASM_EXPR_MUL;
new_base->line = line;
new_base->numterms = 2;
new_base->terms[0].type = YASM_EXPR_INT;
new_base->terms[0].data.intn = yasm_intnum_create_int(-16);
new_base->terms[1].type = YASM_EXPR_EXPR;
new_base->terms[1].data.expn = wrt;
e = yasm_xmalloc(sizeof(yasm_expr)+sizeof(yasm_expr__item));
e->op = YASM_EXPR_ADD;
e->line = line;
e->numterms = 3;
e->terms[0].type = YASM_EXPR_EXPR;
e->terms[0].data.expn = off;
e->terms[1].type = YASM_EXPR_EXPR;
e->terms[1].data.expn = old_base;
e->terms[2].type = YASM_EXPR_EXPR;
e->terms[2].data.expn = new_base;
}
return e;
}
static yasm_expr *
expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident,
int simplify_reg_mul, int calc_bc_dist,
@ -855,6 +917,7 @@ expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident,
int i;
e = expr_xform_neg(e);
e = expr_simplify_seg(e);
/* traverse terms */
for (i=0; i<e->numterms; i++) {
@ -866,16 +929,6 @@ expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident,
expr_xform_extra, expr_xform_extra_data);
}
/* Check for SEG of SEG:OFF, if we match, simplify to just the segment */
if (e->op == YASM_EXPR_SEG && e->terms[0].type == YASM_EXPR_EXPR &&
e->terms[0].data.expn->op == YASM_EXPR_SEGOFF) {
e->op = YASM_EXPR_IDENT;
e->terms[0].data.expn->op = YASM_EXPR_IDENT;
/* Destroy the second (offset) term */
e->terms[0].data.expn->numterms = 1;
expr_delete_term(&e->terms[0].data.expn->terms[1], 1);
}
/* do callback */
e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul);
if (calc_bc_dist || expr_xform_extra) {