Xenomai 3.3.2
Loading...
Searching...
No Matches
arith.h
1
20#ifndef _COBALT_UAPI_ASM_GENERIC_ARITH_H
21#define _COBALT_UAPI_ASM_GENERIC_ARITH_H
22
23#ifndef xnarch_u64tou32
24#define xnarch_u64tou32(ull, h, l) ({ \
25 union { \
26 unsigned long long _ull; \
27 struct endianstruct _s; \
28 } _u; \
29 _u._ull = (ull); \
30 (h) = _u._s._h; \
31 (l) = _u._s._l; \
32})
33#endif /* !xnarch_u64tou32 */
34
35#ifndef xnarch_u64fromu32
36#define xnarch_u64fromu32(h, l) ({ \
37 union { \
38 unsigned long long _ull; \
39 struct endianstruct _s; \
40 } _u; \
41 _u._s._h = (h); \
42 _u._s._l = (l); \
43 _u._ull; \
44})
45#endif /* !xnarch_u64fromu32 */
46
47#ifndef xnarch_ullmul
48static inline __attribute__((__const__)) unsigned long long
49xnarch_generic_ullmul(const unsigned m0, const unsigned m1)
50{
51 return (unsigned long long) m0 * m1;
52}
53#define xnarch_ullmul(m0,m1) xnarch_generic_ullmul((m0),(m1))
54#endif /* !xnarch_ullmul */
55
56#ifndef xnarch_ulldiv
57static inline unsigned long long xnarch_generic_ulldiv (unsigned long long ull,
58 const unsigned uld,
59 unsigned long *const rp)
60{
61 const unsigned r = do_div(ull, uld);
62
63 if (rp)
64 *rp = r;
65
66 return ull;
67}
68#define xnarch_ulldiv(ull,uld,rp) xnarch_generic_ulldiv((ull),(uld),(rp))
69#endif /* !xnarch_ulldiv */
70
71#ifndef xnarch_uldivrem
72#define xnarch_uldivrem(ull,ul,rp) ((unsigned) xnarch_ulldiv((ull),(ul),(rp)))
73#endif /* !xnarch_uldivrem */
74
75#ifndef xnarch_divmod64
76#if defined(__KERNEL__) && BITS_PER_LONG < 64
77unsigned long long xnarch_generic_full_divmod64(unsigned long long a,
78 unsigned long long b,
79 unsigned long long *rem);
80#define IMPLEMENT_GENERIC_FULL_DIVMOD64
81#endif
82
83static inline unsigned long long
84xnarch_generic_divmod64(unsigned long long a,
85 unsigned long long b,
86 unsigned long long *rem)
87{
88 unsigned long long q;
89#if defined(__KERNEL__) && BITS_PER_LONG < 64
90 if (b <= 0xffffffffULL) {
91 unsigned long r;
92 q = xnarch_ulldiv(a, b, &r);
93 if (rem)
94 *rem = r;
95 } else {
96 if (a < b) {
97 if (rem)
98 *rem = a;
99 return 0;
100 }
101
102 return xnarch_generic_full_divmod64(a, b, rem);
103 }
104#else /* !(__KERNEL__ && BITS_PER_LONG < 64) */
105 q = a / b;
106 if (rem)
107 *rem = a % b;
108#endif /* !(__KERNEL__ && BITS_PER_LONG < 64) */
109 return q;
110}
111#define xnarch_divmod64(a,b,rp) xnarch_generic_divmod64((a),(b),(rp))
112#endif /* !xnarch_divmod64 */
113
114#ifndef xnarch_imuldiv
115static inline __attribute__((__const__)) int xnarch_generic_imuldiv(int i,
116 int mult,
117 int div)
118{
119 /* (int)i = (unsigned long long)i*(unsigned)(mult)/(unsigned)div. */
120 const unsigned long long ull = xnarch_ullmul(i, mult);
121 return xnarch_uldivrem(ull, div, NULL);
122}
123#define xnarch_imuldiv(i,m,d) xnarch_generic_imuldiv((i),(m),(d))
124#endif /* !xnarch_imuldiv */
125
126#ifndef xnarch_imuldiv_ceil
127static inline __attribute__((__const__)) int xnarch_generic_imuldiv_ceil(int i,
128 int mult,
129 int div)
130{
131 /* Same as xnarch_generic_imuldiv, rounding up. */
132 const unsigned long long ull = xnarch_ullmul(i, mult);
133 return xnarch_uldivrem(ull + (unsigned)div - 1, div, NULL);
134}
135#define xnarch_imuldiv_ceil(i,m,d) xnarch_generic_imuldiv_ceil((i),(m),(d))
136#endif /* !xnarch_imuldiv_ceil */
137
138/* Division of an unsigned 96 bits ((h << 32) + l) by an unsigned 32 bits.
139 Building block for llimd. Without const qualifiers, gcc reload registers
140 after each call to uldivrem. */
141static inline unsigned long long
142xnarch_generic_div96by32(const unsigned long long h,
143 const unsigned l,
144 const unsigned d,
145 unsigned long *const rp)
146{
147 unsigned long rh;
148 const unsigned qh = xnarch_uldivrem(h, d, &rh);
149 const unsigned long long t = xnarch_u64fromu32(rh, l);
150 const unsigned ql = xnarch_uldivrem(t, d, rp);
151
152 return xnarch_u64fromu32(qh, ql);
153}
154
155#ifndef xnarch_llimd
156static inline __attribute__((__const__))
157unsigned long long xnarch_generic_ullimd(const unsigned long long op,
158 const unsigned m,
159 const unsigned d)
160{
161 unsigned int oph, opl, tlh, tll;
162 unsigned long long th, tl;
163
164 xnarch_u64tou32(op, oph, opl);
165 tl = xnarch_ullmul(opl, m);
166 xnarch_u64tou32(tl, tlh, tll);
167 th = xnarch_ullmul(oph, m);
168 th += tlh;
169
170 return xnarch_generic_div96by32(th, tll, d, NULL);
171}
172
173static inline __attribute__((__const__)) long long
174xnarch_generic_llimd (long long op, unsigned m, unsigned d)
175{
176 long long ret;
177 int sign = 0;
178
179 if (op < 0LL) {
180 sign = 1;
181 op = -op;
182 }
183 ret = xnarch_generic_ullimd(op, m, d);
184
185 return sign ? -ret : ret;
186}
187#define xnarch_llimd(ll,m,d) xnarch_generic_llimd((ll),(m),(d))
188#endif /* !xnarch_llimd */
189
190#ifndef _xnarch_u96shift
191#define xnarch_u96shift(h, m, l, s) ({ \
192 unsigned int _l = (l); \
193 unsigned int _m = (m); \
194 unsigned int _s = (s); \
195 _l >>= _s; \
196 _l |= (_m << (32 - _s)); \
197 _m >>= _s; \
198 _m |= ((h) << (32 - _s)); \
199 xnarch_u64fromu32(_m, _l); \
200})
201#endif /* !xnarch_u96shift */
202
203static inline long long xnarch_llmi(int i, int j)
204{
205 /* Fast 32x32->64 signed multiplication */
206 return (long long) i * j;
207}
208
209#ifndef xnarch_llmulshft
210/* Fast scaled-math-based replacement for long long multiply-divide */
211static inline long long
212xnarch_generic_llmulshft(const long long op,
213 const unsigned m,
214 const unsigned s)
215{
216 unsigned int oph, opl, tlh, tll, thh, thl;
217 unsigned long long th, tl;
218
219 xnarch_u64tou32(op, oph, opl);
220 tl = xnarch_ullmul(opl, m);
221 xnarch_u64tou32(tl, tlh, tll);
222 th = xnarch_llmi(oph, m);
223 th += tlh;
224 xnarch_u64tou32(th, thh, thl);
225
226 return xnarch_u96shift(thh, thl, tll, s);
227}
228#define xnarch_llmulshft(ll, m, s) xnarch_generic_llmulshft((ll), (m), (s))
229#endif /* !xnarch_llmulshft */
230
231#ifdef XNARCH_HAVE_NODIV_LLIMD
232
233/* Representation of a 32 bits fraction. */
234struct xnarch_u32frac {
235 unsigned long long frac;
236 unsigned integ;
237};
238
239static inline void xnarch_init_u32frac(struct xnarch_u32frac *const f,
240 const unsigned m,
241 const unsigned d)
242{
243 /*
244 * Avoid clever compiler optimizations to occur when d is
245 * known at compile-time. The performance of this function is
246 * not critical since it is only called at init time.
247 */
248 volatile unsigned vol_d = d;
249 f->integ = m / d;
250 f->frac = xnarch_generic_div96by32
251 (xnarch_u64fromu32(m % d, 0), 0, vol_d, NULL);
252}
253
254#ifndef xnarch_nodiv_imuldiv
255static inline __attribute__((__const__)) unsigned
256xnarch_generic_nodiv_imuldiv(unsigned op, const struct xnarch_u32frac f)
257{
258 return (xnarch_ullmul(op, f.frac >> 32) >> 32) + f.integ * op;
259}
260#define xnarch_nodiv_imuldiv(op, f) xnarch_generic_nodiv_imuldiv((op),(f))
261#endif /* xnarch_nodiv_imuldiv */
262
263#ifndef xnarch_nodiv_imuldiv_ceil
264static inline __attribute__((__const__)) unsigned
265xnarch_generic_nodiv_imuldiv_ceil(unsigned op, const struct xnarch_u32frac f)
266{
267 unsigned long long full = xnarch_ullmul(op, f.frac >> 32) + ~0U;
268 return (full >> 32) + f.integ * op;
269}
270#define xnarch_nodiv_imuldiv_ceil(op, f) \
271 xnarch_generic_nodiv_imuldiv_ceil((op),(f))
272#endif /* xnarch_nodiv_imuldiv_ceil */
273
274#ifndef xnarch_nodiv_ullimd
275
276#ifndef xnarch_add96and64
277#error "xnarch_add96and64 must be implemented."
278#endif
279
280static inline __attribute__((__const__)) unsigned long long
281xnarch_mul64by64_high(const unsigned long long op, const unsigned long long m)
282{
283 /* Compute high 64 bits of multiplication 64 bits x 64 bits. */
284 register unsigned long long t0, t1, t2, t3;
285 register unsigned int oph, opl, mh, ml, t0h, t0l, t1h, t1l, t2h, t2l, t3h, t3l;
286
287 xnarch_u64tou32(op, oph, opl);
288 xnarch_u64tou32(m, mh, ml);
289 t0 = xnarch_ullmul(opl, ml);
290 xnarch_u64tou32(t0, t0h, t0l);
291 t3 = xnarch_ullmul(oph, mh);
292 xnarch_u64tou32(t3, t3h, t3l);
293 xnarch_add96and64(t3h, t3l, t0h, 0, t0l >> 31);
294 t1 = xnarch_ullmul(oph, ml);
295 xnarch_u64tou32(t1, t1h, t1l);
296 xnarch_add96and64(t3h, t3l, t0h, t1h, t1l);
297 t2 = xnarch_ullmul(opl, mh);
298 xnarch_u64tou32(t2, t2h, t2l);
299 xnarch_add96and64(t3h, t3l, t0h, t2h, t2l);
300
301 return xnarch_u64fromu32(t3h, t3l);
302}
303
304static inline unsigned long long
305xnarch_generic_nodiv_ullimd(const unsigned long long op,
306 const unsigned long long frac,
307 unsigned int integ)
308{
309 return xnarch_mul64by64_high(op, frac) + integ * op;
310}
311#define xnarch_nodiv_ullimd(op, f, i) xnarch_generic_nodiv_ullimd((op),(f), (i))
312#endif /* !xnarch_nodiv_ullimd */
313
314#ifndef xnarch_nodiv_llimd
315static inline __attribute__((__const__)) long long
316xnarch_generic_nodiv_llimd(long long op, unsigned long long frac,
317 unsigned int integ)
318{
319 long long ret;
320 int sign = 0;
321
322 if (op < 0LL) {
323 sign = 1;
324 op = -op;
325 }
326 ret = xnarch_nodiv_ullimd(op, frac, integ);
327
328 return sign ? -ret : ret;
329}
330#define xnarch_nodiv_llimd(ll,frac,integ) xnarch_generic_nodiv_llimd((ll),(frac),(integ))
331#endif /* !xnarch_nodiv_llimd */
332
333#endif /* XNARCH_HAVE_NODIV_LLIMD */
334
335static inline void xnarch_init_llmulshft(const unsigned m_in,
336 const unsigned d_in,
337 unsigned *m_out,
338 unsigned *s_out)
339{
340 /*
341 * Avoid clever compiler optimizations to occur when d is
342 * known at compile-time. The performance of this function is
343 * not critical since it is only called at init time.
344 */
345 volatile unsigned int vol_d = d_in;
346 unsigned long long mult;
347
348 *s_out = 31;
349 while (1) {
350 mult = ((unsigned long long)m_in) << *s_out;
351 do_div(mult, vol_d);
352 if (mult <= 0x7FFFFFFF)
353 break;
354 (*s_out)--;
355 }
356 *m_out = (unsigned int)mult;
357}
358
359#define xnarch_ullmod(ull,uld,rem) ({ xnarch_ulldiv(ull,uld,rem); (*rem); })
360#define xnarch_uldiv(ull, d) xnarch_uldivrem(ull, d, NULL)
361#define xnarch_ulmod(ull, d) ({ unsigned long _rem; \
362 xnarch_uldivrem(ull,d,&_rem); _rem; })
363
364#define xnarch_div64(a,b) xnarch_divmod64((a),(b),NULL)
365#define xnarch_mod64(a,b) ({ unsigned long long _rem; \
366 xnarch_divmod64((a),(b),&_rem); _rem; })
367
368#endif /* _COBALT_UAPI_ASM_GENERIC_ARITH_H */