]> granicus.if.org Git - yasm/commitdiff
Better optimization of expr with segoffs 68/head
authorJannis Harder <jix@jixco.de>
Fri, 3 Aug 2012 15:30:15 +0000 (17:30 +0200)
committerJannis Harder <jix@jixco.de>
Fri, 3 Aug 2012 15:30:15 +0000 (17:30 +0200)
Lift all segoffs to the root of the tree. Combine identical segment
values while doing this.

libyasm/coretype.h
libyasm/expr.c

index 624e3c445c818f2e2ec59a73492f0894f58e0129..c4b82cce9306a5caf89a297be2d8a2afcd0dee9d 100644 (file)
@@ -233,6 +233,7 @@ typedef enum yasm_expr_op {
     YASM_EXPR_NOR,      /**< Bitwise NOR. */
     YASM_EXPR_SHL,      /**< Shift left (logical). */
     YASM_EXPR_SHR,      /**< Shift right (logical). */
+    YASM_EXPR_LOGIC,    /**< Start of logic operations (not an op). */
     YASM_EXPR_LOR,      /**< Logical OR. */
     YASM_EXPR_LAND,     /**< Logical AND. */
     YASM_EXPR_LNOT,     /**< Logical negation. */
index fa817ebd5fc686b2de5eeb04495a8663bdc46bbc..1aad79df021cd378e355414320fd726175519107 100644 (file)
@@ -908,6 +908,58 @@ expr_simplify_seg(yasm_expr *e)
     return e;
 }
 
+static yasm_expr *
+expr_lift_segoff(yasm_expr *e, int calc_bc_dist)
+{
+    yasm_expr *retval = NULL;
+    int i;
+    
+    if (e->op < YASM_EXPR_LOGIC || e->op == YASM_EXPR_SEGOFF) {
+        i = e->op == YASM_EXPR_SEGOFF ? 1 : 0;
+        for (; i<e->numterms; i++) {
+            if (e->terms[i].type == YASM_EXPR_EXPR &&
+                e->terms[i].data.expn->op == YASM_EXPR_SEGOFF) {
+                yasm_expr *sub = e->terms[i].data.expn;
+                e->terms[i] = sub->terms[1];
+                retval = sub;
+                retval->op = YASM_EXPR_SEGOFF;
+                retval->line = e->line;
+                retval->numterms = 2;
+                break;
+            }
+        }
+    }
+
+    if (retval != NULL && e->op == YASM_EXPR_SEGOFF) {
+        yasm_intnum *diff;
+        yasm_expr *helper;
+        e->op = YASM_EXPR_IDENT;
+        e->numterms = 1;
+        retval->op = YASM_EXPR_IDENT;
+        retval->numterms = 1;
+        helper = yasm_xmalloc(sizeof(yasm_expr));
+        helper->op = YASM_EXPR_SUB;
+        helper->numterms = 2;
+        helper->terms[0].type = YASM_EXPR_EXPR;
+        helper->terms[0].data.expn = yasm_expr_copy(e);
+        helper->terms[1].type = YASM_EXPR_EXPR;
+        helper->terms[1].data.expn = yasm_expr_copy(retval);
+        diff = yasm_expr_get_intnum(&helper, calc_bc_dist);
+        if (diff != NULL && yasm_intnum_is_zero(diff)) {
+            yasm_expr_destroy(retval);
+            retval = NULL;
+        } else {
+            retval->op = YASM_EXPR_SEGOFF;
+            retval->numterms = 2;
+        }
+        yasm_expr_destroy(helper);
+        e->op = YASM_EXPR_SEGOFF;
+        e->numterms = 2;
+    }
+
+    return retval;
+}
+
 static yasm_expr *
 expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident,
                 int simplify_reg_mul, int calc_bc_dist,
@@ -915,6 +967,7 @@ expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident,
                 void *expr_xform_extra_data)
 {
     int i;
+    yasm_expr *seg;
 
     e = expr_xform_neg(e);
     e = expr_simplify_seg(e);
@@ -931,6 +984,9 @@ expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident,
 
     /* do callback */
     e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul);
+    seg = expr_lift_segoff(e, calc_bc_dist);
+    if (seg)
+        e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul);
     if (calc_bc_dist || expr_xform_extra) {
         if (calc_bc_dist)
             e = expr_xform_bc_dist(e);
@@ -939,6 +995,11 @@ expr_level_tree(yasm_expr *e, int fold_const, int simplify_ident,
         e = expr_level_tree(e, fold_const, simplify_ident, simplify_reg_mul,
                             0, NULL, NULL);
     }
+    if (seg) {
+        seg->terms[1].type = YASM_EXPR_EXPR;
+        seg->terms[1].data.expn = e;
+        e = seg;
+    }
     return e;
 }