aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--bignum.c40
-rw-r--r--configure.in4
-rw-r--r--insns.def25
4 files changed, 72 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index c826825a60..299d8e52c3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Fri Feb 5 12:22:20 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * insns.def (opt_mult): Use int128_t for overflow detection.
+
+ * bignum.c (rb_uint128t2big): added for opt_mult.
+
+ * bignum.c (rb_uint128t2big): added for rb_uint128t2big..
+
+ * configure.in: define int128_t, uint128_t and related MACROs.
+ Initially introduced by r41379 but reverted by r50749.
+
Thu Feb 4 21:05:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
* enc/unicode.c: Activated :ascii flag for ASCII-only case conversion
diff --git a/bignum.c b/bignum.c
index afd264adec..bc24764b88 100644
--- a/bignum.c
+++ b/bignum.c
@@ -4367,6 +4367,46 @@ rb_ll2inum(LONG_LONG n)
#endif /* HAVE_LONG_LONG */
+#ifdef HAVE_INT128_T
+static VALUE
+rb_uint128t2big(uint128_t n)
+{
+ long i;
+ VALUE big = bignew(bdigit_roomof(SIZEOF_INT128_T), 1);
+ BDIGIT *digits = BDIGITS(big);
+
+ for (i = 0; i < bdigit_roomof(SIZEOF_INT128_T); i++) {
+ digits[i] = BIGLO(RSHIFT(n ,BITSPERDIG*i));
+ }
+
+ i = bdigit_roomof(SIZEOF_INT128_T);
+ while (i-- && !digits[i]) ;
+ BIGNUM_SET_LEN(big, i+1);
+ return big;
+}
+
+VALUE
+rb_int128t2big(int128_t n)
+{
+ int neg = 0;
+ uint128_t u;
+ VALUE big;
+
+ if (n < 0) {
+ u = 1 + (uint128_t)(-(n + 1)); /* u = -n avoiding overflow */
+ neg = 1;
+ }
+ else {
+ u = n;
+ }
+ big = rb_uint128t2big(u);
+ if (neg) {
+ BIGNUM_SET_SIGN(big, 0);
+ }
+ return big;
+}
+#endif
+
VALUE
rb_cstr2inum(const char *str, int base)
{
diff --git a/configure.in b/configure.in
index 4e66b374f9..922d3d0663 100644
--- a/configure.in
+++ b/configure.in
@@ -1472,6 +1472,7 @@ RUBY_CHECK_SIZEOF(short)
RUBY_CHECK_SIZEOF(long, [int], [ILP LP])
RUBY_CHECK_SIZEOF(long long)
RUBY_CHECK_SIZEOF(__int64)
+RUBY_CHECK_SIZEOF(__int128)
RUBY_CHECK_SIZEOF(off_t)
RUBY_CHECK_SIZEOF(void*, [int long "long long"], [ILP LP LLP])
RUBY_CHECK_SIZEOF(float)
@@ -2007,6 +2008,7 @@ typedef $1 t; int s = sizeof(t) == 42;])],
["$ac_cv_sizeof_long"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long"],
["$ac_cv_sizeof_long_long"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long long"],
["$ac_cv_sizeof___int64"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])__int64"],
+ ["$ac_cv_sizeof___int128"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])__int128"],
[ rb_cv_type_$1=no])])])
if test "${rb_cv_type_$1}" != no; then
AC_DEFINE([HAVE_]AS_TR_CPP($1), 1)
@@ -2028,6 +2030,8 @@ RUBY_DEFINT(int32_t, 4)
RUBY_DEFINT(uint32_t, 4, unsigned)
RUBY_DEFINT(int64_t, 8)
RUBY_DEFINT(uint64_t, 8, unsigned)
+RUBY_DEFINT(int128_t, 16)
+RUBY_DEFINT(uint128_t, 16, unsigned)
RUBY_DEFINT(intptr_t, void*)
RUBY_DEFINT(uintptr_t, void*, unsigned)
RUBY_DEFINT(ssize_t, size_t, [], [@%:@include <sys/types.h>]) dnl may differ from int, so not use AC_TYPE_SSIZE_T.
diff --git a/insns.def b/insns.def
index ef0665c50c..72ce1d998f 100644
--- a/insns.def
+++ b/insns.def
@@ -1430,20 +1430,29 @@ opt_mult
{
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_MULT, FIXNUM_REDEFINED_OP_FLAG)) {
- long a, b;
-
- a = FIX2LONG(recv);
+ long a = FIX2LONG(recv);
if (a == 0) {
val = recv;
}
else {
- b = FIX2LONG(obj);
- if (MUL_OVERFLOW_FIXNUM_P(a, b)) {
+#ifdef HAVE_INT128_T
+ VALUE rb_int128t2big(int128_t n);
+ int128_t r = (int128_t)a * FIX2LONG(obj);
+ if (RB_FIXABLE(r)) {
+ val = LONG2FIX((long)r);
+ }
+ else {
+ val = rb_int128t2big(r);
+ }
+#else
+ long b = FIX2LONG(obj);
+ if (MUL_OVERFLOW_FIXNUM_P(a, b)) {
val = rb_big_mul(rb_int2big(a), rb_int2big(b));
- }
- else {
+ }
+ else {
val = LONG2FIX(a * b);
- }
+ }
+#endif
}
}
else if (FLONUM_2_P(recv, obj) &&