aboutsummaryrefslogtreecommitdiff
path: root/kernel/byterun/coq_uint63_native.h
blob: 92f4dc79bc96e41aae237f10ddbfcc0fe6022c84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#define Is_uint63(v) (Is_long(v))

#define uint63_of_value(val) ((uint64_t)(val) >> 1)

/* 2^63 * y + x as a value */
//#define Val_intint(x,y) ((value)(((uint64_t)(x)) << 1 + ((uint64_t)(y) << 64)))

#define uint63_zero ((value) 1) /* 2*0 + 1 */
#define uint63_one() ((value) 3) /* 2*1 + 1 */

#define uint63_eq(x,y) ((x) == (y))
#define uint63_eq0(x) ((x) == (uint64_t)1)
#define uint63_lt(x,y) ((uint64_t) (x) < (uint64_t) (y))
#define uint63_leq(x,y) ((uint64_t) (x) <= (uint64_t) (y))

#define uint63_add(x,y) ((value)((uint64_t) (x) + (uint64_t) (y) - 1))
#define uint63_addcarry(x,y) ((value)((uint64_t) (x) + (uint64_t) (y) + 1))
#define uint63_sub(x,y) ((value)((uint64_t) (x) - (uint64_t) (y) + 1))
#define uint63_subcarry(x,y) ((value)((uint64_t) (x) - (uint64_t) (y) - 1))
#define uint63_mul(x,y) (Val_long(uint63_of_value(x) * uint63_of_value(y)))
#define uint63_div(x,y) (Val_long(uint63_of_value(x) / uint63_of_value(y)))
#define uint63_mod(x,y) (Val_long(uint63_of_value(x) % uint63_of_value(y)))

#define uint63_lxor(x,y) ((value)(((uint64_t)(x) ^ (uint64_t)(y)) | 1))
#define uint63_lor(x,y) ((value)((uint64_t)(x) | (uint64_t)(y)))
#define uint63_land(x,y) ((value)((uint64_t)(x) & (uint64_t)(y)))

/* TODO: is + or | better? OCAML uses + */
/* TODO: is - or ^ better? */
#define uint63_lsl(x,y) ((y) < (uint64_t) 127 ? ((value)((((uint64_t)(x)-1) << (uint63_of_value(y))) | 1)) : uint63_zero)
#define uint63_lsr(x,y) ((y) < (uint64_t) 127 ? ((value)(((uint64_t)(x) >> (uint63_of_value(y))) | 1)) : uint63_zero)
#define uint63_lsl1(x) ((value)((((uint64_t)(x)-1) << 1) +1))
#define uint63_lsr1(x) ((value)(((uint64_t)(x) >> 1) |1))

/* addmuldiv(p,x,y) = x * 2^p + y / 2 ^ (63 - p) */
/* (modulo 2^63) for p <= 63 */
value uint63_addmuldiv(uint64_t p, uint64_t x, uint64_t y) {
  uint64_t shiftby = uint63_of_value(p);
  value r = (value)((uint64_t)(x^1) << shiftby);
  r |= ((uint64_t)y >> (63-shiftby)) | 1;
  return r;
}

value uint63_head0(uint64_t x) {
  int r = 0;
  if (!(x & 0xFFFFFFFF00000000)) { x <<= 32; r += 32; }
  if (!(x & 0xFFFF000000000000)) { x <<= 16; r += 16; }
  if (!(x & 0xFF00000000000000)) { x <<= 8;  r += 8; }
  if (!(x & 0xF000000000000000)) { x <<= 4;  r += 4; }
  if (!(x & 0xC000000000000000)) { x <<= 2;  r += 2; }
  if (!(x & 0x8000000000000000)) { x <<=1;   r += 1; }
  return Val_int(r);
}

value uint63_tail0(value x) {
  int r = 0;
  x = (uint64_t)x >> 1;
  if (!(x & 0xFFFFFFFF)) { x >>= 32; r += 32; }
  if (!(x & 0x0000FFFF)) { x >>= 16; r += 16; }
  if (!(x & 0x000000FF)) { x >>= 8;  r += 8; }
  if (!(x & 0x0000000F)) { x >>= 4;  r += 4; }
  if (!(x & 0x00000003)) { x >>= 2;  r += 2; }
  if (!(x & 0x00000001)) { x >>=1;   r += 1; }
  return Val_int(r);
}

value uint63_mulc(value x, value y, value* h) {
  x = (uint64_t)x >> 1;
  y = (uint64_t)y >> 1;
  uint64_t lx = x & 0xFFFFFFFF;
  uint64_t ly = y & 0xFFFFFFFF;
  uint64_t hx = x >> 32;
  uint64_t hy = y >> 32;
  uint64_t hr = hx * hy;
  uint64_t lr = lx * ly;
  lx *= hy;
  ly *= hx;
  hr += (lx >> 32) + (ly >> 32);
  lx <<= 32;
  lr += lx;
  if (lr < lx) { hr++; }
  ly <<= 32;
  lr += ly;
  if (lr < ly) { hr++; }
  hr = (hr << 1) | (lr >> 63);
  *h = Val_int(hr);
  return Val_int(lr);
}

#define lt128(xh,xl,yh,yl) (uint63_lt(xh,yh) || (uint63_eq(xh,yh) && uint63_lt(xl,yl)))
#define le128(xh,xl,yh,yl) (uint63_lt(xh,yh) || (uint63_eq(xh,yh) && uint63_leq(xl,yl)))

value uint63_div21(value xh, value xl, value y, value* q) {
  xh = (uint64_t)xh >> 1;
  xl = ((uint64_t)xl >> 1) | ((uint64_t)xh << 63);
  xh = (uint64_t)xh >> 1;
  uint64_t maskh = 0;
  uint64_t maskl = 1;
  uint64_t dh = 0;
  uint64_t dl = (uint64_t)y >> 1;
  int cmp = 1;
  while (dh >= 0 && cmp) {
    cmp = lt128(dh,dl,xh,xl);
    dh = (dh << 1) | (dl >> 63);
    dl = dl << 1;
    maskh = (maskh << 1) | (maskl >> 63);
    maskl = maskl << 1;
  }
  uint64_t remh = xh;
  uint64_t reml = xl;
  uint64_t quotient = 0;
  while (maskh | maskl) {
    if (le128(dh,dl,remh,reml)) {
      quotient = quotient | maskl;
      if (uint63_lt(reml,dl)) {remh = remh - dh - 1;} else {remh = remh - dh;}
      reml = reml - dl;
    }
    maskl = (maskl >> 1) | (maskh << 63);
    maskh = maskh >> 1;
    dl = (dl >> 1) | (dh << 63);
    dh = dh >> 1;
  }
  *q = Val_int(quotient);
  return Val_int(reml);
}