aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/yasm/libyasm/expr.c
diff options
context:
space:
mode:
authorsomov <somov@yandex-team.ru>2022-02-10 16:45:47 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:47 +0300
commita5950576e397b1909261050b8c7da16db58f10b1 (patch)
tree7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/libyasm/expr.c
parent81eddc8c0b55990194e112b02d127b87d54164a9 (diff)
downloadydb-a5950576e397b1909261050b8c7da16db58f10b1.tar.gz
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/yasm/libyasm/expr.c')
-rw-r--r--contrib/tools/yasm/libyasm/expr.c3032
1 files changed, 1516 insertions, 1516 deletions
diff --git a/contrib/tools/yasm/libyasm/expr.c b/contrib/tools/yasm/libyasm/expr.c
index c2c868ede28..4c9958449d6 100644
--- a/contrib/tools/yasm/libyasm/expr.c
+++ b/contrib/tools/yasm/libyasm/expr.c
@@ -1,1516 +1,1516 @@
-/*
- * Expression handling
- *
- * Copyright (C) 2001-2007 Michael Urman, 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"
-
-#include "libyasm-stdint.h"
-#include "coretype.h"
-#include "bitvect.h"
-
-#include "errwarn.h"
-#include "intnum.h"
-#include "floatnum.h"
-#include "expr.h"
-#include "symrec.h"
-
-#include "bytecode.h"
-#include "section.h"
-
-#include "arch.h"
-
-
-static /*@only@*/ yasm_expr *expr_level_op
- (/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
- int simplify_ident, int simplify_reg_mul);
-static int expr_traverse_nodes_post(/*@null@*/ yasm_expr *e,
- /*@null@*/ void *d,
- int (*func) (/*@null@*/ yasm_expr *e,
- /*@null@*/ void *d));
-static void expr_delete_term(yasm_expr__item *term, int recurse);
-
-/* Bitmap of used items. We should really never need more than 2 at a time,
- * so 31 is pretty much overkill.
- */
-static unsigned long itempool_used = 0;
-static yasm_expr__item itempool[31];
-
-/* allocate a new expression node, with children as defined.
- * If it's a unary operator, put the element in left and set right=NULL. */
-/*@-compmempass@*/
-yasm_expr *
-yasm_expr_create(yasm_expr_op op, yasm_expr__item *left,
- yasm_expr__item *right, unsigned long line)
-{
- yasm_expr *ptr, *sube;
- unsigned long z;
- ptr = yasm_xmalloc(sizeof(yasm_expr));
-
- ptr->op = op;
- ptr->numterms = 0;
- ptr->terms[0].type = YASM_EXPR_NONE;
- ptr->terms[1].type = YASM_EXPR_NONE;
- if (left) {
- ptr->terms[0] = *left; /* structure copy */
- z = (unsigned long)(left-itempool);
- if (z>=31)
- yasm_internal_error(N_("could not find expritem in pool"));
- itempool_used &= ~(1<<z);
- ptr->numterms++;
-
- /* Search downward until we find something *other* than an
- * IDENT, then bring it up to the current level.
- */
- while (ptr->terms[0].type == YASM_EXPR_EXPR &&
- ptr->terms[0].data.expn->op == YASM_EXPR_IDENT) {
- sube = ptr->terms[0].data.expn;
- ptr->terms[0] = sube->terms[0]; /* structure copy */
- /*@-usereleased@*/
- yasm_xfree(sube);
- /*@=usereleased@*/
- }
- } else {
- yasm_internal_error(N_("Right side of expression must exist"));
- }
-
- if (right) {
- ptr->terms[1] = *right; /* structure copy */
- z = (unsigned long)(right-itempool);
- if (z>=31)
- yasm_internal_error(N_("could not find expritem in pool"));
- itempool_used &= ~(1<<z);
- ptr->numterms++;
-
- /* Search downward until we find something *other* than an
- * IDENT, then bring it up to the current level.
- */
- while (ptr->terms[1].type == YASM_EXPR_EXPR &&
- ptr->terms[1].data.expn->op == YASM_EXPR_IDENT) {
- sube = ptr->terms[1].data.expn;
- ptr->terms[1] = sube->terms[0]; /* structure copy */
- /*@-usereleased@*/
- yasm_xfree(sube);
- /*@=usereleased@*/
- }
- }
-
- ptr->line = line;
-
- return expr_level_op(ptr, 1, 1, 0);
-}
-/*@=compmempass@*/
-
-/* helpers */
-static yasm_expr__item *
-expr_get_item(void)
-{
- int z = 0;
- unsigned long v = itempool_used & 0x7fffffff;
-
- while (v & 1) {
- v >>= 1;
- z++;
- }
- if (z>=31)
- yasm_internal_error(N_("too many expritems"));
- itempool_used |= 1<<z;
- return &itempool[z];
-}
-
-yasm_expr__item *
-yasm_expr_precbc(yasm_bytecode *precbc)
-{
- yasm_expr__item *e = expr_get_item();
- e->type = YASM_EXPR_PRECBC;
- e->data.precbc = precbc;
- return e;
-}
-
-yasm_expr__item *
-yasm_expr_sym(yasm_symrec *s)
-{
- yasm_expr__item *e = expr_get_item();
- e->type = YASM_EXPR_SYM;
- e->data.sym = s;
- return e;
-}
-
-yasm_expr__item *
-yasm_expr_expr(yasm_expr *x)
-{
- yasm_expr__item *e = expr_get_item();
- e->type = YASM_EXPR_EXPR;
- e->data.expn = x;
- return e;
-}
-
-yasm_expr__item *
-yasm_expr_int(yasm_intnum *i)
-{
- yasm_expr__item *e = expr_get_item();
- e->type = YASM_EXPR_INT;
- e->data.intn = i;
- return e;
-}
-
-yasm_expr__item *
-yasm_expr_float(yasm_floatnum *f)
-{
- yasm_expr__item *e = expr_get_item();
- e->type = YASM_EXPR_FLOAT;
- e->data.flt = f;
- return e;
-}
-
-yasm_expr__item *
-yasm_expr_reg(uintptr_t reg)
-{
- yasm_expr__item *e = expr_get_item();
- e->type = YASM_EXPR_REG;
- e->data.reg = reg;
- return e;
-}
-
-/* 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. Also works for precbc-precbc (or symrec-precbc,
- * precbc-symrec).
- */
-static /*@only@*/ yasm_expr *
-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;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- int numterms;
-
- /* Handle symrec-symrec in ADD exprs by looking for (-1*symrec) and
- * symrec term pairs (where both symrecs are in the same segment).
- */
- if (e->op != YASM_EXPR_ADD)
- return e;
-
- for (i=0; i<e->numterms; i++) {
- int j;
- yasm_expr *sube;
- yasm_intnum *intn;
- yasm_symrec *sym = NULL;
- /*@dependent@*/ yasm_section *sect2;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
-
- /* First look for an (-1*symrec) term */
- if (e->terms[i].type != YASM_EXPR_EXPR)
- continue;
- sube = e->terms[i].data.expn;
- if (sube->op != YASM_EXPR_MUL || sube->numterms != 2)
- continue;
-
- if (sube->terms[0].type == YASM_EXPR_INT &&
- (sube->terms[1].type == YASM_EXPR_SYM ||
- sube->terms[1].type == YASM_EXPR_PRECBC)) {
- intn = sube->terms[0].data.intn;
- if (sube->terms[1].type == YASM_EXPR_PRECBC)
- precbc = sube->terms[1].data.precbc;
- else
- sym = sube->terms[1].data.sym;
- } else if ((sube->terms[0].type == YASM_EXPR_SYM ||
- sube->terms[0].type == YASM_EXPR_PRECBC) &&
- sube->terms[1].type == YASM_EXPR_INT) {
- if (sube->terms[0].type == YASM_EXPR_PRECBC)
- precbc = sube->terms[0].data.precbc;
- else
- sym = sube->terms[0].data.sym;
- intn = sube->terms[1].data.intn;
- } else
- continue;
-
- if (!yasm_intnum_is_neg1(intn))
- continue;
-
- if (sym && !yasm_symrec_get_label(sym, &precbc))
- continue;
- sect2 = yasm_bc_get_section(precbc);
-
- /* Now look for a symrec term in the same segment */
- for (j=0; j<e->numterms; j++) {
- if (((e->terms[j].type == YASM_EXPR_SYM &&
- yasm_symrec_get_label(e->terms[j].data.sym, &precbc2)) ||
- (e->terms[j].type == YASM_EXPR_PRECBC &&
- (precbc2 = e->terms[j].data.precbc))) &&
- (sect = yasm_bc_get_section(precbc2)) &&
- sect == sect2 &&
- callback(&e->terms[j], precbc, precbc2, cbd)) {
- /* Delete the matching (-1*symrec) term */
- yasm_expr_destroy(sube);
- e->terms[i].type = YASM_EXPR_NONE;
- break; /* stop looking for matching symrec term */
- }
- }
- }
-
- /* Clean up any deleted (EXPR_NONE) terms */
- numterms = 0;
- for (i=0; i<e->numterms; i++) {
- if (e->terms[i].type != YASM_EXPR_NONE)
- e->terms[numterms++] = e->terms[i]; /* structure copy */
- }
- if (e->numterms != numterms) {
- e->numterms = numterms;
- e = yasm_xrealloc(e, sizeof(yasm_expr)+((numterms<2) ? 0 :
- sizeof(yasm_expr__item)*(numterms-2)));
- if (numterms == 1)
- e->op = YASM_EXPR_IDENT;
- }
-
- 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;
-}
-
-static yasm_expr *
-expr_xform_bc_dist_subst(yasm_expr *e, void *d)
-{
- return expr_xform_bc_dist_base(e, d, expr_bc_dist_subst_cb);
-}
-
-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 = yasm_expr__level_tree(*ep, 1, 1, 1, 0, &expr_xform_bc_dist_subst,
- &my_cbd);
- 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)
-{
- yasm_expr *sube = yasm_xmalloc(sizeof(yasm_expr));
-
- /* Build -1*ei subexpression */
- sube->op = YASM_EXPR_MUL;
- sube->line = e->line;
- sube->numterms = 2;
- sube->terms[0].type = YASM_EXPR_INT;
- sube->terms[0].data.intn = yasm_intnum_create_int(-1);
- sube->terms[1] = *ei; /* structure copy */
-
- /* Replace original ExprItem with subexp */
- ei->type = YASM_EXPR_EXPR;
- ei->data.expn = sube;
-}
-
-/* Negates e by multiplying by -1, with distribution over lower-precedence
- * operators (eg ADD) and special handling to simplify result w/ADD, NEG, and
- * others.
- *
- * Returns a possibly reallocated e.
- */
-static /*@only@*/ yasm_expr *
-expr_xform_neg_helper(/*@returned@*/ /*@only@*/ yasm_expr *e)
-{
- yasm_expr *ne;
- int i;
-
- switch (e->op) {
- case YASM_EXPR_ADD:
- /* distribute (recursively if expr) over terms */
- for (i=0; i<e->numterms; i++) {
- if (e->terms[i].type == YASM_EXPR_EXPR)
- e->terms[i].data.expn =
- expr_xform_neg_helper(e->terms[i].data.expn);
- else
- expr_xform_neg_item(e, &e->terms[i]);
- }
- break;
- case YASM_EXPR_SUB:
- /* change op to ADD, and recursively negate left side (if expr) */
- e->op = YASM_EXPR_ADD;
- if (e->terms[0].type == YASM_EXPR_EXPR)
- e->terms[0].data.expn =
- expr_xform_neg_helper(e->terms[0].data.expn);
- else
- expr_xform_neg_item(e, &e->terms[0]);
- break;
- case YASM_EXPR_NEG:
- /* Negating a negated value? Make it an IDENT. */
- e->op = YASM_EXPR_IDENT;
- break;
- case YASM_EXPR_IDENT:
- /* Negating an ident? Change it into a MUL w/ -1 if there's no
- * floatnums present below; if there ARE floatnums, recurse.
- */
- if (e->terms[0].type == YASM_EXPR_FLOAT)
- yasm_floatnum_calc(e->terms[0].data.flt, YASM_EXPR_NEG, NULL);
- else if (e->terms[0].type == YASM_EXPR_INT)
- yasm_intnum_calc(e->terms[0].data.intn, YASM_EXPR_NEG, NULL);
- else if (e->terms[0].type == YASM_EXPR_EXPR &&
- yasm_expr__contains(e->terms[0].data.expn, YASM_EXPR_FLOAT))
- expr_xform_neg_helper(e->terms[0].data.expn);
- else {
- e->op = YASM_EXPR_MUL;
- e->numterms = 2;
- e->terms[1].type = YASM_EXPR_INT;
- e->terms[1].data.intn = yasm_intnum_create_int(-1);
- }
- break;
- default:
- /* Everything else. MUL will be combined when it's leveled.
- * Make a new expr (to replace e) with -1*e.
- */
- ne = yasm_xmalloc(sizeof(yasm_expr));
- ne->op = YASM_EXPR_MUL;
- ne->line = e->line;
- ne->numterms = 2;
- ne->terms[0].type = YASM_EXPR_INT;
- ne->terms[0].data.intn = yasm_intnum_create_int(-1);
- ne->terms[1].type = YASM_EXPR_EXPR;
- ne->terms[1].data.expn = e;
- return ne;
- }
- return e;
-}
-
-/* Transforms negatives into expressions that are easier to combine:
- * -x -> -1*x
- * a-b -> a+(-1*b)
- *
- * Call post-order on an expression tree to transform the entire tree.
- *
- * Returns a possibly reallocated e.
- */
-static /*@only@*/ yasm_expr *
-expr_xform_neg(/*@returned@*/ /*@only@*/ yasm_expr *e)
-{
- switch (e->op) {
- case YASM_EXPR_NEG:
- /* Turn -x into -1*x */
- e->op = YASM_EXPR_IDENT;
- return expr_xform_neg_helper(e);
- case YASM_EXPR_SUB:
- /* Turn a-b into a+(-1*b) */
-
- /* change op to ADD, and recursively negate right side (if expr) */
- e->op = YASM_EXPR_ADD;
- if (e->terms[1].type == YASM_EXPR_EXPR)
- e->terms[1].data.expn =
- expr_xform_neg_helper(e->terms[1].data.expn);
- else
- expr_xform_neg_item(e, &e->terms[1]);
- break;
- default:
- break;
- }
-
- return e;
-}
-
-/* Look for simple identities that make the entire result constant:
- * 0*&x, -1|x, etc.
- */
-static int
-expr_is_constant(yasm_expr_op op, yasm_intnum *intn)
-{
- int iszero = yasm_intnum_is_zero(intn);
- return ((iszero && op == YASM_EXPR_MUL) ||
- (iszero && op == YASM_EXPR_AND) ||
- (iszero && op == YASM_EXPR_LAND) ||
- (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_OR));
-}
-
-/* Look for simple "left" identities like 0+x, 1*x, etc. */
-static int
-expr_can_destroy_int_left(yasm_expr_op op, yasm_intnum *intn)
-{
- int iszero = yasm_intnum_is_zero(intn);
- return ((yasm_intnum_is_pos1(intn) && op == YASM_EXPR_MUL) ||
- (iszero && op == YASM_EXPR_ADD) ||
- (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) ||
- (!iszero && op == YASM_EXPR_LAND) ||
- (iszero && op == YASM_EXPR_OR) ||
- (iszero && op == YASM_EXPR_LOR));
-}
-
-/* Look for simple "right" identities like x+|-0, x*&/1 */
-static int
-expr_can_destroy_int_right(yasm_expr_op op, yasm_intnum *intn)
-{
- int iszero = yasm_intnum_is_zero(intn);
- int ispos1 = yasm_intnum_is_pos1(intn);
- return ((ispos1 && op == YASM_EXPR_MUL) ||
- (ispos1 && op == YASM_EXPR_DIV) ||
- (iszero && op == YASM_EXPR_ADD) ||
- (iszero && op == YASM_EXPR_SUB) ||
- (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) ||
- (!iszero && op == YASM_EXPR_LAND) ||
- (iszero && op == YASM_EXPR_OR) ||
- (iszero && op == YASM_EXPR_LOR) ||
- (iszero && op == YASM_EXPR_SHL) ||
- (iszero && op == YASM_EXPR_SHR));
-}
-
-/* Check for and simplify identities. Returns new number of expr terms.
- * Sets e->op = EXPR_IDENT if numterms ends up being 1.
- * Uses numterms parameter instead of e->numterms for basis of "new" number
- * of terms.
- * Assumes int_term is *only* integer term in e.
- * NOTE: Really designed to only be used by expr_level_op().
- */
-static int
-expr_simplify_identity(yasm_expr *e, int numterms, int *int_term,
- int simplify_reg_mul)
-{
- int i;
- int save_numterms;
-
- /* Don't do this step if it's 1*REG. Save and restore numterms so
- * yasm_expr__contains() works correctly.
- */
- save_numterms = e->numterms;
- e->numterms = numterms;
- if (simplify_reg_mul || e->op != YASM_EXPR_MUL
- || !yasm_intnum_is_pos1(e->terms[*int_term].data.intn)
- || !yasm_expr__contains(e, YASM_EXPR_REG)) {
- /* Check for simple identities that delete the intnum.
- * Don't delete if the intnum is the only thing in the expn.
- */
- if ((*int_term == 0 && numterms > 1 &&
- expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) ||
- (*int_term > 0 &&
- expr_can_destroy_int_right(e->op,
- e->terms[*int_term].data.intn))) {
- /* Delete the intnum */
- yasm_intnum_destroy(e->terms[*int_term].data.intn);
-
- /* Slide everything to its right over by 1 */
- if (*int_term != numterms-1) /* if it wasn't last.. */
- memmove(&e->terms[*int_term], &e->terms[*int_term+1],
- (numterms-1-*int_term)*sizeof(yasm_expr__item));
-
- /* Update numterms */
- numterms--;
- *int_term = -1; /* no longer an int term */
- }
- }
- e->numterms = save_numterms;
-
- /* Check for simple identites that delete everything BUT the intnum.
- * Don't bother if the intnum is the only thing in the expn.
- */
- if (numterms > 1 && *int_term != -1 &&
- expr_is_constant(e->op, e->terms[*int_term].data.intn)) {
- /* Loop through, deleting everything but the integer term */
- for (i=0; i<e->numterms; i++)
- if (i != *int_term)
- expr_delete_term(&e->terms[i], 1);
-
- /* Move integer term to the first term (if not already there) */
- if (*int_term != 0)
- e->terms[0] = e->terms[*int_term]; /* structure copy */
-
- /* Set numterms to 1 */
- numterms = 1;
- }
-
- /* Compute NOT, NEG, and LNOT on single intnum. */
- if (numterms == 1 && *int_term == 0 &&
- (e->op == YASM_EXPR_NOT || e->op == YASM_EXPR_NEG ||
- e->op == YASM_EXPR_LNOT))
- yasm_intnum_calc(e->terms[0].data.intn, e->op, NULL);
-
- /* Change expression to IDENT if possible. */
- if (numterms == 1)
- e->op = YASM_EXPR_IDENT;
-
- /* Return the updated numterms */
- return numterms;
-}
-
-/* Levels the expression tree starting at e. Eg:
- * a+(b+c) -> a+b+c
- * (a+b)+(c+d) -> a+b+c+d
- * Naturally, only levels operators that allow more than two operand terms.
- * NOTE: only does *one* level of leveling (no recursion). Should be called
- * post-order on a tree to combine deeper levels.
- * Also brings up any IDENT values into the current level (for ALL operators).
- * Folds (combines by evaluation) *integer* constant values if fold_const != 0.
- *
- * Returns a possibly reallocated e.
- */
-/*@-mustfree@*/
-static /*@only@*/ yasm_expr *
-expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
- int simplify_ident, int simplify_reg_mul)
-{
- int i, j, o, fold_numterms, level_numterms, level_fold_numterms;
- int first_int_term = -1;
-
- /* Determine how many operands will need to be brought up (for leveling).
- * Go ahead and bring up any IDENT'ed values.
- */
- while (e->op == YASM_EXPR_IDENT && e->terms[0].type == YASM_EXPR_EXPR) {
- yasm_expr *sube = e->terms[0].data.expn;
- yasm_xfree(e);
- e = sube;
- }
-
- /* If non-numeric expression, don't fold constants. */
- if (e->op > YASM_EXPR_NONNUM)
- fold_const = 0;
-
- level_numterms = e->numterms;
- level_fold_numterms = 0;
- for (i=0; i<e->numterms; i++) {
- /* Search downward until we find something *other* than an
- * IDENT, then bring it up to the current level.
- */
- while (e->terms[i].type == YASM_EXPR_EXPR &&
- e->terms[i].data.expn->op == YASM_EXPR_IDENT) {
- yasm_expr *sube = e->terms[i].data.expn;
- e->terms[i] = sube->terms[0];
- yasm_xfree(sube);
- }
-
- if (e->terms[i].type == YASM_EXPR_EXPR &&
- e->terms[i].data.expn->op == e->op) {
- /* It's an expression w/the same operator, add in its numterms.
- * But don't forget to subtract one for the expr itself!
- */
- level_numterms += e->terms[i].data.expn->numterms - 1;
-
- /* If we're folding constants, count up the number of constants
- * that will be merged in.
- */
- if (fold_const)
- for (j=0; j<e->terms[i].data.expn->numterms; j++)
- if (e->terms[i].data.expn->terms[j].type ==
- YASM_EXPR_INT)
- level_fold_numterms++;
- }
-
- /* Find the first integer term (if one is present) if we're folding
- * constants.
- */
- if (fold_const && first_int_term == -1 &&
- e->terms[i].type == YASM_EXPR_INT)
- first_int_term = i;
- }
-
- /* Look for other integer terms if there's one and combine.
- * Also eliminate empty spaces when combining and adjust numterms
- * variables.
- */
- fold_numterms = e->numterms;
- if (first_int_term != -1) {
- for (i=first_int_term+1, o=first_int_term+1; i<e->numterms; i++) {
- if (e->terms[i].type == YASM_EXPR_INT) {
- yasm_intnum_calc(e->terms[first_int_term].data.intn, e->op,
- e->terms[i].data.intn);
- fold_numterms--;
- level_numterms--;
- /* make sure to delete folded intnum */
- yasm_intnum_destroy(e->terms[i].data.intn);
- } else if (o != i) {
- /* copy term if it changed places */
- e->terms[o++] = e->terms[i];
- } else
- o++;
- }
-
- if (simplify_ident) {
- int new_fold_numterms;
- /* Simplify identities and make IDENT if possible. */
- new_fold_numterms =
- expr_simplify_identity(e, fold_numterms, &first_int_term,
- simplify_reg_mul);
- level_numterms -= fold_numterms-new_fold_numterms;
- fold_numterms = new_fold_numterms;
- }
- if (fold_numterms == 1)
- e->op = YASM_EXPR_IDENT;
- }
-
- /* Only level operators that allow more than two operand terms.
- * Also don't bother leveling if it's not necessary to bring up any terms.
- */
- if ((e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL &&
- e->op != YASM_EXPR_OR && e->op != YASM_EXPR_AND &&
- e->op != YASM_EXPR_LOR && e->op != YASM_EXPR_LAND &&
- e->op != YASM_EXPR_LXOR && e->op != YASM_EXPR_XOR) ||
- level_numterms <= fold_numterms) {
- /* Downsize e if necessary */
- if (fold_numterms < e->numterms && e->numterms > 2)
- e = yasm_xrealloc(e, sizeof(yasm_expr)+((fold_numterms<2) ? 0 :
- sizeof(yasm_expr__item)*(fold_numterms-2)));
- /* Update numterms */
- e->numterms = fold_numterms;
- return e;
- }
-
- /* Adjust numterms for constant folding from terms being "pulled up".
- * Careful: if there's no integer term in e, then save space for it.
- */
- if (fold_const) {
- level_numterms -= level_fold_numterms;
- if (first_int_term == -1 && level_fold_numterms != 0)
- level_numterms++;
- }
-
- /* Alloc more (or conceivably less, but not usually) space for e */
- e = yasm_xrealloc(e, sizeof(yasm_expr)+((level_numterms<2) ? 0 :
- sizeof(yasm_expr__item)*(level_numterms-2)));
-
- /* Copy up ExprItem's. Iterate from right to left to keep the same
- * ordering as was present originally.
- * Combine integer terms as necessary.
- */
- for (i=fold_numterms-1, o=level_numterms-1; i>=0; i--) {
- if (e->terms[i].type == YASM_EXPR_EXPR &&
- e->terms[i].data.expn->op == e->op) {
- /* bring up subexpression */
- yasm_expr *sube = e->terms[i].data.expn;
-
- /* copy terms right to left */
- for (j=sube->numterms-1; j>=0; j--) {
- if (fold_const && sube->terms[j].type == YASM_EXPR_INT) {
- /* Need to fold it in.. but if there's no int term already,
- * just copy into a new one.
- */
- if (first_int_term == -1) {
- first_int_term = o--;
- e->terms[first_int_term] = sube->terms[j]; /* struc */
- } else {
- yasm_intnum_calc(e->terms[first_int_term].data.intn,
- e->op, sube->terms[j].data.intn);
- /* make sure to delete folded intnum */
- yasm_intnum_destroy(sube->terms[j].data.intn);
- }
- } else {
- if (o == first_int_term)
- o--;
- e->terms[o--] = sube->terms[j]; /* structure copy */
- }
- }
-
- /* delete subexpression, but *don't delete nodes* (as we've just
- * copied them!)
- */
- yasm_xfree(sube);
- } else if (o != i) {
- /* copy operand if it changed places */
- if (o == first_int_term)
- o--;
- e->terms[o] = e->terms[i];
- /* If we moved the first_int_term, change first_int_num too */
- if (i == first_int_term)
- first_int_term = o;
- o--;
- } else
- o--;
- }
-
- /* Simplify identities, make IDENT if possible, and save to e->numterms. */
- if (simplify_ident && first_int_term != -1) {
- e->numterms = expr_simplify_identity(e, level_numterms,
- &first_int_term, simplify_reg_mul);
- } else {
- e->numterms = level_numterms;
- if (level_numterms == 1)
- e->op = YASM_EXPR_IDENT;
- }
-
- return e;
-}
-/*@=mustfree@*/
-
-typedef SLIST_HEAD(yasm__exprhead, yasm__exprentry) yasm__exprhead;
-typedef struct yasm__exprentry {
- /*@reldef@*/ SLIST_ENTRY(yasm__exprentry) next;
- /*@null@*/ const yasm_expr *e;
-} yasm__exprentry;
-
-static yasm_expr *
-expr_expand_equ(yasm_expr *e, yasm__exprhead *eh)
-{
- int i;
- yasm__exprentry ee;
-
- /* traverse terms */
- for (i=0; i<e->numterms; i++) {
- const yasm_expr *equ_expr;
-
- /* Expand equ's. */
- if (e->terms[i].type == YASM_EXPR_SYM &&
- (equ_expr = yasm_symrec_get_equ(e->terms[i].data.sym))) {
- yasm__exprentry *np;
-
- /* Check for circular reference */
- SLIST_FOREACH(np, eh, next) {
- if (np->e == equ_expr) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("circular reference detected"));
- return e;
- }
- }
-
- e->terms[i].type = YASM_EXPR_EXPR;
- e->terms[i].data.expn = yasm_expr_copy(equ_expr);
-
- /* Remember we saw this equ and recurse */
- ee.e = equ_expr;
- SLIST_INSERT_HEAD(eh, &ee, next);
- e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh);
- SLIST_REMOVE_HEAD(eh, next);
- } else if (e->terms[i].type == YASM_EXPR_EXPR)
- /* Recurse */
- e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh);
- }
-
- 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,
- yasm_expr_xform_func expr_xform_extra,
- void *expr_xform_extra_data)
-{
- int i;
-
- e = expr_xform_neg(e);
-
- /* traverse terms */
- for (i=0; i<e->numterms; i++) {
- /* Recurse */
- if (e->terms[i].type == YASM_EXPR_EXPR)
- e->terms[i].data.expn =
- expr_level_tree(e->terms[i].data.expn, fold_const,
- simplify_ident, simplify_reg_mul, calc_bc_dist,
- 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) {
- if (calc_bc_dist)
- e = expr_xform_bc_dist(e);
- if (expr_xform_extra)
- e = expr_xform_extra(e, expr_xform_extra_data);
- e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul,
- 0, NULL, NULL);
- }
- return e;
-}
-
-/* Level an entire expn tree, expanding equ's as we go */
-yasm_expr *
-yasm_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)
-{
- yasm__exprhead eh;
- SLIST_INIT(&eh);
-
- if (!e)
- return 0;
-
- e = expr_expand_equ(e, &eh);
- e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul,
- calc_bc_dist, expr_xform_extra, expr_xform_extra_data);
-
- return e;
-}
-
-/* Comparison function for expr_order_terms().
- * Assumes ExprType enum is in canonical order.
- */
-static int
-expr_order_terms_compare(const void *va, const void *vb)
-{
- const yasm_expr__item *a = va, *b = vb;
- return (a->type - b->type);
-}
-
-/* Reorder terms of e into canonical order. Only reorders if reordering
- * doesn't change meaning of expression. (eg, doesn't reorder SUB).
- * Canonical order: REG, INT, FLOAT, SYM, EXPR.
- * Multiple terms of a single type are kept in the same order as in
- * the original expression.
- * NOTE: Only performs reordering on *one* level (no recursion).
- */
-void
-yasm_expr__order_terms(yasm_expr *e)
-{
- /* don't bother reordering if only one element */
- if (e->numterms == 1)
- return;
-
- /* only reorder some types of operations */
- switch (e->op) {
- case YASM_EXPR_ADD:
- case YASM_EXPR_MUL:
- case YASM_EXPR_OR:
- case YASM_EXPR_AND:
- case YASM_EXPR_XOR:
- case YASM_EXPR_LOR:
- case YASM_EXPR_LAND:
- case YASM_EXPR_LXOR:
- /* Use mergesort to sort. It's fast on already sorted values and a
- * stable sort (multiple terms of same type are kept in the same
- * order).
- */
- yasm__mergesort(e->terms, (size_t)e->numterms,
- sizeof(yasm_expr__item), expr_order_terms_compare);
- break;
- default:
- break;
- }
-}
-
-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:
- /* Symbols don't need to be copied */
- dest->data.sym = src->data.sym;
- break;
- case YASM_EXPR_PRECBC:
- /* Nor do direct bytecode references */
- dest->data.precbc = src->data.precbc;
- 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)
-{
- yasm_expr *n;
- int i;
-
- n = yasm_xmalloc(sizeof(yasm_expr) +
- sizeof(yasm_expr__item)*(e->numterms<2?0:e->numterms-2));
-
- n->op = e->op;
- n->line = e->line;
- n->numterms = e->numterms;
- for (i=0; i<e->numterms; i++) {
- if (i != except)
- expr_item_copy(&n->terms[i], &e->terms[i]);
- }
-
- return n;
-}
-
-static void
-expr_delete_term(yasm_expr__item *term, int recurse)
-{
- switch (term->type) {
- case YASM_EXPR_INT:
- yasm_intnum_destroy(term->data.intn);
- break;
- case YASM_EXPR_FLOAT:
- yasm_floatnum_destroy(term->data.flt);
- break;
- case YASM_EXPR_EXPR:
- if (recurse)
- yasm_expr_destroy(term->data.expn);
- break;
- default:
- break;
- }
-}
-
-static int
-expr_destroy_each(/*@only@*/ yasm_expr *e, /*@unused@*/ void *d)
-{
- int i;
- for (i=0; i<e->numterms; i++)
- expr_delete_term(&e->terms[i], 0);
- yasm_xfree(e); /* free ourselves */
- return 0; /* don't stop recursion */
-}
-
-/*@-mustfree@*/
-void
-yasm_expr_destroy(yasm_expr *e)
-{
- expr_traverse_nodes_post(e, NULL, expr_destroy_each);
-}
-/*@=mustfree@*/
-
-int
-yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op)
-{
- return (e->op == op);
-}
-
-static int
-expr_contains_callback(const yasm_expr__item *ei, void *d)
-{
- yasm_expr__type *t = d;
- return (ei->type & *t);
-}
-
-int
-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.
- *
- * Stops early (and returns 1) if func returns 1. Otherwise returns 0.
- */
-static int
-expr_traverse_nodes_post(yasm_expr *e, void *d,
- int (*func) (/*@null@*/ yasm_expr *e,
- /*@null@*/ void *d))
-{
- int i;
-
- if (!e)
- return 0;
-
- /* traverse terms */
- for (i=0; i<e->numterms; i++) {
- if (e->terms[i].type == YASM_EXPR_EXPR &&
- expr_traverse_nodes_post(e->terms[i].data.expn, d, func))
- return 1;
- }
-
- /* do callback */
- return func(e, d);
-}
-
-/* Traverse over expression tree in order, calling func for each leaf
- * (non-operation). The data pointer d is passed to each func call.
- *
- * Stops early (and returns 1) if func returns 1. Otherwise returns 0.
- */
-int
-yasm_expr__traverse_leaves_in_const(const yasm_expr *e, void *d,
- int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d))
-{
- int i;
-
- if (!e)
- return 0;
-
- for (i=0; i<e->numterms; i++) {
- if (e->terms[i].type == YASM_EXPR_EXPR) {
- if (yasm_expr__traverse_leaves_in_const(e->terms[i].data.expn, d,
- func))
- return 1;
- } else {
- if (func(&e->terms[i], d))
- return 1;
- }
- }
- return 0;
-}
-
-/* Traverse over expression tree in order, calling func for each leaf
- * (non-operation). The data pointer d is passed to each func call.
- *
- * Stops early (and returns 1) if func returns 1. Otherwise returns 0.
- */
-int
-yasm_expr__traverse_leaves_in(yasm_expr *e, void *d,
- int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d))
-{
- int i;
-
- if (!e)
- return 0;
-
- for (i=0; i<e->numterms; i++) {
- if (e->terms[i].type == YASM_EXPR_EXPR) {
- if (yasm_expr__traverse_leaves_in(e->terms[i].data.expn, d, func))
- return 1;
- } else {
- if (func(&e->terms[i], d))
- return 1;
- }
- }
- return 0;
-}
-
-yasm_expr *
-yasm_expr_extract_deep_segoff(yasm_expr **ep)
-{
- yasm_expr *retval;
- yasm_expr *e = *ep;
- int i;
-
- /* Try to extract at this level */
- retval = yasm_expr_extract_segoff(ep);
- if (retval)
- return retval;
-
- /* Not at this level? Search any expr children. */
- for (i=0; i<e->numterms; i++) {
- if (e->terms[i].type == YASM_EXPR_EXPR) {
- retval = yasm_expr_extract_deep_segoff(&e->terms[i].data.expn);
- if (retval)
- return retval;
- }
- }
-
- /* Didn't find one */
- return NULL;
-}
-
-yasm_expr *
-yasm_expr_extract_segoff(yasm_expr **ep)
-{
- yasm_expr *retval;
- yasm_expr *e = *ep;
-
- /* If not SEG:OFF, we can't do this transformation */
- if (e->op != YASM_EXPR_SEGOFF)
- return NULL;
-
- /* Extract the SEG portion out to its own expression */
- if (e->terms[0].type == YASM_EXPR_EXPR)
- retval = e->terms[0].data.expn;
- else {
- /* Need to build IDENT expression to hold non-expression contents */
- retval = yasm_xmalloc(sizeof(yasm_expr));
- retval->op = YASM_EXPR_IDENT;
- retval->numterms = 1;
- retval->terms[0] = e->terms[0]; /* structure copy */
- }
-
- /* Delete the SEG: portion by changing the expression into an IDENT */
- e->op = YASM_EXPR_IDENT;
- e->numterms = 1;
- e->terms[0] = e->terms[1]; /* structure copy */
-
- return retval;
-}
-
-yasm_expr *
-yasm_expr_extract_wrt(yasm_expr **ep)
-{
- yasm_expr *retval;
- yasm_expr *e = *ep;
-
- /* If not WRT, we can't do this transformation */
- if (e->op != YASM_EXPR_WRT)
- return NULL;
-
- /* Extract the right side portion out to its own expression */
- if (e->terms[1].type == YASM_EXPR_EXPR)
- retval = e->terms[1].data.expn;
- else {
- /* Need to build IDENT expression to hold non-expression contents */
- retval = yasm_xmalloc(sizeof(yasm_expr));
- retval->op = YASM_EXPR_IDENT;
- retval->numterms = 1;
- retval->terms[0] = e->terms[1]; /* structure copy */
- }
-
- /* Delete the right side portion by changing the expr into an IDENT */
- e->op = YASM_EXPR_IDENT;
- e->numterms = 1;
-
- return retval;
-}
-
-/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
-yasm_intnum *
-yasm_expr_get_intnum(yasm_expr **ep, int calc_bc_dist)
-{
- *ep = yasm_expr_simplify(*ep, calc_bc_dist);
-
- if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_INT)
- return (*ep)->terms[0].data.intn;
- else
- return (yasm_intnum *)NULL;
-}
-/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
-
-/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
-const yasm_symrec *
-yasm_expr_get_symrec(yasm_expr **ep, int simplify)
-{
- if (simplify)
- *ep = yasm_expr_simplify(*ep, 0);
-
- if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_SYM)
- return (*ep)->terms[0].data.sym;
- else
- return (yasm_symrec *)NULL;
-}
-/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
-
-/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
-const uintptr_t *
-yasm_expr_get_reg(yasm_expr **ep, int simplify)
-{
- if (simplify)
- *ep = yasm_expr_simplify(*ep, 0);
-
- if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_REG)
- return &((*ep)->terms[0].data.reg);
- else
- return NULL;
-}
-/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
-
-void
-yasm_expr_print(const yasm_expr *e, FILE *f)
-{
- char opstr[8];
- int i;
-
- if (!e) {
- fprintf(f, "(nil)");
- return;
- }
-
- switch (e->op) {
- case YASM_EXPR_ADD:
- strcpy(opstr, "+");
- break;
- case YASM_EXPR_SUB:
- strcpy(opstr, "-");
- break;
- case YASM_EXPR_MUL:
- strcpy(opstr, "*");
- break;
- case YASM_EXPR_DIV:
- strcpy(opstr, "/");
- break;
- case YASM_EXPR_SIGNDIV:
- strcpy(opstr, "//");
- break;
- case YASM_EXPR_MOD:
- strcpy(opstr, "%");
- break;
- case YASM_EXPR_SIGNMOD:
- strcpy(opstr, "%%");
- break;
- case YASM_EXPR_NEG:
- fprintf(f, "-");
- opstr[0] = 0;
- break;
- case YASM_EXPR_NOT:
- fprintf(f, "~");
- opstr[0] = 0;
- break;
- case YASM_EXPR_OR:
- strcpy(opstr, "|");
- break;
- case YASM_EXPR_AND:
- strcpy(opstr, "&");
- break;
- case YASM_EXPR_XOR:
- strcpy(opstr, "^");
- break;
- case YASM_EXPR_XNOR:
- strcpy(opstr, "XNOR");
- break;
- case YASM_EXPR_NOR:
- strcpy(opstr, "NOR");
- break;
- case YASM_EXPR_SHL:
- strcpy(opstr, "<<");
- break;
- case YASM_EXPR_SHR:
- strcpy(opstr, ">>");
- break;
- case YASM_EXPR_LOR:
- strcpy(opstr, "||");
- break;
- case YASM_EXPR_LAND:
- strcpy(opstr, "&&");
- break;
- case YASM_EXPR_LNOT:
- strcpy(opstr, "!");
- break;
- case YASM_EXPR_LXOR:
- strcpy(opstr, "^^");
- break;
- case YASM_EXPR_LXNOR:
- strcpy(opstr, "LXNOR");
- break;
- case YASM_EXPR_LNOR:
- strcpy(opstr, "LNOR");
- break;
- case YASM_EXPR_LT:
- strcpy(opstr, "<");
- break;
- case YASM_EXPR_GT:
- strcpy(opstr, ">");
- break;
- case YASM_EXPR_LE:
- strcpy(opstr, "<=");
- break;
- case YASM_EXPR_GE:
- strcpy(opstr, ">=");
- break;
- case YASM_EXPR_NE:
- strcpy(opstr, "!=");
- break;
- case YASM_EXPR_EQ:
- strcpy(opstr, "==");
- break;
- case YASM_EXPR_SEG:
- fprintf(f, "SEG ");
- opstr[0] = 0;
- break;
- case YASM_EXPR_WRT:
- strcpy(opstr, " WRT ");
- break;
- case YASM_EXPR_SEGOFF:
- strcpy(opstr, ":");
- break;
- case YASM_EXPR_IDENT:
- opstr[0] = 0;
- break;
- default:
- strcpy(opstr, " !UNK! ");
- break;
- }
- for (i=0; i<e->numterms; i++) {
- switch (e->terms[i].type) {
- case YASM_EXPR_PRECBC:
- fprintf(f, "{%lx}",
- yasm_bc_next_offset(e->terms[i].data.precbc));
- break;
- case YASM_EXPR_SYM:
- fprintf(f, "%s", yasm_symrec_get_name(e->terms[i].data.sym));
- break;
- case YASM_EXPR_EXPR:
- fprintf(f, "(");
- yasm_expr_print(e->terms[i].data.expn, f);
- fprintf(f, ")");
- break;
- case YASM_EXPR_INT:
- yasm_intnum_print(e->terms[i].data.intn, f);
- break;
- case YASM_EXPR_FLOAT:
- yasm_floatnum_print(e->terms[i].data.flt, f);
- break;
- case YASM_EXPR_REG:
- /* 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;
- }
- if (i < e->numterms-1)
- fprintf(f, "%s", opstr);
- }
-}
-
-unsigned int
-yasm_expr_size(const yasm_expr *e)
-{
- int i;
- int seen = 0;
- unsigned int size = 0, newsize;
-
- if (e->op == YASM_EXPR_IDENT) {
- if (e->terms[0].type == YASM_EXPR_SYM)
- return yasm_symrec_get_size(e->terms[0].data.sym);
- return 0;
- }
- if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB)
- return 0;
-
- for (i=0; i<e->numterms; i++) {
- newsize = 0;
- switch (e->terms[i].type) {
- case YASM_EXPR_EXPR:
- newsize = yasm_expr_size(e->terms[i].data.expn);
- break;
- case YASM_EXPR_SYM:
- newsize = yasm_symrec_get_size(e->terms[i].data.sym);
- break;
- default:
- break;
- }
- if (newsize) {
- size = newsize;
- if (seen)
- /* either sum of idents (?!) or substract of idents */
- return 0;
- seen = 1;
- }
- }
- /* exactly one offset */
- return size;
-}
-
-const char *
-yasm_expr_segment(const yasm_expr *e)
-{
- int i;
- int seen = 0;
- const char *segment = NULL;
-
- if (e->op == YASM_EXPR_IDENT) {
- if (e->terms[0].type == YASM_EXPR_SYM)
- return yasm_symrec_get_segment(e->terms[0].data.sym);
- return NULL;
- }
- if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB)
- return NULL;
-
- for (i=0; i<e->numterms; i++) {
- if ((e->op == YASM_EXPR_ADD || !i) &&
- e->terms[i].type == YASM_EXPR_EXPR) {
- if ((segment = yasm_expr_segment(e->terms[i].data.expn))) {
- if (seen) {
- /* either sum of idents (?!) or substract of idents */
- return NULL;
- }
- seen = 1;
- }
- }
- }
- /* exactly one offset */
- return segment;
-}
+/*
+ * Expression handling
+ *
+ * Copyright (C) 2001-2007 Michael Urman, 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"
+
+#include "libyasm-stdint.h"
+#include "coretype.h"
+#include "bitvect.h"
+
+#include "errwarn.h"
+#include "intnum.h"
+#include "floatnum.h"
+#include "expr.h"
+#include "symrec.h"
+
+#include "bytecode.h"
+#include "section.h"
+
+#include "arch.h"
+
+
+static /*@only@*/ yasm_expr *expr_level_op
+ (/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
+ int simplify_ident, int simplify_reg_mul);
+static int expr_traverse_nodes_post(/*@null@*/ yasm_expr *e,
+ /*@null@*/ void *d,
+ int (*func) (/*@null@*/ yasm_expr *e,
+ /*@null@*/ void *d));
+static void expr_delete_term(yasm_expr__item *term, int recurse);
+
+/* Bitmap of used items. We should really never need more than 2 at a time,
+ * so 31 is pretty much overkill.
+ */
+static unsigned long itempool_used = 0;
+static yasm_expr__item itempool[31];
+
+/* allocate a new expression node, with children as defined.
+ * If it's a unary operator, put the element in left and set right=NULL. */
+/*@-compmempass@*/
+yasm_expr *
+yasm_expr_create(yasm_expr_op op, yasm_expr__item *left,
+ yasm_expr__item *right, unsigned long line)
+{
+ yasm_expr *ptr, *sube;
+ unsigned long z;
+ ptr = yasm_xmalloc(sizeof(yasm_expr));
+
+ ptr->op = op;
+ ptr->numterms = 0;
+ ptr->terms[0].type = YASM_EXPR_NONE;
+ ptr->terms[1].type = YASM_EXPR_NONE;
+ if (left) {
+ ptr->terms[0] = *left; /* structure copy */
+ z = (unsigned long)(left-itempool);
+ if (z>=31)
+ yasm_internal_error(N_("could not find expritem in pool"));
+ itempool_used &= ~(1<<z);
+ ptr->numterms++;
+
+ /* Search downward until we find something *other* than an
+ * IDENT, then bring it up to the current level.
+ */
+ while (ptr->terms[0].type == YASM_EXPR_EXPR &&
+ ptr->terms[0].data.expn->op == YASM_EXPR_IDENT) {
+ sube = ptr->terms[0].data.expn;
+ ptr->terms[0] = sube->terms[0]; /* structure copy */
+ /*@-usereleased@*/
+ yasm_xfree(sube);
+ /*@=usereleased@*/
+ }
+ } else {
+ yasm_internal_error(N_("Right side of expression must exist"));
+ }
+
+ if (right) {
+ ptr->terms[1] = *right; /* structure copy */
+ z = (unsigned long)(right-itempool);
+ if (z>=31)
+ yasm_internal_error(N_("could not find expritem in pool"));
+ itempool_used &= ~(1<<z);
+ ptr->numterms++;
+
+ /* Search downward until we find something *other* than an
+ * IDENT, then bring it up to the current level.
+ */
+ while (ptr->terms[1].type == YASM_EXPR_EXPR &&
+ ptr->terms[1].data.expn->op == YASM_EXPR_IDENT) {
+ sube = ptr->terms[1].data.expn;
+ ptr->terms[1] = sube->terms[0]; /* structure copy */
+ /*@-usereleased@*/
+ yasm_xfree(sube);
+ /*@=usereleased@*/
+ }
+ }
+
+ ptr->line = line;
+
+ return expr_level_op(ptr, 1, 1, 0);
+}
+/*@=compmempass@*/
+
+/* helpers */
+static yasm_expr__item *
+expr_get_item(void)
+{
+ int z = 0;
+ unsigned long v = itempool_used & 0x7fffffff;
+
+ while (v & 1) {
+ v >>= 1;
+ z++;
+ }
+ if (z>=31)
+ yasm_internal_error(N_("too many expritems"));
+ itempool_used |= 1<<z;
+ return &itempool[z];
+}
+
+yasm_expr__item *
+yasm_expr_precbc(yasm_bytecode *precbc)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_PRECBC;
+ e->data.precbc = precbc;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_sym(yasm_symrec *s)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_SYM;
+ e->data.sym = s;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_expr(yasm_expr *x)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_EXPR;
+ e->data.expn = x;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_int(yasm_intnum *i)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_INT;
+ e->data.intn = i;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_float(yasm_floatnum *f)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_FLOAT;
+ e->data.flt = f;
+ return e;
+}
+
+yasm_expr__item *
+yasm_expr_reg(uintptr_t reg)
+{
+ yasm_expr__item *e = expr_get_item();
+ e->type = YASM_EXPR_REG;
+ e->data.reg = reg;
+ return e;
+}
+
+/* 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. Also works for precbc-precbc (or symrec-precbc,
+ * precbc-symrec).
+ */
+static /*@only@*/ yasm_expr *
+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;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ int numterms;
+
+ /* Handle symrec-symrec in ADD exprs by looking for (-1*symrec) and
+ * symrec term pairs (where both symrecs are in the same segment).
+ */
+ if (e->op != YASM_EXPR_ADD)
+ return e;
+
+ for (i=0; i<e->numterms; i++) {
+ int j;
+ yasm_expr *sube;
+ yasm_intnum *intn;
+ yasm_symrec *sym = NULL;
+ /*@dependent@*/ yasm_section *sect2;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
+
+ /* First look for an (-1*symrec) term */
+ if (e->terms[i].type != YASM_EXPR_EXPR)
+ continue;
+ sube = e->terms[i].data.expn;
+ if (sube->op != YASM_EXPR_MUL || sube->numterms != 2)
+ continue;
+
+ if (sube->terms[0].type == YASM_EXPR_INT &&
+ (sube->terms[1].type == YASM_EXPR_SYM ||
+ sube->terms[1].type == YASM_EXPR_PRECBC)) {
+ intn = sube->terms[0].data.intn;
+ if (sube->terms[1].type == YASM_EXPR_PRECBC)
+ precbc = sube->terms[1].data.precbc;
+ else
+ sym = sube->terms[1].data.sym;
+ } else if ((sube->terms[0].type == YASM_EXPR_SYM ||
+ sube->terms[0].type == YASM_EXPR_PRECBC) &&
+ sube->terms[1].type == YASM_EXPR_INT) {
+ if (sube->terms[0].type == YASM_EXPR_PRECBC)
+ precbc = sube->terms[0].data.precbc;
+ else
+ sym = sube->terms[0].data.sym;
+ intn = sube->terms[1].data.intn;
+ } else
+ continue;
+
+ if (!yasm_intnum_is_neg1(intn))
+ continue;
+
+ if (sym && !yasm_symrec_get_label(sym, &precbc))
+ continue;
+ sect2 = yasm_bc_get_section(precbc);
+
+ /* Now look for a symrec term in the same segment */
+ for (j=0; j<e->numterms; j++) {
+ if (((e->terms[j].type == YASM_EXPR_SYM &&
+ yasm_symrec_get_label(e->terms[j].data.sym, &precbc2)) ||
+ (e->terms[j].type == YASM_EXPR_PRECBC &&
+ (precbc2 = e->terms[j].data.precbc))) &&
+ (sect = yasm_bc_get_section(precbc2)) &&
+ sect == sect2 &&
+ callback(&e->terms[j], precbc, precbc2, cbd)) {
+ /* Delete the matching (-1*symrec) term */
+ yasm_expr_destroy(sube);
+ e->terms[i].type = YASM_EXPR_NONE;
+ break; /* stop looking for matching symrec term */
+ }
+ }
+ }
+
+ /* Clean up any deleted (EXPR_NONE) terms */
+ numterms = 0;
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type != YASM_EXPR_NONE)
+ e->terms[numterms++] = e->terms[i]; /* structure copy */
+ }
+ if (e->numterms != numterms) {
+ e->numterms = numterms;
+ e = yasm_xrealloc(e, sizeof(yasm_expr)+((numterms<2) ? 0 :
+ sizeof(yasm_expr__item)*(numterms-2)));
+ if (numterms == 1)
+ e->op = YASM_EXPR_IDENT;
+ }
+
+ 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;
+}
+
+static yasm_expr *
+expr_xform_bc_dist_subst(yasm_expr *e, void *d)
+{
+ return expr_xform_bc_dist_base(e, d, expr_bc_dist_subst_cb);
+}
+
+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 = yasm_expr__level_tree(*ep, 1, 1, 1, 0, &expr_xform_bc_dist_subst,
+ &my_cbd);
+ 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)
+{
+ yasm_expr *sube = yasm_xmalloc(sizeof(yasm_expr));
+
+ /* Build -1*ei subexpression */
+ sube->op = YASM_EXPR_MUL;
+ sube->line = e->line;
+ sube->numterms = 2;
+ sube->terms[0].type = YASM_EXPR_INT;
+ sube->terms[0].data.intn = yasm_intnum_create_int(-1);
+ sube->terms[1] = *ei; /* structure copy */
+
+ /* Replace original ExprItem with subexp */
+ ei->type = YASM_EXPR_EXPR;
+ ei->data.expn = sube;
+}
+
+/* Negates e by multiplying by -1, with distribution over lower-precedence
+ * operators (eg ADD) and special handling to simplify result w/ADD, NEG, and
+ * others.
+ *
+ * Returns a possibly reallocated e.
+ */
+static /*@only@*/ yasm_expr *
+expr_xform_neg_helper(/*@returned@*/ /*@only@*/ yasm_expr *e)
+{
+ yasm_expr *ne;
+ int i;
+
+ switch (e->op) {
+ case YASM_EXPR_ADD:
+ /* distribute (recursively if expr) over terms */
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR)
+ e->terms[i].data.expn =
+ expr_xform_neg_helper(e->terms[i].data.expn);
+ else
+ expr_xform_neg_item(e, &e->terms[i]);
+ }
+ break;
+ case YASM_EXPR_SUB:
+ /* change op to ADD, and recursively negate left side (if expr) */
+ e->op = YASM_EXPR_ADD;
+ if (e->terms[0].type == YASM_EXPR_EXPR)
+ e->terms[0].data.expn =
+ expr_xform_neg_helper(e->terms[0].data.expn);
+ else
+ expr_xform_neg_item(e, &e->terms[0]);
+ break;
+ case YASM_EXPR_NEG:
+ /* Negating a negated value? Make it an IDENT. */
+ e->op = YASM_EXPR_IDENT;
+ break;
+ case YASM_EXPR_IDENT:
+ /* Negating an ident? Change it into a MUL w/ -1 if there's no
+ * floatnums present below; if there ARE floatnums, recurse.
+ */
+ if (e->terms[0].type == YASM_EXPR_FLOAT)
+ yasm_floatnum_calc(e->terms[0].data.flt, YASM_EXPR_NEG, NULL);
+ else if (e->terms[0].type == YASM_EXPR_INT)
+ yasm_intnum_calc(e->terms[0].data.intn, YASM_EXPR_NEG, NULL);
+ else if (e->terms[0].type == YASM_EXPR_EXPR &&
+ yasm_expr__contains(e->terms[0].data.expn, YASM_EXPR_FLOAT))
+ expr_xform_neg_helper(e->terms[0].data.expn);
+ else {
+ e->op = YASM_EXPR_MUL;
+ e->numterms = 2;
+ e->terms[1].type = YASM_EXPR_INT;
+ e->terms[1].data.intn = yasm_intnum_create_int(-1);
+ }
+ break;
+ default:
+ /* Everything else. MUL will be combined when it's leveled.
+ * Make a new expr (to replace e) with -1*e.
+ */
+ ne = yasm_xmalloc(sizeof(yasm_expr));
+ ne->op = YASM_EXPR_MUL;
+ ne->line = e->line;
+ ne->numterms = 2;
+ ne->terms[0].type = YASM_EXPR_INT;
+ ne->terms[0].data.intn = yasm_intnum_create_int(-1);
+ ne->terms[1].type = YASM_EXPR_EXPR;
+ ne->terms[1].data.expn = e;
+ return ne;
+ }
+ return e;
+}
+
+/* Transforms negatives into expressions that are easier to combine:
+ * -x -> -1*x
+ * a-b -> a+(-1*b)
+ *
+ * Call post-order on an expression tree to transform the entire tree.
+ *
+ * Returns a possibly reallocated e.
+ */
+static /*@only@*/ yasm_expr *
+expr_xform_neg(/*@returned@*/ /*@only@*/ yasm_expr *e)
+{
+ switch (e->op) {
+ case YASM_EXPR_NEG:
+ /* Turn -x into -1*x */
+ e->op = YASM_EXPR_IDENT;
+ return expr_xform_neg_helper(e);
+ case YASM_EXPR_SUB:
+ /* Turn a-b into a+(-1*b) */
+
+ /* change op to ADD, and recursively negate right side (if expr) */
+ e->op = YASM_EXPR_ADD;
+ if (e->terms[1].type == YASM_EXPR_EXPR)
+ e->terms[1].data.expn =
+ expr_xform_neg_helper(e->terms[1].data.expn);
+ else
+ expr_xform_neg_item(e, &e->terms[1]);
+ break;
+ default:
+ break;
+ }
+
+ return e;
+}
+
+/* Look for simple identities that make the entire result constant:
+ * 0*&x, -1|x, etc.
+ */
+static int
+expr_is_constant(yasm_expr_op op, yasm_intnum *intn)
+{
+ int iszero = yasm_intnum_is_zero(intn);
+ return ((iszero && op == YASM_EXPR_MUL) ||
+ (iszero && op == YASM_EXPR_AND) ||
+ (iszero && op == YASM_EXPR_LAND) ||
+ (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_OR));
+}
+
+/* Look for simple "left" identities like 0+x, 1*x, etc. */
+static int
+expr_can_destroy_int_left(yasm_expr_op op, yasm_intnum *intn)
+{
+ int iszero = yasm_intnum_is_zero(intn);
+ return ((yasm_intnum_is_pos1(intn) && op == YASM_EXPR_MUL) ||
+ (iszero && op == YASM_EXPR_ADD) ||
+ (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) ||
+ (!iszero && op == YASM_EXPR_LAND) ||
+ (iszero && op == YASM_EXPR_OR) ||
+ (iszero && op == YASM_EXPR_LOR));
+}
+
+/* Look for simple "right" identities like x+|-0, x*&/1 */
+static int
+expr_can_destroy_int_right(yasm_expr_op op, yasm_intnum *intn)
+{
+ int iszero = yasm_intnum_is_zero(intn);
+ int ispos1 = yasm_intnum_is_pos1(intn);
+ return ((ispos1 && op == YASM_EXPR_MUL) ||
+ (ispos1 && op == YASM_EXPR_DIV) ||
+ (iszero && op == YASM_EXPR_ADD) ||
+ (iszero && op == YASM_EXPR_SUB) ||
+ (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) ||
+ (!iszero && op == YASM_EXPR_LAND) ||
+ (iszero && op == YASM_EXPR_OR) ||
+ (iszero && op == YASM_EXPR_LOR) ||
+ (iszero && op == YASM_EXPR_SHL) ||
+ (iszero && op == YASM_EXPR_SHR));
+}
+
+/* Check for and simplify identities. Returns new number of expr terms.
+ * Sets e->op = EXPR_IDENT if numterms ends up being 1.
+ * Uses numterms parameter instead of e->numterms for basis of "new" number
+ * of terms.
+ * Assumes int_term is *only* integer term in e.
+ * NOTE: Really designed to only be used by expr_level_op().
+ */
+static int
+expr_simplify_identity(yasm_expr *e, int numterms, int *int_term,
+ int simplify_reg_mul)
+{
+ int i;
+ int save_numterms;
+
+ /* Don't do this step if it's 1*REG. Save and restore numterms so
+ * yasm_expr__contains() works correctly.
+ */
+ save_numterms = e->numterms;
+ e->numterms = numterms;
+ if (simplify_reg_mul || e->op != YASM_EXPR_MUL
+ || !yasm_intnum_is_pos1(e->terms[*int_term].data.intn)
+ || !yasm_expr__contains(e, YASM_EXPR_REG)) {
+ /* Check for simple identities that delete the intnum.
+ * Don't delete if the intnum is the only thing in the expn.
+ */
+ if ((*int_term == 0 && numterms > 1 &&
+ expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) ||
+ (*int_term > 0 &&
+ expr_can_destroy_int_right(e->op,
+ e->terms[*int_term].data.intn))) {
+ /* Delete the intnum */
+ yasm_intnum_destroy(e->terms[*int_term].data.intn);
+
+ /* Slide everything to its right over by 1 */
+ if (*int_term != numterms-1) /* if it wasn't last.. */
+ memmove(&e->terms[*int_term], &e->terms[*int_term+1],
+ (numterms-1-*int_term)*sizeof(yasm_expr__item));
+
+ /* Update numterms */
+ numterms--;
+ *int_term = -1; /* no longer an int term */
+ }
+ }
+ e->numterms = save_numterms;
+
+ /* Check for simple identites that delete everything BUT the intnum.
+ * Don't bother if the intnum is the only thing in the expn.
+ */
+ if (numterms > 1 && *int_term != -1 &&
+ expr_is_constant(e->op, e->terms[*int_term].data.intn)) {
+ /* Loop through, deleting everything but the integer term */
+ for (i=0; i<e->numterms; i++)
+ if (i != *int_term)
+ expr_delete_term(&e->terms[i], 1);
+
+ /* Move integer term to the first term (if not already there) */
+ if (*int_term != 0)
+ e->terms[0] = e->terms[*int_term]; /* structure copy */
+
+ /* Set numterms to 1 */
+ numterms = 1;
+ }
+
+ /* Compute NOT, NEG, and LNOT on single intnum. */
+ if (numterms == 1 && *int_term == 0 &&
+ (e->op == YASM_EXPR_NOT || e->op == YASM_EXPR_NEG ||
+ e->op == YASM_EXPR_LNOT))
+ yasm_intnum_calc(e->terms[0].data.intn, e->op, NULL);
+
+ /* Change expression to IDENT if possible. */
+ if (numterms == 1)
+ e->op = YASM_EXPR_IDENT;
+
+ /* Return the updated numterms */
+ return numterms;
+}
+
+/* Levels the expression tree starting at e. Eg:
+ * a+(b+c) -> a+b+c
+ * (a+b)+(c+d) -> a+b+c+d
+ * Naturally, only levels operators that allow more than two operand terms.
+ * NOTE: only does *one* level of leveling (no recursion). Should be called
+ * post-order on a tree to combine deeper levels.
+ * Also brings up any IDENT values into the current level (for ALL operators).
+ * Folds (combines by evaluation) *integer* constant values if fold_const != 0.
+ *
+ * Returns a possibly reallocated e.
+ */
+/*@-mustfree@*/
+static /*@only@*/ yasm_expr *
+expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
+ int simplify_ident, int simplify_reg_mul)
+{
+ int i, j, o, fold_numterms, level_numterms, level_fold_numterms;
+ int first_int_term = -1;
+
+ /* Determine how many operands will need to be brought up (for leveling).
+ * Go ahead and bring up any IDENT'ed values.
+ */
+ while (e->op == YASM_EXPR_IDENT && e->terms[0].type == YASM_EXPR_EXPR) {
+ yasm_expr *sube = e->terms[0].data.expn;
+ yasm_xfree(e);
+ e = sube;
+ }
+
+ /* If non-numeric expression, don't fold constants. */
+ if (e->op > YASM_EXPR_NONNUM)
+ fold_const = 0;
+
+ level_numterms = e->numterms;
+ level_fold_numterms = 0;
+ for (i=0; i<e->numterms; i++) {
+ /* Search downward until we find something *other* than an
+ * IDENT, then bring it up to the current level.
+ */
+ while (e->terms[i].type == YASM_EXPR_EXPR &&
+ e->terms[i].data.expn->op == YASM_EXPR_IDENT) {
+ yasm_expr *sube = e->terms[i].data.expn;
+ e->terms[i] = sube->terms[0];
+ yasm_xfree(sube);
+ }
+
+ if (e->terms[i].type == YASM_EXPR_EXPR &&
+ e->terms[i].data.expn->op == e->op) {
+ /* It's an expression w/the same operator, add in its numterms.
+ * But don't forget to subtract one for the expr itself!
+ */
+ level_numterms += e->terms[i].data.expn->numterms - 1;
+
+ /* If we're folding constants, count up the number of constants
+ * that will be merged in.
+ */
+ if (fold_const)
+ for (j=0; j<e->terms[i].data.expn->numterms; j++)
+ if (e->terms[i].data.expn->terms[j].type ==
+ YASM_EXPR_INT)
+ level_fold_numterms++;
+ }
+
+ /* Find the first integer term (if one is present) if we're folding
+ * constants.
+ */
+ if (fold_const && first_int_term == -1 &&
+ e->terms[i].type == YASM_EXPR_INT)
+ first_int_term = i;
+ }
+
+ /* Look for other integer terms if there's one and combine.
+ * Also eliminate empty spaces when combining and adjust numterms
+ * variables.
+ */
+ fold_numterms = e->numterms;
+ if (first_int_term != -1) {
+ for (i=first_int_term+1, o=first_int_term+1; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_INT) {
+ yasm_intnum_calc(e->terms[first_int_term].data.intn, e->op,
+ e->terms[i].data.intn);
+ fold_numterms--;
+ level_numterms--;
+ /* make sure to delete folded intnum */
+ yasm_intnum_destroy(e->terms[i].data.intn);
+ } else if (o != i) {
+ /* copy term if it changed places */
+ e->terms[o++] = e->terms[i];
+ } else
+ o++;
+ }
+
+ if (simplify_ident) {
+ int new_fold_numterms;
+ /* Simplify identities and make IDENT if possible. */
+ new_fold_numterms =
+ expr_simplify_identity(e, fold_numterms, &first_int_term,
+ simplify_reg_mul);
+ level_numterms -= fold_numterms-new_fold_numterms;
+ fold_numterms = new_fold_numterms;
+ }
+ if (fold_numterms == 1)
+ e->op = YASM_EXPR_IDENT;
+ }
+
+ /* Only level operators that allow more than two operand terms.
+ * Also don't bother leveling if it's not necessary to bring up any terms.
+ */
+ if ((e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL &&
+ e->op != YASM_EXPR_OR && e->op != YASM_EXPR_AND &&
+ e->op != YASM_EXPR_LOR && e->op != YASM_EXPR_LAND &&
+ e->op != YASM_EXPR_LXOR && e->op != YASM_EXPR_XOR) ||
+ level_numterms <= fold_numterms) {
+ /* Downsize e if necessary */
+ if (fold_numterms < e->numterms && e->numterms > 2)
+ e = yasm_xrealloc(e, sizeof(yasm_expr)+((fold_numterms<2) ? 0 :
+ sizeof(yasm_expr__item)*(fold_numterms-2)));
+ /* Update numterms */
+ e->numterms = fold_numterms;
+ return e;
+ }
+
+ /* Adjust numterms for constant folding from terms being "pulled up".
+ * Careful: if there's no integer term in e, then save space for it.
+ */
+ if (fold_const) {
+ level_numterms -= level_fold_numterms;
+ if (first_int_term == -1 && level_fold_numterms != 0)
+ level_numterms++;
+ }
+
+ /* Alloc more (or conceivably less, but not usually) space for e */
+ e = yasm_xrealloc(e, sizeof(yasm_expr)+((level_numterms<2) ? 0 :
+ sizeof(yasm_expr__item)*(level_numterms-2)));
+
+ /* Copy up ExprItem's. Iterate from right to left to keep the same
+ * ordering as was present originally.
+ * Combine integer terms as necessary.
+ */
+ for (i=fold_numterms-1, o=level_numterms-1; i>=0; i--) {
+ if (e->terms[i].type == YASM_EXPR_EXPR &&
+ e->terms[i].data.expn->op == e->op) {
+ /* bring up subexpression */
+ yasm_expr *sube = e->terms[i].data.expn;
+
+ /* copy terms right to left */
+ for (j=sube->numterms-1; j>=0; j--) {
+ if (fold_const && sube->terms[j].type == YASM_EXPR_INT) {
+ /* Need to fold it in.. but if there's no int term already,
+ * just copy into a new one.
+ */
+ if (first_int_term == -1) {
+ first_int_term = o--;
+ e->terms[first_int_term] = sube->terms[j]; /* struc */
+ } else {
+ yasm_intnum_calc(e->terms[first_int_term].data.intn,
+ e->op, sube->terms[j].data.intn);
+ /* make sure to delete folded intnum */
+ yasm_intnum_destroy(sube->terms[j].data.intn);
+ }
+ } else {
+ if (o == first_int_term)
+ o--;
+ e->terms[o--] = sube->terms[j]; /* structure copy */
+ }
+ }
+
+ /* delete subexpression, but *don't delete nodes* (as we've just
+ * copied them!)
+ */
+ yasm_xfree(sube);
+ } else if (o != i) {
+ /* copy operand if it changed places */
+ if (o == first_int_term)
+ o--;
+ e->terms[o] = e->terms[i];
+ /* If we moved the first_int_term, change first_int_num too */
+ if (i == first_int_term)
+ first_int_term = o;
+ o--;
+ } else
+ o--;
+ }
+
+ /* Simplify identities, make IDENT if possible, and save to e->numterms. */
+ if (simplify_ident && first_int_term != -1) {
+ e->numterms = expr_simplify_identity(e, level_numterms,
+ &first_int_term, simplify_reg_mul);
+ } else {
+ e->numterms = level_numterms;
+ if (level_numterms == 1)
+ e->op = YASM_EXPR_IDENT;
+ }
+
+ return e;
+}
+/*@=mustfree@*/
+
+typedef SLIST_HEAD(yasm__exprhead, yasm__exprentry) yasm__exprhead;
+typedef struct yasm__exprentry {
+ /*@reldef@*/ SLIST_ENTRY(yasm__exprentry) next;
+ /*@null@*/ const yasm_expr *e;
+} yasm__exprentry;
+
+static yasm_expr *
+expr_expand_equ(yasm_expr *e, yasm__exprhead *eh)
+{
+ int i;
+ yasm__exprentry ee;
+
+ /* traverse terms */
+ for (i=0; i<e->numterms; i++) {
+ const yasm_expr *equ_expr;
+
+ /* Expand equ's. */
+ if (e->terms[i].type == YASM_EXPR_SYM &&
+ (equ_expr = yasm_symrec_get_equ(e->terms[i].data.sym))) {
+ yasm__exprentry *np;
+
+ /* Check for circular reference */
+ SLIST_FOREACH(np, eh, next) {
+ if (np->e == equ_expr) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("circular reference detected"));
+ return e;
+ }
+ }
+
+ e->terms[i].type = YASM_EXPR_EXPR;
+ e->terms[i].data.expn = yasm_expr_copy(equ_expr);
+
+ /* Remember we saw this equ and recurse */
+ ee.e = equ_expr;
+ SLIST_INSERT_HEAD(eh, &ee, next);
+ e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh);
+ SLIST_REMOVE_HEAD(eh, next);
+ } else if (e->terms[i].type == YASM_EXPR_EXPR)
+ /* Recurse */
+ e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh);
+ }
+
+ 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,
+ yasm_expr_xform_func expr_xform_extra,
+ void *expr_xform_extra_data)
+{
+ int i;
+
+ e = expr_xform_neg(e);
+
+ /* traverse terms */
+ for (i=0; i<e->numterms; i++) {
+ /* Recurse */
+ if (e->terms[i].type == YASM_EXPR_EXPR)
+ e->terms[i].data.expn =
+ expr_level_tree(e->terms[i].data.expn, fold_const,
+ simplify_ident, simplify_reg_mul, calc_bc_dist,
+ 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) {
+ if (calc_bc_dist)
+ e = expr_xform_bc_dist(e);
+ if (expr_xform_extra)
+ e = expr_xform_extra(e, expr_xform_extra_data);
+ e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul,
+ 0, NULL, NULL);
+ }
+ return e;
+}
+
+/* Level an entire expn tree, expanding equ's as we go */
+yasm_expr *
+yasm_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)
+{
+ yasm__exprhead eh;
+ SLIST_INIT(&eh);
+
+ if (!e)
+ return 0;
+
+ e = expr_expand_equ(e, &eh);
+ e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul,
+ calc_bc_dist, expr_xform_extra, expr_xform_extra_data);
+
+ return e;
+}
+
+/* Comparison function for expr_order_terms().
+ * Assumes ExprType enum is in canonical order.
+ */
+static int
+expr_order_terms_compare(const void *va, const void *vb)
+{
+ const yasm_expr__item *a = va, *b = vb;
+ return (a->type - b->type);
+}
+
+/* Reorder terms of e into canonical order. Only reorders if reordering
+ * doesn't change meaning of expression. (eg, doesn't reorder SUB).
+ * Canonical order: REG, INT, FLOAT, SYM, EXPR.
+ * Multiple terms of a single type are kept in the same order as in
+ * the original expression.
+ * NOTE: Only performs reordering on *one* level (no recursion).
+ */
+void
+yasm_expr__order_terms(yasm_expr *e)
+{
+ /* don't bother reordering if only one element */
+ if (e->numterms == 1)
+ return;
+
+ /* only reorder some types of operations */
+ switch (e->op) {
+ case YASM_EXPR_ADD:
+ case YASM_EXPR_MUL:
+ case YASM_EXPR_OR:
+ case YASM_EXPR_AND:
+ case YASM_EXPR_XOR:
+ case YASM_EXPR_LOR:
+ case YASM_EXPR_LAND:
+ case YASM_EXPR_LXOR:
+ /* Use mergesort to sort. It's fast on already sorted values and a
+ * stable sort (multiple terms of same type are kept in the same
+ * order).
+ */
+ yasm__mergesort(e->terms, (size_t)e->numterms,
+ sizeof(yasm_expr__item), expr_order_terms_compare);
+ break;
+ default:
+ break;
+ }
+}
+
+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:
+ /* Symbols don't need to be copied */
+ dest->data.sym = src->data.sym;
+ break;
+ case YASM_EXPR_PRECBC:
+ /* Nor do direct bytecode references */
+ dest->data.precbc = src->data.precbc;
+ 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)
+{
+ yasm_expr *n;
+ int i;
+
+ n = yasm_xmalloc(sizeof(yasm_expr) +
+ sizeof(yasm_expr__item)*(e->numterms<2?0:e->numterms-2));
+
+ n->op = e->op;
+ n->line = e->line;
+ n->numterms = e->numterms;
+ for (i=0; i<e->numterms; i++) {
+ if (i != except)
+ expr_item_copy(&n->terms[i], &e->terms[i]);
+ }
+
+ return n;
+}
+
+static void
+expr_delete_term(yasm_expr__item *term, int recurse)
+{
+ switch (term->type) {
+ case YASM_EXPR_INT:
+ yasm_intnum_destroy(term->data.intn);
+ break;
+ case YASM_EXPR_FLOAT:
+ yasm_floatnum_destroy(term->data.flt);
+ break;
+ case YASM_EXPR_EXPR:
+ if (recurse)
+ yasm_expr_destroy(term->data.expn);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+expr_destroy_each(/*@only@*/ yasm_expr *e, /*@unused@*/ void *d)
+{
+ int i;
+ for (i=0; i<e->numterms; i++)
+ expr_delete_term(&e->terms[i], 0);
+ yasm_xfree(e); /* free ourselves */
+ return 0; /* don't stop recursion */
+}
+
+/*@-mustfree@*/
+void
+yasm_expr_destroy(yasm_expr *e)
+{
+ expr_traverse_nodes_post(e, NULL, expr_destroy_each);
+}
+/*@=mustfree@*/
+
+int
+yasm_expr_is_op(const yasm_expr *e, yasm_expr_op op)
+{
+ return (e->op == op);
+}
+
+static int
+expr_contains_callback(const yasm_expr__item *ei, void *d)
+{
+ yasm_expr__type *t = d;
+ return (ei->type & *t);
+}
+
+int
+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.
+ *
+ * Stops early (and returns 1) if func returns 1. Otherwise returns 0.
+ */
+static int
+expr_traverse_nodes_post(yasm_expr *e, void *d,
+ int (*func) (/*@null@*/ yasm_expr *e,
+ /*@null@*/ void *d))
+{
+ int i;
+
+ if (!e)
+ return 0;
+
+ /* traverse terms */
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR &&
+ expr_traverse_nodes_post(e->terms[i].data.expn, d, func))
+ return 1;
+ }
+
+ /* do callback */
+ return func(e, d);
+}
+
+/* Traverse over expression tree in order, calling func for each leaf
+ * (non-operation). The data pointer d is passed to each func call.
+ *
+ * Stops early (and returns 1) if func returns 1. Otherwise returns 0.
+ */
+int
+yasm_expr__traverse_leaves_in_const(const yasm_expr *e, void *d,
+ int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d))
+{
+ int i;
+
+ if (!e)
+ return 0;
+
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR) {
+ if (yasm_expr__traverse_leaves_in_const(e->terms[i].data.expn, d,
+ func))
+ return 1;
+ } else {
+ if (func(&e->terms[i], d))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Traverse over expression tree in order, calling func for each leaf
+ * (non-operation). The data pointer d is passed to each func call.
+ *
+ * Stops early (and returns 1) if func returns 1. Otherwise returns 0.
+ */
+int
+yasm_expr__traverse_leaves_in(yasm_expr *e, void *d,
+ int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d))
+{
+ int i;
+
+ if (!e)
+ return 0;
+
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR) {
+ if (yasm_expr__traverse_leaves_in(e->terms[i].data.expn, d, func))
+ return 1;
+ } else {
+ if (func(&e->terms[i], d))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+yasm_expr *
+yasm_expr_extract_deep_segoff(yasm_expr **ep)
+{
+ yasm_expr *retval;
+ yasm_expr *e = *ep;
+ int i;
+
+ /* Try to extract at this level */
+ retval = yasm_expr_extract_segoff(ep);
+ if (retval)
+ return retval;
+
+ /* Not at this level? Search any expr children. */
+ for (i=0; i<e->numterms; i++) {
+ if (e->terms[i].type == YASM_EXPR_EXPR) {
+ retval = yasm_expr_extract_deep_segoff(&e->terms[i].data.expn);
+ if (retval)
+ return retval;
+ }
+ }
+
+ /* Didn't find one */
+ return NULL;
+}
+
+yasm_expr *
+yasm_expr_extract_segoff(yasm_expr **ep)
+{
+ yasm_expr *retval;
+ yasm_expr *e = *ep;
+
+ /* If not SEG:OFF, we can't do this transformation */
+ if (e->op != YASM_EXPR_SEGOFF)
+ return NULL;
+
+ /* Extract the SEG portion out to its own expression */
+ if (e->terms[0].type == YASM_EXPR_EXPR)
+ retval = e->terms[0].data.expn;
+ else {
+ /* Need to build IDENT expression to hold non-expression contents */
+ retval = yasm_xmalloc(sizeof(yasm_expr));
+ retval->op = YASM_EXPR_IDENT;
+ retval->numterms = 1;
+ retval->terms[0] = e->terms[0]; /* structure copy */
+ }
+
+ /* Delete the SEG: portion by changing the expression into an IDENT */
+ e->op = YASM_EXPR_IDENT;
+ e->numterms = 1;
+ e->terms[0] = e->terms[1]; /* structure copy */
+
+ return retval;
+}
+
+yasm_expr *
+yasm_expr_extract_wrt(yasm_expr **ep)
+{
+ yasm_expr *retval;
+ yasm_expr *e = *ep;
+
+ /* If not WRT, we can't do this transformation */
+ if (e->op != YASM_EXPR_WRT)
+ return NULL;
+
+ /* Extract the right side portion out to its own expression */
+ if (e->terms[1].type == YASM_EXPR_EXPR)
+ retval = e->terms[1].data.expn;
+ else {
+ /* Need to build IDENT expression to hold non-expression contents */
+ retval = yasm_xmalloc(sizeof(yasm_expr));
+ retval->op = YASM_EXPR_IDENT;
+ retval->numterms = 1;
+ retval->terms[0] = e->terms[1]; /* structure copy */
+ }
+
+ /* Delete the right side portion by changing the expr into an IDENT */
+ e->op = YASM_EXPR_IDENT;
+ e->numterms = 1;
+
+ return retval;
+}
+
+/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
+yasm_intnum *
+yasm_expr_get_intnum(yasm_expr **ep, int calc_bc_dist)
+{
+ *ep = yasm_expr_simplify(*ep, calc_bc_dist);
+
+ if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_INT)
+ return (*ep)->terms[0].data.intn;
+ else
+ return (yasm_intnum *)NULL;
+}
+/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
+
+/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
+const yasm_symrec *
+yasm_expr_get_symrec(yasm_expr **ep, int simplify)
+{
+ if (simplify)
+ *ep = yasm_expr_simplify(*ep, 0);
+
+ if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_SYM)
+ return (*ep)->terms[0].data.sym;
+ else
+ return (yasm_symrec *)NULL;
+}
+/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
+
+/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
+const uintptr_t *
+yasm_expr_get_reg(yasm_expr **ep, int simplify)
+{
+ if (simplify)
+ *ep = yasm_expr_simplify(*ep, 0);
+
+ if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_REG)
+ return &((*ep)->terms[0].data.reg);
+ else
+ return NULL;
+}
+/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
+
+void
+yasm_expr_print(const yasm_expr *e, FILE *f)
+{
+ char opstr[8];
+ int i;
+
+ if (!e) {
+ fprintf(f, "(nil)");
+ return;
+ }
+
+ switch (e->op) {
+ case YASM_EXPR_ADD:
+ strcpy(opstr, "+");
+ break;
+ case YASM_EXPR_SUB:
+ strcpy(opstr, "-");
+ break;
+ case YASM_EXPR_MUL:
+ strcpy(opstr, "*");
+ break;
+ case YASM_EXPR_DIV:
+ strcpy(opstr, "/");
+ break;
+ case YASM_EXPR_SIGNDIV:
+ strcpy(opstr, "//");
+ break;
+ case YASM_EXPR_MOD:
+ strcpy(opstr, "%");
+ break;
+ case YASM_EXPR_SIGNMOD:
+ strcpy(opstr, "%%");
+ break;
+ case YASM_EXPR_NEG:
+ fprintf(f, "-");
+ opstr[0] = 0;
+ break;
+ case YASM_EXPR_NOT:
+ fprintf(f, "~");
+ opstr[0] = 0;
+ break;
+ case YASM_EXPR_OR:
+ strcpy(opstr, "|");
+ break;
+ case YASM_EXPR_AND:
+ strcpy(opstr, "&");
+ break;
+ case YASM_EXPR_XOR:
+ strcpy(opstr, "^");
+ break;
+ case YASM_EXPR_XNOR:
+ strcpy(opstr, "XNOR");
+ break;
+ case YASM_EXPR_NOR:
+ strcpy(opstr, "NOR");
+ break;
+ case YASM_EXPR_SHL:
+ strcpy(opstr, "<<");
+ break;
+ case YASM_EXPR_SHR:
+ strcpy(opstr, ">>");
+ break;
+ case YASM_EXPR_LOR:
+ strcpy(opstr, "||");
+ break;
+ case YASM_EXPR_LAND:
+ strcpy(opstr, "&&");
+ break;
+ case YASM_EXPR_LNOT:
+ strcpy(opstr, "!");
+ break;
+ case YASM_EXPR_LXOR:
+ strcpy(opstr, "^^");
+ break;
+ case YASM_EXPR_LXNOR:
+ strcpy(opstr, "LXNOR");
+ break;
+ case YASM_EXPR_LNOR:
+ strcpy(opstr, "LNOR");
+ break;
+ case YASM_EXPR_LT:
+ strcpy(opstr, "<");
+ break;
+ case YASM_EXPR_GT:
+ strcpy(opstr, ">");
+ break;
+ case YASM_EXPR_LE:
+ strcpy(opstr, "<=");
+ break;
+ case YASM_EXPR_GE:
+ strcpy(opstr, ">=");
+ break;
+ case YASM_EXPR_NE:
+ strcpy(opstr, "!=");
+ break;
+ case YASM_EXPR_EQ:
+ strcpy(opstr, "==");
+ break;
+ case YASM_EXPR_SEG:
+ fprintf(f, "SEG ");
+ opstr[0] = 0;
+ break;
+ case YASM_EXPR_WRT:
+ strcpy(opstr, " WRT ");
+ break;
+ case YASM_EXPR_SEGOFF:
+ strcpy(opstr, ":");
+ break;
+ case YASM_EXPR_IDENT:
+ opstr[0] = 0;
+ break;
+ default:
+ strcpy(opstr, " !UNK! ");
+ break;
+ }
+ for (i=0; i<e->numterms; i++) {
+ switch (e->terms[i].type) {
+ case YASM_EXPR_PRECBC:
+ fprintf(f, "{%lx}",
+ yasm_bc_next_offset(e->terms[i].data.precbc));
+ break;
+ case YASM_EXPR_SYM:
+ fprintf(f, "%s", yasm_symrec_get_name(e->terms[i].data.sym));
+ break;
+ case YASM_EXPR_EXPR:
+ fprintf(f, "(");
+ yasm_expr_print(e->terms[i].data.expn, f);
+ fprintf(f, ")");
+ break;
+ case YASM_EXPR_INT:
+ yasm_intnum_print(e->terms[i].data.intn, f);
+ break;
+ case YASM_EXPR_FLOAT:
+ yasm_floatnum_print(e->terms[i].data.flt, f);
+ break;
+ case YASM_EXPR_REG:
+ /* 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;
+ }
+ if (i < e->numterms-1)
+ fprintf(f, "%s", opstr);
+ }
+}
+
+unsigned int
+yasm_expr_size(const yasm_expr *e)
+{
+ int i;
+ int seen = 0;
+ unsigned int size = 0, newsize;
+
+ if (e->op == YASM_EXPR_IDENT) {
+ if (e->terms[0].type == YASM_EXPR_SYM)
+ return yasm_symrec_get_size(e->terms[0].data.sym);
+ return 0;
+ }
+ if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB)
+ return 0;
+
+ for (i=0; i<e->numterms; i++) {
+ newsize = 0;
+ switch (e->terms[i].type) {
+ case YASM_EXPR_EXPR:
+ newsize = yasm_expr_size(e->terms[i].data.expn);
+ break;
+ case YASM_EXPR_SYM:
+ newsize = yasm_symrec_get_size(e->terms[i].data.sym);
+ break;
+ default:
+ break;
+ }
+ if (newsize) {
+ size = newsize;
+ if (seen)
+ /* either sum of idents (?!) or substract of idents */
+ return 0;
+ seen = 1;
+ }
+ }
+ /* exactly one offset */
+ return size;
+}
+
+const char *
+yasm_expr_segment(const yasm_expr *e)
+{
+ int i;
+ int seen = 0;
+ const char *segment = NULL;
+
+ if (e->op == YASM_EXPR_IDENT) {
+ if (e->terms[0].type == YASM_EXPR_SYM)
+ return yasm_symrec_get_segment(e->terms[0].data.sym);
+ return NULL;
+ }
+ if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB)
+ return NULL;
+
+ for (i=0; i<e->numterms; i++) {
+ if ((e->op == YASM_EXPR_ADD || !i) &&
+ e->terms[i].type == YASM_EXPR_EXPR) {
+ if ((segment = yasm_expr_segment(e->terms[i].data.expn))) {
+ if (seen) {
+ /* either sum of idents (?!) or substract of idents */
+ return NULL;
+ }
+ seen = 1;
+ }
+ }
+ }
+ /* exactly one offset */
+ return segment;
+}