diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-08-23 07:22:40 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-08-23 07:22:40 +0000 |
commit | b3b5e626ad69bf22be3228f847f94e1b68f40888 (patch) | |
tree | 17e1c7ec5995e9ab60632bd2a9756695b32b614c /include/ruby | |
parent | ce5af582a0552d1ccbe66e8b3ee3ca046f6b18c3 (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
Diffstat (limited to 'include/ruby')
-rw-r--r-- | include/ruby/intern.h | 1 | ||||
-rw-r--r-- | include/ruby/ruby.h | 154 |
2 files changed, 150 insertions, 5 deletions
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__ |