aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-03-06 06:04:52 +0000
committershyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-03-06 06:04:52 +0000
commit9d184819146bb7d24b30fc54ef206d9a592c9be4 (patch)
tree508d56481df15bcd86ad634e7e25a19e6c55bc9a
parent60ac2d5cc84cf1aa0f4993211f73f22013349e1d (diff)
downloadruby-9d184819146bb7d24b30fc54ef206d9a592c9be4.tar.gz
use HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW
We already check for __builtin_mul_overflow in configure but never actually referred it before. Why not call it if available, because that should render supposedly-optimial assembly outputs. Optionally if __builtin_mul_overflow_p is available, which is the case for recent GCC, use that to detect fixnum overflow. This is much faster than the previous. On my machine generated assembly of numeric.c:int_pow reduces from 480 to 448 bytes, according to nm(1). Also on my machine, following script boosts from 7.819 to 6.929 sec. time ./miniruby -e 'i=0; while i < 30_000_000 do i += 1; 7 ** 23; end' Signed-off-by: Urabe, Shyouhei <shyouhei@ruby-lang.org> git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57784 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--configure.in1
-rw-r--r--internal.h30
-rw-r--r--process.c5
3 files changed, 32 insertions, 4 deletions
diff --git a/configure.in b/configure.in
index 9eec2e9fa2..756f499387 100644
--- a/configure.in
+++ b/configure.in
@@ -2528,6 +2528,7 @@ RUBY_CHECK_BUILTIN_FUNC(__builtin_ctzll, [__builtin_ctzll(0)])
RUBY_CHECK_BUILTIN_FUNC(__builtin_add_overflow, [int x;__builtin_add_overflow(0,0,&x)])
RUBY_CHECK_BUILTIN_FUNC(__builtin_sub_overflow, [int x;__builtin_sub_overflow(0,0,&x)])
RUBY_CHECK_BUILTIN_FUNC(__builtin_mul_overflow, [int x;__builtin_mul_overflow(0,0,&x)])
+RUBY_CHECK_BUILTIN_FUNC(__builtin_mul_overflow_p, [__builtin_mul_overflow_p(0,0,(int)0)])
RUBY_CHECK_BUILTIN_FUNC(__builtin_constant_p, [__builtin_constant_p(0)])
RUBY_CHECK_BUILTIN_FUNC(__builtin_choose_expr, [
[int x[__extension__(__builtin_choose_expr(1, 1, -1))]];
diff --git a/internal.h b/internal.h
index e74b91f667..eebd31073c 100644
--- a/internal.h
+++ b/internal.h
@@ -96,15 +96,41 @@ extern "C" {
#endif
#define TIMET_MAX_PLUS_ONE (2*(double)(TIMET_MAX/2+1))
+#ifdef HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW_P
+#define MUL_OVERFLOW_P(a, b) \
+ __builtin_mul_overflow_p((a), (b), (__typeof__(a * b))0)
+#elif defined HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW
+#define MUL_OVERFLOW_P(a, b) \
+ ({__typeof__(a) c; __builtin_mul_overflow((a), (b), &c);})
+#endif
+
#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
(a) == 0 ? 0 : \
(a) == -1 ? (b) < -(max) : \
(a) > 0 ? \
((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \
((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b)))
+
+#ifdef HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW_P
+/* __builtin_mul_overflow_p can take bitfield */
+/* and GCC permits bitfields for integers other than int */
+#define MUL_OVERFLOW_FIXNUM_P(a, b) ({ \
+ struct { SIGNED_VALUE fixnum : SIZEOF_VALUE * CHAR_BIT - 1; } c; \
+ __builtin_mul_overflow_p((a), (b), c.fixnum); \
+})
+#else
#define MUL_OVERFLOW_FIXNUM_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
-#define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
-#define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
+#endif
+
+#ifdef MUL_OVERFLOW_P
+#define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
+#define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
+#define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_P(a, b)
+#else
+#define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_LONG_MIN, LONG_LONG_MAX)
+#define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
+#define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
+#endif
#ifndef swap16
# ifdef HAVE_BUILTIN___BUILTIN_BSWAP16
diff --git a/process.c b/process.c
index d4d15a69b3..cd6e59e290 100644
--- a/process.c
+++ b/process.c
@@ -6916,11 +6916,13 @@ typedef LONG_LONG timetick_int_t;
#define TIMETICK_INT_MIN LLONG_MIN
#define TIMETICK_INT_MAX LLONG_MAX
#define TIMETICK_INT2NUM(v) LL2NUM(v)
+#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
#else
typedef long timetick_int_t;
#define TIMETICK_INT_MIN LONG_MIN
#define TIMETICK_INT_MAX LONG_MAX
#define TIMETICK_INT2NUM(v) LONG2NUM(v)
+#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
#endif
CONSTFUNC(static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
@@ -7036,8 +7038,7 @@ timetick2integer(struct timetick *ttp,
timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
for (i = 0; i < num_numerators; i++) {
timetick_int_t factor = numerators[i];
- if (MUL_OVERFLOW_SIGNED_INTEGER_P(factor, t,
- TIMETICK_INT_MIN, TIMETICK_INT_MAX))
+ if (MUL_OVERFLOW_TIMETICK_P(factor, t))
goto generic;
t *= factor;
}