From b3b5e626ad69bf22be3228f847f94e1b68f40888 Mon Sep 17 00:00:00 2001 From: ko1 Date: Thu, 23 Aug 2012 07:22:40 +0000 Subject: [PATCH] * include/ruby/ruby.h: introduce flonum technique for 64bit CPU environment (sizeof(double) == sizeof(VALUE)). flonum technique enables to avoid double object creation if the double value d is in range about between 1.72723e-77 < |d| <= 1.15792e+77 or 0.0. flonum Float value is immediate and their lowest two bits are b10. If flonum is activated, then USE_FLONUM macro is 1. I'll write detailed in this technique on https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/Flonum_tech * benchmark/bmx_temp.rb: add an benchmark for simple Float calculation. * gc.c (id2ref, rb_obj_id): add flonum Float support. * include/ruby/intern.h: move decl of rb_float_new(double) to include/ruby/ruby.h. * insns.def, vm.c, vm_insnhelper.c: add flonum optimization and simplify source code. * vm_insnhelper.h (FLONUM_2_P): added. * marshal.c: support flonum output. * numeric.c (rb_float_new_in_heap): added. * parse.y: support flonum. * random.c: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36798 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 34 ++++++++++ benchmark/bmx_temp.rb | 6 +- gc.c | 12 +++- include/ruby/intern.h | 1 - include/ruby/ruby.h | 154 ++++++++++++++++++++++++++++++++++++++++-- insns.def | 143 +++++++++++++++++---------------------- marshal.c | 4 ++ numeric.c | 2 +- parse.y | 9 +++ random.c | 3 +- vm.c | 10 +-- vm_insnhelper.c | 40 ++++++++++- vm_insnhelper.h | 10 ++- 13 files changed, 324 insertions(+), 104 deletions(-) diff --git a/ChangeLog b/ChangeLog index 97ee6450f1..892bbf209b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +Thu Aug 23 16:20:04 2012 Koichi Sasada + + * include/ruby/ruby.h: introduce flonum technique for + 64bit CPU environment (sizeof(double) == sizeof(VALUE)). + flonum technique enables to avoid double object creation + if the double value d is in range about between + 1.72723e-77 < |d| <= 1.15792e+77 or 0.0. + flonum Float value is immediate and their lowest two bits + are b10. + If flonum is activated, then USE_FLONUM macro is 1. + I'll write detailed in this technique on + https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/Flonum_tech + + * benchmark/bmx_temp.rb: add an benchmark for simple + Float calculation. + + * gc.c (id2ref, rb_obj_id): add flonum Float support. + + * include/ruby/intern.h: move decl of rb_float_new(double) + to include/ruby/ruby.h. + + * insns.def, vm.c, vm_insnhelper.c: add flonum optimization + and simplify source code. + + * vm_insnhelper.h (FLONUM_2_P): added. + + * marshal.c: support flonum output. + + * numeric.c (rb_float_new_in_heap): added. + + * parse.y: support flonum. + + * random.c: ditto. + Thu Aug 23 16:12:40 2012 NAKAMURA Usaku * lib/mkmf.rb (create_makefile): add dependency to header files when diff --git a/benchmark/bmx_temp.rb b/benchmark/bmx_temp.rb index 9f49e20ac6..ef762de204 100644 --- a/benchmark/bmx_temp.rb +++ b/benchmark/bmx_temp.rb @@ -1,9 +1,5 @@ -def m - nil -end - i = 0 while i<800000 # benchmark loop 2 i+=1 - m; m; m; m; m; m; m; m; + a = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 end diff --git a/gc.c b/gc.c index 34d942298d..333cb2a53c 100644 --- a/gc.c +++ b/gc.c @@ -1606,6 +1606,7 @@ id2ref(VALUE obj, VALUE objid) if (ptr == Qfalse) return Qfalse; if (ptr == Qnil) return Qnil; if (FIXNUM_P(ptr)) return (VALUE)ptr; + if (FLONUM_P(ptr)) return (VALUE)ptr; ptr = objid ^ FIXNUM_FLAG; /* unset FIXNUM_FLAG */ if ((ptr % sizeof(RVALUE)) == (4 << 2)) { @@ -1685,8 +1686,15 @@ rb_obj_id(VALUE obj) if (SYMBOL_P(obj)) { return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG; } - if (SPECIAL_CONST_P(obj)) { - return LONG2NUM((SIGNED_VALUE)obj); + else if (FLONUM_P(obj)) { +#if SIZEOF_LONG == SIZEOF_VOIDP + return LONG2NUM((SIGNED_VALUE)obj); +#else + return LL2NUM((SIGNED_VALUE)obj); +#endif + } + else if (SPECIAL_CONST_P(obj)) { + return LONG2NUM((SIGNED_VALUE)obj); } return nonspecial_obj_id(obj); } diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 71f5442a7a..3f03d4dab7 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -516,7 +516,6 @@ NORETURN(void rb_num_zerodiv(void)); VALUE rb_num_coerce_bin(VALUE, VALUE, ID); VALUE rb_num_coerce_cmp(VALUE, VALUE, ID); VALUE rb_num_coerce_relop(VALUE, VALUE, ID); -VALUE rb_float_new(double); VALUE rb_num2fix(VALUE); VALUE rb_fix2str(VALUE, int); VALUE rb_dbl_cmp(double, double); diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 6f8ae89658..b0267600cb 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -350,11 +350,59 @@ rb_long2int_inline(long n) #define ID2SYM(x) (((VALUE)(x)<= SIZEOF_DOUBLE +#define USE_FLONUM 1 +#else +#define USE_FLONUM 0 +#endif +#endif + +#if USE_FLONUM +#define FLONUM_P(x) ((((int)(SIGNED_VALUE)(x))&FLONUM_MASK) == FLONUM_FLAG) +#else +#define FLONUM_P(x) 0 +#endif + /* Module#methods, #singleton_methods and so on return Symbols */ #define USE_SYMBOL_AS_METHOD_NAME 1 +/* +!USE_FLONUM +------------------------- +...xxxx xxx1 Fixnum +...0000 1110 Symbol +...0000 0000 Qfalse +...0000 0010 Qtrue +...0000 0100 Qnil +...0000 0110 Qundef + +USE_FLONUM +------------------------- +...xxxx xxx1 Fixnum +...xxxx xx10 Flonum +...0000 1100 Symbol +...0000 0000 Qfalse 0x00 = 0 +...0000 1000 Qnil 0x08 = 8 +...0001 0100 Qtrue 0x14 = 20 +...0011 0100 Qundef 0x34 = 52 + */ + /* special constants - i.e. non-zero and non-fixnum constants */ enum ruby_special_consts { +#if USE_FLONUM + RUBY_Qfalse = 0x00, + RUBY_Qtrue = 0x14, + RUBY_Qnil = 0x08, + RUBY_Qundef = 0x34, + + RUBY_IMMEDIATE_MASK = 0x07, + RUBY_FIXNUM_FLAG = 0x01, + RUBY_FLONUM_MASK = 0x03, + RUBY_FLONUM_FLAG = 0x02, + RUBY_SYMBOL_FLAG = 0x0c, + RUBY_SPECIAL_SHIFT = 8 +#else RUBY_Qfalse = 0, RUBY_Qtrue = 2, RUBY_Qnil = 4, @@ -364,6 +412,7 @@ enum ruby_special_consts { RUBY_FIXNUM_FLAG = 0x01, RUBY_SYMBOL_FLAG = 0x0e, RUBY_SPECIAL_SHIFT = 8 +#endif }; #define Qfalse ((VALUE)RUBY_Qfalse) @@ -372,6 +421,10 @@ enum ruby_special_consts { #define Qundef ((VALUE)RUBY_Qundef) /* undefined value for placeholder */ #define IMMEDIATE_MASK RUBY_IMMEDIATE_MASK #define FIXNUM_FLAG RUBY_FIXNUM_FLAG +#if USE_FLONUM +#define FLONUM_MASK RUBY_FLONUM_MASK +#define FLONUM_FLAG RUBY_FLONUM_FLAG +#endif #define SYMBOL_FLAG RUBY_SYMBOL_FLAG #define RTEST(v) (((VALUE)(v) & ~Qnil) != 0) @@ -669,7 +722,87 @@ struct RFloat { struct RBasic basic; double float_value; }; -#define RFLOAT_VALUE(v) (RFLOAT(v)->float_value) + +VALUE rb_float_new_in_heap(double); + +#if USE_FLONUM +#define RUBY_BIT_ROTL(v, n) (((v) << (n)) | ((v) >> ((sizeof(v) * 8) - n))) +#define RUBY_BIT_ROTR(v, n) (((v) >> (n)) | ((v) << ((sizeof(v) * 8) - n))) + +static inline double +rb_float_value(VALUE v) +{ + if (FLONUM_P(v)) { + if (v == (VALUE)0x8000000000000002) { + return 0.0; + } + else { + union { + double d; + VALUE v; + } t; + + VALUE b63 = (v >> 63); + /* e: xx1... -> 011... */ + /* xx0... -> 100... */ + /* ^b63 */ + t.v = RUBY_BIT_ROTR(((b63 ^ 1) << 1) | b63 | (v & ~0x03), 3); + return t.d; + } + } + else { + return ((struct RFloat *)v)->float_value; + } +} + +static inline VALUE +rb_float_new(double d) +{ + union { + double d; + VALUE v; + } t; + int bits; + + t.d = d; + bits = (int)((VALUE)(t.v >> 60) & 0x7); + /* bits contains 3 bits of b62..b60. */ + /* bits - 3 = */ + /* b011 -> b000 */ + /* b100 -> b001 */ + + if (t.v != 0x3000000000000000 /* 1.72723e-77 */ && + !((bits-3) & ~0x01)) { + return (RUBY_BIT_ROTL(t.v, 3) & ~0x01 | 0x02); + } + else { + if (t.v == (VALUE)0) { + /* +0.0 */ + return 0x8000000000000002; + } + else { + /* out of range */ + return rb_float_new_in_heap(d); + } + } +} + +#else /* USE_FLONUM */ + +static inline double +rb_float_value(VALUE v) +{ + return ((struct RFloat *)v)->float_value; +} + +static inline VALUE +rb_float_new(double d) +{ + return rb_float_new_in_heap(d); +} +#endif + +#define RFLOAT_VALUE(v) rb_float_value(v) #define DBL2NUM(dbl) rb_float_new(dbl) #define ELTS_SHARED FL_USER2 @@ -990,7 +1123,11 @@ struct RBignum { #define OBJ_TAINT(x) FL_SET((x), FL_TAINT) #define OBJ_UNTRUSTED(x) (!!FL_TEST((x), FL_UNTRUSTED)) #define OBJ_UNTRUST(x) FL_SET((x), FL_UNTRUSTED) -#define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & (FL_TAINT | FL_UNTRUSTED);} while (0) +#define OBJ_INFECT(x,s) do { \ + if (FL_ABLE(x) && FL_ABLE(s)) \ + RBASIC(x)->flags |= RBASIC(s)->flags & \ + (FL_TAINT | FL_UNTRUSTED); \ +} while (0) #define OBJ_FROZEN(x) (!!FL_TEST((x), FL_FREEZE)) #define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE) @@ -1332,6 +1469,7 @@ rb_class_of(VALUE obj) { if (IMMEDIATE_P(obj)) { if (FIXNUM_P(obj)) return rb_cFixnum; + if (FLONUM_P(obj)) return rb_cFloat; if (obj == Qtrue) return rb_cTrueClass; if (SYMBOL_P(obj)) return rb_cSymbol; } @@ -1347,17 +1485,24 @@ rb_type(VALUE obj) { if (IMMEDIATE_P(obj)) { if (FIXNUM_P(obj)) return T_FIXNUM; - if (obj == Qtrue) return T_TRUE; + if (FLONUM_P(obj)) return T_FLOAT; + if (obj == Qtrue) return T_TRUE; if (SYMBOL_P(obj)) return T_SYMBOL; if (obj == Qundef) return T_UNDEF; } else if (!RTEST(obj)) { - if (obj == Qnil) return T_NIL; + if (obj == Qnil) return T_NIL; if (obj == Qfalse) return T_FALSE; } return BUILTIN_TYPE(obj); } +#if USE_FLONUM +#define RB_FLOAT_TYPE_P(obj) (FLONUM_P(obj) || TYPE(obj) == T_FLOAT) +#else +#define RB_FLOAT_TYPE_P(obj) (!SPECIAL_CONST_P(obj) && BUILTIN_TYPE(obj) == T_FLOAT) +#endif + #define RB_TYPE_P(obj, type) ( \ ((type) == T_FIXNUM) ? FIXNUM_P(obj) : \ ((type) == T_TRUE) ? ((obj) == Qtrue) : \ @@ -1365,6 +1510,7 @@ rb_type(VALUE obj) ((type) == T_NIL) ? ((obj) == Qnil) : \ ((type) == T_UNDEF) ? ((obj) == Qundef) : \ ((type) == T_SYMBOL) ? SYMBOL_P(obj) : \ + ((type) == T_FLOAT) ? RB_FLOAT_TYPE_P(obj) : \ (!SPECIAL_CONST_P(obj) && BUILTIN_TYPE(obj) == (type))) #ifdef __GNUC__ diff --git a/insns.def b/insns.def index 7c9dd6ae6c..d123ec2b33 100644 --- a/insns.def +++ b/insns.def @@ -1333,12 +1333,8 @@ opt_plus (VALUE recv, VALUE obj) (VALUE val) { - if (0) { - - } -#if 1 - else if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_PLUS,FIXNUM_REDEFINED_OP_FLAG)) { + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_PLUS,FIXNUM_REDEFINED_OP_FLAG)) { /* fixnum + fixnum */ #ifndef LONG_LONG_VALUE val = (recv + (obj & (~1))); @@ -1360,38 +1356,29 @@ opt_plus } #endif } -#endif - + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) { + val = DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj)); + } else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (0) { - } -#if 1 - else if (HEAP_CLASS_OF(recv) == rb_cFloat && - HEAP_CLASS_OF(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) { + if (HEAP_CLASS_OF(recv) == rb_cFloat && HEAP_CLASS_OF(obj) == rb_cFloat && + BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) { val = DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj)); } -#endif - -#if 1 - else if (HEAP_CLASS_OF(recv) == rb_cString && - HEAP_CLASS_OF(obj) == rb_cString && + else if (HEAP_CLASS_OF(recv) == rb_cString && HEAP_CLASS_OF(obj) == rb_cString && BASIC_OP_UNREDEFINED_P(BOP_PLUS, STRING_REDEFINED_OP_FLAG)) { val = rb_str_plus(recv, obj); } -#endif -#if 1 else if (HEAP_CLASS_OF(recv) == rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_PLUS, ARRAY_REDEFINED_OP_FLAG)) { val = rb_ary_plus(recv, obj); } -#endif else { goto INSN_LABEL(normal_dispatch); } } else { - INSN_LABEL(normal_dispatch): + INSN_LABEL(normal_dispatch): PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(1, idPLUS, recv); @@ -1424,16 +1411,15 @@ opt_minus val = rb_big_minus(rb_int2big(a), rb_int2big(b)); } } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) { + val = DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj)); + } else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (0) { - } -#if 1 - else if (HEAP_CLASS_OF(recv) == rb_cFloat && - HEAP_CLASS_OF(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) { + if (HEAP_CLASS_OF(recv) == rb_cFloat && HEAP_CLASS_OF(obj) == rb_cFloat && + BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) { val = DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj)); } -#endif else { goto INSN_LABEL(normal_dispatch); } @@ -1479,16 +1465,15 @@ opt_mult } } } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { + val = DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj)); + } else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (0) { - } -#if 1 - else if (HEAP_CLASS_OF(recv) == rb_cFloat && - HEAP_CLASS_OF(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { + if (HEAP_CLASS_OF(recv) == rb_cFloat && HEAP_CLASS_OF(obj) == rb_cFloat && + BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { val = DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj)); } -#endif else { goto INSN_LABEL(normal_dispatch); } @@ -1543,16 +1528,15 @@ opt_div } val = LONG2NUM(div); } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { + val = DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj)); + } else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (0) { - } -#if 1 - else if (HEAP_CLASS_OF(recv) == rb_cFloat && - HEAP_CLASS_OF(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) { + if (HEAP_CLASS_OF(recv) == rb_cFloat && HEAP_CLASS_OF(obj) == rb_cFloat && + BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) { val = DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj)); } -#endif else { goto INSN_LABEL(normal_dispatch); } @@ -1608,12 +1592,13 @@ opt_mod } val = LONG2FIX(mod); } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { + val = DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj))); + } else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (0) { - } - else if (HEAP_CLASS_OF(recv) == rb_cFloat && - HEAP_CLASS_OF(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { + if (HEAP_CLASS_OF(recv) == rb_cFloat && HEAP_CLASS_OF(obj) == rb_cFloat && + BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { val = DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj))); } else { @@ -1702,22 +1687,16 @@ opt_lt val = Qfalse; } } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { + /* flonum is not NaN */ + val = RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj) ? Qtrue : Qfalse; + } else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (0) { + if (HEAP_CLASS_OF(recv) == rb_cFloat && HEAP_CLASS_OF(obj) == rb_cFloat && + BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { + val = double_cmp_lt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); } -#if 1 - else if (HEAP_CLASS_OF(recv) == rb_cFloat && - HEAP_CLASS_OF(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { - double a = RFLOAT_VALUE(recv); - double b = RFLOAT_VALUE(obj); -#if defined(_MSC_VER) && _MSC_VER < 1300 - if (isnan(a) || isnan(b)) val = Qfalse; - else -#endif - val = a < b ? Qtrue : Qfalse; - } -#endif else { goto INSN_LABEL(normal_dispatch); } @@ -1752,6 +1731,11 @@ opt_le val = Qfalse; } } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_LE, FLOAT_REDEFINED_OP_FLAG)) { + /* flonum is not NaN */ + val = RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj) ? Qtrue : Qfalse; + } else { /* other */ PUSH(recv); @@ -1782,22 +1766,16 @@ opt_gt val = Qfalse; } } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { + /* flonum is not NaN */ + val = RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj) ? Qtrue : Qfalse; + } else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (0) { + if (HEAP_CLASS_OF(recv) == rb_cFloat && HEAP_CLASS_OF(obj) == rb_cFloat && + BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { + val = double_cmp_gt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); } -#if 1 - else if (HEAP_CLASS_OF(recv) == rb_cFloat && - HEAP_CLASS_OF(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { - double a = RFLOAT_VALUE(recv); - double b = RFLOAT_VALUE(obj); -#if defined(_MSC_VER) && _MSC_VER < 1300 - if (isnan(a) || isnan(b)) val = Qfalse; - else -#endif - val = a > b ? Qtrue : Qfalse; - } -#endif else { goto INSN_LABEL(normal_dispatch); } @@ -1832,6 +1810,11 @@ opt_ge val = Qfalse; } } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_GE, FLOAT_REDEFINED_OP_FLAG)) { + /* flonum is not NaN */ + val = RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj) ? Qtrue : Qfalse; + } else { PUSH(recv); PUSH(obj); @@ -1851,10 +1834,8 @@ opt_ltlt (VALUE val) { if (!SPECIAL_CONST_P(recv)) { - if (0) { - } - else if (HEAP_CLASS_OF(recv) == rb_cString && - BASIC_OP_UNREDEFINED_P(BOP_LTLT, STRING_REDEFINED_OP_FLAG)) { + if (HEAP_CLASS_OF(recv) == rb_cString && + BASIC_OP_UNREDEFINED_P(BOP_LTLT, STRING_REDEFINED_OP_FLAG)) { val = rb_str_concat(recv, obj); } else if (HEAP_CLASS_OF(recv) == rb_cArray && diff --git a/marshal.c b/marshal.c index a8850aadb2..60922ad784 100644 --- a/marshal.c +++ b/marshal.c @@ -636,6 +636,10 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) else if (SYMBOL_P(obj)) { w_symbol(SYM2ID(obj), arg); } + else if (FLONUM_P(obj)) { + w_byte(TYPE_FLOAT, arg); + w_float(RFLOAT_VALUE(obj), arg); + } else { arg->infection |= (int)FL_TEST(obj, MARSHAL_INFECTION); diff --git a/numeric.c b/numeric.c index 5ac5449238..58ac7adf8d 100644 --- a/numeric.c +++ b/numeric.c @@ -615,7 +615,7 @@ num_to_int(VALUE num) */ VALUE -rb_float_new(double d) +rb_float_new_in_heap(double d) { NEWOBJ(flt, struct RFloat); OBJSETUP(flt, rb_cFloat, T_FLOAT); diff --git a/parse.y b/parse.y index c28b9a91a6..df6476384c 100644 --- a/parse.y +++ b/parse.y @@ -9346,7 +9346,16 @@ negate_lit(NODE *node) node->nd_lit = rb_funcall(node->nd_lit,tUMINUS,0,0); break; case T_FLOAT: +#if USE_FLONUM + if (FLONUM_P(node->nd_lit)) { + node->nd_lit = DBL2NUM(-RFLOAT_VALUE(node->nd_lit)); + } + else { + RFLOAT(node->nd_lit)->float_value = -RFLOAT_VALUE(node->nd_lit); + } +#else RFLOAT(node->nd_lit)->float_value = -RFLOAT_VALUE(node->nd_lit); +#endif break; default: break; diff --git a/random.c b/random.c index a1fb3a800b..b36784c405 100644 --- a/random.c +++ b/random.c @@ -1122,8 +1122,7 @@ rand_range(struct MT* mt, VALUE range) case T_FLOAT: { VALUE f = rb_check_to_float(beg); if (!NIL_P(f)) { - RFLOAT_VALUE(v) += RFLOAT_VALUE(f); - return v; + return DBL2NUM(RFLOAT_VALUE(v) + RFLOAT_VALUE(f)); } } default: diff --git a/vm.c b/vm.c index 53a0aba6bc..ed4d31e95f 100644 --- a/vm.c +++ b/vm.c @@ -990,22 +990,22 @@ vm_init_redefined_flag(void) #define OP(mid_, bop_) (mid = id##mid_, bop = BOP_##bop_, ruby_vm_redefined_flag[bop] = 0) #define C(k) add_opt_method(rb_c##k, mid, bop) OP(PLUS, PLUS), (C(Fixnum), C(Float), C(String), C(Array)); - OP(MINUS, MINUS), (C(Fixnum)); + OP(MINUS, MINUS), (C(Fixnum), C(Float)); OP(MULT, MULT), (C(Fixnum), C(Float)); OP(DIV, DIV), (C(Fixnum), C(Float)); OP(MOD, MOD), (C(Fixnum), C(Float)); OP(Eq, EQ), (C(Fixnum), C(Float), C(String)); OP(Eqq, EQQ), (C(Fixnum), C(Bignum), C(Float), C(Symbol), C(String)); - OP(LT, LT), (C(Fixnum)); - OP(LE, LE), (C(Fixnum)); + OP(LT, LT), (C(Fixnum), C(Float)); + OP(LE, LE), (C(Fixnum), C(Float)); + OP(GT, GT), (C(Fixnum), C(Float)); + OP(GE, GE), (C(Fixnum), C(Float)); OP(LTLT, LTLT), (C(String), C(Array)); OP(AREF, AREF), (C(Array), C(Hash)); OP(ASET, ASET), (C(Array), C(Hash)); OP(Length, LENGTH), (C(Array), C(String), C(Hash)); OP(Size, SIZE), (C(Array), C(String), C(Hash)); OP(Succ, SUCC), (C(Fixnum), C(String), C(Time)); - OP(GT, GT), (C(Fixnum)); - OP(GE, GE), (C(Fixnum)); #undef C #undef OP } diff --git a/vm_insnhelper.c b/vm_insnhelper.c index dc6c8f519d..1a8f325e2d 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1776,10 +1776,14 @@ opt_eq_func(VALUE recv, VALUE obj, IC ic) BASIC_OP_UNREDEFINED_P(BOP_EQ, FIXNUM_REDEFINED_OP_FLAG)) { return (recv == obj) ? Qtrue : Qfalse; } + else if (FLONUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_EQ, FLOAT_REDEFINED_OP_FLAG)) { + return (recv == obj) ? Qtrue : Qfalse; + } else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { if (HEAP_CLASS_OF(recv) == rb_cFloat && HEAP_CLASS_OF(obj) == rb_cFloat && - BASIC_OP_UNREDEFINED_P(BOP_EQ, FLOAT_REDEFINED_OP_FLAG)) { + BASIC_OP_UNREDEFINED_P(BOP_EQ, FLOAT_REDEFINED_OP_FLAG)) { double a = RFLOAT_VALUE(recv); double b = RFLOAT_VALUE(obj); @@ -1865,3 +1869,37 @@ check_match(VALUE pattern, VALUE target, enum vm_check_match_type type) } } + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define CHECK_CMP_NAN(a, b) if (isnan(a) || isnan(b)) return Qfalse; +#else +#define CHECK_CMP_NAN(a, b) +#endif + +static inline VALUE +double_cmp_lt(double a, double b) +{ + CHECK_CMP_NAN(a, b); + return a < b ? Qtrue : Qfalse; +} + +static inline VALUE +double_cmp_le(double a, double b) +{ + CHECK_CMP_NAN(a, b); + return a <= b ? Qtrue : Qfalse; +} + +static inline VALUE +double_cmp_gt(double a, double b) +{ + CHECK_CMP_NAN(a, b); + return a > b ? Qtrue : Qfalse; +} + +static inline VALUE +double_cmp_ge(double a, double b) +{ + CHECK_CMP_NAN(a, b); + return a >= b ? Qtrue : Qfalse; +} diff --git a/vm_insnhelper.h b/vm_insnhelper.h index d78a84c3dc..4d5f0e36b6 100644 --- a/vm_insnhelper.h +++ b/vm_insnhelper.h @@ -211,9 +211,15 @@ enum vm_regan_acttype { #define SYMBOL_REDEFINED_OP_FLAG (1 << 6) #define TIME_REDEFINED_OP_FLAG (1 << 7) -#define FIXNUM_2_P(a, b) ((a) & (b) & 1) #define BASIC_OP_UNREDEFINED_P(op, klass) (LIKELY((ruby_vm_redefined_flag[(op)]&(klass)) == 0)) -#define HEAP_CLASS_OF(obj) RBASIC(obj)->klass + +#define FIXNUM_2_P(a, b) ((a) & (b) & 1) +#if USE_FLONUM +#define FLONUM_2_P(a, b) (((((a)^2) | ((b)^2)) & 3) == 0) /* (FLONUM_P(a) && FLONUM_P(b)) */ +#else +#define FLONUM_2_P(a, b) 0 +#endif +#define HEAP_CLASS_OF(obj) (RBASIC(obj)->klass) #ifndef USE_IC_FOR_SPECIALIZED_METHOD #define USE_IC_FOR_SPECIALIZED_METHOD 1