summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-08-23 07:22:40 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-08-23 07:22:40 +0000
commitb3b5e626ad69bf22be3228f847f94e1b68f40888 (patch)
tree17e1c7ec5995e9ab60632bd2a9756695b32b614c
parentce5af582a0552d1ccbe66e8b3ee3ca046f6b18c3 (diff)
* 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
-rw-r--r--ChangeLog34
-rw-r--r--benchmark/bmx_temp.rb6
-rw-r--r--gc.c12
-rw-r--r--include/ruby/intern.h1
-rw-r--r--include/ruby/ruby.h154
-rw-r--r--insns.def143
-rw-r--r--marshal.c4
-rw-r--r--numeric.c2
-rw-r--r--parse.y9
-rw-r--r--random.c3
-rw-r--r--vm.c10
-rw-r--r--vm_insnhelper.c40
-rw-r--r--vm_insnhelper.h10
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 <ko1@atdot.net>
+
+ * 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 <usa@ruby-lang.org>
* 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)<<RUBY_SPECIAL_SHIFT)|SYMBOL_FLAG)
#define SYM2ID(x) RSHIFT((unsigned long)(x),RUBY_SPECIAL_SHIFT)
+#ifndef USE_FLONUM
+#if SIZEOF_VALUE >= 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 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;
+ 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));
}
-#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 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;
+ 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));
}
-#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