]> granicus.if.org Git - yasm/commitdiff
Check for more complex circular references.
authorPeter Johnson <peter@tortall.net>
Sat, 24 Jun 2006 06:56:49 +0000 (06:56 -0000)
committerPeter Johnson <peter@tortall.net>
Sat, 24 Jun 2006 06:56:49 +0000 (06:56 -0000)
svn path=/branches/new-optimizer/; revision=1590

libyasm/section.c
libyasm/tests/Makefile.inc
libyasm/tests/opt-circular3-err.asm [new file with mode: 0644]
libyasm/tests/opt-circular3-err.errwarn [new file with mode: 0644]

index 531b1fee34f7d644eb3e58b695578d29ccaf407e..341c47d9ee42017a081c846035b2b7a62a4f221f 100644 (file)
@@ -746,6 +746,11 @@ struct yasm_span {
     int id;
 
     int active;
+
+    /* NULL-terminated array of spans that led to this span.  Used only for
+     * checking for circular references (cycles) with id=0 spans.
+     */
+    yasm_span **backtrace;
 };
 
 typedef struct optimize_data {
@@ -753,6 +758,7 @@ typedef struct optimize_data {
     /*@reldef@*/ STAILQ_HEAD(, yasm_span) QA, QB;
     /*@only@*/ IntervalTree *itree;
     long len_diff;     /* used only for optimize_term_expand */
+    yasm_span *span;   /* used only for check_cycle */
 } optimize_data;
 
 static yasm_span *
@@ -777,6 +783,7 @@ create_span(yasm_bytecode *bc, int id, /*@null@*/ const yasm_value *value,
     span->pos_thres = pos_thres;
     span->id = id;
     span->active = 1;
+    span->backtrace = NULL;
 
     return span;
 }
@@ -835,9 +842,9 @@ span_create_terms(yasm_span *span)
                span->items[i].data.intn = yasm_intnum_create_int(0);
 
                /* Check for circular references */
-               if ((span->bc->bc_index >= span->terms[i].precbc->bc_index &&
+               if ((span->bc->bc_index > span->terms[i].precbc->bc_index &&
                     span->bc->bc_index <= span->terms[i].precbc2->bc_index) ||
-                   (span->bc->bc_index >= span->terms[i].precbc2->bc_index &&
+                   (span->bc->bc_index > span->terms[i].precbc2->bc_index &&
                     span->bc->bc_index <= span->terms[i].precbc->bc_index))
                    yasm_error_set(YASM_ERROR_VALUE,
                                   N_("circular reference detected"));
@@ -972,6 +979,8 @@ span_destroy(/*@only@*/ yasm_span *span)
            yasm_intnum_destroy(span->items[i].data.intn);
        yasm_xfree(span->items);
     }
+    if (span->backtrace)
+       yasm_xfree(span->backtrace);
     yasm_xfree(span);
 }
 
@@ -990,6 +999,54 @@ optimize_cleanup(optimize_data *optd)
     }
 }
 
+static void
+check_cycle(IntervalTreeNode *node, void *d)
+{
+    optimize_data *optd = d;
+    yasm_span_term *term = node->data;
+    yasm_span *depspan = term->span;
+    int bt_size = 0, dep_bt_size = 0;
+
+    /* Only check for cycles in id=0 spans */
+    if (depspan->id != 0)
+       return;
+
+    /* Check for a circular reference by looking to see if this dependent
+     * span is in our backtrace.
+     */
+    if (optd->span->backtrace) {
+       yasm_span *s;
+       while ((s = optd->span->backtrace[bt_size])) {
+           bt_size++;
+           if (s == depspan)
+               yasm_error_set(YASM_ERROR_VALUE,
+                              N_("circular reference detected"));
+       }
+    }
+
+    /* Add our complete backtrace and ourselves to backtrace of dependent
+     * span.
+     */
+    if (!depspan->backtrace) {
+       depspan->backtrace = yasm_xmalloc((bt_size+2)*sizeof(yasm_span *));
+       memcpy(depspan->backtrace, optd->span->backtrace,
+              bt_size*sizeof(yasm_span *));
+       depspan->backtrace[bt_size] = optd->span;
+       depspan->backtrace[bt_size+1] = NULL;
+       return;
+    }
+
+    while (depspan->backtrace[dep_bt_size])
+       dep_bt_size++;
+    depspan->backtrace =
+       yasm_xrealloc(depspan->backtrace,
+                     (dep_bt_size+bt_size+2)*sizeof(yasm_span *));
+    memcpy(&depspan->backtrace[dep_bt_size], optd->span->backtrace,
+          (bt_size-1)*sizeof(yasm_span *));
+    depspan->backtrace[dep_bt_size+bt_size] = optd->span;
+    depspan->backtrace[dep_bt_size+bt_size+1] = NULL;
+}
+
 static void
 optimize_term_expand(IntervalTreeNode *node, void *d)
 {
@@ -1220,6 +1277,24 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch,
        }
     }
 
+    /* Look for cycles in times expansion (span.id==0) */
+    TAILQ_FOREACH(span, &optd.spans, link) {
+       if (span->id != 0)
+           continue;
+       optd.span = span;
+       IT_enumerate(optd.itree, (long)span->bc->bc_index,
+                    (long)span->bc->bc_index, &optd, check_cycle);
+       if (yasm_error_occurred()) {
+           yasm_errwarn_propagate(errwarns, span->bc->line);
+           saw_error = 1;
+       }
+    }
+
+    if (saw_error) {
+       optimize_cleanup(&optd);
+       return;
+    }
+
     /* Step 2 */
     STAILQ_INIT(&optd.QA);
     while (!STAILQ_EMPTY(&optd.QA) || !(STAILQ_EMPTY(&optd.QB))) {
index 08c7b10f0a072da6508bdd9f98c1326a01f79ce0..d13186357db47e4398ded76520a3858679b52f57 100644 (file)
@@ -42,6 +42,8 @@ EXTRA_DIST += libyasm/tests/opt-circular1-err.asm
 EXTRA_DIST += libyasm/tests/opt-circular1-err.errwarn
 EXTRA_DIST += libyasm/tests/opt-circular2-err.asm
 EXTRA_DIST += libyasm/tests/opt-circular2-err.errwarn
+EXTRA_DIST += libyasm/tests/opt-circular3-err.asm
+EXTRA_DIST += libyasm/tests/opt-circular3-err.errwarn
 EXTRA_DIST += libyasm/tests/opt-immexpand.asm
 EXTRA_DIST += libyasm/tests/opt-immexpand.errwarn
 EXTRA_DIST += libyasm/tests/opt-immexpand.hex
diff --git a/libyasm/tests/opt-circular3-err.asm b/libyasm/tests/opt-circular3-err.asm
new file mode 100644 (file)
index 0000000..61f818a
--- /dev/null
@@ -0,0 +1,7 @@
+label1:
+times label4-label3+1 db 0
+label2:
+db 0
+label3:
+times label2-label1+1 db 0
+label4:
diff --git a/libyasm/tests/opt-circular3-err.errwarn b/libyasm/tests/opt-circular3-err.errwarn
new file mode 100644 (file)
index 0000000..bf1d3fa
--- /dev/null
@@ -0,0 +1 @@
+-:6: circular reference detected