diff options
| author | Yukihiro Matsumoto <[email protected]> | 2012-06-13 15:38:18 +0900 |
|---|---|---|
| committer | Yukihiro Matsumoto <[email protected]> | 2012-06-13 15:38:18 +0900 |
| commit | 6a5019d37fd595abd9e8297bb3d35a1ee054becf (patch) | |
| tree | c9c021c80d5d9f0ccf940f07c487264ac167fea5 /src | |
| parent | 38941772333d5d9298b76dfc8a97c5b076daedc2 (diff) | |
| download | mruby-6a5019d37fd595abd9e8297bb3d35a1ee054becf.tar.gz mruby-6a5019d37fd595abd9e8297bb3d35a1ee054becf.zip | |
optimized OP_{ADD,SUB,MUL,DIV} to use numeric function for fixnums to handle overflow
Diffstat (limited to 'src')
| -rw-r--r-- | src/numeric.c | 198 | ||||
| -rw-r--r-- | src/vm.c | 39 |
2 files changed, 128 insertions, 109 deletions
diff --git a/src/numeric.c b/src/numeric.c index e1f711478..2d668fa79 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -118,6 +118,12 @@ num_pow(mrb_state *mrb, mrb_value x) * result. */ +mrb_value +mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) +{ + return mrb_float_value(mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y)); +} + /* 15.2.9.3.19(x) */ /* * call-seq: @@ -404,7 +410,7 @@ flo_to_f(mrb_state *mrb, mrb_value num) */ static mrb_value -flo_is_infinite_p(mrb_state *mrb, mrb_value num) +flo_infinite_p(mrb_state *mrb, mrb_value num) { mrb_float value = mrb_float(num); @@ -426,7 +432,7 @@ flo_is_infinite_p(mrb_state *mrb, mrb_value num) */ static mrb_value -flo_is_finite_p(mrb_state *mrb, mrb_value num) +flo_finite_p(mrb_state *mrb, mrb_value num) { mrb_float value = mrb_float(num); @@ -691,9 +697,31 @@ int_succ(mrb_state *mrb, mrb_value num) return mrb_funcall(mrb, num, "+", 1, mrb_fixnum_value(1)); } -#define SQRT_LONG_MAX ((SIGNED_VALUE)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2)) +#define SQRT_INT_MAX ((SIGNED_VALUE)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2)) /*tests if N*N would overflow*/ -#define FIT_SQRT_LONG(n) (((n)<SQRT_LONG_MAX)&&((n)>=-SQRT_LONG_MAX)) +#define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX)) + +mrb_value +mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) +{ + mrb_int a; + + a = mrb_fixnum(x); + if (a == 0) return x; + if (FIXNUM_P(y)) { + mrb_int b, c; + + b = mrb_fixnum(y); + if (FIT_SQRT_INT(a) && FIT_SQRT_INT(b)) + return mrb_fixnum_value(a*b); + c = a * b; + if (c/a != b) { + return mrb_float_value((mrb_float)a*(mrb_float)b); + } + return mrb_fixnum_value(c);; + } + return mrb_float_value((mrb_float)a * mrb_to_flo(mrb, y)); +} /* 15.2.8.3.3 */ /* @@ -709,27 +737,8 @@ static mrb_value fix_mul(mrb_state *mrb, mrb_value x) { mrb_value y; - mrb_int a; mrb_get_args(mrb, "o", &y); - - a = mrb_fixnum(x); - if (FIXNUM_P(y)) { - mrb_int b, c; - mrb_value r; - - b = mrb_fixnum(y); - if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b)) - return mrb_fixnum_value(a*b); - c = a * b; - r = mrb_fixnum_value(c); - - if (a == 0) return x; - if (mrb_fixnum(r) != c || c/a != b) { - r = mrb_float_value((mrb_float)a*(mrb_float)b); - } - return r; - } - return mrb_float_value((mrb_float)a * mrb_to_flo(mrb, y)); + return mrb_fixnum_mul(mrb, x, y); } static void @@ -942,8 +951,28 @@ fix_xor(mrb_state *mrb, mrb_value x) return mrb_fixnum_value(val); } -static mrb_value fix_lshift(mrb_state *mrb, mrb_int, unsigned long); -static mrb_value fix_rshift(mrb_int, unsigned long); +static mrb_value +lshift(mrb_state *mrb, mrb_int val, unsigned long width) +{ + if (width > (sizeof(mrb_int)*CHAR_BIT-1) + || ((unsigned long)abs(val))>>(sizeof(mrb_int)*CHAR_BIT-1-width) > 0) { + mrb_raise(mrb, E_RANGE_ERROR, "width(%d) > (%d:sizeof(mrb_int)*CHAR_BIT-1)", width, + sizeof(mrb_int)*CHAR_BIT-1); + } + val = val << width; + return mrb_fixnum_value(val); +} + +static mrb_value +rshift(mrb_int val, unsigned long i) +{ + if (i >= sizeof(mrb_int)*CHAR_BIT-1) { + if (val < 0) return mrb_fixnum_value(-1); + return mrb_fixnum_value(0); + } + val = RSHIFT(val, i); + return mrb_fixnum_value(val); +} /* 15.2.8.3.12 */ /* @@ -954,7 +983,7 @@ static mrb_value fix_rshift(mrb_int, unsigned long); */ static mrb_value -mrb_fix_lshift(mrb_state *mrb, mrb_value x) +fix_lshift(mrb_state *mrb, mrb_value x) { mrb_value y; mrb_int val, width; @@ -964,20 +993,8 @@ mrb_fix_lshift(mrb_state *mrb, mrb_value x) y = bit_coerce(mrb, y); width = mrb_fixnum(y); if (width < 0) - return fix_rshift(val, (unsigned long)-width); - return fix_lshift(mrb, val, width); -} - -static mrb_value -fix_lshift(mrb_state *mrb, mrb_int val, unsigned long width) -{ - if (width > (sizeof(mrb_int)*CHAR_BIT-1) - || ((unsigned long)abs(val))>>(sizeof(mrb_int)*CHAR_BIT-1-width) > 0) { - mrb_raise(mrb, E_RANGE_ERROR, "width(%d) > (%d:sizeof(mrb_int)*CHAR_BIT-1)", width, - sizeof(mrb_int)*CHAR_BIT-1); - } - val = val << width; - return mrb_fixnum_value(val); + return rshift(val, (unsigned long)-width); + return lshift(mrb, val, width); } /* 15.2.8.3.13 */ @@ -989,7 +1006,7 @@ fix_lshift(mrb_state *mrb, mrb_int val, unsigned long width) */ static mrb_value -mrb_fix_rshift(mrb_state *mrb, mrb_value x) +fix_rshift(mrb_state *mrb, mrb_value x) { mrb_value y; mrb_int i, val; @@ -1000,19 +1017,8 @@ mrb_fix_rshift(mrb_state *mrb, mrb_value x) i = mrb_fixnum(y); if (i == 0) return x; if (i < 0) - return fix_lshift(mrb, val, (unsigned long)-i); - return fix_rshift(val, i); -} - -static mrb_value -fix_rshift(mrb_int val, unsigned long i) -{ - if (i >= sizeof(mrb_int)*CHAR_BIT-1) { - if (val < 0) return mrb_fixnum_value(-1); - return mrb_fixnum_value(0); - } - val = RSHIFT(val, i); - return mrb_fixnum_value(val); + return lshift(mrb, val, (unsigned long)-i); + return rshift(val, i); } /* 15.2.8.3.23 */ @@ -1066,7 +1072,27 @@ flt2big(mrb_state *mrb, mrb_float d) mrb_value mrb_flt2big(mrb_state *mrb, mrb_float d) { - return mrb_fixnum_value(flt2big(mrb, d)); + return mrb_fixnum_value(flt2big(mrb, d)); +} + +mrb_value +mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + mrb_int a; + + a = mrb_fixnum(x); + if (a == 0) return y; + if (FIXNUM_P(y)) { + mrb_int b, c; + + b = mrb_fixnum(y); + c = a + b; + if (c - b != a) { + return mrb_float_value((mrb_float)a + (mrb_float)b); + } + return mrb_fixnum_value(c); + } + return mrb_float_value((mrb_float)a + mrb_to_flo(mrb, y)); } /* 15.2.8.3.1 */ @@ -1079,15 +1105,32 @@ mrb_flt2big(mrb_state *mrb, mrb_float d) * result. */ static mrb_value -mrb_fixnum_plus(mrb_state *mrb, mrb_value self) +fix_plus(mrb_state *mrb, mrb_value self) { - mrb_int x, y; + mrb_value other; + + mrb_get_args(mrb, "o", &other); + return mrb_fixnum_plus(mrb, self, other); +} - x = mrb_fixnum(self); - mrb_get_args(mrb, "i", &y); +mrb_value +mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + mrb_int a; + + a = mrb_fixnum(x); + if (a == 0) return y; + if (FIXNUM_P(y)) { + mrb_int b, c; - DEBUG(printf("%d + %d = %d\n", x, y, x+y)); - return mrb_fixnum_value(x + y); + b = mrb_fixnum(y); + c = a - b; + if (c + b != a) { + return mrb_float_value((mrb_float)a - (mrb_float)b); + } + return mrb_fixnum_value(c); + } + return mrb_float_value((mrb_float)a - mrb_to_flo(mrb, y)); } /* 15.2.8.3.2 */ @@ -1101,15 +1144,12 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value self) * result. */ static mrb_value -mrb_fixnum_minus(mrb_state *mrb, mrb_value self) +fix_minus(mrb_state *mrb, mrb_value self) { - mrb_int x, y; - - x = mrb_fixnum(self); - mrb_get_args(mrb, "i", &y); + mrb_value other; - DEBUG(printf("%d - %d = %d\n", x, y, x-y)); - return mrb_fixnum_value(x - y); + mrb_get_args(mrb, "o", &other); + return mrb_fixnum_minus(mrb, self, other); } /* 15.2.8.3.29 (x) */ @@ -1179,7 +1219,7 @@ mrb_fix_to_s(mrb_state *mrb, mrb_value self, int argc, mrb_value *argv) * */ static mrb_value -mrb_fixnum_to_s(mrb_state *mrb, mrb_value self) /* fix_to_s */ +fix_to_s(mrb_state *mrb, mrb_value self) /* fix_to_s */ { mrb_value *argv; int argc; @@ -1236,7 +1276,7 @@ num_cmp(mrb_state *mrb, mrb_value self) * and <code>other</code>. */ static mrb_value -mrb_float_plus(mrb_state *mrb, mrb_value self) +flo_plus(mrb_state *mrb, mrb_value self) { mrb_float x, y; @@ -1267,8 +1307,8 @@ mrb_init_numeric(mrb_state *mrb) fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer); mrb_undef_method(mrb, fixnum, "new"); - mrb_define_method(mrb, fixnum, "+", mrb_fixnum_plus, ARGS_REQ(1)); /* 15.2.8.3.1 */ - mrb_define_method(mrb, fixnum, "-", mrb_fixnum_minus, ARGS_REQ(1)); /* 15.2.8.3.2 */ + mrb_define_method(mrb, fixnum, "+", fix_plus, ARGS_REQ(1)); /* 15.2.8.3.1 */ + mrb_define_method(mrb, fixnum, "-", fix_minus, ARGS_REQ(1)); /* 15.2.8.3.2 */ mrb_define_method(mrb, fixnum, "-@", fix_uminus, ARGS_REQ(1)); /* 15.2.7.4.2 */ mrb_define_method(mrb, fixnum, "*", fix_mul, ARGS_REQ(1)); /* 15.2.8.3.3 */ mrb_define_method(mrb, fixnum, "%", fix_mod, ARGS_REQ(1)); /* 15.2.8.3.5 */ @@ -1277,8 +1317,8 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fixnum, "&", fix_and, ARGS_REQ(1)); /* 15.2.8.3.9 */ mrb_define_method(mrb, fixnum, "|", fix_or, ARGS_REQ(1)); /* 15.2.8.3.10 */ mrb_define_method(mrb, fixnum, "^", fix_xor, ARGS_REQ(1)); /* 15.2.8.3.11 */ - mrb_define_method(mrb, fixnum, "<<", mrb_fix_lshift, ARGS_REQ(1)); /* 15.2.8.3.12 */ - mrb_define_method(mrb, fixnum, ">>", mrb_fix_rshift, ARGS_REQ(1)); /* 15.2.8.3.13 */ + mrb_define_method(mrb, fixnum, "<<", fix_lshift, ARGS_REQ(1)); /* 15.2.8.3.12 */ + mrb_define_method(mrb, fixnum, ">>", fix_rshift, ARGS_REQ(1)); /* 15.2.8.3.13 */ mrb_define_method(mrb, fixnum, "ceil", int_to_i, ARGS_NONE()); /* 15.2.8.3.14 */ mrb_define_method(mrb, fixnum, "eql?", num_eql, ARGS_REQ(1)); /* 15.2.8.3.16 */ mrb_define_method(mrb, fixnum, "floor", num_floor, ARGS_NONE()); /* 15.2.8.3.17 */ @@ -1288,22 +1328,22 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fixnum, "succ", fix_succ, ARGS_NONE()); /* 15.2.8.3.21 */ mrb_define_method(mrb, fixnum, "to_f", fix_to_f, ARGS_NONE()); /* 15.2.8.3.23 */ mrb_define_method(mrb, fixnum, "to_i", int_to_i, ARGS_NONE()); /* 15.2.8.3.24 */ - mrb_define_method(mrb, fixnum, "to_s", mrb_fixnum_to_s, ARGS_NONE()); /* 15.2.8.3.25 */ + mrb_define_method(mrb, fixnum, "to_s", fix_to_s, ARGS_NONE()); /* 15.2.8.3.25 */ mrb_define_method(mrb, fixnum, "truncate", int_to_i, ARGS_NONE()); /* 15.2.8.3.26 */ mrb_define_method(mrb, fixnum, "divmod", fix_divmod, ARGS_REQ(1)); /* 15.2.8.3.30 (x) */ /* Float Class */ fl = mrb->float_class = mrb_define_class(mrb, "Float", numeric); mrb_undef_method(mrb, fl, "new"); - mrb_define_method(mrb, fl, "+", mrb_float_plus, ARGS_REQ(1)); /* 15.2.9.3.1 */ + mrb_define_method(mrb, fl, "+", flo_plus, ARGS_REQ(1)); /* 15.2.9.3.1 */ mrb_define_method(mrb, fl, "-", flo_minus, ARGS_REQ(1)); /* 15.2.9.3.2 */ mrb_define_method(mrb, fl, "*", flo_mul, ARGS_REQ(1)); /* 15.2.9.3.3 */ mrb_define_method(mrb, fl, "%", flo_mod, ARGS_REQ(1)); /* 15.2.9.3.5 */ mrb_define_method(mrb, fl, "==", flo_eq, ARGS_REQ(1)); /* 15.2.9.3.7 */ mrb_define_method(mrb, fl, "ceil", flo_ceil, ARGS_NONE()); /* 15.2.9.3.8 */ - mrb_define_method(mrb, fl, "finite?", flo_is_finite_p, ARGS_NONE()); /* 15.2.9.3.9 */ + mrb_define_method(mrb, fl, "finite?", flo_finite_p, ARGS_NONE()); /* 15.2.9.3.9 */ mrb_define_method(mrb, fl, "floor", flo_floor, ARGS_NONE()); /* 15.2.9.3.10 */ - mrb_define_method(mrb, fl, "infinite?", flo_is_infinite_p,ARGS_NONE()); /* 15.2.9.3.11 */ + mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, ARGS_NONE()); /* 15.2.9.3.11 */ mrb_define_method(mrb, fl, "round", flo_round, ARGS_ANY()); /* 15.2.9.3.12 */ mrb_define_method(mrb, fl, "to_f", flo_to_f, ARGS_NONE()); /* 15.2.9.3.13 */ mrb_define_method(mrb, fl, "to_i", flo_truncate, ARGS_NONE()); /* 15.2.9.3.14 */ @@ -1162,12 +1162,12 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) regs[a].value.v1 = regs[a].value.v1 op regs[a+1].value.v2;\ } while(0) -#define OP_MATH(op) do {\ +#define OP_MATH(op,iop,s) do {\ int a = GETARG_A(i);\ - /* need to check if - is overridden */\ + /* need to check if op is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\ - OP_MATH_BODY(op,i,i); \ + regs[a] = iop(mrb, regs[a], regs[a+1]);\ break;\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\ {\ @@ -1182,6 +1182,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\ OP_MATH_BODY(op,f,f);\ break;\ + s\ default:\ i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i));\ goto L_SEND;\ @@ -1190,50 +1191,28 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) CASE(OP_ADD) { /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/ - int a = GETARG_A(i); - - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - OP_MATH_BODY(+,i,i); - break; - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = regs[a].value.i; - mrb_float y = regs[a+1].value.f; - SET_FLOAT_VALUE(regs[a], (mrb_float)x + y); - } - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_BODY(+,f,i); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_BODY(+,f,f); - break; + OP_MATH(+,mrb_fixnum_plus, case TYPES2(MRB_TT_STRING,MRB_TT_STRING): regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); - break; - default: - i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i)); - goto L_SEND; - } + break;); NEXT; } CASE(OP_SUB) { /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/ - OP_MATH(-); + OP_MATH(-,mrb_fixnum_minus,;); NEXT; } CASE(OP_MUL) { /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/ - OP_MATH(*); + OP_MATH(*,mrb_fixnum_mul,;); NEXT; } CASE(OP_DIV) { /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/ - OP_MATH(/); + OP_MATH(/,mrb_num_div,;); NEXT; } |
