summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;