~ubuntu-branches/ubuntu/lucid/bin-prot/lucid

« back to all changes in this revision

Viewing changes to lib/int64_emul.h

  • Committer: Bazaar Package Importer
  • Author(s): Stefano Zacchiroli
  • Date: 2008-05-09 15:24:37 UTC
  • Revision ID: james.westby@ubuntu.com-20080509152437-7gils45p37xcs40c
Tags: upstream-1.0.5
ImportĀ upstreamĀ versionĀ 1.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***********************************************************************/
 
2
/*                                                                     */
 
3
/*                           Objective Caml                            */
 
4
/*                                                                     */
 
5
/*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         */
 
6
/*                                                                     */
 
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.     */
 
11
/*                                                                     */
 
12
/***********************************************************************/
 
13
 
 
14
/* $Id: int64_emul.h,v 1.5 2005/09/22 14:21:50 xleroy Exp $ */
 
15
 
 
16
/* Software emulation of 64-bit integer arithmetic, for C compilers
 
17
   that do not support it.  */
 
18
 
 
19
#ifndef CAML_INT64_EMUL_H
 
20
#define CAML_INT64_EMUL_H
 
21
 
 
22
#include <math.h>
 
23
 
 
24
#ifdef ARCH_BIG_ENDIAN
 
25
#define I64_literal(hi,lo) { hi, lo }
 
26
#else
 
27
#define I64_literal(hi,lo) { lo, hi }
 
28
#endif
 
29
 
 
30
/* Unsigned comparison */
 
31
static int I64_ucompare(uint64 x, uint64 y)
 
32
{
 
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;
 
37
  return 0;
 
38
}
 
39
 
 
40
#define I64_ult(x, y) (I64_ucompare(x, y) < 0)
 
41
 
 
42
/* Signed comparison */
 
43
static int I64_compare(int64 x, int64 y)
 
44
{
 
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;
 
49
  return 0;
 
50
}
 
51
 
 
52
/* Negation */
 
53
static int64 I64_neg(int64 x)
 
54
{
 
55
  int64 res;
 
56
  res.l = -x.l;
 
57
  res.h = ~x.h;
 
58
  if (res.l == 0) res.h++;
 
59
  return res;
 
60
}
 
61
 
 
62
/* Addition */
 
63
static int64 I64_add(int64 x, int64 y)
 
64
{
 
65
  int64 res;
 
66
  res.l = x.l + y.l;
 
67
  res.h = x.h + y.h;
 
68
  if (res.l < x.l) res.h++;
 
69
  return res;
 
70
}
 
71
 
 
72
/* Subtraction */
 
73
static int64 I64_sub(int64 x, int64 y)
 
74
{
 
75
  int64 res;
 
76
  res.l = x.l - y.l;
 
77
  res.h = x.h - y.h;
 
78
  if (x.l < y.l) res.h--;
 
79
  return res;
 
80
}
 
81
 
 
82
/* Multiplication */
 
83
static int64 I64_mul(int64 x, int64 y)
 
84
{
 
85
  int64 res;
 
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);
 
90
  res.l = prod00;
 
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;
 
95
  return res;
 
96
}
 
97
 
 
98
#define I64_is_zero(x) (((x).l | (x).h) == 0)
 
99
 
 
100
#define I64_is_negative(x) ((int32) (x).h < 0)
 
101
 
 
102
/* Bitwise operations */
 
103
static int64 I64_and(int64 x, int64 y)
 
104
{
 
105
  int64 res;
 
106
  res.l = x.l & y.l;
 
107
  res.h = x.h & y.h;
 
108
  return res;
 
109
}
 
110
 
 
111
static int64 I64_or(int64 x, int64 y)
 
112
{
 
113
  int64 res;
 
114
  res.l = x.l | y.l;
 
115
  res.h = x.h | y.h;
 
116
  return res;
 
117
}
 
118
 
 
119
static int64 I64_xor(int64 x, int64 y)
 
120
{
 
121
  int64 res;
 
122
  res.l = x.l ^ y.l;
 
123
  res.h = x.h ^ y.h;
 
124
  return res;
 
125
}
 
126
 
 
127
/* Shifts */
 
128
static int64 I64_lsl(int64 x, int s)
 
129
{
 
130
  int64 res;
 
131
  s = s & 63;
 
132
  if (s == 0) return x;
 
133
  if (s < 32) {
 
134
    res.l = x.l << s;
 
135
    res.h = (x.h << s) | (x.l >> (32 - s));
 
136
  } else {
 
137
    res.l = 0;
 
138
    res.h = x.l << (s - 32);
 
139
  }
 
140
  return res;
 
141
}
 
142
 
 
143
static int64 I64_lsr(int64 x, int s)
 
144
{
 
145
  int64 res;
 
146
  s = s & 63;
 
147
  if (s == 0) return x;
 
148
  if (s < 32) {
 
149
    res.l = (x.l >> s) | (x.h << (32 - s));
 
150
    res.h = x.h >> s;
 
151
  } else {
 
152
    res.l = x.h >> (s - 32);
 
153
    res.h = 0;
 
154
  }
 
155
  return res;
 
156
}
 
157
 
 
158
static int64 I64_asr(int64 x, int s)
 
159
{
 
160
  int64 res;
 
161
  s = s & 63;
 
162
  if (s == 0) return x;
 
163
  if (s < 32) {
 
164
    res.l = (x.l >> s) | (x.h << (32 - s));
 
165
    res.h = (int32) x.h >> s;
 
166
  } else {
 
167
    res.l = (int32) x.h >> (s - 32);
 
168
    res.h = (int32) x.h >> 31;
 
169
  }
 
170
  return res;
 
171
}
 
172
 
 
173
/* Division and modulus */
 
174
 
 
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
 
177
 
 
178
static void I64_udivmod(uint64 modulus, uint64 divisor,
 
179
                        uint64 * quo, uint64 * mod)
 
180
{
 
181
  int64 quotient, mask;
 
182
  int cmp;
 
183
 
 
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);
 
188
    I64_SHL1(divisor);
 
189
    I64_SHL1(mask);
 
190
    if (cmp >= 0) break;
 
191
  }
 
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);
 
196
    }
 
197
    I64_SHR1(mask);
 
198
    I64_SHR1(divisor);
 
199
  }
 
200
  *quo = quotient;
 
201
  *mod = modulus;
 
202
}
 
203
 
 
204
static int64 I64_div(int64 x, int64 y)
 
205
{
 
206
  int64 q, r;
 
207
  int32 sign;
 
208
 
 
209
  sign = x.h ^ y.h;
 
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);
 
214
  return q;
 
215
}
 
216
 
 
217
static int64 I64_mod(int64 x, int64 y)
 
218
{
 
219
  int64 q, r;
 
220
  int32 sign;
 
221
 
 
222
  sign = x.h;
 
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);
 
227
  return r;
 
228
}
 
229
 
 
230
/* Coercions */
 
231
 
 
232
static int64 I64_of_int32(int32 x)
 
233
{
 
234
  int64 res;
 
235
  res.l = x;
 
236
  res.h = x >> 31;
 
237
  return res;
 
238
}
 
239
 
 
240
#define I64_to_int32(x) ((int32) (x).l)
 
241
 
 
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
 
246
 
 
247
static double I64_to_double(int64 x)
 
248
{
 
249
  double res;
 
250
  int32 sign = x.h;
 
251
  if (sign < 0) x = I64_neg(x);
 
252
  res = ldexp((double) x.h, 32) + x.l;
 
253
  if (sign < 0) res = -res;
 
254
  return res;
 
255
}
 
256
 
 
257
static int64 I64_of_double(double f)
 
258
{
 
259
  int64 res;
 
260
  double frac, integ;
 
261
  int neg;
 
262
 
 
263
  neg = (f < 0);
 
264
  f = fabs(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);
 
269
  return res;
 
270
}
 
271
 
 
272
#endif /* CAML_INT64_EMUL_H */