CS318 - Pintos
Pintos source browser for JHU CS318 course
arithmetic.c
Go to the documentation of this file.
1 #include <stdint.h>
2 
3 /** On x86, division of one 64-bit integer by another cannot be
4  done with a single instruction or a short sequence. Thus, GCC
5  implements 64-bit division and remainder operations through
6  function calls. These functions are normally obtained from
7  libgcc, which is automatically included by GCC in any link
8  that it does.
9 
10  Some x86-64 machines, however, have a compiler and utilities
11  that can generate 32-bit x86 code without having any of the
12  necessary libraries, including libgcc. Thus, we can make
13  Pintos work on these machines by simply implementing our own
14  64-bit division routines, which are the only routines from
15  libgcc that Pintos requires.
16 
17  Completeness is another reason to include these routines. If
18  Pintos is completely self-contained, then that makes it that
19  much less mysterious. */
20 
21 /** Uses x86 DIVL instruction to divide 64-bit N by 32-bit D to
22  yield a 32-bit quotient. Returns the quotient.
23  Traps with a divide error (#DE) if the quotient does not fit
24  in 32 bits. */
25 static inline uint32_t
27 {
28  uint32_t n1 = n >> 32;
29  uint32_t n0 = n;
30  uint32_t q, r;
31 
32  asm ("divl %4"
33  : "=d" (r), "=a" (q)
34  : "0" (n1), "1" (n0), "rm" (d));
35 
36  return q;
37 }
38 
39 /** Returns the number of leading zero bits in X,
40  which must be nonzero. */
41 static int
43 {
44  /* This technique is portable, but there are better ways to do
45  it on particular systems. With sufficiently new enough GCC,
46  you can use __builtin_clz() to take advantage of GCC's
47  knowledge of how to do it. Or you can use the x86 BSR
48  instruction directly. */
49  int n = 0;
50  if (x <= 0x0000FFFF)
51  {
52  n += 16;
53  x <<= 16;
54  }
55  if (x <= 0x00FFFFFF)
56  {
57  n += 8;
58  x <<= 8;
59  }
60  if (x <= 0x0FFFFFFF)
61  {
62  n += 4;
63  x <<= 4;
64  }
65  if (x <= 0x3FFFFFFF)
66  {
67  n += 2;
68  x <<= 2;
69  }
70  if (x <= 0x7FFFFFFF)
71  n++;
72  return n;
73 }
74 
75 /** Divides unsigned 64-bit N by unsigned 64-bit D and returns the
76  quotient. */
77 static uint64_t
79 {
80  if ((d >> 32) == 0)
81  {
82  /* Proof of correctness:
83 
84  Let n, d, b, n1, and n0 be defined as in this function.
85  Let [x] be the "floor" of x. Let T = b[n1/d]. Assume d
86  nonzero. Then:
87  [n/d] = [n/d] - T + T
88  = [n/d - T] + T by (1) below
89  = [(b*n1 + n0)/d - T] + T by definition of n
90  = [(b*n1 + n0)/d - dT/d] + T
91  = [(b(n1 - d[n1/d]) + n0)/d] + T
92  = [(b[n1 % d] + n0)/d] + T, by definition of %
93  which is the expression calculated below.
94 
95  (1) Note that for any real x, integer i: [x] + i = [x + i].
96 
97  To prevent divl() from trapping, [(b[n1 % d] + n0)/d] must
98  be less than b. Assume that [n1 % d] and n0 take their
99  respective maximum values of d - 1 and b - 1:
100  [(b(d - 1) + (b - 1))/d] < b
101  <=> [(bd - 1)/d] < b
102  <=> [b - 1/d] < b
103  which is a tautology.
104 
105  Therefore, this code is correct and will not trap. */
106  uint64_t b = 1ULL << 32;
107  uint32_t n1 = n >> 32;
108  uint32_t n0 = n;
109  uint32_t d0 = d;
110 
111  return divl (b * (n1 % d0) + n0, d0) + b * (n1 / d0);
112  }
113  else
114  {
115  /* Based on the algorithm and proof available from
116  http://www.hackersdelight.org/revisions.pdf. */
117  if (n < d)
118  return 0;
119  else
120  {
121  uint32_t d1 = d >> 32;
122  int s = nlz (d1);
123  uint64_t q = divl (n >> 1, (d << s) >> 32) >> (31 - s);
124  return n - (q - 1) * d < d ? q - 1 : q;
125  }
126  }
127 }
128 
129 /** Divides unsigned 64-bit N by unsigned 64-bit D and returns the
130  remainder. */
131 static uint32_t
133 {
134  return n - d * udiv64 (n, d);
135 }
136 
137 /** Divides signed 64-bit N by signed 64-bit D and returns the
138  quotient. */
139 static int64_t
141 {
142  uint64_t n_abs = n >= 0 ? (uint64_t) n : -(uint64_t) n;
143  uint64_t d_abs = d >= 0 ? (uint64_t) d : -(uint64_t) d;
144  uint64_t q_abs = udiv64 (n_abs, d_abs);
145  return (n < 0) == (d < 0) ? (int64_t) q_abs : -(int64_t) q_abs;
146 }
147 
148 /** Divides signed 64-bit N by signed 64-bit D and returns the
149  remainder. */
150 static int32_t
152 {
153  return n - d * sdiv64 (n, d);
154 }
155 
156 /** These are the routines that GCC calls. */
157 
158 long long __divdi3 (long long n, long long d);
159 long long __moddi3 (long long n, long long d);
160 unsigned long long __udivdi3 (unsigned long long n, unsigned long long d);
161 unsigned long long __umoddi3 (unsigned long long n, unsigned long long d);
162 
163 /** Signed 64-bit division. */
164 long long
165 __divdi3 (long long n, long long d)
166 {
167  return sdiv64 (n, d);
168 }
169 
170 /** Signed 64-bit remainder. */
171 long long
172 __moddi3 (long long n, long long d)
173 {
174  return smod64 (n, d);
175 }
176 
177 /** Unsigned 64-bit division. */
178 unsigned long long
179 __udivdi3 (unsigned long long n, unsigned long long d)
180 {
181  return udiv64 (n, d);
182 }
183 
184 /** Unsigned 64-bit remainder. */
185 unsigned long long
186 __umoddi3 (unsigned long long n, unsigned long long d)
187 {
188  return umod64 (n, d);
189 }
uint64_t
unsigned long long int uint64_t
Definition: stdint.h:29
sdiv64
static int64_t sdiv64(int64_t n, int64_t d)
Divides signed 64-bit N by signed 64-bit D and returns the quotient.
Definition: arithmetic.c:140
__umoddi3
unsigned long long __umoddi3(unsigned long long n, unsigned long long d)
Unsigned 64-bit remainder.
Definition: arithmetic.c:186
__udivdi3
unsigned long long __udivdi3(unsigned long long n, unsigned long long d)
Unsigned 64-bit division.
Definition: arithmetic.c:179
nlz
static int nlz(uint32_t x)
Returns the number of leading zero bits in X, which must be nonzero.
Definition: arithmetic.c:42
smod64
static int32_t smod64(int64_t n, int64_t d)
Divides signed 64-bit N by signed 64-bit D and returns the remainder.
Definition: arithmetic.c:151
int64_t
signed long long int int64_t
Definition: stdint.h:16
uint32_t
unsigned int uint32_t
Definition: stdint.h:26
__divdi3
long long __divdi3(long long n, long long d)
These are the routines that GCC calls.
Definition: arithmetic.c:165
stdint.h
umod64
static uint32_t umod64(uint64_t n, uint64_t d)
Divides unsigned 64-bit N by unsigned 64-bit D and returns the remainder.
Definition: arithmetic.c:132
x
static char x
Verifies that mapping over the data segment is disallowed.
Definition: mmap-over-data.c:9
divl
static uint32_t divl(uint64_t n, uint32_t d)
On x86, division of one 64-bit integer by another cannot be done with a single instruction or a short...
Definition: arithmetic.c:26
s
static uint8_t s[256]
RC4-based pseudo-random number generator (PRNG).
Definition: random.c:17
int32_t
signed int int32_t
Definition: stdint.h:12
udiv64
static uint64_t udiv64(uint64_t n, uint64_t d)
Divides unsigned 64-bit N by unsigned 64-bit D and returns the quotient.
Definition: arithmetic.c:78
__moddi3
long long __moddi3(long long n, long long d)
Signed 64-bit remainder.
Definition: arithmetic.c:172