145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*
245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Expression handling
345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *  Copyright (C) 2001-2007  Michael Urman, Peter Johnson
545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Redistribution and use in source and binary forms, with or without
745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * modification, are permitted provided that the following conditions
845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * are met:
945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * 1. Redistributions of source code must retain the above copyright
1045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    notice, this list of conditions and the following disclaimer.
1145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * 2. Redistributions in binary form must reproduce the above copyright
1245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    notice, this list of conditions and the following disclaimer in the
1345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    documentation and/or other materials provided with the distribution.
1445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
1545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
1645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
1945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * POSSIBILITY OF SUCH DAMAGE.
2645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
2745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "util.h"
2845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
2945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "libyasm-stdint.h"
3045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "coretype.h"
3145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "bitvect.h"
3245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
3345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "errwarn.h"
3445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "intnum.h"
3545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "floatnum.h"
3645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "expr.h"
3745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "symrec.h"
3845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
3945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "bytecode.h"
4045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "section.h"
4145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "arch.h"
4345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic /*@only@*/ yasm_expr *expr_level_op
4645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    (/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
4745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     int simplify_ident, int simplify_reg_mul);
4845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int expr_traverse_nodes_post(/*@null@*/ yasm_expr *e,
4945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                    /*@null@*/ void *d,
5045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                    int (*func) (/*@null@*/ yasm_expr *e,
5145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                                 /*@null@*/ void *d));
5245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void expr_delete_term(yasm_expr__item *term, int recurse);
5345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Bitmap of used items.  We should really never need more than 2 at a time,
5545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * so 31 is pretty much overkill.
5645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
5745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic unsigned long itempool_used = 0;
5845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic yasm_expr__item itempool[31];
5945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
6045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* allocate a new expression node, with children as defined.
6145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * If it's a unary operator, put the element in left and set right=NULL. */
6245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@-compmempass@*/
6345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr *
6445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_create(yasm_expr_op op, yasm_expr__item *left,
6545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 yasm_expr__item *right, unsigned long line)
6645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
6745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *ptr, *sube;
6845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned long z;
6945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ptr = yasm_xmalloc(sizeof(yasm_expr));
7045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
7145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ptr->op = op;
7245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ptr->numterms = 0;
7345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ptr->terms[0].type = YASM_EXPR_NONE;
7445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ptr->terms[1].type = YASM_EXPR_NONE;
7545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (left) {
7645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        ptr->terms[0] = *left;  /* structure copy */
7745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        z = (unsigned long)(left-itempool);
7845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (z>=31)
7945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_internal_error(N_("could not find expritem in pool"));
8045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        itempool_used &= ~(1<<z);
8145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        ptr->numterms++;
8245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Search downward until we find something *other* than an
8445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * IDENT, then bring it up to the current level.
8545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
8645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        while (ptr->terms[0].type == YASM_EXPR_EXPR &&
8745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org               ptr->terms[0].data.expn->op == YASM_EXPR_IDENT) {
8845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            sube = ptr->terms[0].data.expn;
8945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ptr->terms[0] = sube->terms[0];     /* structure copy */
9045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /*@-usereleased@*/
9145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_xfree(sube);
9245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /*@=usereleased@*/
9345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
9445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    } else {
9545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_internal_error(N_("Right side of expression must exist"));
9645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
9745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
9845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (right) {
9945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        ptr->terms[1] = *right; /* structure copy */
10045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        z = (unsigned long)(right-itempool);
10145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (z>=31)
10245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_internal_error(N_("could not find expritem in pool"));
10345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        itempool_used &= ~(1<<z);
10445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        ptr->numterms++;
10545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
10645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Search downward until we find something *other* than an
10745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * IDENT, then bring it up to the current level.
10845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
10945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        while (ptr->terms[1].type == YASM_EXPR_EXPR &&
11045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org               ptr->terms[1].data.expn->op == YASM_EXPR_IDENT) {
11145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            sube = ptr->terms[1].data.expn;
11245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ptr->terms[1] = sube->terms[0];     /* structure copy */
11345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /*@-usereleased@*/
11445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_xfree(sube);
11545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /*@=usereleased@*/
11645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
11745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
11845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
11945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ptr->line = line;
12045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
12145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return expr_level_op(ptr, 1, 1, 0);
12245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
12345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@=compmempass@*/
12445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
12545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* helpers */
12645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic yasm_expr__item *
12745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_get_item(void)
12845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
12945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int z = 0;
13045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned long v = itempool_used & 0x7fffffff;
13145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
13245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while (v & 1) {
13345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        v >>= 1;
13445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        z++;
13545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
13645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (z>=31)
13745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_internal_error(N_("too many expritems"));
13845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    itempool_used |= 1<<z;
13945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return &itempool[z];
14045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
14145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
14245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__item *
14345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_precbc(yasm_bytecode *precbc)
14445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
14545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr__item *e = expr_get_item();
14645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->type = YASM_EXPR_PRECBC;
14745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->data.precbc = precbc;
14845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
14945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
15045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
15145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__item *
15245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_sym(yasm_symrec *s)
15345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
15445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr__item *e = expr_get_item();
15545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->type = YASM_EXPR_SYM;
15645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->data.sym = s;
15745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
15845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
15945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
16045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__item *
16145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_expr(yasm_expr *x)
16245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
16345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr__item *e = expr_get_item();
16445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->type = YASM_EXPR_EXPR;
16545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->data.expn = x;
16645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
16745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
16845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
16945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__item *
17045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_int(yasm_intnum *i)
17145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
17245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr__item *e = expr_get_item();
17345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->type = YASM_EXPR_INT;
17445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->data.intn = i;
17545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
17645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
17745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
17845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__item *
17945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_float(yasm_floatnum *f)
18045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
18145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr__item *e = expr_get_item();
18245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->type = YASM_EXPR_FLOAT;
18345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->data.flt = f;
18445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
18545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
18645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
18745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__item *
18845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_reg(uintptr_t reg)
18945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
19045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr__item *e = expr_get_item();
19145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->type = YASM_EXPR_REG;
19245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->data.reg = reg;
19345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
19445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
19545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
19645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into single
19745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * expritems if possible.  Uses a simple n^2 algorithm because n is usually
19845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * quite small.  Also works for precbc-precbc (or symrec-precbc,
19945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * precbc-symrec).
20045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
20145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic /*@only@*/ yasm_expr *
20245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e,
20345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        /*@null@*/ void *cbd,
20445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        int (*callback) (yasm_expr__item *ei,
20545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                         yasm_bytecode *precbc,
20645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                         yasm_bytecode *precbc2,
20745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                         void *cbd))
20845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
20945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
21045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@dependent@*/ yasm_section *sect;
21145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
21245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int numterms;
21345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
21445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Handle symrec-symrec in ADD exprs by looking for (-1*symrec) and
21545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * symrec term pairs (where both symrecs are in the same segment).
21645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
21745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->op != YASM_EXPR_ADD)
21845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return e;
21945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
22045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
22145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        int j;
22245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_expr *sube;
22345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum *intn;
22445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_symrec *sym = NULL;
22545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /*@dependent@*/ yasm_section *sect2;
22645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
22745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
22845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* First look for an (-1*symrec) term */
22945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type != YASM_EXPR_EXPR)
23045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            continue;
23145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sube = e->terms[i].data.expn;
23245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (sube->op != YASM_EXPR_MUL || sube->numterms != 2)
23345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            continue;
23445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
23545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (sube->terms[0].type == YASM_EXPR_INT &&
23645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (sube->terms[1].type == YASM_EXPR_SYM ||
23745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             sube->terms[1].type == YASM_EXPR_PRECBC)) {
23845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            intn = sube->terms[0].data.intn;
23945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (sube->terms[1].type == YASM_EXPR_PRECBC)
24045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                precbc = sube->terms[1].data.precbc;
24145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
24245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                sym = sube->terms[1].data.sym;
24345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else if ((sube->terms[0].type == YASM_EXPR_SYM ||
24445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    sube->terms[0].type == YASM_EXPR_PRECBC) &&
24545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                   sube->terms[1].type == YASM_EXPR_INT) {
24645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (sube->terms[0].type == YASM_EXPR_PRECBC)
24745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                precbc = sube->terms[0].data.precbc;
24845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
24945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                sym = sube->terms[0].data.sym;
25045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            intn = sube->terms[1].data.intn;
25145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else
25245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            continue;
25345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
25445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (!yasm_intnum_is_neg1(intn))
25545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            continue;
25645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
25745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (sym && !yasm_symrec_get_label(sym, &precbc))
25845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            continue;
25945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sect2 = yasm_bc_get_section(precbc);
26045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
26145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Now look for a symrec term in the same segment */
26245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for (j=0; j<e->numterms; j++) {
26345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (((e->terms[j].type == YASM_EXPR_SYM &&
26445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                  yasm_symrec_get_label(e->terms[j].data.sym, &precbc2)) ||
26545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 (e->terms[j].type == YASM_EXPR_PRECBC &&
26645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                  (precbc2 = e->terms[j].data.precbc))) &&
26745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                (sect = yasm_bc_get_section(precbc2)) &&
26845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                sect == sect2 &&
26945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                callback(&e->terms[j], precbc, precbc2, cbd)) {
27045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Delete the matching (-1*symrec) term */
27145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_expr_destroy(sube);
27245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                e->terms[i].type = YASM_EXPR_NONE;
27345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;  /* stop looking for matching symrec term */
27445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
27545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
27645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
27745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
27845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Clean up any deleted (EXPR_NONE) terms */
27945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    numterms = 0;
28045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
28145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type != YASM_EXPR_NONE)
28245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[numterms++] = e->terms[i]; /* structure copy */
28345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
28445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->numterms != numterms) {
28545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e->numterms = numterms;
28645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e = yasm_xrealloc(e, sizeof(yasm_expr)+((numterms<2) ? 0 :
28745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                          sizeof(yasm_expr__item)*(numterms-2)));
28845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (numterms == 1)
28945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->op = YASM_EXPR_IDENT;
29045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
29145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
29245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
29345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
29445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
29545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
29645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_xform_bc_dist_cb(yasm_expr__item *ei, yasm_bytecode *precbc,
29745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      yasm_bytecode *precbc2, /*@null@*/ void *d)
29845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
29945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_intnum *dist = yasm_calc_bc_dist(precbc, precbc2);
30045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!dist)
30145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
30245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Change the term to an integer */
30345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ei->type = YASM_EXPR_INT;
30445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ei->data.intn = dist;
30545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 1;
30645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
30745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
30845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into integers if
30945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * possible.
31045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
31145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic /*@only@*/ yasm_expr *
31245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_xform_bc_dist(/*@returned@*/ /*@only@*/ yasm_expr *e)
31345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
31445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return expr_xform_bc_dist_base(e, NULL, expr_xform_bc_dist_cb);
31545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
31645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
31745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgtypedef struct bc_dist_subst_cbd {
31845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    void (*callback) (unsigned int subst, yasm_bytecode *precbc,
31945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      yasm_bytecode *precbc2, void *cbd);
32045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    void *cbd;
32145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned int subst;
32245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org} bc_dist_subst_cbd;
32345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
32445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
32545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_bc_dist_subst_cb(yasm_expr__item *ei, yasm_bytecode *precbc,
32645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      yasm_bytecode *precbc2, /*@null@*/ void *d)
32745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
32845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc_dist_subst_cbd *my_cbd = d;
32945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    assert(my_cbd != NULL);
33045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Call higher-level callback */
33145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    my_cbd->callback(my_cbd->subst, precbc, precbc2, my_cbd->cbd);
33245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Change the term to an subst */
33345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ei->type = YASM_EXPR_SUBST;
33445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ei->data.subst = my_cbd->subst;
33545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    my_cbd->subst++;
33645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 1;
33745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
33845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
33945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic yasm_expr *
34045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_xform_bc_dist_subst(yasm_expr *e, void *d)
34145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
34245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return expr_xform_bc_dist_base(e, d, expr_bc_dist_subst_cb);
34345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
34445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
34545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
34645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__bc_dist_subst(yasm_expr **ep, void *cbd,
34745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                         void (*callback) (unsigned int subst,
34845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                           yasm_bytecode *precbc,
34945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                           yasm_bytecode *precbc2,
35045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                           void *cbd))
35145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
35245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc_dist_subst_cbd my_cbd;   /* callback info for low-level callback */
35345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    my_cbd.callback = callback;
35445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    my_cbd.cbd = cbd;
35545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    my_cbd.subst = 0;
35645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    *ep = yasm_expr__level_tree(*ep, 1, 1, 1, 0, &expr_xform_bc_dist_subst,
35745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                &my_cbd);
35845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return my_cbd.subst;
35945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
36045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
36145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Negate just a single ExprItem by building a -1*ei subexpression */
36245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
36345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_xform_neg_item(yasm_expr *e, yasm_expr__item *ei)
36445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
36545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *sube = yasm_xmalloc(sizeof(yasm_expr));
36645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
36745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Build -1*ei subexpression */
36845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    sube->op = YASM_EXPR_MUL;
36945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    sube->line = e->line;
37045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    sube->numterms = 2;
37145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    sube->terms[0].type = YASM_EXPR_INT;
37245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    sube->terms[0].data.intn = yasm_intnum_create_int(-1);
37345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    sube->terms[1] = *ei;       /* structure copy */
37445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
37545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Replace original ExprItem with subexp */
37645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ei->type = YASM_EXPR_EXPR;
37745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    ei->data.expn = sube;
37845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
37945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
38045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Negates e by multiplying by -1, with distribution over lower-precedence
38145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * operators (eg ADD) and special handling to simplify result w/ADD, NEG, and
38245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * others.
38345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
38445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Returns a possibly reallocated e.
38545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
38645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic /*@only@*/ yasm_expr *
38745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_xform_neg_helper(/*@returned@*/ /*@only@*/ yasm_expr *e)
38845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
38945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *ne;
39045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
39145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
39245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    switch (e->op) {
39345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_ADD:
39445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* distribute (recursively if expr) over terms */
39545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            for (i=0; i<e->numterms; i++) {
39645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (e->terms[i].type == YASM_EXPR_EXPR)
39745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    e->terms[i].data.expn =
39845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        expr_xform_neg_helper(e->terms[i].data.expn);
39945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                else
40045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    expr_xform_neg_item(e, &e->terms[i]);
40145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
40245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
40345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SUB:
40445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* change op to ADD, and recursively negate left side (if expr) */
40545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->op = YASM_EXPR_ADD;
40645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (e->terms[0].type == YASM_EXPR_EXPR)
40745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                e->terms[0].data.expn =
40845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    expr_xform_neg_helper(e->terms[0].data.expn);
40945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
41045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                expr_xform_neg_item(e, &e->terms[0]);
41145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
41245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_NEG:
41345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Negating a negated value?  Make it an IDENT. */
41445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->op = YASM_EXPR_IDENT;
41545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
41645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_IDENT:
41745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Negating an ident?  Change it into a MUL w/ -1 if there's no
41845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * floatnums present below; if there ARE floatnums, recurse.
41945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
42045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (e->terms[0].type == YASM_EXPR_FLOAT)
42145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_floatnum_calc(e->terms[0].data.flt, YASM_EXPR_NEG, NULL);
42245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else if (e->terms[0].type == YASM_EXPR_INT)
42345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum_calc(e->terms[0].data.intn, YASM_EXPR_NEG, NULL);
42445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else if (e->terms[0].type == YASM_EXPR_EXPR &&
42545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_expr__contains(e->terms[0].data.expn, YASM_EXPR_FLOAT))
42645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    expr_xform_neg_helper(e->terms[0].data.expn);
42745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else {
42845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                e->op = YASM_EXPR_MUL;
42945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                e->numterms = 2;
43045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                e->terms[1].type = YASM_EXPR_INT;
43145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                e->terms[1].data.intn = yasm_intnum_create_int(-1);
43245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
43345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
43445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
43545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Everything else.  MUL will be combined when it's leveled.
43645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * Make a new expr (to replace e) with -1*e.
43745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
43845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ne = yasm_xmalloc(sizeof(yasm_expr));
43945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ne->op = YASM_EXPR_MUL;
44045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ne->line = e->line;
44145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ne->numterms = 2;
44245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ne->terms[0].type = YASM_EXPR_INT;
44345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ne->terms[0].data.intn = yasm_intnum_create_int(-1);
44445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ne->terms[1].type = YASM_EXPR_EXPR;
44545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ne->terms[1].data.expn = e;
44645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return ne;
44745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
44845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
44945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
45045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
45145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Transforms negatives into expressions that are easier to combine:
45245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * -x -> -1*x
45345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * a-b -> a+(-1*b)
45445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
45545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Call post-order on an expression tree to transform the entire tree.
45645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
45745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Returns a possibly reallocated e.
45845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
45945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic /*@only@*/ yasm_expr *
46045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_xform_neg(/*@returned@*/ /*@only@*/ yasm_expr *e)
46145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
46245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    switch (e->op) {
46345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_NEG:
46445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Turn -x into -1*x */
46545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->op = YASM_EXPR_IDENT;
46645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return expr_xform_neg_helper(e);
46745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SUB:
46845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Turn a-b into a+(-1*b) */
46945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
47045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* change op to ADD, and recursively negate right side (if expr) */
47145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->op = YASM_EXPR_ADD;
47245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (e->terms[1].type == YASM_EXPR_EXPR)
47345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                e->terms[1].data.expn =
47445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    expr_xform_neg_helper(e->terms[1].data.expn);
47545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
47645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                expr_xform_neg_item(e, &e->terms[1]);
47745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
47845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
47945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
48045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
48145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
48245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
48345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
48445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
48545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Look for simple identities that make the entire result constant:
48645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * 0*&x, -1|x, etc.
48745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
48845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
48945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_is_constant(yasm_expr_op op, yasm_intnum *intn)
49045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
49145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int iszero = yasm_intnum_is_zero(intn);
49245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return ((iszero && op == YASM_EXPR_MUL) ||
49345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_AND) ||
49445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_LAND) ||
49545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_OR));
49645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
49745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
49845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Look for simple "left" identities like 0+x, 1*x, etc. */
49945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
50045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_can_destroy_int_left(yasm_expr_op op, yasm_intnum *intn)
50145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
50245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int iszero = yasm_intnum_is_zero(intn);
50345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return ((yasm_intnum_is_pos1(intn) && op == YASM_EXPR_MUL) ||
50445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_ADD) ||
50545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) ||
50645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (!iszero && op == YASM_EXPR_LAND) ||
50745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_OR) ||
50845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_LOR));
50945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
51045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
51145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Look for simple "right" identities like x+|-0, x*&/1 */
51245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
51345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_can_destroy_int_right(yasm_expr_op op, yasm_intnum *intn)
51445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
51545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int iszero = yasm_intnum_is_zero(intn);
51645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int ispos1 = yasm_intnum_is_pos1(intn);
51745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return ((ispos1 && op == YASM_EXPR_MUL) ||
51845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (ispos1 && op == YASM_EXPR_DIV) ||
51945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_ADD) ||
52045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_SUB) ||
52145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (yasm_intnum_is_neg1(intn) && op == YASM_EXPR_AND) ||
52245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (!iszero && op == YASM_EXPR_LAND) ||
52345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_OR) ||
52445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_LOR) ||
52545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_SHL) ||
52645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (iszero && op == YASM_EXPR_SHR));
52745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
52845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
52945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Check for and simplify identities.  Returns new number of expr terms.
53045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Sets e->op = EXPR_IDENT if numterms ends up being 1.
53145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Uses numterms parameter instead of e->numterms for basis of "new" number
53245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * of terms.
53345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Assumes int_term is *only* integer term in e.
53445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * NOTE: Really designed to only be used by expr_level_op().
53545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
53645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
537d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.orgexpr_simplify_identity(yasm_expr *e, int numterms, int *int_term,
53845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                       int simplify_reg_mul)
53945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
54045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
54145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int save_numterms;
54245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
54345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Don't do this step if it's 1*REG.  Save and restore numterms so
54445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * yasm_expr__contains() works correctly.
54545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
54645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    save_numterms = e->numterms;
54745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->numterms = numterms;
54845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (simplify_reg_mul || e->op != YASM_EXPR_MUL
549d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org        || !yasm_intnum_is_pos1(e->terms[*int_term].data.intn)
55045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        || !yasm_expr__contains(e, YASM_EXPR_REG)) {
55145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Check for simple identities that delete the intnum.
55245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * Don't delete if the intnum is the only thing in the expn.
55345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
554d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org        if ((*int_term == 0 && numterms > 1 &&
55545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) ||
556d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org            (*int_term > 0 &&
557d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org             expr_can_destroy_int_right(e->op,
558d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                                        e->terms[*int_term].data.intn))) {
55945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Delete the intnum */
560d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org            yasm_intnum_destroy(e->terms[*int_term].data.intn);
56145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
56245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Slide everything to its right over by 1 */
563d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org            if (*int_term != numterms-1) /* if it wasn't last.. */
564d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                memmove(&e->terms[*int_term], &e->terms[*int_term+1],
565d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                        (numterms-1-*int_term)*sizeof(yasm_expr__item));
56645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
56745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Update numterms */
56845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            numterms--;
569d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org            *int_term = -1;     /* no longer an int term */
57045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
57145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
57245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->numterms = save_numterms;
57345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
57445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Check for simple identites that delete everything BUT the intnum.
57545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * Don't bother if the intnum is the only thing in the expn.
57645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
577d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    if (numterms > 1 && *int_term != -1 &&
578d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org        expr_is_constant(e->op, e->terms[*int_term].data.intn)) {
57945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Loop through, deleting everything but the integer term */
58045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for (i=0; i<e->numterms; i++)
581d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org            if (i != *int_term)
58245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                expr_delete_term(&e->terms[i], 1);
58345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
58445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Move integer term to the first term (if not already there) */
585d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org        if (*int_term != 0)
586d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org            e->terms[0] = e->terms[*int_term];  /* structure copy */
58745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
58845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Set numterms to 1 */
58945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        numterms = 1;
59045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
59145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
59245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Compute NOT, NEG, and LNOT on single intnum. */
593d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    if (numterms == 1 && *int_term == 0 &&
59445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        (e->op == YASM_EXPR_NOT || e->op == YASM_EXPR_NEG ||
59545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         e->op == YASM_EXPR_LNOT))
59645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum_calc(e->terms[0].data.intn, e->op, NULL);
59745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
59845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Change expression to IDENT if possible. */
59945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (numterms == 1)
60045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e->op = YASM_EXPR_IDENT;
60145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
60245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Return the updated numterms */
60345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return numterms;
60445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
60545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
60645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Levels the expression tree starting at e.  Eg:
60745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * a+(b+c) -> a+b+c
60845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * (a+b)+(c+d) -> a+b+c+d
60945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Naturally, only levels operators that allow more than two operand terms.
61045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * NOTE: only does *one* level of leveling (no recursion).  Should be called
61145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *  post-order on a tree to combine deeper levels.
61245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Also brings up any IDENT values into the current level (for ALL operators).
61345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Folds (combines by evaluation) *integer* constant values if fold_const != 0.
61445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
61545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Returns a possibly reallocated e.
61645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
61745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@-mustfree@*/
61845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic /*@only@*/ yasm_expr *
61945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
62045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org              int simplify_ident, int simplify_reg_mul)
62145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
62245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i, j, o, fold_numterms, level_numterms, level_fold_numterms;
62345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int first_int_term = -1;
62445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
62545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Determine how many operands will need to be brought up (for leveling).
62645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * Go ahead and bring up any IDENT'ed values.
62745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
62845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while (e->op == YASM_EXPR_IDENT && e->terms[0].type == YASM_EXPR_EXPR) {
62945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_expr *sube = e->terms[0].data.expn;
63045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_xfree(e);
63145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e = sube;
63245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
63345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
63445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* If non-numeric expression, don't fold constants. */
63545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->op > YASM_EXPR_NONNUM)
63645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        fold_const = 0;
63745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
63845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    level_numterms = e->numterms;
63945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    level_fold_numterms = 0;
64045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
64145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Search downward until we find something *other* than an
64245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * IDENT, then bring it up to the current level.
64345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
64445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        while (e->terms[i].type == YASM_EXPR_EXPR &&
64545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org               e->terms[i].data.expn->op == YASM_EXPR_IDENT) {
64645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_expr *sube = e->terms[i].data.expn;
64745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[i] = sube->terms[0];
64845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_xfree(sube);
64945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
65045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
65145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type == YASM_EXPR_EXPR &&
65245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[i].data.expn->op == e->op) {
65345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* It's an expression w/the same operator, add in its numterms.
65445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * But don't forget to subtract one for the expr itself!
65545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 */
65645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                level_numterms += e->terms[i].data.expn->numterms - 1;
65745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
65845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* If we're folding constants, count up the number of constants
65945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * that will be merged in.
66045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 */
66145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (fold_const)
66245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    for (j=0; j<e->terms[i].data.expn->numterms; j++)
66345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        if (e->terms[i].data.expn->terms[j].type ==
66445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            YASM_EXPR_INT)
66545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            level_fold_numterms++;
66645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
66745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
66845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Find the first integer term (if one is present) if we're folding
66945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * constants.
67045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
67145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (fold_const && first_int_term == -1 &&
67245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[i].type == YASM_EXPR_INT)
67345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            first_int_term = i;
67445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
67545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
67645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Look for other integer terms if there's one and combine.
67745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * Also eliminate empty spaces when combining and adjust numterms
67845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * variables.
67945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
68045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fold_numterms = e->numterms;
68145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (first_int_term != -1) {
68245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for (i=first_int_term+1, o=first_int_term+1; i<e->numterms; i++) {
68345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (e->terms[i].type == YASM_EXPR_INT) {
68445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum_calc(e->terms[first_int_term].data.intn, e->op,
68545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                 e->terms[i].data.intn);
68645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                fold_numterms--;
68745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                level_numterms--;
68845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* make sure to delete folded intnum */
68945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum_destroy(e->terms[i].data.intn);
69045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            } else if (o != i) {
69145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* copy term if it changed places */
69245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                e->terms[o++] = e->terms[i];
69345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            } else
69445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                o++;
69545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
69645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
69745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (simplify_ident) {
69845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            int new_fold_numterms;
69945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Simplify identities and make IDENT if possible. */
70045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            new_fold_numterms =
701d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                expr_simplify_identity(e, fold_numterms, &first_int_term,
70245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                       simplify_reg_mul);
70345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            level_numterms -= fold_numterms-new_fold_numterms;
70445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fold_numterms = new_fold_numterms;
70545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
70645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (fold_numterms == 1)
70745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->op = YASM_EXPR_IDENT;
70845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
70945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
71045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Only level operators that allow more than two operand terms.
71145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * Also don't bother leveling if it's not necessary to bring up any terms.
71245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
71345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if ((e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_MUL &&
71445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         e->op != YASM_EXPR_OR && e->op != YASM_EXPR_AND &&
71545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         e->op != YASM_EXPR_LOR && e->op != YASM_EXPR_LAND &&
71645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         e->op != YASM_EXPR_LXOR && e->op != YASM_EXPR_XOR) ||
71745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        level_numterms <= fold_numterms) {
71845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Downsize e if necessary */
71945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (fold_numterms < e->numterms && e->numterms > 2)
72045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e = yasm_xrealloc(e, sizeof(yasm_expr)+((fold_numterms<2) ? 0 :
72145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                              sizeof(yasm_expr__item)*(fold_numterms-2)));
72245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Update numterms */
72345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e->numterms = fold_numterms;
72445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return e;
72545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
72645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
72745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Adjust numterms for constant folding from terms being "pulled up".
72845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * Careful: if there's no integer term in e, then save space for it.
72945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
73045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fold_const) {
73145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        level_numterms -= level_fold_numterms;
73245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (first_int_term == -1 && level_fold_numterms != 0)
73345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            level_numterms++;
73445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
73545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
73645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Alloc more (or conceivably less, but not usually) space for e */
73745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e = yasm_xrealloc(e, sizeof(yasm_expr)+((level_numterms<2) ? 0 :
73845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      sizeof(yasm_expr__item)*(level_numterms-2)));
73945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
74045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Copy up ExprItem's.  Iterate from right to left to keep the same
74145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * ordering as was present originally.
74245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * Combine integer terms as necessary.
74345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
74445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=fold_numterms-1, o=level_numterms-1; i>=0; i--) {
74545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type == YASM_EXPR_EXPR &&
74645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[i].data.expn->op == e->op) {
74745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* bring up subexpression */
74845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_expr *sube = e->terms[i].data.expn;
74945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
75045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* copy terms right to left */
75145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            for (j=sube->numterms-1; j>=0; j--) {
75245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (fold_const && sube->terms[j].type == YASM_EXPR_INT) {
75345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* Need to fold it in.. but if there's no int term already,
75445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                     * just copy into a new one.
75545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                     */
75645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (first_int_term == -1) {
75745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        first_int_term = o--;
75845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        e->terms[first_int_term] = sube->terms[j];  /* struc */
75945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    } else {
76045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        yasm_intnum_calc(e->terms[first_int_term].data.intn,
76145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                         e->op, sube->terms[j].data.intn);
76245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        /* make sure to delete folded intnum */
76345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        yasm_intnum_destroy(sube->terms[j].data.intn);
76445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    }
76545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                } else {
76645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (o == first_int_term)
76745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        o--;
76845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    e->terms[o--] = sube->terms[j];     /* structure copy */
76945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
77045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
77145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
77245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* delete subexpression, but *don't delete nodes* (as we've just
77345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * copied them!)
77445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
77545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_xfree(sube);
77645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else if (o != i) {
77745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* copy operand if it changed places */
77845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (o == first_int_term)
77945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                o--;
78045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[o] = e->terms[i];
78145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* If we moved the first_int_term, change first_int_num too */
78245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (i == first_int_term)
78345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                first_int_term = o;
78445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            o--;
78545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else
78645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            o--;
78745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
78845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
78945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Simplify identities, make IDENT if possible, and save to e->numterms. */
79045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (simplify_ident && first_int_term != -1) {
79145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e->numterms = expr_simplify_identity(e, level_numterms,
792d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                                             &first_int_term, simplify_reg_mul);
79345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    } else {
79445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e->numterms = level_numterms;
79545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (level_numterms == 1)
79645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->op = YASM_EXPR_IDENT;
79745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
79845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
79945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
80045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
80145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@=mustfree@*/
80245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
80345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgtypedef SLIST_HEAD(yasm__exprhead, yasm__exprentry) yasm__exprhead;
80445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgtypedef struct yasm__exprentry {
80545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@reldef@*/ SLIST_ENTRY(yasm__exprentry) next;
80645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@null@*/ const yasm_expr *e;
80745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org} yasm__exprentry;
80845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
80945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic yasm_expr *
81045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_expand_equ(yasm_expr *e, yasm__exprhead *eh)
81145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
81245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
81345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm__exprentry ee;
81445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
81545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* traverse terms */
81645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
81745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        const yasm_expr *equ_expr;
81845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
81945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Expand equ's. */
82045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type == YASM_EXPR_SYM &&
82145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (equ_expr = yasm_symrec_get_equ(e->terms[i].data.sym))) {
82245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm__exprentry *np;
82345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
82445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Check for circular reference */
82545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            SLIST_FOREACH(np, eh, next) {
82645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (np->e == equ_expr) {
82745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_error_set(YASM_ERROR_TOO_COMPLEX,
82845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                   N_("circular reference detected"));
82945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    return e;
83045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
83145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
83245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
83345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[i].type = YASM_EXPR_EXPR;
83445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[i].data.expn = yasm_expr_copy(equ_expr);
83545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
83645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Remember we saw this equ and recurse */
83745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ee.e = equ_expr;
83845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            SLIST_INSERT_HEAD(eh, &ee, next);
83945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh);
84045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            SLIST_REMOVE_HEAD(eh, next);
84145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else if (e->terms[i].type == YASM_EXPR_EXPR)
84245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Recurse */
84345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[i].data.expn = expr_expand_equ(e->terms[i].data.expn, eh);
84445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
84545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
84645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
84745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
84845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
84945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic yasm_expr *
85045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_level_tree(yasm_expr *e, int fold_const, int simplify_ident,
85145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                int simplify_reg_mul, int calc_bc_dist,
85245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_expr_xform_func expr_xform_extra,
85345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                void *expr_xform_extra_data)
85445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
85545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
85645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
85745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e = expr_xform_neg(e);
85845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
85945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* traverse terms */
86045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
86145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Recurse */
86245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type == YASM_EXPR_EXPR)
86345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[i].data.expn =
86445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                expr_level_tree(e->terms[i].data.expn, fold_const,
86545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                simplify_ident, simplify_reg_mul, calc_bc_dist,
86645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                expr_xform_extra, expr_xform_extra_data);
86745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
86845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
86945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Check for SEG of SEG:OFF, if we match, simplify to just the segment */
87045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->op == YASM_EXPR_SEG && e->terms[0].type == YASM_EXPR_EXPR &&
87145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e->terms[0].data.expn->op == YASM_EXPR_SEGOFF) {
87245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e->op = YASM_EXPR_IDENT;
87345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e->terms[0].data.expn->op = YASM_EXPR_IDENT;
87445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Destroy the second (offset) term */
87545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e->terms[0].data.expn->numterms = 1;
87645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        expr_delete_term(&e->terms[0].data.expn->terms[1], 1);
87745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
87845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
87945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* do callback */
88045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul);
88145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (calc_bc_dist || expr_xform_extra) {
88245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (calc_bc_dist)
88345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e = expr_xform_bc_dist(e);
88445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (expr_xform_extra)
88545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e = expr_xform_extra(e, expr_xform_extra_data);
88645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul,
88745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            0, NULL, NULL);
88845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
88945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
89045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
89145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
89245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Level an entire expn tree, expanding equ's as we go */
89345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr *
89445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
89545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      int simplify_reg_mul, int calc_bc_dist,
89645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      yasm_expr_xform_func expr_xform_extra,
89745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      void *expr_xform_extra_data)
89845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
89945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm__exprhead eh;
90045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    SLIST_INIT(&eh);
90145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
90245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!e)
90345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
90445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
90545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e = expr_expand_equ(e, &eh);
90645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul,
90745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        calc_bc_dist, expr_xform_extra, expr_xform_extra_data);
90845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
90945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return e;
91045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
91145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
91245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Comparison function for expr_order_terms().
91345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Assumes ExprType enum is in canonical order.
91445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
91545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
91645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_order_terms_compare(const void *va, const void *vb)
91745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
91845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const yasm_expr__item *a = va, *b = vb;
91945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return (a->type - b->type);
92045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
92145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
92245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Reorder terms of e into canonical order.  Only reorders if reordering
92345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * doesn't change meaning of expression.  (eg, doesn't reorder SUB).
92445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Canonical order: REG, INT, FLOAT, SYM, EXPR.
92545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Multiple terms of a single type are kept in the same order as in
92645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * the original expression.
92745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * NOTE: Only performs reordering on *one* level (no recursion).
92845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
92945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
93045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__order_terms(yasm_expr *e)
93145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
93245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* don't bother reordering if only one element */
93345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->numterms == 1)
93445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return;
93545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
93645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* only reorder some types of operations */
93745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    switch (e->op) {
93845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_ADD:
93945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_MUL:
94045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_OR:
94145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_AND:
94245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_XOR:
94345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LOR:
94445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LAND:
94545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LXOR:
94645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Use mergesort to sort.  It's fast on already sorted values and a
94745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * stable sort (multiple terms of same type are kept in the same
94845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * order).
94945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
95045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm__mergesort(e->terms, (size_t)e->numterms,
95145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            sizeof(yasm_expr__item), expr_order_terms_compare);
95245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
95345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
95445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
95545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
95645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
95745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
95845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
95945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_item_copy(yasm_expr__item *dest, const yasm_expr__item *src)
96045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
96145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    dest->type = src->type;
96245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    switch (src->type) {
96345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SYM:
96445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Symbols don't need to be copied */
96545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            dest->data.sym = src->data.sym;
96645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
96745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_PRECBC:
96845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Nor do direct bytecode references */
96945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            dest->data.precbc = src->data.precbc;
97045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
97145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_EXPR:
97245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            dest->data.expn = yasm_expr__copy_except(src->data.expn, -1);
97345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
97445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_INT:
97545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            dest->data.intn = yasm_intnum_copy(src->data.intn);
97645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
97745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_FLOAT:
97845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            dest->data.flt = yasm_floatnum_copy(src->data.flt);
97945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
98045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_REG:
98145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            dest->data.reg = src->data.reg;
98245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
98345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SUBST:
98445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            dest->data.subst = src->data.subst;
98545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
98645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
98745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
98845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
98945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
99045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
99145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Copy entire expression EXCEPT for index "except" at *top level only*. */
99245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr *
99345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__copy_except(const yasm_expr *e, int except)
99445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
99545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *n;
99645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
99745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
99845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    n = yasm_xmalloc(sizeof(yasm_expr) +
99945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                     sizeof(yasm_expr__item)*(e->numterms<2?0:e->numterms-2));
100045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
100145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    n->op = e->op;
100245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    n->line = e->line;
100345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    n->numterms = e->numterms;
100445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
100545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (i != except)
100645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            expr_item_copy(&n->terms[i], &e->terms[i]);
100745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
100845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
100945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return n;
101045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
101145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
101245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
101345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_delete_term(yasm_expr__item *term, int recurse)
101445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
101545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    switch (term->type) {
101645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_INT:
101745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_intnum_destroy(term->data.intn);
101845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
101945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_FLOAT:
102045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_floatnum_destroy(term->data.flt);
102145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
102245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_EXPR:
102345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (recurse)
102445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_expr_destroy(term->data.expn);
102545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
102645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
102745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
102845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
102945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
103045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
103145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
103245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_destroy_each(/*@only@*/ yasm_expr *e, /*@unused@*/ void *d)
103345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
103445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
103545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++)
103645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        expr_delete_term(&e->terms[i], 0);
103745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_xfree(e);      /* free ourselves */
103845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;   /* don't stop recursion */
103945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
104045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
104145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@-mustfree@*/
104245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
104345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_destroy(yasm_expr *e)
104445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
104545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    expr_traverse_nodes_post(e, NULL, expr_destroy_each);
104645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
104745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@=mustfree@*/
104845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
104945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
105045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_is_op(const yasm_expr *e, yasm_expr_op op)
105145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
105245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return (e->op == op);
105345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
105445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
105545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
105645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_contains_callback(const yasm_expr__item *ei, void *d)
105745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
105845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr__type *t = d;
105945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return (ei->type & *t);
106045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
106145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
106245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
106345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__contains(const yasm_expr *e, yasm_expr__type t)
106445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
106545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return yasm_expr__traverse_leaves_in_const(e, &t, expr_contains_callback);
106645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
106745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
106845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgtypedef struct subst_cbd {
106945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned int num_items;
107045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const yasm_expr__item *items;
107145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org} subst_cbd;
107245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
107345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
107445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_subst_callback(yasm_expr__item *ei, void *d)
107545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
107645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    subst_cbd *cbd = d;
107745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (ei->type != YASM_EXPR_SUBST)
107845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
107945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (ei->data.subst >= cbd->num_items)
108045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 1;   /* error */
108145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    expr_item_copy(ei, &cbd->items[ei->data.subst]);
108245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
108345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
108445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
108545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
108645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__subst(yasm_expr *e, unsigned int num_items,
108745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 const yasm_expr__item *items)
108845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
108945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    subst_cbd cbd;
109045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    cbd.num_items = num_items;
109145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    cbd.items = items;
109245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return yasm_expr__traverse_leaves_in(e, &cbd, expr_subst_callback);
109345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
109445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
109545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Traverse over expression tree, calling func for each operation AFTER the
109645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * branches (if expressions) have been traversed (eg, postorder
109745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * traversal).  The data pointer d is passed to each func call.
109845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
109945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Stops early (and returns 1) if func returns 1.  Otherwise returns 0.
110045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
110145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
110245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgexpr_traverse_nodes_post(yasm_expr *e, void *d,
110345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                         int (*func) (/*@null@*/ yasm_expr *e,
110445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                      /*@null@*/ void *d))
110545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
110645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
110745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
110845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!e)
110945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
111045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
111145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* traverse terms */
111245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
111345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type == YASM_EXPR_EXPR &&
111445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            expr_traverse_nodes_post(e->terms[i].data.expn, d, func))
111545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return 1;
111645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
111745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
111845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* do callback */
111945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return func(e, d);
112045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
112145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
112245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Traverse over expression tree in order, calling func for each leaf
112345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * (non-operation).  The data pointer d is passed to each func call.
112445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
112545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Stops early (and returns 1) if func returns 1.  Otherwise returns 0.
112645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
112745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
112845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__traverse_leaves_in_const(const yasm_expr *e, void *d,
112945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int (*func) (/*@null@*/ const yasm_expr__item *ei, /*@null@*/ void *d))
113045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
113145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
113245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
113345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!e)
113445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
113545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
113645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
113745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type == YASM_EXPR_EXPR) {
113845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (yasm_expr__traverse_leaves_in_const(e->terms[i].data.expn, d,
113945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                                    func))
114045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
114145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else {
114245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (func(&e->terms[i], d))
114345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
114445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
114545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
114645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
114745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
114845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
114945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Traverse over expression tree in order, calling func for each leaf
115045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * (non-operation).  The data pointer d is passed to each func call.
115145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
115245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Stops early (and returns 1) if func returns 1.  Otherwise returns 0.
115345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
115445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
115545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr__traverse_leaves_in(yasm_expr *e, void *d,
115645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int (*func) (/*@null@*/ yasm_expr__item *ei, /*@null@*/ void *d))
115745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
115845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
115945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
116045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!e)
116145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
116245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
116345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
116445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type == YASM_EXPR_EXPR) {
116545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (yasm_expr__traverse_leaves_in(e->terms[i].data.expn, d, func))
116645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
116745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else {
116845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (func(&e->terms[i], d))
116945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
117045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
117145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
117245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
117345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
117445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
117545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr *
117645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_extract_deep_segoff(yasm_expr **ep)
117745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
117845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *retval;
117945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *e = *ep;
118045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
118145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
118245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Try to extract at this level */
118345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    retval = yasm_expr_extract_segoff(ep);
118445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (retval)
118545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return retval;
118645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
118745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Not at this level?  Search any expr children. */
118845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
118945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[i].type == YASM_EXPR_EXPR) {
119045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            retval = yasm_expr_extract_deep_segoff(&e->terms[i].data.expn);
119145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (retval)
119245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return retval;
119345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
119445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
119545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
119645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Didn't find one */
119745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return NULL;
119845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
119945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
120045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr *
120145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_extract_segoff(yasm_expr **ep)
120245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
120345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *retval;
120445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *e = *ep;
120545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
120645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* If not SEG:OFF, we can't do this transformation */
120745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->op != YASM_EXPR_SEGOFF)
120845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return NULL;
120945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
121045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Extract the SEG portion out to its own expression */
121145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->terms[0].type == YASM_EXPR_EXPR)
121245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval = e->terms[0].data.expn;
121345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else {
121445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Need to build IDENT expression to hold non-expression contents */
121545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval = yasm_xmalloc(sizeof(yasm_expr));
121645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval->op = YASM_EXPR_IDENT;
121745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval->numterms = 1;
121845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval->terms[0] = e->terms[0]; /* structure copy */
121945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
122045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
122145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Delete the SEG: portion by changing the expression into an IDENT */
122245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->op = YASM_EXPR_IDENT;
122345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->numterms = 1;
122445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->terms[0] = e->terms[1];  /* structure copy */
122545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
122645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return retval;
122745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
122845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
122945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr *
123045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_extract_wrt(yasm_expr **ep)
123145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
123245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *retval;
123345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr *e = *ep;
123445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
123545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* If not WRT, we can't do this transformation */
123645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->op != YASM_EXPR_WRT)
123745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return NULL;
123845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
123945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Extract the right side portion out to its own expression */
124045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->terms[1].type == YASM_EXPR_EXPR)
124145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval = e->terms[1].data.expn;
124245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else {
124345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Need to build IDENT expression to hold non-expression contents */
124445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval = yasm_xmalloc(sizeof(yasm_expr));
124545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval->op = YASM_EXPR_IDENT;
124645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval->numterms = 1;
124745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        retval->terms[0] = e->terms[1]; /* structure copy */
124845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
124945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
125045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Delete the right side portion by changing the expr into an IDENT */
125145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->op = YASM_EXPR_IDENT;
125245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    e->numterms = 1;
125345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
125445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return retval;
125545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
125645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
125745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
125845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_intnum *
125945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_get_intnum(yasm_expr **ep, int calc_bc_dist)
126045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
126145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    *ep = yasm_expr_simplify(*ep, calc_bc_dist);
126245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
126345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_INT)
126445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return (*ep)->terms[0].data.intn;
126545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else
126645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return (yasm_intnum *)NULL;
126745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
126845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
126945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
127045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
127145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgconst yasm_symrec *
127245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_get_symrec(yasm_expr **ep, int simplify)
127345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
127445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (simplify)
127545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        *ep = yasm_expr_simplify(*ep, 0);
127645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
127745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_SYM)
127845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return (*ep)->terms[0].data.sym;
127945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else
128045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return (yasm_symrec *)NULL;
128145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
128245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
128345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
128445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
128545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgconst uintptr_t *
128645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_get_reg(yasm_expr **ep, int simplify)
128745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
128845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (simplify)
128945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        *ep = yasm_expr_simplify(*ep, 0);
129045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
129145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if ((*ep)->op == YASM_EXPR_IDENT && (*ep)->terms[0].type == YASM_EXPR_REG)
129245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return &((*ep)->terms[0].data.reg);
129345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else
129445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return NULL;
129545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
129645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
129745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
129845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
129945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_print(const yasm_expr *e, FILE *f)
130045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
130145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    char opstr[8];
130245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
130345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
130445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!e) {
130545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        fprintf(f, "(nil)");
130645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return;
130745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
130845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
130945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    switch (e->op) {
131045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_ADD:
131145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "+");
131245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
131345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SUB:
131445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "-");
131545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
131645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_MUL:
131745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "*");
131845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
131945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_DIV:
132045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "/");
132145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
132245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SIGNDIV:
132345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "//");
132445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
132545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_MOD:
132645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "%");
132745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
132845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SIGNMOD:
132945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "%%");
133045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
133145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_NEG:
133245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "-");
133345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            opstr[0] = 0;
133445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
133545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_NOT:
133645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "~");
133745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            opstr[0] = 0;
133845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
133945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_OR:
134045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "|");
134145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
134245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_AND:
134345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "&");
134445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
134545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_XOR:
134645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "^");
134745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
134845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_XNOR:
134945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "XNOR");
135045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
135145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_NOR:
135245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "NOR");
135345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
135445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SHL:
135545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "<<");
135645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
135745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SHR:
135845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, ">>");
135945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
136045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LOR:
136145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "||");
136245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
136345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LAND:
136445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "&&");
136545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
136645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LNOT:
136745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "!");
136845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
136945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LXOR:
137045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "^^");
137145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
137245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LXNOR:
137345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "LXNOR");
137445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
137545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LNOR:
137645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "LNOR");
137745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
137845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LT:
137945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "<");
138045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
138145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_GT:
138245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, ">");
138345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
138445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_LE:
138545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "<=");
138645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
138745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_GE:
138845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, ">=");
138945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
139045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_NE:
139145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "!=");
139245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
139345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_EQ:
139445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, "==");
139545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
139645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SEG:
139745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "SEG ");
139845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            opstr[0] = 0;
139945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
140045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_WRT:
140145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, " WRT ");
140245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
140345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SEGOFF:
140445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, ":");
140545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
140645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_IDENT:
140745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            opstr[0] = 0;
140845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
140945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
141045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            strcpy(opstr, " !UNK! ");
141145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
141245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
141345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
141445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        switch (e->terms[i].type) {
141545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_PRECBC:
141645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                fprintf(f, "{%lx}",
141745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        yasm_bc_next_offset(e->terms[i].data.precbc));
141845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
141945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_SYM:
142045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                fprintf(f, "%s", yasm_symrec_get_name(e->terms[i].data.sym));
142145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
142245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_EXPR:
142345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                fprintf(f, "(");
142445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_expr_print(e->terms[i].data.expn, f);
142545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                fprintf(f, ")");
142645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
142745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_INT:
142845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum_print(e->terms[i].data.intn, f);
142945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
143045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_FLOAT:
143145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_floatnum_print(e->terms[i].data.flt, f);
143245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
143345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_REG:
143445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* FIXME */
143545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /*yasm_arch_reg_print(arch, e->terms[i].data.reg, f);*/
143645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
143745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_SUBST:
143845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                fprintf(f, "[%u]", e->terms[i].data.subst);
143945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
144045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_NONE:
144145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
144245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
144345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (i < e->numterms-1)
144445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "%s", opstr);
144545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
144645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
144745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
144845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgunsigned int
144945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_size(const yasm_expr *e)
145045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
145145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
145245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int seen = 0;
145345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned int size = 0, newsize;
145445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
145545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->op == YASM_EXPR_IDENT) {
145645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[0].type == YASM_EXPR_SYM)
145745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return yasm_symrec_get_size(e->terms[0].data.sym);
145845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
145945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
146045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB)
146145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
146245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
146345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
146445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        newsize = 0;
146545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        switch (e->terms[i].type) {
146645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_EXPR:
146745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            newsize = yasm_expr_size(e->terms[i].data.expn);
146845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
146945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SYM:
147045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            newsize = yasm_symrec_get_size(e->terms[i].data.sym);
147145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
147245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
147345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
147445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
147545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (newsize) {
147645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            size = newsize;
147745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (seen)
147845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* either sum of idents (?!) or substract of idents */
147945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 0;
148045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            seen = 1;
148145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
148245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
148345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* exactly one offset */
148445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return size;
148545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
148645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
148745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgconst char *
148845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_expr_segment(const yasm_expr *e)
148945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
149045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
149145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int seen = 0;
149245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const char *segment = NULL;
149345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
149445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->op == YASM_EXPR_IDENT) {
149545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->terms[0].type == YASM_EXPR_SYM)
149645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return yasm_symrec_get_segment(e->terms[0].data.sym);
149745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return NULL;
149845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
149945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (e->op != YASM_EXPR_ADD && e->op != YASM_EXPR_SUB)
150045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return NULL;
150145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
150245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<e->numterms; i++) {
150345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if ((e->op == YASM_EXPR_ADD || !i) &&
150445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                e->terms[i].type == YASM_EXPR_EXPR) {
150545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if ((segment = yasm_expr_segment(e->terms[i].data.expn))) {
150645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (seen) {
150745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* either sum of idents (?!) or substract of idents */
150845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    return NULL;
150945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
151045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                seen = 1;
151145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
151245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
151345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
151445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* exactly one offset */
151545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return segment;
151645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
1517