# HG changeset patch # User William Astle # Date 1348427203 21600 # Node ID d0e9dbe9afbe4093b8b7a56d9704ebf749fa21f5 # Parent 41d64951eb32cad3fd89d962bf960949647bc65d Add new heuristic for resolving instruction sizes. Add new heuristic for resolving instruction sizes. This applies to the the decision between extended and base page addressing by calculating the range of possible addresses (if reasonably knowable) and deciding on whether to force extended addressing based on that. (If the whole range is outside the direct page, extended addressing is required.) diff -r 41d64951eb32 -r d0e9dbe9afbe lwasm/insn_gen.c --- a/lwasm/insn_gen.c Tue Aug 14 23:03:59 2012 -0600 +++ b/lwasm/insn_gen.c Sun Sep 23 13:06:43 2012 -0600 @@ -50,6 +50,8 @@ l -> lint = -1; l -> lint2 = 1; insn_parse_indexed_aux(as, l, p); + l -> minlen = OPLEN(instab[l -> insn].ops[1]) + 1 + elen; + l -> maxlen = OPLEN(instab[l -> insn].ops[1]) + 3 + elen; goto out; } @@ -80,6 +82,8 @@ l -> lint2 = -1; } + l -> minlen = OPLEN(instab[l -> insn].ops[0]) + 1 + elen; + l -> maxlen = OPLEN(instab[l -> insn].ops[2]) + 2 + elen; s = lwasm_parse_expr(as, p); if (!s) { @@ -109,6 +113,30 @@ } l -> lint2 = 2; } + else + { + int min; + int max; + + if (lwasm_calculate_range(as, s, &min, &max) == 0) + { +// fprintf(stderr, "range (P) %d...%d for %s\n", min, max, lw_expr_print(s)); + if (min > max) + { + // we don't know what to do in this case so don't do anything + goto out; + } + min = (min >> 8) & 0xff; + max = (max >> 8) & 0xff; + if ((l -> dpval & 0xff) < min || (l -> dpval & 0xff) > max) + { + l -> lint2 = 2; + goto out; + } + l -> lint2 = 0; + goto out; + } + } out: if (l -> lint2 != -1) @@ -143,6 +171,7 @@ return; e = lwasm_fetch_expr(l, 0); + lwasm_reduce_expr(as, e); if (lw_expr_istype(e, lw_expr_type_int)) { int v; @@ -157,6 +186,30 @@ l -> lint2 = 2; goto out; } + else + { + int min; + int max; + + if (lwasm_calculate_range(as, e, &min, &max) == 0) + { +// fprintf(stderr, "range (R) %d...%d for %s\n", min, max, lw_expr_print(e)); + if (min > max) + { + // we don't know what to do in this case so don't do anything + goto out; + } + min = (min >> 8) & 0xff; + max = (max >> 8) & 0xff; + if ((l -> dpval & 0xff) < min || (l -> dpval & 0xff) > max) + { + l -> lint2 = 2; + goto out; + } + l -> lint2 = 0; + goto out; + } + } if (force) { diff -r 41d64951eb32 -r d0e9dbe9afbe lwasm/insn_rel.c --- a/lwasm/insn_rel.c Tue Aug 14 23:03:59 2012 -0600 +++ b/lwasm/insn_rel.c Sun Sep 23 13:06:43 2012 -0600 @@ -51,6 +51,7 @@ l -> lint = -1; l -> maxlen = OPLEN(instab[l -> insn].ops[3]) + 2; + l -> minlen = OPLEN(instab[l -> insn].ops[2]) + 1; if (CURPRAGMA(l, PRAGMA_AUTOBRANCHLENGTH) == 0) { l -> lint = instab[l -> insn].ops[1]; diff -r 41d64951eb32 -r d0e9dbe9afbe lwasm/lwasm.c --- a/lwasm/lwasm.c Tue Aug 14 23:03:59 2012 -0600 +++ b/lwasm/lwasm.c Sun Sep 23 13:06:43 2012 -0600 @@ -988,3 +988,93 @@ debug_message(as, 250, "Returning expression"); return e; } + +struct range_data +{ + int min; + int max; + asmstate_t *as; +}; +int lwasm_calculate_range(asmstate_t *as, lw_expr_t expr, int *min, int *max); +int lwasm_calculate_range_tf(lw_expr_t e, void *info) +{ + struct range_data *rd = info; + int i; + + if (lw_expr_istype(e, lw_expr_type_int)) + { + i = lw_expr_intval(e); + rd -> min += i; + rd -> max += i; + return 0; + } + + if (lw_expr_istype(e, lw_expr_type_special)) + { + line_t *l; + if (lw_expr_specint(e) != lwasm_expr_linelen) + { + rd -> min = -1; + return -1; + } + l = (line_t *)lw_expr_specptr(e); + if (l -> len == -1) + { + rd -> min += l -> minlen; + rd -> max += l -> maxlen; + } + else + { + rd -> min += l -> len; + } + return 0; + } + + if (lw_expr_istype(e, lw_expr_type_var)) + { + lw_expr_t te; + te = lw_expr_copy(e); + lwasm_reduce_expr(rd -> as, te); + if (lw_expr_istype(te, lw_expr_type_int)) + { + i = lw_expr_intval(te); + rd -> min += i; + rd -> max += i; + } + else + { + rd -> min = -1; + } + lw_expr_destroy(te); + if (rd -> min == -1) + return -1; + return 0; + } + + if (lw_expr_istype(e, lw_expr_type_oper)) + { + if (lw_expr_whichop(e) == lw_expr_oper_plus) + return 0; + rd -> min = -1; + return -1; + } + + rd -> min = -1; + return -1; +} + +int lwasm_calculate_range(asmstate_t *as, lw_expr_t expr, int *min, int *max) +{ + struct range_data rd; + + rd.min = 0; + rd.max = 0; + rd.as = as; + + lw_expr_testterms(expr, lwasm_calculate_range_tf, (void *)&rd); + *min = rd.min; + *max = rd.max; + if (rd.min == -1) + return -1; + return 0; +} diff -r 41d64951eb32 -r d0e9dbe9afbe lwasm/lwasm.h --- a/lwasm/lwasm.h Tue Aug 14 23:03:59 2012 -0600 +++ b/lwasm/lwasm.h Sun Sep 23 13:06:43 2012 -0600 @@ -158,7 +158,8 @@ lw_expr_t daddr; // data address of the line (os9 only) int len; // the "size" this line occupies (address space wise) (-1 if unknown) int dlen; // the data "size" this line occupies (-1 if unknown) - int maxlen; // maximum length; will be zero if not relevant + int minlen; // minimum length + int maxlen; // maximum length int insn; // number of insn in insn table int symset; // set if the line symbol was consumed by the instruction char *sym; // symbol, if any, on the line @@ -347,6 +348,8 @@ extern lw_expr_t lwasm_parse_cond(asmstate_t *as, char **p); +extern int lwasm_calculate_range(asmstate_t *as, lw_expr_t expr, int *min, int *max); + #endif extern void debug_message(asmstate_t *as, int level, const char *fmt, ...);