Skip to content

Commit d962f60

Browse files
committed
ATRONIX: Move integer arithmetic operations into their own functions
Such that they can be used elsewhere. Also makes it possible to take advantages of builtin functions provided by compilers like clang.
1 parent 2e98817 commit d962f60

File tree

6 files changed

+453
-38
lines changed

6 files changed

+453
-38
lines changed

src/core/f-int.c

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/***********************************************************************
2+
**
3+
** REBOL [R3] Language Interpreter and Run-time Environment
4+
**
5+
** Copyright 2014 Atronix Engineering, Inc
6+
** REBOL is a trademark of REBOL Technologies
7+
**
8+
** Licensed under the Apache License, Version 2.0 (the "License");
9+
** you may not use this file except in compliance with the License.
10+
** You may obtain a copy of the License at
11+
**
12+
** http://www.apache.org/licenses/LICENSE-2.0
13+
**
14+
** Unless required by applicable law or agreed to in writing, software
15+
** distributed under the License is distributed on an "AS IS" BASIS,
16+
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
** See the License for the specific language governing permissions and
18+
** limitations under the License.
19+
**
20+
************************************************************************
21+
**
22+
** Module: f-int.c
23+
** Summary: integer arithmetic functions
24+
** Section: functional
25+
** Author: Shixin Zeng
26+
** Notes: Based on original code in t-integer.c
27+
**
28+
***********************************************************************/
29+
30+
#include "reb-c.h"
31+
#include "sys-int-funcs.h"
32+
33+
REBOOL reb_i32_add_overflow(i32 x, i32 y, i32 *sum)
34+
{
35+
i64 sum64 = (i64)x + (i64)y;
36+
if (sum64 > MAX_I32 || sum64 < MIN_I32) return TRUE;
37+
*sum = (i32)sum64;
38+
return FALSE;
39+
}
40+
41+
REBOOL reb_u32_add_overflow(u32 x, u32 y, u32 *sum)
42+
{
43+
u64 s = (u64)x + (u64)y;
44+
if (s > MAX_I32) return TRUE;
45+
*sum = (u32)s;
46+
return FALSE;
47+
}
48+
49+
REBOOL reb_i64_add_overflow(i64 x, i64 y, i64 *sum)
50+
{
51+
*sum = (REBU64)x + (REBU64)y; /* never overflow with unsigned integers*/
52+
if (((x < 0) == (y < 0))
53+
&& ((x < 0) != (*sum < 0))) return TRUE;
54+
return FALSE;
55+
}
56+
57+
REBOOL reb_u64_add_overflow(u64 x, u64 y, u64 *sum)
58+
{
59+
*sum = x + y;
60+
if (*sum < x || *sum < y) return TRUE;
61+
return FALSE;
62+
}
63+
64+
REBOOL reb_i32_sub_overflow(i32 x, i32 y, i32 *diff)
65+
{
66+
*diff = (i64)x - (i64)y;
67+
if (((x < 0) != (y < 0)) && ((x < 0) != (*diff < 0))) return TRUE;
68+
69+
return FALSE;
70+
}
71+
72+
REBOOL reb_i64_sub_overflow(i64 x, i64 y, i64 *diff)
73+
{
74+
*diff = (REBU64)x - (REBU64)y;
75+
if (((x < 0) != (y < 0)) && ((x < 0) != (*diff < 0))) return TRUE;
76+
77+
return FALSE;
78+
}
79+
80+
REBOOL reb_i32_mul_overflow(i32 x, i32 y, i32 *prod)
81+
{
82+
i64 p = (i64)x * (i64)y;
83+
if (p > MAX_I32 || p < MIN_I32) return TRUE;
84+
*prod = (i32)p;
85+
return FALSE;
86+
}
87+
88+
REBOOL reb_u32_mul_overflow(u32 x, u32 y, u32 *prod)
89+
{
90+
u64 p = (u64)x * (u64)y;
91+
if (p > MAX_U32) return TRUE;
92+
*prod = (u32)p;
93+
return FALSE;
94+
}
95+
96+
REBOOL reb_i64_mul_overflow(i64 x, i64 y, i64 *prod)
97+
{
98+
REBFLG sgn;
99+
u64 p = 0;
100+
101+
sgn = (x < 0);
102+
if (sgn) {
103+
if (x == MIN_I64) {
104+
switch (y) {
105+
case 0:
106+
*prod = 0;
107+
return 0;
108+
case 1:
109+
*prod = x;
110+
return 0;
111+
default:
112+
return 1;
113+
}
114+
}
115+
x = -x; /* undefined when x == MIN_I64 */
116+
}
117+
if (y < 0) {
118+
sgn = !sgn;
119+
if (y == MIN_I64) {
120+
switch (x) {
121+
case 0:
122+
*prod = 0;
123+
return 0;
124+
case 1:
125+
if (!sgn) {
126+
return 1;
127+
} else {
128+
*prod = y;
129+
return 0;
130+
}
131+
default:
132+
return 1;
133+
}
134+
}
135+
y = -y; /* undefined when y == MIN_I64 */
136+
}
137+
138+
if (REB_U64_MUL_OF(x, y, (u64 *)&p)
139+
|| (!sgn && p > MAX_I64)
140+
|| (sgn && p - 1 > MAX_I64)) return TRUE; /* assumes 2's complements */
141+
142+
if (sgn && p == (u64)MIN_I64) {
143+
*prod = MIN_I64;
144+
return FALSE;
145+
}
146+
147+
*prod = sgn? -(i64)p : p;
148+
return FALSE;
149+
}
150+
151+
REBOOL reb_u64_mul_overflow(u64 x, u64 y, u64 *prod)
152+
{
153+
u64 x0, y0, x1, y1;
154+
u64 b = U64_C(1) << 32;
155+
u64 tmp = 0;
156+
x1 = x >> 32;
157+
x0 = (u32)x;
158+
y1 = y >> 32;
159+
y0 = (u32)y;
160+
161+
/* p = (x1 * y1) * b^2 + (x0 * y1 + x1 * y0) * b + x0 * y0 */
162+
163+
if (x1 && y1) return TRUE; /* (x1 * y1) * b^2 overflows */
164+
165+
tmp = (x0 * y1 + x1 * y0); /* never overflow, because x1 * y1 == 0 */
166+
if (tmp >= b) return TRUE; /*(x0 * y1 + x1 * y0) * b overflows */
167+
168+
return REB_U64_ADD_OF(tmp << 32, x0 * y0, prod);
169+
}

src/core/f-random.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ static REBI64 ran_arr_cycle()
149149
return tmp;
150150
}
151151

152-
#define MAX_U64 ((REBU64)(REBI64)-1)
152+
//#define MAX_U64 ((REBU64)(REBI64)-1) //defined in reb-c.h
153153
/***********************************************************************
154154
**
155155
*/ REBI64 Random_Range(REBI64 r, REBFLG secure)

src/core/t-integer.c

+5-27
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include "sys-core.h"
3131
#include "sys-deci-funcs.h"
32+
#include "sys-int-funcs.h"
3233

3334

3435
/***********************************************************************
@@ -110,41 +111,18 @@
110111
switch (action) {
111112

112113
case A_ADD:
113-
anum = (REBU64)num + (REBU64)arg;
114-
if (
115-
((num < 0) == (arg < 0)) && ((num < 0) != (anum < 0))
116-
) Trap0(RE_OVERFLOW);
114+
if (REB_I64_ADD_OF(num, arg, &anum)) Trap0(RE_OVERFLOW);
117115
num = anum;
118116
break;
119117

120118
case A_SUBTRACT:
121-
anum = (REBU64)num - (REBU64)arg;
122-
if (
123-
((num < 0) != (arg < 0)) && ((num < 0) != (anum < 0))
124-
) Trap0(RE_OVERFLOW);
119+
if (REB_I64_SUB_OF(num, arg, &anum)) Trap0(RE_OVERFLOW);
125120
num = anum;
126121
break;
127122

128123
case A_MULTIPLY:
129-
a = num;
130-
sgn = (num < 0);
131-
if (sgn) a = -a;
132-
b = arg;
133-
if (arg < 0) {
134-
sgn = !sgn;
135-
b = -b;
136-
}
137-
p = a * b;
138-
a1 = a>>32;
139-
a0 = a;
140-
b1 = b>>32;
141-
b0 = b;
142-
if (
143-
(a1 && b1)
144-
|| ((REBU64)a0 * b1 + (REBU64)a1 * b0 > p >> 32)
145-
|| ((p > (REBU64)MAX_I64) && (!sgn || (p > -(REBU64)MIN_I64)))
146-
) Trap0(RE_OVERFLOW);
147-
num = sgn ? -p : p;
124+
if (REB_I64_MUL_OF(num, arg, &p)) Trap0(RE_OVERFLOW);
125+
num = p;
148126
break;
149127

150128
case A_DIVIDE:

0 commit comments

Comments
 (0)