1
/***********************************************************************/
5
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
7
/* Copyright 2002 Institut National de Recherche en Informatique et */
8
/* en Automatique. All rights reserved. This file is distributed */
9
/* under the terms of the GNU Library General Public License, with */
10
/* the special exception on linking described in file ../LICENSE. */
12
/***********************************************************************/
14
/* $Id: int64_emul.h,v 1.5 2005/09/22 14:21:50 xleroy Exp $ */
16
/* Software emulation of 64-bit integer arithmetic, for C compilers
17
that do not support it. */
19
#ifndef CAML_INT64_EMUL_H
20
#define CAML_INT64_EMUL_H
24
#ifdef ARCH_BIG_ENDIAN
25
#define I64_literal(hi,lo) { hi, lo }
27
#define I64_literal(hi,lo) { lo, hi }
30
/* Unsigned comparison */
31
static int I64_ucompare(uint64 x, uint64 y)
33
if (x.h > y.h) return 1;
34
if (x.h < y.h) return -1;
35
if (x.l > y.l) return 1;
36
if (x.l < y.l) return -1;
40
#define I64_ult(x, y) (I64_ucompare(x, y) < 0)
42
/* Signed comparison */
43
static int I64_compare(int64 x, int64 y)
45
if ((int32)x.h > (int32)y.h) return 1;
46
if ((int32)x.h < (int32)y.h) return -1;
47
if (x.l > y.l) return 1;
48
if (x.l < y.l) return -1;
53
static int64 I64_neg(int64 x)
58
if (res.l == 0) res.h++;
63
static int64 I64_add(int64 x, int64 y)
68
if (res.l < x.l) res.h++;
73
static int64 I64_sub(int64 x, int64 y)
78
if (x.l < y.l) res.h--;
83
static int64 I64_mul(int64 x, int64 y)
86
uint32 prod00 = (x.l & 0xFFFF) * (y.l & 0xFFFF);
87
uint32 prod10 = (x.l >> 16) * (y.l & 0xFFFF);
88
uint32 prod01 = (x.l & 0xFFFF) * (y.l >> 16);
89
uint32 prod11 = (x.l >> 16) * (y.l >> 16);
91
res.h = prod11 + (prod01 >> 16) + (prod10 >> 16);
92
prod01 = prod01 << 16; res.l += prod01; if (res.l < prod01) res.h++;
93
prod10 = prod10 << 16; res.l += prod10; if (res.l < prod10) res.h++;
94
res.h += x.l * y.h + x.h * y.l;
98
#define I64_is_zero(x) (((x).l | (x).h) == 0)
100
#define I64_is_negative(x) ((int32) (x).h < 0)
102
/* Bitwise operations */
103
static int64 I64_and(int64 x, int64 y)
111
static int64 I64_or(int64 x, int64 y)
119
static int64 I64_xor(int64 x, int64 y)
128
static int64 I64_lsl(int64 x, int s)
132
if (s == 0) return x;
135
res.h = (x.h << s) | (x.l >> (32 - s));
138
res.h = x.l << (s - 32);
143
static int64 I64_lsr(int64 x, int s)
147
if (s == 0) return x;
149
res.l = (x.l >> s) | (x.h << (32 - s));
152
res.l = x.h >> (s - 32);
158
static int64 I64_asr(int64 x, int s)
162
if (s == 0) return x;
164
res.l = (x.l >> s) | (x.h << (32 - s));
165
res.h = (int32) x.h >> s;
167
res.l = (int32) x.h >> (s - 32);
168
res.h = (int32) x.h >> 31;
173
/* Division and modulus */
175
#define I64_SHL1(x) x.h = (x.h << 1) | (x.l >> 31); x.l <<= 1
176
#define I64_SHR1(x) x.l = (x.l >> 1) | (x.h << 31); x.h >>= 1
178
static void I64_udivmod(uint64 modulus, uint64 divisor,
179
uint64 * quo, uint64 * mod)
181
int64 quotient, mask;
184
quotient.h = 0; quotient.l = 0;
185
mask.h = 0; mask.l = 1;
186
while ((int32) divisor.h >= 0) {
187
cmp = I64_ucompare(divisor, modulus);
192
while (mask.l | mask.h) {
193
if (I64_ucompare(modulus, divisor) >= 0) {
194
quotient.h |= mask.h; quotient.l |= mask.l;
195
modulus = I64_sub(modulus, divisor);
204
static int64 I64_div(int64 x, int64 y)
210
if ((int32) x.h < 0) x = I64_neg(x);
211
if ((int32) y.h < 0) y = I64_neg(y);
212
I64_udivmod(x, y, &q, &r);
213
if (sign < 0) q = I64_neg(q);
217
static int64 I64_mod(int64 x, int64 y)
223
if ((int32) x.h < 0) x = I64_neg(x);
224
if ((int32) y.h < 0) y = I64_neg(y);
225
I64_udivmod(x, y, &q, &r);
226
if (sign < 0) r = I64_neg(r);
232
static int64 I64_of_int32(int32 x)
240
#define I64_to_int32(x) ((int32) (x).l)
242
/* Note: we assume sizeof(intnat) = 4 here, which is true otherwise
243
autoconfiguration would have selected native 64-bit integers */
244
#define I64_of_intnat I64_of_int32
245
#define I64_to_intnat I64_to_int32
247
static double I64_to_double(int64 x)
251
if (sign < 0) x = I64_neg(x);
252
res = ldexp((double) x.h, 32) + x.l;
253
if (sign < 0) res = -res;
257
static int64 I64_of_double(double f)
265
frac = modf(ldexp(f, -32), &integ);
266
res.h = (uint32) integ;
267
res.l = (uint32) ldexp(frac, 32);
268
if (neg) res = I64_neg(res);
272
#endif /* CAML_INT64_EMUL_H */