hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
/**
 *   Generic arithmetic/conversion routines.
 *   Copyright © 2005 Stelian Pop.
 *   Copyright © 2005 Gilles Chanteperdrix.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */
#ifndef _COBALT_UAPI_ASM_GENERIC_ARITH_H
#define _COBALT_UAPI_ASM_GENERIC_ARITH_H
 
#ifndef xnarch_u64tou32
#define xnarch_u64tou32(ull, h, l) ({        \
      union {                    \
         unsigned long long _ull;        \
         struct endianstruct _s;        \
      } _u;                    \
      _u._ull = (ull);                \
      (h) = _u._s._h;                \
      (l) = _u._s._l;                \
})
#endif /* !xnarch_u64tou32 */
 
#ifndef xnarch_u64fromu32
#define xnarch_u64fromu32(h, l) ({        \
   union {                    \
       unsigned long long _ull;    \
       struct endianstruct _s;        \
   } _u;                    \
   _u._s._h = (h);                \
   _u._s._l = (l);                \
   _u._ull;                \
})
#endif /* !xnarch_u64fromu32 */
 
#ifndef xnarch_ullmul
static inline __attribute__((__const__)) unsigned long long
xnarch_generic_ullmul(const unsigned m0, const unsigned m1)
{
   return (unsigned long long) m0 * m1;
}
#define xnarch_ullmul(m0,m1) xnarch_generic_ullmul((m0),(m1))
#endif /* !xnarch_ullmul */
 
#ifndef xnarch_ulldiv
static inline unsigned long long xnarch_generic_ulldiv (unsigned long long ull,
                           const unsigned uld,
                           unsigned long *const rp)
{
   const unsigned r = do_div(ull, uld);
 
   if (rp)
       *rp = r;
 
   return ull;
}
#define xnarch_ulldiv(ull,uld,rp) xnarch_generic_ulldiv((ull),(uld),(rp))
#endif /* !xnarch_ulldiv */
 
#ifndef xnarch_uldivrem
#define xnarch_uldivrem(ull,ul,rp) ((unsigned) xnarch_ulldiv((ull),(ul),(rp)))
#endif /* !xnarch_uldivrem */
 
#ifndef xnarch_divmod64
static inline unsigned long long
xnarch_generic_divmod64(unsigned long long a,
           unsigned long long b,
           unsigned long long *rem)
{
   unsigned long long q;
#if defined(__KERNEL__) && BITS_PER_LONG < 64
   unsigned long long
       xnarch_generic_full_divmod64(unsigned long long a,
                        unsigned long long b,
                        unsigned long long *rem);
   if (b <= 0xffffffffULL) {
       unsigned long r;
       q = xnarch_ulldiv(a, b, &r);
       if (rem)
           *rem = r;
   } else {
       if (a < b) {
           if (rem)
               *rem = a;
           return 0;
       }
 
       return xnarch_generic_full_divmod64(a, b, rem);
   }
#else /* !(__KERNEL__ && BITS_PER_LONG < 64) */
   q = a / b;
   if (rem)
       *rem = a % b;
#endif  /* !(__KERNEL__ && BITS_PER_LONG < 64) */
   return q;
}
#define xnarch_divmod64(a,b,rp) xnarch_generic_divmod64((a),(b),(rp))
#endif /* !xnarch_divmod64 */
 
#ifndef xnarch_imuldiv
static inline __attribute__((__const__)) int xnarch_generic_imuldiv(int i,
                                   int mult,
                                   int div)
{
   /* (int)i = (unsigned long long)i*(unsigned)(mult)/(unsigned)div. */
   const unsigned long long ull = xnarch_ullmul(i, mult);
   return xnarch_uldivrem(ull, div, NULL);
}
#define xnarch_imuldiv(i,m,d) xnarch_generic_imuldiv((i),(m),(d))
#endif /* !xnarch_imuldiv */
 
#ifndef xnarch_imuldiv_ceil
static inline __attribute__((__const__)) int xnarch_generic_imuldiv_ceil(int i,
                                    int mult,
                                    int div)
{
   /* Same as xnarch_generic_imuldiv, rounding up. */
   const unsigned long long ull = xnarch_ullmul(i, mult);
   return xnarch_uldivrem(ull + (unsigned)div - 1, div, NULL);
}
#define xnarch_imuldiv_ceil(i,m,d) xnarch_generic_imuldiv_ceil((i),(m),(d))
#endif /* !xnarch_imuldiv_ceil */
 
/* Division of an unsigned 96 bits ((h << 32) + l) by an unsigned 32 bits.
   Building block for llimd. Without const qualifiers, gcc reload registers
   after each call to uldivrem. */
static inline unsigned long long
xnarch_generic_div96by32(const unsigned long long h,
            const unsigned l,
            const unsigned d,
            unsigned long *const rp)
{
   unsigned long rh;
   const unsigned qh = xnarch_uldivrem(h, d, &rh);
   const unsigned long long t = xnarch_u64fromu32(rh, l);
   const unsigned ql = xnarch_uldivrem(t, d, rp);
 
   return xnarch_u64fromu32(qh, ql);
}
 
#ifndef xnarch_llimd
static inline __attribute__((__const__))
unsigned long long xnarch_generic_ullimd(const unsigned long long op,
                    const unsigned m,
                    const unsigned d)
{
   unsigned int oph, opl, tlh, tll;
   unsigned long long th, tl;
 
   xnarch_u64tou32(op, oph, opl);
   tl = xnarch_ullmul(opl, m);
   xnarch_u64tou32(tl, tlh, tll);
   th = xnarch_ullmul(oph, m);
   th += tlh;
 
   return xnarch_generic_div96by32(th, tll, d, NULL);
}
 
static inline __attribute__((__const__)) long long
xnarch_generic_llimd (long long op, unsigned m, unsigned d)
{
   long long ret;
   int sign = 0;
 
   if (op < 0LL) {
       sign = 1;
       op = -op;
   }
   ret = xnarch_generic_ullimd(op, m, d);
 
   return sign ? -ret : ret;
}
#define xnarch_llimd(ll,m,d) xnarch_generic_llimd((ll),(m),(d))
#endif /* !xnarch_llimd */
 
#ifndef _xnarch_u96shift
#define xnarch_u96shift(h, m, l, s) ({        \
   unsigned int _l = (l);            \
   unsigned int _m = (m);            \
   unsigned int _s = (s);            \
   _l >>= _s;                \
   _l |= (_m << (32 - _s));        \
   _m >>= _s;                \
   _m |= ((h) << (32 - _s));        \
   xnarch_u64fromu32(_m, _l);        \
})
#endif /* !xnarch_u96shift */
 
static inline long long xnarch_llmi(int i, int j)
{
   /* Fast 32x32->64 signed multiplication */
   return (long long) i * j;
}
 
#ifndef xnarch_llmulshft
/* Fast scaled-math-based replacement for long long multiply-divide */
static inline long long
xnarch_generic_llmulshft(const long long op,
             const unsigned m,
             const unsigned s)
{
   unsigned int oph, opl, tlh, tll, thh, thl;
   unsigned long long th, tl;
 
   xnarch_u64tou32(op, oph, opl);
   tl = xnarch_ullmul(opl, m);
   xnarch_u64tou32(tl, tlh, tll);
   th = xnarch_llmi(oph, m);
   th += tlh;
   xnarch_u64tou32(th, thh, thl);
 
   return xnarch_u96shift(thh, thl, tll, s);
}
#define xnarch_llmulshft(ll, m, s) xnarch_generic_llmulshft((ll), (m), (s))
#endif /* !xnarch_llmulshft */
 
#ifdef XNARCH_HAVE_NODIV_LLIMD
 
/* Representation of a 32 bits fraction. */
struct xnarch_u32frac {
   unsigned long long frac;
   unsigned integ;
};
 
static inline void xnarch_init_u32frac(struct xnarch_u32frac *const f,
                      const unsigned m,
                      const unsigned d)
{
   /*
    * Avoid clever compiler optimizations to occur when d is
    * known at compile-time. The performance of this function is
    * not critical since it is only called at init time.
    */
   volatile unsigned vol_d = d;
   f->integ = m / d;
   f->frac = xnarch_generic_div96by32
       (xnarch_u64fromu32(m % d, 0), 0, vol_d, NULL);
}
 
#ifndef xnarch_nodiv_imuldiv
static inline __attribute__((__const__)) unsigned
xnarch_generic_nodiv_imuldiv(unsigned op, const struct xnarch_u32frac f)
{
   return (xnarch_ullmul(op, f.frac >> 32) >> 32) + f.integ * op;
}
#define xnarch_nodiv_imuldiv(op, f) xnarch_generic_nodiv_imuldiv((op),(f))
#endif /* xnarch_nodiv_imuldiv */
 
#ifndef xnarch_nodiv_imuldiv_ceil
static inline __attribute__((__const__)) unsigned
xnarch_generic_nodiv_imuldiv_ceil(unsigned op, const struct xnarch_u32frac f)
{
   unsigned long long full = xnarch_ullmul(op, f.frac >> 32) + ~0U;
   return (full >> 32) + f.integ * op;
}
#define xnarch_nodiv_imuldiv_ceil(op, f) \
   xnarch_generic_nodiv_imuldiv_ceil((op),(f))
#endif /* xnarch_nodiv_imuldiv_ceil */
 
#ifndef xnarch_nodiv_ullimd
 
#ifndef xnarch_add96and64
#error "xnarch_add96and64 must be implemented."
#endif
 
static inline __attribute__((__const__)) unsigned long long
xnarch_mul64by64_high(const unsigned long long op, const unsigned long long m)
{
   /* Compute high 64 bits of multiplication 64 bits x 64 bits. */
   register unsigned long long t0, t1, t2, t3;
   register unsigned int oph, opl, mh, ml, t0h, t0l, t1h, t1l, t2h, t2l, t3h, t3l;
 
   xnarch_u64tou32(op, oph, opl);
   xnarch_u64tou32(m, mh, ml);
   t0 = xnarch_ullmul(opl, ml);
   xnarch_u64tou32(t0, t0h, t0l);
   t3 = xnarch_ullmul(oph, mh);
   xnarch_u64tou32(t3, t3h, t3l);
   xnarch_add96and64(t3h, t3l, t0h, 0, t0l >> 31);
   t1 = xnarch_ullmul(oph, ml);
   xnarch_u64tou32(t1, t1h, t1l);
   xnarch_add96and64(t3h, t3l, t0h, t1h, t1l);
   t2 = xnarch_ullmul(opl, mh);
   xnarch_u64tou32(t2, t2h, t2l);
   xnarch_add96and64(t3h, t3l, t0h, t2h, t2l);
 
   return xnarch_u64fromu32(t3h, t3l);
}
 
static inline unsigned long long
xnarch_generic_nodiv_ullimd(const unsigned long long op,
               const unsigned long long frac,
               unsigned int integ)
{
   return xnarch_mul64by64_high(op, frac) + integ * op;
}
#define xnarch_nodiv_ullimd(op, f, i)  xnarch_generic_nodiv_ullimd((op),(f), (i))
#endif /* !xnarch_nodiv_ullimd */
 
#ifndef xnarch_nodiv_llimd
static inline __attribute__((__const__)) long long
xnarch_generic_nodiv_llimd(long long op, unsigned long long frac,
              unsigned int integ)
{
   long long ret;
   int sign = 0;
 
   if (op < 0LL) {
       sign = 1;
       op = -op;
   }
   ret = xnarch_nodiv_ullimd(op, frac, integ);
 
   return sign ? -ret : ret;
}
#define xnarch_nodiv_llimd(ll,frac,integ) xnarch_generic_nodiv_llimd((ll),(frac),(integ))
#endif /* !xnarch_nodiv_llimd */
 
#endif /* XNARCH_HAVE_NODIV_LLIMD */
 
static inline void xnarch_init_llmulshft(const unsigned m_in,
                    const unsigned d_in,
                    unsigned *m_out,
                    unsigned *s_out)
{
   /*
    * Avoid clever compiler optimizations to occur when d is
    * known at compile-time. The performance of this function is
    * not critical since it is only called at init time.
    */
   volatile unsigned int vol_d = d_in;
   unsigned long long mult;
 
   *s_out = 31;
   while (1) {
       mult = ((unsigned long long)m_in) << *s_out;
       do_div(mult, vol_d);
       if (mult <= 0x7FFFFFFF)
           break;
       (*s_out)--;
   }
   *m_out = (unsigned int)mult;
}
 
#define xnarch_ullmod(ull,uld,rem)   ({ xnarch_ulldiv(ull,uld,rem); (*rem); })
#define xnarch_uldiv(ull, d)         xnarch_uldivrem(ull, d, NULL)
#define xnarch_ulmod(ull, d)         ({ unsigned long _rem;    \
                   xnarch_uldivrem(ull,d,&_rem); _rem; })
 
#define xnarch_div64(a,b)            xnarch_divmod64((a),(b),NULL)
#define xnarch_mod64(a,b)            ({ unsigned long long _rem; \
                   xnarch_divmod64((a),(b),&_rem); _rem; })
 
#endif /* _COBALT_UAPI_ASM_GENERIC_ARITH_H */