summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-03-06 11:14:05 +0000
committershyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-03-06 11:14:05 +0000
commit74cdd893eb102ba98e735f2a24c710e1928261a9 (patch)
tree148c82adfc714aaa2a3d60cda2c18c4f78ed9f76
parentcf2a68662aadcbed4a92cfdad4d992f894f3767f (diff)
optimize FIXABLE macro
Looking at the source code, FIXABLE tends to be just before LOING2FIX to check applicability of that operation. Why not try computing first then check for overflow, which should be optimial. I also tried the same thing for unsigned types but resulted in slower execution. It seems RB_POSFIXABLE() is fast enough on modern CPUs. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57789 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--bignum.c16
-rw-r--r--compile.c2
-rw-r--r--include/ruby/ruby.h37
-rw-r--r--insns.def2
-rw-r--r--internal.h12
-rw-r--r--numeric.c33
-rw-r--r--object.c5
-rw-r--r--sprintf.c6
8 files changed, 71 insertions, 42 deletions
diff --git a/bignum.c b/bignum.c
index 8c723300f4..50700b4c4a 100644
--- a/bignum.c
+++ b/bignum.c
@@ -3184,15 +3184,13 @@ rb_int2big(SIGNED_VALUE n)
VALUE
rb_uint2inum(VALUE n)
{
- if (POSFIXABLE(n)) return LONG2FIX(n);
- return rb_uint2big(n);
+ return ULONG2NUM(n);
}
VALUE
rb_int2inum(SIGNED_VALUE n)
{
- if (FIXABLE(n)) return LONG2FIX(n);
- return rb_int2big(n);
+ return LONG2NUM(n);
}
void
@@ -4438,8 +4436,18 @@ rb_ull2inum(unsigned LONG_LONG n)
VALUE
rb_ll2inum(LONG_LONG n)
{
+#ifdef HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW
+ SIGNED_VALUE v;
+ if (__builtin_mul_overflow(n, 2, &v)) {
+ return rb_ll2big(n);
+ }
+ else {
+ return ((VALUE)v) | RUBY_FIXNUM_FLAG;
+ }
+#else
if (FIXABLE(n)) return LONG2FIX(n);
return rb_ll2big(n);
+#endif
}
#endif /* HAVE_LONG_LONG */
diff --git a/compile.c b/compile.c
index f1ba0946b3..835fa41414 100644
--- a/compile.c
+++ b/compile.c
@@ -3190,7 +3190,7 @@ case_when_optimizable_literal(NODE *node)
double ival;
if (RB_TYPE_P(v, T_FLOAT) &&
modf(RFLOAT_VALUE(v), &ival) == 0.0) {
- return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
+ return rb_dbl2ival(ival);
}
if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
return v;
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index d770c30735..0cd88fb002 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -1504,6 +1504,29 @@ rb_integer_type_p(VALUE obj)
}
#endif
+static inline int
+rb_long2fix_overflow(long l, VALUE *ptr)
+{
+#ifdef HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW
+ SIGNED_VALUE v;
+ if (__builtin_mul_overflow(l, 2, &v)) {
+ return 1;
+ }
+ else {
+ *ptr = ((VALUE)v) | RUBY_FIXNUM_FLAG;
+ return 0;
+ }
+#else
+ if (RB_FIXABLE(l)) {
+ *ptr = RB_LONG2FIX(l);
+ return 0;
+ }
+ else {
+ return 1;
+ }
+#endif
+}
+
#if SIZEOF_INT < SIZEOF_LONG
# define RB_INT2NUM(v) RB_INT2FIX((int)(v))
# define RB_UINT2NUM(v) RB_LONG2FIX((unsigned int)(v))
@@ -1511,10 +1534,11 @@ rb_integer_type_p(VALUE obj)
static inline VALUE
rb_int2num_inline(int v)
{
- if (RB_FIXABLE(v))
- return RB_INT2FIX(v);
- else
+ VALUE ret;
+ if (rb_long2fix_overflow(v, &ret))
return rb_int2big(v);
+ else
+ return ret;
}
#define RB_INT2NUM(x) rb_int2num_inline(x)
@@ -1534,10 +1558,11 @@ rb_uint2num_inline(unsigned int v)
static inline VALUE
rb_long2num_inline(long v)
{
- if (RB_FIXABLE(v))
- return RB_LONG2FIX(v);
- else
+ VALUE ret;
+ if (rb_long2fix_overflow(v, &ret))
return rb_int2big(v);
+ else
+ return ret;
}
#define RB_LONG2NUM(x) rb_long2num_inline(x)
diff --git a/insns.def b/insns.def
index 9bae14b5a9..15e9d828ea 100644
--- a/insns.def
+++ b/insns.def
@@ -1345,7 +1345,7 @@ opt_case_dispatch
if (RB_FLOAT_TYPE_P(key)) {
double kval = RFLOAT_VALUE(key);
if (!isinf(kval) && modf(kval, &kval) == 0.0) {
- key = FIXABLE(kval) ? LONG2FIX((long)kval) : rb_dbl2big(kval);
+ key = rb_dbl2ival(kval);
}
}
if (st_lookup(RHASH_TBL_RAW(hash), key, &val)) {
diff --git a/internal.h b/internal.h
index 06455f9409..bf54c64be7 100644
--- a/internal.h
+++ b/internal.h
@@ -1383,6 +1383,18 @@ rb_float_new_inline(double d)
#define rb_float_value(v) rb_float_value_inline(v)
#define rb_float_new(d) rb_float_new_inline(d)
+static inline VALUE
+rb_dbl2ival(double d)
+{
+ VALUE val;
+ if (rb_long2fix_overflow(d, &val)) {
+ return rb_dbl2big(d);
+ }
+ else {
+ return val;
+ }
+}
+
/* object.c */
void rb_obj_copy_ivar(VALUE dest, VALUE obj);
CONSTFUNC(VALUE rb_obj_equal(VALUE obj1, VALUE obj2));
diff --git a/numeric.c b/numeric.c
index 3d2b501ab2..4f789e47a4 100644
--- a/numeric.c
+++ b/numeric.c
@@ -1279,10 +1279,7 @@ flo_mod(VALUE x, VALUE y)
static VALUE
dbl2ival(double d)
{
- if (FIXABLE(d)) {
- return LONG2FIX((long)d);
- }
- return rb_dbl2big(d);
+ return rb_dbl2ival(d);
}
/*
@@ -1967,7 +1964,6 @@ static VALUE
flo_floor(int argc, VALUE *argv, VALUE num)
{
double number, f;
- long val;
int ndigits = 0;
if (rb_check_arity(argc, 0, 1)) {
@@ -1984,11 +1980,7 @@ flo_floor(int argc, VALUE *argv, VALUE num)
return DBL2NUM(f);
}
f = floor(number);
- if (!FIXABLE(f)) {
- return rb_dbl2big(f);
- }
- val = (long)f;
- return LONG2FIX(val);
+ return dbl2ival(f);
}
/*
@@ -2327,16 +2319,11 @@ static VALUE
flo_to_i(VALUE num)
{
double f = RFLOAT_VALUE(num);
- long val;
if (f > 0.0) f = floor(f);
if (f < 0.0) f = ceil(f);
- if (!FIXABLE(f)) {
- return rb_dbl2big(f);
- }
- val = (long)f;
- return LONG2FIX(val);
+ return dbl2ival(f);
}
/*
@@ -3020,13 +3007,17 @@ VALUE
rb_num2fix(VALUE val)
{
long v;
+ VALUE w;
- if (FIXNUM_P(val)) return val;
-
- v = rb_num2long(val);
- if (!FIXABLE(v))
+ if (FIXNUM_P(val)) {
+ return val;
+ }
+ else if (rb_long2fix_overflow((v = rb_num2long(val)), &w)) {
rb_raise(rb_eRangeError, "integer %ld out of range of fixnum", v);
- return LONG2FIX(v);
+ }
+ else {
+ return w;
+ }
}
#if HAVE_LONG_LONG
diff --git a/object.c b/object.c
index 9ec96687e9..21779401fb 100644
--- a/object.c
+++ b/object.c
@@ -2747,11 +2747,8 @@ rb_convert_to_integer(VALUE val, int base)
VALUE tmp;
if (RB_FLOAT_TYPE_P(val)) {
- double f;
if (base != 0) goto arg_error;
- f = RFLOAT_VALUE(val);
- if (FIXABLE(f)) return LONG2FIX((long)f);
- return rb_dbl2big(f);
+ return rb_dbl2ival(RFLOAT_VALUE(val));
}
else if (RB_INTEGER_TYPE_P(val)) {
if (base != 0) goto arg_error;
diff --git a/sprintf.c b/sprintf.c
index 40872c0c16..72ac664e0e 100644
--- a/sprintf.c
+++ b/sprintf.c
@@ -832,11 +832,7 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)
bin_retry:
switch (TYPE(val)) {
case T_FLOAT:
- if (FIXABLE(RFLOAT_VALUE(val))) {
- val = LONG2FIX((long)RFLOAT_VALUE(val));
- goto bin_retry;
- }
- val = rb_dbl2big(RFLOAT_VALUE(val));
+ val = rb_dbl2ival(RFLOAT_VALUE(val));
if (FIXNUM_P(val)) goto bin_retry;
bignum = 1;
break;