Ruby  3.1.4p223 (2023-03-30 revision HEAD)
fixnum.h
1 #ifndef INTERNAL_FIXNUM_H /*-*-C-*-vi:se ft=c:*/
2 #define INTERNAL_FIXNUM_H
11 #include "ruby/internal/config.h" /* for HAVE_LONG_LONG */
12 #include <limits.h> /* for CHAR_BIT */
13 #include "internal/compilers.h" /* for __has_builtin */
14 #include "ruby/internal/stdbool.h" /* for bool */
15 #include "ruby/intern.h" /* for rb_big_mul */
16 #include "ruby/ruby.h" /* for RB_FIXABLE */
17 
18 #if HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
19 # define DLONG LONG_LONG
20 # define DL2NUM(x) LL2NUM(x)
21 #elif defined(HAVE_INT128_T)
22 # define DLONG int128_t
23 # define DL2NUM(x) (RB_FIXABLE(x) ? LONG2FIX(x) : rb_int128t2big(x))
24 VALUE rb_int128t2big(int128_t n); /* in bignum.c */
25 #endif
26 
27 static inline long rb_overflowed_fix_to_int(long x);
28 static inline VALUE rb_fix_plus_fix(VALUE x, VALUE y);
29 static inline VALUE rb_fix_minus_fix(VALUE x, VALUE y);
30 static inline VALUE rb_fix_mul_fix(VALUE x, VALUE y);
31 static inline void rb_fix_divmod_fix(VALUE x, VALUE y, VALUE *divp, VALUE *modp);
32 static inline VALUE rb_fix_div_fix(VALUE x, VALUE y);
33 static inline VALUE rb_fix_mod_fix(VALUE x, VALUE y);
34 static inline bool FIXNUM_POSITIVE_P(VALUE num);
35 static inline bool FIXNUM_NEGATIVE_P(VALUE num);
36 static inline bool FIXNUM_ZERO_P(VALUE num);
37 
38 static inline long
39 rb_overflowed_fix_to_int(long x)
40 {
41  return (long)((unsigned long)(x >> 1) ^ (1LU << (SIZEOF_LONG * CHAR_BIT - 1)));
42 }
43 
44 static inline VALUE
45 rb_fix_plus_fix(VALUE x, VALUE y)
46 {
47 #if !__has_builtin(__builtin_add_overflow)
48  long lz = FIX2LONG(x) + FIX2LONG(y);
49  return LONG2NUM(lz);
50 #else
51  long lz;
52  /* NOTE
53  * (1) `LONG2FIX(FIX2LONG(x)+FIX2LONG(y))`
54  + = `((lx*2+1)/2 + (ly*2+1)/2)*2+1`
55  + = `lx*2 + ly*2 + 1`
56  + = `(lx*2+1) + (ly*2+1) - 1`
57  + = `x + y - 1`
58  * (2) Fixnum's LSB is always 1.
59  * It means you can always run `x - 1` without overflow.
60  * (3) Of course `z = x + (y-1)` may overflow.
61  * At that time true value is
62  * * positive: 0b0 1xxx...1, and z = 0b1xxx...1
63  * * negative: 0b1 0xxx...1, and z = 0b0xxx...1
64  * To convert this true value to long,
65  * (a) Use arithmetic shift
66  * * positive: 0b11xxx...
67  * * negative: 0b00xxx...
68  * (b) invert MSB
69  * * positive: 0b01xxx...
70  * * negative: 0b10xxx...
71  */
72  if (__builtin_add_overflow((long)x, (long)y-1, &lz)) {
73  return rb_int2big(rb_overflowed_fix_to_int(lz));
74  }
75  else {
76  return (VALUE)lz;
77  }
78 #endif
79 }
80 
81 static inline VALUE
82 rb_fix_minus_fix(VALUE x, VALUE y)
83 {
84 #if !__has_builtin(__builtin_sub_overflow)
85  long lz = FIX2LONG(x) - FIX2LONG(y);
86  return LONG2NUM(lz);
87 #else
88  long lz;
89  if (__builtin_sub_overflow((long)x, (long)y-1, &lz)) {
90  return rb_int2big(rb_overflowed_fix_to_int(lz));
91  }
92  else {
93  return (VALUE)lz;
94  }
95 #endif
96 }
97 
98 /* arguments must be Fixnum */
99 static inline VALUE
100 rb_fix_mul_fix(VALUE x, VALUE y)
101 {
102  long lx = FIX2LONG(x);
103  long ly = FIX2LONG(y);
104 #ifdef DLONG
105  return DL2NUM((DLONG)lx * (DLONG)ly);
106 #else
107  if (MUL_OVERFLOW_FIXNUM_P(lx, ly)) {
108  return rb_big_mul(rb_int2big(lx), rb_int2big(ly));
109  }
110  else {
111  return LONG2FIX(lx * ly);
112  }
113 #endif
114 }
115 
116 /*
117  * This behaves different from C99 for negative arguments.
118  * Note that div may overflow fixnum.
119  */
120 static inline void
121 rb_fix_divmod_fix(VALUE a, VALUE b, VALUE *divp, VALUE *modp)
122 {
123  /* assume / and % comply C99.
124  * ldiv(3) won't be inlined by GCC and clang.
125  * I expect / and % are compiled as single idiv.
126  */
127  long x = FIX2LONG(a);
128  long y = FIX2LONG(b);
129  long div, mod;
130  if (x == FIXNUM_MIN && y == -1) {
131  if (divp) *divp = LONG2NUM(-FIXNUM_MIN);
132  if (modp) *modp = LONG2FIX(0);
133  return;
134  }
135  div = x / y;
136  mod = x % y;
137  if (y > 0 ? mod < 0 : mod > 0) {
138  mod += y;
139  div -= 1;
140  }
141  if (divp) *divp = LONG2FIX(div);
142  if (modp) *modp = LONG2FIX(mod);
143 }
144 
145 /* div() for Ruby
146  * This behaves different from C99 for negative arguments.
147  */
148 static inline VALUE
149 rb_fix_div_fix(VALUE x, VALUE y)
150 {
151  VALUE div;
152  rb_fix_divmod_fix(x, y, &div, NULL);
153  return div;
154 }
155 
156 /* mod() for Ruby
157  * This behaves different from C99 for negative arguments.
158  */
159 static inline VALUE
160 rb_fix_mod_fix(VALUE x, VALUE y)
161 {
162  VALUE mod;
163  rb_fix_divmod_fix(x, y, NULL, &mod);
164  return mod;
165 }
166 
167 static inline bool
168 FIXNUM_POSITIVE_P(VALUE num)
169 {
170  return (SIGNED_VALUE)num > (SIGNED_VALUE)INT2FIX(0);
171 }
172 
173 static inline bool
174 FIXNUM_NEGATIVE_P(VALUE num)
175 {
176  return (SIGNED_VALUE)num < 0;
177 }
178 
179 static inline bool
180 FIXNUM_ZERO_P(VALUE num)
181 {
182  return num == INT2FIX(0);
183 }
184 #endif /* INTERNAL_FIXNUM_H */
#define INT2FIX
Old name of RB_INT2FIX.
Definition: long.h:48
#define LONG2FIX
Old name of RB_INT2FIX.
Definition: long.h:49
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition: long.h:50
#define FIXNUM_MIN
Old name of RUBY_FIXNUM_MIN.
Definition: fixnum.h:27
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition: long.h:46
VALUE rb_big_mul(VALUE x, VALUE y)
Performs multiplication of the passed two objects.
Definition: bignum.c:5930
VALUE rb_int2big(intptr_t i)
Converts a C's intptr_t into an instance of rb_cInteger.
Definition: bignum.c:3191
C99 shim for <stdbool.h>
Definition: dtoa.c:302
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition: value.h:63
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40