]> granicus.if.org Git - yasm/commitdiff
Change calc_len to call back to add_span function so that multiple spans can
authorPeter Johnson <peter@tortall.net>
Sun, 28 May 2006 04:54:44 +0000 (04:54 -0000)
committerPeter Johnson <peter@tortall.net>
Sun, 28 May 2006 04:54:44 +0000 (04:54 -0000)
be added by a single calc_len.

svn path=/branches/new-optimizer/; revision=1544

libyasm/bc-int.h
libyasm/bytecode.c
libyasm/bytecode.h
libyasm/intnum.c
libyasm/intnum.h
libyasm/section.c
modules/arch/x86/x86bc.c

index 66c079ddf3514bdfeb1f6d41e03c7d34c623a76c..9bdea87cb059dd73ff7bcacf99abbede62e4cc08 100644 (file)
@@ -59,10 +59,10 @@ typedef struct yasm_bytecode_callback {
     void (*destroy) (/*@only@*/ void *contents);
     void (*print) (const void *contents, FILE *f, int indent_level);
     void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc);
-    int (*calc_len) (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-                    /*@out@*/ /*@only@*/ yasm_expr **critical,
-                    /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
-    void (*set_long) (yasm_bytecode *bc);
+    int (*calc_len) (yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                    void *add_span_data);
+    int (*expand) (yasm_bytecode *bc, int span, long old_val, long new_val,
+                  /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
     int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d,
                    yasm_output_expr_func output_expr,
                    /*@null@*/ yasm_output_reloc_func output_reloc);
@@ -79,8 +79,8 @@ struct yasm_bytecode {
     /* number of times bytecode is repeated, NULL=1. */
     /*@only@*/ /*@null@*/ yasm_expr *multiple;
 
-    unsigned long len;         /* total length of entire bytecode (including
-                                  multiple copies), 0 if unknown */
+    unsigned long len;         /* total length of entire bytecode
+                                  (not including multiple copies) */
 
     /* where it came from */
     unsigned long line;
@@ -125,11 +125,13 @@ void yasm_bc_transform(yasm_bytecode *bc,
  */
 void yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 
-/** Common bytecode callback set_long function, for where the bytecode is
- * always short (calc_len always returns 0, never 1).  Causes an internal
+/** Common bytecode callback expand function, for where the bytecode is
+ * always short (calc_len never calls add_span).  Causes an internal
  * error if called.
  */
-void yasm_bc_set_long_common(yasm_bytecode *bc);
+int yasm_bc_expand_common
+    (yasm_bytecode *bc, int span, long old_val, long new_val,
+     /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
 
 #define yasm_bc__next(x)               STAILQ_NEXT(x, link)
 
index d9968adbdb53a9f44ddd3cbaa1a3c04ebec63d7b..daffb2baf393d59f51c42ef7c2243f927b348d15 100644 (file)
@@ -134,10 +134,8 @@ typedef struct bytecode_insn {
 
 static void bc_data_destroy(void *contents);
 static void bc_data_print(const void *contents, FILE *f, int indent_level);
-static int bc_data_calc_len
-    (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-     /*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
-     /*@out@*/ long *pos_thres);
+static int bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                           void *add_span_data);
 static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
                           yasm_output_expr_func output_expr,
                           /*@null@*/ yasm_output_reloc_func output_reloc);
@@ -145,30 +143,27 @@ static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 static void bc_leb128_destroy(void *contents);
 static void bc_leb128_print(const void *contents, FILE *f, int indent_level);
 static void bc_leb128_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
-static int bc_leb128_calc_len
-    (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-     /*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
-     /*@out@*/ long *pos_thres);
+static int bc_leb128_calc_len(yasm_bytecode *bc,
+                             yasm_bc_add_span_func add_span,
+                             void *add_span_data);
 static int bc_leb128_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
                             yasm_output_expr_func output_expr,
                             /*@null@*/ yasm_output_reloc_func output_reloc);
 
 static void bc_reserve_destroy(void *contents);
 static void bc_reserve_print(const void *contents, FILE *f, int indent_level);
-static int bc_reserve_calc_len
-    (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-     /*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
-     /*@out@*/ long *pos_thres);
+static int bc_reserve_calc_len(yasm_bytecode *bc,
+                              yasm_bc_add_span_func add_span,
+                              void *add_span_data);
 static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
                              yasm_output_expr_func output_expr,
                              /*@null@*/ yasm_output_reloc_func output_reloc);
 
 static void bc_incbin_destroy(void *contents);
 static void bc_incbin_print(const void *contents, FILE *f, int indent_level);
-static int bc_incbin_calc_len
-    (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-     /*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
-     /*@out@*/ long *pos_thres);
+static int bc_incbin_calc_len(yasm_bytecode *bc,
+                             yasm_bc_add_span_func add_span,
+                             void *add_span_data);
 static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
                             yasm_output_expr_func output_expr,
                             /*@null@*/ yasm_output_reloc_func output_reloc);
@@ -176,20 +171,16 @@ static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 static void bc_align_destroy(void *contents);
 static void bc_align_print(const void *contents, FILE *f, int indent_level);
 static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
-static int bc_align_calc_len
-    (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-     /*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
-     /*@out@*/ long *pos_thres);
+static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                            void *add_span_data);
 static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
                            yasm_output_expr_func output_expr,
                            /*@null@*/ yasm_output_reloc_func output_reloc);
 
 static void bc_org_destroy(void *contents);
 static void bc_org_print(const void *contents, FILE *f, int indent_level);
-static int bc_org_calc_len
-    (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-     /*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
-     /*@out@*/ long *pos_thres);
+static int bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                          void *add_span_data);
 static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
                          yasm_output_expr_func output_expr,
                          /*@null@*/ yasm_output_reloc_func output_reloc);
@@ -197,10 +188,8 @@ static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
 static void bc_insn_destroy(void *contents);
 static void bc_insn_print(const void *contents, FILE *f, int indent_level);
 static void bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
-static int bc_insn_calc_len
-    (yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-     /*@out@*/ /*@only@*/ yasm_expr **critical, /*@out@*/ long *neg_thres,
-     /*@out@*/ long *pos_thres);
+static int bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                           void *add_span_data);
 static int bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
                           yasm_output_expr_func output_expr,
                           /*@null@*/ yasm_output_reloc_func output_reloc);
@@ -212,7 +201,7 @@ static const yasm_bytecode_callback bc_data_callback = {
     bc_data_print,
     yasm_bc_finalize_common,
     bc_data_calc_len,
-    yasm_bc_set_long_common,
+    yasm_bc_expand_common,
     bc_data_tobytes
 };
 
@@ -221,7 +210,7 @@ static const yasm_bytecode_callback bc_leb128_callback = {
     bc_leb128_print,
     bc_leb128_finalize,
     bc_leb128_calc_len,
-    yasm_bc_set_long_common,
+    yasm_bc_expand_common,
     bc_leb128_tobytes
 };
 
@@ -230,7 +219,7 @@ static const yasm_bytecode_callback bc_reserve_callback = {
     bc_reserve_print,
     yasm_bc_finalize_common,
     bc_reserve_calc_len,
-    yasm_bc_set_long_common,
+    yasm_bc_expand_common,
     bc_reserve_tobytes
 };
 
@@ -239,7 +228,7 @@ static const yasm_bytecode_callback bc_incbin_callback = {
     bc_incbin_print,
     yasm_bc_finalize_common,
     bc_incbin_calc_len,
-    yasm_bc_set_long_common,
+    yasm_bc_expand_common,
     bc_incbin_tobytes
 };
 
@@ -248,7 +237,7 @@ static const yasm_bytecode_callback bc_align_callback = {
     bc_align_print,
     bc_align_finalize,
     bc_align_calc_len,
-    yasm_bc_set_long_common,
+    yasm_bc_expand_common,
     bc_align_tobytes
 };
 
@@ -257,7 +246,7 @@ static const yasm_bytecode_callback bc_org_callback = {
     bc_org_print,
     yasm_bc_finalize_common,
     bc_org_calc_len,
-    yasm_bc_set_long_common,
+    yasm_bc_expand_common,
     bc_org_tobytes
 };
 
@@ -266,7 +255,7 @@ static const yasm_bytecode_callback bc_insn_callback = {
     bc_insn_print,
     bc_insn_finalize,
     bc_insn_calc_len,
-    yasm_bc_set_long_common,
+    yasm_bc_expand_common,
     bc_insn_tobytes
 };
 
@@ -382,10 +371,13 @@ yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc)
 {
 }
 
-void
-yasm_bc_set_long_common(yasm_bytecode *bc)
+int
+yasm_bc_expand_common(yasm_bytecode *bc, int span, long old_val, long new_val,
+                     /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
 {
-    yasm_internal_error(N_("bytecode does not have a long format"));
+    yasm_internal_error(N_("bytecode does not have any dependent spans"));
+    /*@unreached@*/
+    return 0;
 }
 
 void
@@ -444,8 +436,8 @@ bc_data_print(const void *contents, FILE *f, int indent_level)
 }
 
 static int
-bc_data_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                yasm_expr **critical, long *neg_thres, long *pos_thres)
+bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                void *add_span_data)
 {
     bytecode_data *bc_data = (bytecode_data *)bc->contents;
     yasm_dataval *dv;
@@ -588,8 +580,8 @@ bc_leb128_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
 }
 
 static int
-bc_leb128_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                  yasm_expr **critical, long *neg_thres, long *pos_thres)
+bc_leb128_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                  void *add_span_data)
 {
     bytecode_leb128 *bc_leb128 = (bytecode_leb128 *)bc->contents;
     bc->len += bc_leb128->len;
@@ -654,8 +646,8 @@ bc_reserve_print(const void *contents, FILE *f, int indent_level)
 }
 
 static int
-bc_reserve_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                   yasm_expr **critical, long *neg_thres, long *pos_thres)
+bc_reserve_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                   void *add_span_data)
 {
     bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
     /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
@@ -734,8 +726,8 @@ bc_incbin_print(const void *contents, FILE *f, int indent_level)
 }
 
 static int
-bc_incbin_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                  yasm_expr **critical, long *neg_thres, long *pos_thres)
+bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                  void *add_span_data)
 {
     bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
     FILE *f;
@@ -902,8 +894,8 @@ bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
 }
 
 static int
-bc_align_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                 yasm_expr **critical, long *neg_thres, long *pos_thres)
+bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                 void *add_span_data)
 {
     yasm_internal_error(N_("align not yet implemented"));
     /*
@@ -1028,8 +1020,8 @@ bc_org_print(const void *contents, FILE *f, int indent_level)
 }
 
 static int
-bc_org_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-               yasm_expr **critical, long *neg_thres, long *pos_thres)
+bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+               void *add_span_data)
 {
     yasm_internal_error(N_("org not yet implemented"));
 #if 0
@@ -1136,8 +1128,8 @@ bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
 }
 
 static int
-bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                 yasm_expr **critical, long *neg_thres, long *pos_thres)
+bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                void *add_span_data)
 {
     yasm_internal_error(N_("bc_insn_calc_len() is not implemented"));
     /*@notreached@*/
@@ -1324,24 +1316,18 @@ yasm_common_calc_bc_dist(/*@null@*/ yasm_bytecode *precbc1,
 }
 
 int
-yasm_bc_calc_len(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-                /*@out@*/ /*@only@*/ yasm_expr **critical,
-                /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                void *add_span_data)
 {
     int retval = 0;
 
     bc->len = 0;
-    *critical = NULL;
-    *neg_thres = 0;
-    *pos_thres = 0;
-    *long_len = 0;
 
     if (!bc->callback)
        yasm_internal_error(N_("got empty bytecode in bc_resolve"));
     else
-       retval = bc->callback->calc_len(bc, long_len, critical, neg_thres,
-                                       pos_thres);
-
+       retval = bc->callback->calc_len(bc, add_span, add_span_data);
+#if 0
     /* Check for multiples */
     if (bc->multiple) {
        /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
@@ -1360,24 +1346,25 @@ yasm_bc_calc_len(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
            }
        }
     }
-
+#endif
     /* If we got an error somewhere along the line, clear out any calc len */
-    if (retval < 0) {
+    if (retval < 0)
        bc->len = 0;
-       *long_len = 0;
-    }
 
     return retval;
 }
 
-void
-yasm_bc_set_long(yasm_bytecode *bc, unsigned long long_len)
+int
+yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+              /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
 {
-    if (!bc->callback)
+    if (!bc->callback) {
        yasm_internal_error(N_("got empty bytecode in bc_set_long"));
-    else
-       bc->callback->set_long(bc);
-    bc->len = long_len;
+       /*@unreached@*/
+       return 0;
+    } else
+       return bc->callback->expand(bc, span, old_val, new_val, neg_thres,
+                                   pos_thres);
 }
 
 /*@null@*/ /*@only@*/ unsigned char *
index 62dea6398c2d4e3bf129011bb5ad5343fa43c519..8260c88e2b1e6c782ea7b0e14e007c27f1e73004 100644 (file)
@@ -273,40 +273,44 @@ void yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
 /*@null@*/ yasm_intnum *yasm_common_calc_bc_dist
     (/*@null@*/ yasm_bytecode *precbc1, /*@null@*/ yasm_bytecode *precbc2);
 
-/** Resolve EQUs in a bytecode and calculate its possible lengths.
- * Tries to minimize the length as much as possible for short_len.
- * The short length is set in the bytecode, and the long length is returned
- * in long_len (if applicable).  Any bytecode multiple is NOT included in
- * the length or critical expression calculations.
+/**
+ * \param critical     dependent expression for bytecode expansion
+ * \param neg_thres    negative threshold for long/short decision
+ * \param pos_thres    positive threshold for long/short decision
+ */
+typedef void (*yasm_bc_add_span_func)
+    (void *add_span_data, yasm_bytecode *bc, int id,
+     /*@only@*/ yasm_expr *dependent, long neg_thres, long pos_thres);
+
+/** Resolve EQUs in a bytecode and calculate its minimum size.
+ * Returns dependent bytecode spans for cases where, if the length spanned
+ * increases, it could cause the bytecode size to increase.
+ * Any bytecode multiple is NOT included in the length or spans generation;
+ * this must be handled at a higher level.
  * \param bc           bytecode
- * \param long_len     longer length (returned).  0 returned if no longer
- *                      length is available (must be short).
- * \param critical     critical expression if bytecode could be longer
- *                     (returned).  NULL returned if no critical expression.
- * \param neg_thres    negative threshold for long/short decision (returned)
- * \param pos_thres    positive threshold for long/short decision (returned)
- * \return 0 if length is minimum (no way it can ever increase), negative if
- *        there was an error recognized (and output) during execution, and
- *        positive if the length may increase based on the critical expr.
+ * \return 0 if no error occurred, nonzero if there was an error recognized
+ *         (and output) during execution.
  * \note May store to bytecode updated expressions and the short length.
  */
-int yasm_bc_calc_len(yasm_bytecode *bc, /*@out@*/ unsigned long *long_len,
-                    /*@out@*/ /*@only@*/ yasm_expr **critical,
-                    /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
+int yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                    void *add_span_data);
 
-/** Mark a bytecode as long.  Has no effect if the bytecode does not have
- * a long form.  May return back a new longer threshold that can be reached.
+/** Recalculate a bytecode's length based on an expanded span length.
  * \param bc           bytecode
- * \param long_len     long length (as given by yasm_bc_calc_len)
- * \param longer_len   next stage of lengthening (returned)
+ * \param span         span ID (as given to yasm_bc_add_span_func in
+ *                      yasm_bc_calc_len)
+ * \param old_val      previous span value
+ * \param new_val      new span value
  * \param neg_thres    negative threshold for long/short decision (returned)
  * \param pos_thres    postivie threshold for long/short decision (returned)
- * \return 0 if no longer threshold, positive if length may increase further
- *         based on the new negative and positive thresholds.
- */
-int yasm_bc_set_long(yasm_bytecode *bc, unsigned long long_len,
-                    /*@out@*/ unsigned long *longer_len,
-                    /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
+ * \return 0 if bc no longer dependent on this span's length, negative if
+ *         there was an error recognized (and output) during execution, and
+ *         positive if bc size may increase for this span further based on the
+ *         new negative and positive thresholds returned.
+ * \note May store to bytecode updated expressions and the updated length.
+ */
+int yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+                  /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
 
 /** Convert a bytecode into its byte representation.
  * \param bc           bytecode
index 3b594e3c90d988e7eb7f03869b30f8559d788083..b8e0a5acd5d4f6496258345033b58e4a039dd4e8 100644 (file)
@@ -650,6 +650,43 @@ yasm_intnum_check_size(const yasm_intnum *intn, size_t size, size_t rshift,
     return (Set_Max(val) < (long)size);
 }
 
+int
+yasm_intnum_in_range(const yasm_intnum *intn, long low, long high)
+{
+    wordptr val = result;
+    wordptr lval = op1static;
+    wordptr hval = op2static;
+
+    /* If not already a bitvect, convert value to be written to a bitvect */
+    if (intn->type == INTNUM_BV)
+       val = intn->val.bv;
+    else {
+       BitVector_Empty(val);
+       BitVector_Chunk_Store(val, 32, 0, intn->val.ul);
+    }
+
+    /* Convert high and low to bitvects */
+    BitVector_Empty(lval);
+    if (low >= 0)
+       BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low);
+    else {
+       BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low));
+       BitVector_Negate(lval, lval);
+    }
+
+    BitVector_Empty(hval);
+    if (high >= 0)
+       BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high);
+    else {
+       BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high));
+       BitVector_Negate(hval, hval);
+    }
+
+    /* Compare! */
+    return (BitVector_Compare(val, lval) >= 0
+           && BitVector_Compare(val, hval) <= 0);
+}
+
 unsigned long
 yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign)
 {
index ccda97beaef17ccf7909d2a1595e6d3ee4011bc4..5edff6eb6fe97939a08b1036ac4b09105ce67c00 100644 (file)
@@ -192,6 +192,14 @@ void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr,
 int yasm_intnum_check_size(const yasm_intnum *intn, size_t size,
                           size_t rshift, int rangetype);
 
+/** Check to see if intnum will fit into a particular numeric range.
+ * \param intn     intnum
+ * \param low      low end of range (inclusive)
+ * \param high     high end of range (inclusive)
+ * \return Nonzero if intnum is within range.
+ */
+int yasm_intnum_in_range(const yasm_intnum *intn, long low, long high);
+
 /** Output #yasm_intnum to buffer in LEB128-encoded form.
  * \param intn     intnum
  * \param ptr      pointer to storage for output bytes
index 1271c2843e1aed1650a32cee1735abbb1ea36e2a..346f18c7102efd790b9bf1277551d92426f07bc6 100644 (file)
@@ -28,6 +28,8 @@
 #include "util.h"
 /*@unused@*/ RCSID("$Id$");
 
+#include <limits.h>
+
 #include "coretype.h"
 #include "valparam.h"
 #include "assocdat.h"
@@ -296,22 +298,18 @@ void
 yasm_object_finalize(yasm_object *object)
 {
     yasm_section *sect;
-    unsigned long bc_index = 0;
 
     /* Iterate through sections */
     STAILQ_FOREACH(sect, &object->sections, link) {
        yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
        yasm_bytecode *prev;
 
-       cur->bc_index = bc_index++;
-
        /* Skip our locally created empty bytecode first. */
        prev = cur;
        cur = STAILQ_NEXT(cur, link);
 
        /* Iterate through the remainder, if any. */
        while (cur) {
-           cur->bc_index = bc_index++;
            /* Finalize */
            yasm_bc_finalize(cur, prev);
            prev = cur;
@@ -541,7 +539,7 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level,
 
 /*
  * Robertson (1977) optimizer
- * Based on the algorithm given in:
+ * Based (somewhat loosely) on the algorithm given in:
  *   MRC Technical Summary Report # 1779
  *   CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES
  *   Edward L. Robertson
@@ -567,67 +565,129 @@ yasm_section_print(const yasm_section *sect, FILE *f, int indent_level,
  *
  * Each span keeps track of:
  *  - Associated bytecode (bytecode that depends on the span length)
+ *  - Active/inactive state (starts out active)
  *  - Sign (negative/positive; negative being "backwards" in address)
  *  - Current length in bytes
  *  - New length in bytes
  *  - Negative/Positive thresholds
  *  - Span ID (unique within each bytecode)
- *    = 0 -- need to update bytecode length on any span length change
- *    > 0 -- only need to update bytecode length if exceeds thresholds
- *    Span ID 0 is reserved for times, org, and align; other IDs can be
- *    arbitrarily chosen by the bytecode.
  *
- * How org, align, and times are handled:
+ * How org and align are handled:
  * Some portions are critical values that must not depend on any bytecode
  * offset (either relative or absolute).
  *
- * ALIGN: Start with 0 length.  Span from 0 to align bytecode, update
- *        on any change (span ID 0).  Alignment is critical value.
- * ORG:   0 length (always).  Bump offset to org value.  Span from 0 to
- *        org bytecode, update on any change (span ID 0).  If span's length
- *        exceeds org value, error.  ORG value is critical value.
+ * ALIGN: 0 length (always).  Bump offset to alignment.  Span from 0 to
+ *        align bytecode, update on any change.  If span length
+ *        increases past alignment, increase offset by alignment and update
+ *        dependent spans.  Alignment is critical value.
+ * ORG:   Same as align, but if span's length exceeds org value, error.
+ *        ORG value is critical value.
+ *
+ * How times is handled:
+ *
  * TIMES: Handled separately from bytecode "raw" size.  If not span-dependent,
  *        trivial (just multiplied in at any bytecode size increase).  Span
- *        dependent times update on any change (span ID 0).
+ *        dependent times update on any change (span ID 0).  If the resultant
+ *        next bytecode offset would be less than the old next bytecode offset,
+ *        error.  Otherwise increase offset and update dependent spans.
+ *
+ * To reduce interval tree size, a first expansion pass is performed
+ * before the spans are added to the tree.
  *
  * Basic algorithm outline:
  *
  * 1. Initialization:
  *  a. Number bytecodes sequentially (via bc_index) and calculate offsets
- *     of all bytecodes assuming minimum length (done in object_finalize).
+ *     of all bytecodes assuming minimum length, building a list of all
+ *     dependent spans as we go.
  *     "minimum" here means absolute minimum:
- *      - align and org bytecodes will be 0 length
+ *      - align 0 length
  *      - times values (with span-dependent values) assumed to be 0
- *  b. Second pass through bytecodes continues to assume absolute minimum
- *     bytecode length but builds spans if necessary.  To reduce interval
- *     tree size, this step avoids building spans for things that are
- *     considered "certainly long" such as inter-section references or if
- *     the distance calculated based on minimum length is already greater
- *     than the long threshold.  If already certainly long, bytecode is
- *     updated with new length and subsequent bytecode offsets are updated
- *     with a running delta.
- *  c. Iterate over spans.  Update span's length based on new bytecode offsets
- *     determined in 1b.  If span's length exceeds long threshold, add that
+ *      - org bumps offset
+ *  b. Iterate over spans.  Set span length based on bytecode offsets
+ *     determined in 1a.  If span is "certainly" long because the span
+ *     is an absolute reference to another section (or external) or the
+ *     distance calculated based on the minimum length is greater than the
+ *     span's threshold, expand the span's bytecode, and if no further
+ *     expansion can result, delete the span.  Otherwise (or if the
+ *     expansion results in another threshold of expansion), add span to
+ *     interval tree.
+ *  c. Iterate over bytecodes to update all bytecode offsets based on new
+ *     (expanded) lengths calculated in 1b.
+ *  d. Iterate over spans.  Update span's length based on new bytecode offsets
+ *     determined in 1c.  If span's length exceeds long threshold, add that
  *     span to Q.
  * 2. Main loop:
  *   While Q not empty:
  *     Expand BC dependent on span at head of Q (and remove span from Q).
- *     For each span that contains BC:
+ *     Update span:
+ *       If BC no longer dependent on span, mark span as inactive.
+ *       If BC has new thresholds for span, update span.
+ *     If BC increased in size, for each active span that contains BC:
  *       Increase span length by difference between short and long BC length.
  *       If span exceeds long threshold (or is flagged to recalculate on any
  *       change), add it to tail of Q.
  * 3. Final pass over bytecodes to generate final offsets.
  */
 
-void
-yasm_object_optimize(yasm_object *object, yasm_arch *arch)
+typedef struct yasm_span {
+    /*@reldef@*/ STAILQ_ENTRY(yasm_span) link;
+
+    /*@dependent@*/ yasm_bytecode *bc;
+
+    /*@owned@*/ yasm_expr *dependent;
+
+    /* Special handling: see descriptions above */
+    enum {
+       NOT_SPECIAL = 0,
+       SPECIAL_ALIGN,
+       SPECIAL_ORG,
+       SPECIAL_TIMES
+    } special;
+
+    long cur_val;
+    long new_val;
+
+    long neg_thres;
+    long pos_thres;
+
+    int id;
+
+    int active;
+} yasm_span;
+
+typedef struct optimize_data {
+    /*@reldef@*/ STAILQ_HEAD(yasm_spanhead, yasm_span) spans;
+} optimize_data;
+
+static void
+optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id,
+                 /*@only@*/ yasm_expr *dependent, long neg_thres,
+                 long pos_thres)
+{
+    optimize_data *optd = (optimize_data *)add_span_data;
+    yasm_span *span = yasm_xmalloc(sizeof(yasm_span));
+
+    span->bc = bc;
+    span->dependent = dependent;
+    span->special = NOT_SPECIAL;
+    span->cur_val = 0;
+    span->new_val = 0;
+    span->neg_thres = neg_thres;
+    span->pos_thres = pos_thres;
+    span->id = id;
+    span->active = 1;
+
+    STAILQ_INSERT_TAIL(&optd->spans, span, link);
+}
+
+static void
+update_all_bc_offsets(yasm_object *object)
 {
     yasm_section *sect;
-    int saw_error = 0;
 
-    /* Step 1b */
     STAILQ_FOREACH(sect, &object->sections, link) {
-       unsigned long i;
+       unsigned long offset = 0;
 
        yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
        yasm_bytecode *prev;
@@ -638,54 +698,103 @@ yasm_object_optimize(yasm_object *object, yasm_arch *arch)
 
        /* Iterate through the remainder, if any. */
        while (cur) {
-           unsigned long long_len;
-           /*@only@*/ /*@null@*/ yasm_expr *critical;
-           long neg_thres;
-           long pos_thres;
-           int retval;
-
-           switch (yasm_bc_calc_len(cur, &long_len, &critical, &neg_thres,
-                                    &pos_thres)) {
-               case -1:
-                   saw_error = 1;
-                   break;
-               case 0:
-                   /* No special action required */
-                   break;
-               case 1:
-                   /* Need to build a span */
-                   yasm_bc_set_long(cur, long_len);
-                   yasm_expr_destroy(critical);
-                   break;
-               default:
-                   yasm_internal_error(N_("bad return value from bc_calc_len"));
-           }
-
+           cur->offset = offset;
+           offset += cur->len;
            prev = cur;
            cur = STAILQ_NEXT(cur, link);
        }
     }
+}
 
-    if (saw_error)
-       return;
+void
+yasm_object_optimize(yasm_object *object, yasm_arch *arch)
+{
+    yasm_section *sect;
+    unsigned long bc_index = 0;
+    int saw_error = 0;
+    optimize_data optd;
+    yasm_span *span;
+    long neg_thres, pos_thres;
 
-    /* Step 3 */
+    STAILQ_INIT(&optd.spans);
+
+    /* Step 1a */
     STAILQ_FOREACH(sect, &object->sections, link) {
        unsigned long offset = 0;
 
        yasm_bytecode *cur = STAILQ_FIRST(&sect->bcs);
        yasm_bytecode *prev;
 
+       cur->bc_index = bc_index++;
+
        /* Skip our locally created empty bytecode first. */
        prev = cur;
        cur = STAILQ_NEXT(cur, link);
 
        /* Iterate through the remainder, if any. */
        while (cur) {
+           cur->bc_index = bc_index++;
+
+           if (yasm_bc_calc_len(cur, optimize_add_span, &optd))
+               saw_error = 1;
+
+           /* TODO: times */
+           if (cur->multiple)
+               yasm_internal_error("multiple not yet supported");
+
            cur->offset = offset;
            offset += cur->len;
            prev = cur;
            cur = STAILQ_NEXT(cur, link);
        }
     }
+
+    if (saw_error)
+       return;
+
+    /* Step 1b */
+    STAILQ_FOREACH(span, &optd.spans, link) {
+       yasm_expr *depcopy = yasm_expr_copy(span->dependent);
+       yasm_intnum *intn =
+           yasm_expr_get_intnum(&depcopy, yasm_common_calc_bc_dist);
+       if (intn)
+           span->new_val = yasm_intnum_get_int(intn);
+       else {
+           /* absolute, external, or too complex; force to longer form */
+           span->new_val = LONG_MAX;
+           span->active = 0;
+       }
+
+       if (span->new_val < span->neg_thres
+           || span->new_val > span->pos_thres) {
+           int retval = yasm_bc_expand(span->bc, span->id, span->cur_val,
+                                       span->new_val, &neg_thres, &pos_thres);
+           if (retval < 0)
+               saw_error = 1;
+           else if (retval > 0) {
+               span->neg_thres = neg_thres;
+               span->pos_thres = pos_thres;
+           } else
+               span->active = 0;
+       }
+       span->cur_val = span->new_val;
+       yasm_expr_destroy(depcopy);
+    }
+
+    if (saw_error)
+       return;
+
+    /* Step 1c */
+    update_all_bc_offsets(object);
+
+    /* Step 1d */
+    STAILQ_FOREACH(span, &optd.spans, link) {
+       if (!span->active)
+           continue;
+    }
+
+    /* Step 2 */
+
+    /* Step 3 */
+    update_all_bc_offsets(object);
 }
index d97399b043b5d6fc9d4a82299a7a7886cf5b7a2d..7bfc4cc648124922f84e297a8b04f6bf404a9327 100644 (file)
@@ -69,20 +69,24 @@ static void x86_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level);
 static void x86_bc_insn_destroy(void *contents);
 static void x86_bc_insn_print(const void *contents, FILE *f,
                              int indent_level);
-static int x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                               yasm_expr **critical, long *neg_thres,
-                               long *pos_thres);
-static void x86_bc_insn_set_long(yasm_bytecode *bc);
+static int x86_bc_insn_calc_len(yasm_bytecode *bc,
+                               yasm_bc_add_span_func add_span,
+                               void *add_span_data);
+static int x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val,
+                             long new_val, /*@out@*/ long *neg_thres,
+                             /*@out@*/ long *pos_thres);
 static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
                               void *d, yasm_output_expr_func output_expr,
                               /*@null@*/ yasm_output_reloc_func output_reloc);
 
 static void x86_bc_jmp_destroy(void *contents);
 static void x86_bc_jmp_print(const void *contents, FILE *f, int indent_level);
-static int x86_bc_jmp_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                              yasm_expr **critical, long *neg_thres,
-                              long *pos_thres);
-static void x86_bc_jmp_set_long(yasm_bytecode *bc);
+static int x86_bc_jmp_calc_len(yasm_bytecode *bc,
+                              yasm_bc_add_span_func add_span,
+                              void *add_span_data);
+static int x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val,
+                            long new_val, /*@out@*/ long *neg_thres,
+                            /*@out@*/ long *pos_thres);
 static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
                              void *d, yasm_output_expr_func output_expr,
                              /*@null@*/ yasm_output_reloc_func output_reloc);
@@ -90,9 +94,9 @@ static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
 static void x86_bc_jmpfar_destroy(void *contents);
 static void x86_bc_jmpfar_print(const void *contents, FILE *f,
                                int indent_level);
-static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                                 yasm_expr **critical, long *neg_thres,
-                                 long *pos_thres);
+static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc,
+                                 yasm_bc_add_span_func add_span,
+                                 void *add_span_data);
 static int x86_bc_jmpfar_tobytes
     (yasm_bytecode *bc, unsigned char **bufp, void *d,
      yasm_output_expr_func output_expr,
@@ -112,7 +116,7 @@ static const yasm_bytecode_callback x86_bc_callback_insn = {
     x86_bc_insn_print,
     yasm_bc_finalize_common,
     x86_bc_insn_calc_len,
-    x86_bc_insn_set_long,
+    x86_bc_insn_expand,
     x86_bc_insn_tobytes
 };
 
@@ -121,7 +125,7 @@ static const yasm_bytecode_callback x86_bc_callback_jmp = {
     x86_bc_jmp_print,
     yasm_bc_finalize_common,
     x86_bc_jmp_calc_len,
-    x86_bc_jmp_set_long,
+    x86_bc_jmp_expand,
     x86_bc_jmp_tobytes
 };
 
@@ -130,7 +134,7 @@ static const yasm_bytecode_callback x86_bc_callback_jmpfar = {
     x86_bc_jmpfar_print,
     yasm_bc_finalize_common,
     x86_bc_jmpfar_calc_len,
-    yasm_bc_set_long_common,
+    yasm_bc_expand_common,
     x86_bc_jmpfar_tobytes
 };
 
@@ -534,16 +538,14 @@ x86_common_calc_len(const x86_common *common)
 }
 
 static int
-x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                    yasm_expr **critical, long *neg_thres, long *pos_thres)
+x86_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                    void *add_span_data)
 {
     x86_insn *insn = (x86_insn *)bc->contents;
     /*@null@*/ yasm_expr *temp;
     x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
     yasm_effaddr *ea = &x86_ea->ea;
     yasm_immval *imm = insn->imm;
-    int retval = 0;
-    int common_len = 0;
 
     if (ea) {
        if (ea->disp) {
@@ -579,18 +581,15 @@ x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
                 * critical expression.
                 */
                bc->len += 1;
-               long_len += (insn->common.addrsize == 16) ? 2U : 4U;
-               *critical = yasm_expr_copy(ea->disp);
-               *neg_thres = -128;
-               *pos_thres = 127;
-               retval = 1;
+               add_span(add_span_data, bc, 1, yasm_expr_copy(ea->disp), -128,
+                        127);
            } else
                bc->len += ea->len;
        }
 
        /* Compute length of ea and add to total */
-       common_len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0);
-       common_len += (x86_ea->ea.segreg != 0) ? 1 : 0;
+       bc->len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0);
+       bc->len += (x86_ea->ea.segreg != 0) ? 1 : 0;
     }
 
     if (imm) {
@@ -609,6 +608,7 @@ x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
                        /* We can use the sign-extended byte form: shorten
                         * the immediate length to 1.
                         */
+                       imm->len = 1;
                        immlen = 1;
                    } else {
                        /* We can't use the ,1. */
@@ -620,11 +620,8 @@ x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
                     * expression.
                     */
                    immlen = 1;
-                   long_len += imm->len;
-                   *critical = yasm_expr_copy(imm->val);
-                   *neg_thres = -128;
-                   *pos_thres = 127;
-                   retval = 1;
+                   add_span(add_span_data, bc, 2, yasm_expr_copy(imm->val),
+                            -128, 127);
                }
            }
 
@@ -645,40 +642,32 @@ x86_bc_insn_calc_len(yasm_bytecode *bc, unsigned long *long_len,
                    }
                    insn->postop = X86_POSTOP_NONE;
                } else {
-                   /* Unknown; default to ,1 form and set as critical
-                    * expression.
+                   /* Just assume we can't use the ,1 form: allowing this
+                    * is more work than it's worth.
                     */
-                   immlen = 0;
-                   long_len += imm->len;
-                   *critical = yasm_expr_copy(imm->val);
-                   *neg_thres = 1;
-                   *pos_thres = 1;
-                   retval = 1;
+                   insn->opcode.opcode[0] = insn->opcode.opcode[1];
+                   insn->postop = X86_POSTOP_NONE;
                }
            }
        }
 
-       common_len += immlen;
+       bc->len += immlen;
     }
 
-    common_len += insn->opcode.len;
-    common_len += x86_common_calc_len(&insn->common);
-    common_len += (insn->special_prefix != 0) ? 1:0;
+    bc->len += insn->opcode.len;
+    bc->len += x86_common_calc_len(&insn->common);
+    bc->len += (insn->special_prefix != 0) ? 1:0;
     if (insn->rex != 0xff &&
        (insn->rex != 0 ||
         (insn->common.mode_bits == 64 && insn->common.opersize == 64 &&
          insn->def_opersize_64 != 64)))
-       common_len++;
-
-    bc->len += common_len;
-    if (retval > 0)
-       *long_len += common_len;
-
-    return retval;
+       bc->len++;
+    return 0;
 }
 
-static void
-x86_bc_insn_set_long(yasm_bytecode *bc)
+static int
+x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+                  /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
 {
     x86_insn *insn = (x86_insn *)bc->contents;
     /*@null@*/ yasm_expr *temp;
@@ -692,93 +681,99 @@ x86_bc_insn_set_long(yasm_bytecode *bc)
            ea->len = (insn->common.addrsize == 16) ? 2U : 4U;
            x86_ea->modrm &= ~0300;
            x86_ea->modrm |= 0200;
+           bc->len--;
+           bc->len += ea->len;
        }
     }
 
     if (imm && imm->val) {
-       /* Handle shift postop special-casing */
-       if (insn->postop == X86_POSTOP_SHIFT) {
-           /* We can't use the ,1 form. */
-           insn->opcode.opcode[0] = insn->opcode.opcode[1];
+       if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
+           bc->len--;
+           bc->len += imm->len;
            insn->postop = X86_POSTOP_NONE;
        }
     }
+
+    return 0;
 }
 
 static int
-x86_bc_jmp_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                   yasm_expr **critical, long *neg_thres, long *pos_thres)
+x86_bc_jmp_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                   void *add_span_data)
 {
     x86_jmp *jmp = (x86_jmp *)bc->contents;
-    int retval = 0;
-    unsigned int common_len;
     unsigned char opersize;
 
     /* As opersize may be 0, figure out its "real" value. */
     opersize = (jmp->common.opersize == 0) ?
        jmp->common.mode_bits : jmp->common.opersize;
 
-    if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
-       if (jmp->shortop.len == 0) {
-           yasm__error(bc->line, N_("short jump does not exist"));
-           return -1;
-       }
+    bc->len += x86_common_calc_len(&jmp->common);
 
-       /* We want to be sure to error if we exceed short length, so still
-        * put it in as a critical expression, but leave the return value as
-        * 0.
-        */
-       bc->len += jmp->shortop.len + 1;
-       *critical = yasm_expr_create(YASM_EXPR_SUB,
-           yasm_expr_expr(yasm_expr_copy(jmp->target)),
-           yasm_expr_sym(jmp->origin), bc->line);
-       *neg_thres = -128;
-       *pos_thres = 127;
-    } else if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) {
+    if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) {
        if (jmp->nearop.len == 0) {
            yasm__error(bc->line, N_("near jump does not exist"));
            return -1;
        }
 
+       /* Near jump, no spans needed */
        bc->len += jmp->nearop.len;
        bc->len += (opersize == 16) ? 2 : 4;
-    } else {
-       /* short length goes into bytecode */
-       retval = 1;
-       bc->len += jmp->shortop.len + 1;
-       *long_len += jmp->nearop.len;
-       *long_len += (opersize == 16) ? 2 : 4;
-       *critical = yasm_expr_create(YASM_EXPR_SUB,
-           yasm_expr_expr(yasm_expr_copy(jmp->target)),
-           yasm_expr_sym(jmp->origin), bc->line);
-       *neg_thres = -128;
-       *pos_thres = 127;
+       return 0;
     }
 
-    common_len = x86_common_calc_len(&jmp->common);
-    bc->len += common_len;
-    if (retval > 0)
-       *long_len += common_len;
+    if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
+       if (jmp->shortop.len == 0) {
+           yasm__error(bc->line, N_("short jump does not exist"));
+           return -1;
+       }
+
+       /* We want to be sure to error if we exceed short length, so
+        * put it in as a dependent expression (falling through).
+        */
+    }
 
-    return retval;
+    /* Short jump, generate span */
+    bc->len += jmp->shortop.len + 1;
+    add_span(add_span_data, bc, 1,
+            yasm_expr_create(YASM_EXPR_SUB,
+                             yasm_expr_expr(yasm_expr_copy(jmp->target)),
+                             yasm_expr_sym(jmp->origin), bc->line),
+            -128, 127);
+    return 0;
 }
 
-static void
-x86_bc_jmp_set_long(yasm_bytecode *bc)
+static int
+x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+                 /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
 {
     x86_jmp *jmp = (x86_jmp *)bc->contents;
+    unsigned char opersize;
+
+    if (span != 1)
+       yasm_internal_error(N_("unrecognized span id"));
+
+    /* As opersize may be 0, figure out its "real" value. */
+    opersize = (jmp->common.opersize == 0) ?
+       jmp->common.mode_bits : jmp->common.opersize;
 
     if (jmp->nearop.len == 0) {
-       yasm__error(bc->line,
-                   N_("short jump out of range"));
-       return;
+       yasm__error(bc->line, N_("short jump out of range"));
+       return -1;
     }
+
+    /* Upgrade to a near jump */
     jmp->op_sel = JMP_NEAR;
+    bc->len -= jmp->shortop.len + 1;
+    bc->len += jmp->nearop.len;
+    bc->len += (opersize == 16) ? 2 : 4;
+
+    return 0;
 }
 
 static int
-x86_bc_jmpfar_calc_len(yasm_bytecode *bc, unsigned long *long_len,
-                      yasm_expr **critical, long *neg_thres, long *pos_thres)
+x86_bc_jmpfar_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+                      void *add_span_data)
 {
     x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
     unsigned char opersize;