AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
arith.c
Go to the documentation of this file.
1
10
11#include <stdint.h>
12
16static inline uint32_t divl(uint64_t n, uint32_t d)
17{
18 uint32_t n1 = n >> 32;
19 uint32_t n0 = n;
20 uint32_t q, r;
21
22 asm ("divl %4"
23 : "=d" (r), "=a" (q)
24 : "0" (n1), "1" (n0), "rm" (d));
25
26 return q;
27}
28
31static int nlz(uint32_t x)
32{
33 int n = 0;
34 if (x <= 0x0000FFFF) {
35 n += 16;
36 x <<= 16;
37 }
38
39 if (x <= 0x00FFFFFF) {
40 n += 8;
41 x <<= 8;
42 }
43
44 if (x <= 0x0FFFFFFF) {
45 n += 4;
46 x <<= 4;
47 }
48
49 if (x <= 0x3FFFFFFF) {
50 n += 2;
51 x <<= 2;
52 }
53
54 if (x <= 0x7FFFFFFF)
55 n++;
56
57 return n;
58}
59
63{
64 if ((d >> 32) == 0) {
65 /* Proof of correctness:
66 * Let n, d, b, n1, and n0 be defined as in this function.
67 * Let [x] be the "floor" of x. Let T = b[n1/d]. Assume d
68 * nonzero. Then:
69 * [n/d] = [n/d] - T + T
70 * = [n/d - T] + T by (1) below
71 * = [(b*n1 + n0)/d - T] + T by definition of n
72 * = [(b*n1 + n0)/d - dT/d] + T
73 * = [(b(n1 - d[n1/d]) + n0)/d] + T
74 * = [(b[n1 % d] + n0)/d] + T, by definition of %
75 * which is the expression calculated below.
76 *
77 * (1) Note that for any real x, integer i: [x] + i = [x + i].
78 *
79 * To prevent divl() from trapping, [(b[n1 % d] + n0)/d] must
80 * be less than b. Assume that [n1 % d] and n0 take their
81 * respective maximum values of d - 1 and b - 1:
82 * [(b(d - 1) + (b - 1))/d] < b
83 * <=> [(bd - 1)/d] < b
84 * <=> [b - 1/d] < b
85 * which is a tautology.
86 *
87 * Therefore, this code is correct and will not trap.
88 */
89
90 uint64_t b = 1ULL << 32;
91 uint32_t n1 = n >> 32;
92 uint32_t n0 = n;
93 uint32_t d0 = d;
94
95 return divl(b * (n1 % d0) + n0, d0) + b * (n1 / d0);
96 } else {
97 /* Based on the algorithm and proof available from
98 * http://www.hackersdelight.org/revisions.pdf.
99 */
100 if (n < d) {
101 return 0;
102 } else {
103 uint32_t d1 = d >> 32;
104 int s = nlz(d1);
105 uint64_t q = divl(n >> 1, (d << s) >> 32) >> (31 - s);
106 return n - (q - 1) * d < d ? q - 1 : q;
107 }
108 }
109}
110
114{
115 return n - d * udiv64(n, d);
116}
117
121{
122 uint64_t n_abs = n >= 0 ? (uint64_t) n : -(uint64_t) n;
123 uint64_t d_abs = d >= 0 ? (uint64_t) d : -(uint64_t) d;
124 uint64_t q_abs = udiv64 (n_abs, d_abs);
125 return (n < 0) == (d < 0) ? (int64_t) q_abs : -(int64_t) q_abs;
126}
127
131{
132 return n - d * sdiv64(n, d);
133}
134
135/* The routines that GCC calls. */
136
137long long __divdi3(long long n, long long d);
138long long __moddi3(long long n, long long d);
139unsigned long long __udivdi3(unsigned long long n, unsigned long long d);
140unsigned long long __umoddi3(unsigned long long n, unsigned long long d);
141unsigned long long __udivmoddi4(unsigned long long n, unsigned long long d, unsigned long long *rem);
142
150long long __divdi3(long long n, long long d)
151{
152 return sdiv64(n, d);
153}
154
162long long __moddi3(long long n, long long d)
163{
164 return smod64 (n, d);
165}
166
174unsigned long long __udivdi3(unsigned long long n, unsigned long long d)
175{
176 return udiv64 (n, d);
177}
178
186unsigned long long __umoddi3(unsigned long long n, unsigned long long d)
187{
188 return umod64 (n, d);
189}
190
200unsigned long long __udivmoddi4(unsigned long long n, unsigned long long d, unsigned long long *rem)
201{
202 uint64_t q = udiv64(n, d);
203
204 if (rem)
205 *rem = n - d * q;
206
207 return q;
208}
static uint64_t udiv64(uint64_t n, uint64_t d)
Divides the unsigned 64-bit n by the unsigned 64-bit d, and returns the quotient.
Definition arith.c:62
static uint64_t umod64(uint64_t n, uint64_t d)
Divides the unsigned 64-bit n by the unsigned 64-bit d, and returns the remainder.
Definition arith.c:113
static int64_t smod64(int64_t n, int64_t d)
Divides the signed 64-bit n by the signed 64-bit d, and returns the remainder.
Definition arith.c:130
long long __moddi3(long long n, long long d)
Computes the remainder of two signed 64-bit integers.
Definition arith.c:162
unsigned long long __udivdi3(unsigned long long n, unsigned long long d)
Divides two unsigned 64-bit integers.
Definition arith.c:174
unsigned long long __umoddi3(unsigned long long n, unsigned long long d)
Computes the remainder of two unsigned 64-bit integers.
Definition arith.c:186
static int64_t sdiv64(int64_t n, int64_t d)
Divides the signed 64-bit n by the signed 64-bit d, and returns the quotient.
Definition arith.c:120
static uint32_t divl(uint64_t n, uint32_t d)
Divides the 64-bit n by the 32-bit d with the x86 DIVL instruction, and returns the 32-bit quotient.
Definition arith.c:16
static int nlz(uint32_t x)
Returns the number of leading zero bits in x, which must not be 0.
Definition arith.c:31
unsigned long long __udivmoddi4(unsigned long long n, unsigned long long d, unsigned long long *rem)
Divides two unsigned 64-bit integers, giving both the quotient and the remainder.
Definition arith.c:200
long long __divdi3(long long n, long long d)
Divides two signed 64-bit integers.
Definition arith.c:150
unsigned int uint32_t
Definition stddef.h:22
signed long long int int64_t
Definition stddef.h:19
unsigned long long int uint64_t
Definition stddef.h:23