rcuja fix: del wrt concurrency
[userspace-rcu.git] / rcuja / bitfield.h
CommitLineData
d68c6810
MD
1#ifndef _URCU_RCUJA_BITFIELD_H
2#define _URCU_RCUJA_BITFIELD_H
3
4/*
5 * Bitfields read/write functions.
6 *
7 * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 */
19
20#include <stdint.h> /* C99 5.2.4.2 Numerical limits */
21#include <limits.h> /* C99 5.2.4.2 Numerical limits */
22#include <assert.h>
23#include "endian.h" /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */
24
25/* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
26#define _ja_piecewise_rshift(_v, _shift) \
27({ \
28 typeof(_v) ___v = (_v); \
29 typeof(_shift) ___shift = (_shift); \
30 unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \
31 unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \
32 \
33 for (; sb; sb--) \
34 ___v >>= sizeof(___v) * CHAR_BIT - 1; \
35 ___v >>= final; \
36})
37
38#define _ja_piecewise_lshift(_v, _shift) \
39({ \
40 typeof(_v) ___v = (_v); \
41 typeof(_shift) ___shift = (_shift); \
42 unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \
43 unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \
44 \
45 for (; sb; sb--) \
46 ___v <<= sizeof(___v) * CHAR_BIT - 1; \
47 ___v <<= final; \
48})
49
50#define _ja_is_signed_type(type) (((type)(-1)) < 0)
51
52#define _ja_unsigned_cast(type, v) \
53({ \
54 (sizeof(v) < sizeof(type)) ? \
55 ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \
56 (type) (v); \
57})
58
59/*
60 * ja_bitfield_write - write integer to a bitfield in native endianness
61 *
62 * Save integer to the bitfield, which starts at the "start" bit, has "len"
63 * bits.
64 * The inside of a bitfield is from high bits to low bits.
65 * Uses native endianness.
66 * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
67 * For signed "v", sign-extend v if bitfield is larger than v.
68 *
69 * On little endian, bytes are placed from the less significant to the most
70 * significant. Also, consecutive bitfields are placed from lower bits to higher
71 * bits.
72 *
73 * On big endian, bytes are places from most significant to less significant.
74 * Also, consecutive bitfields are placed from higher to lower bits.
75 */
76
77#define _ja_bitfield_write_le(_ptr, type, _start, _length, _v) \
78do { \
79 typeof(_v) __v = (_v); \
80 type *__ptr = (void *) (_ptr); \
81 unsigned long __start = (_start), __length = (_length); \
82 type mask, cmask; \
83 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
84 unsigned long start_unit, end_unit, this_unit; \
85 unsigned long end, cshift; /* cshift is "complement shift" */ \
86 \
87 if (!__length) \
88 break; \
89 \
90 end = __start + __length; \
91 start_unit = __start / ts; \
92 end_unit = (end + (ts - 1)) / ts; \
93 \
94 /* Trim v high bits */ \
95 if (__length < sizeof(__v) * CHAR_BIT) \
96 __v &= ~((~(typeof(__v)) 0) << __length); \
97 \
98 /* We can now append v with a simple "or", shift it piece-wise */ \
99 this_unit = start_unit; \
100 if (start_unit == end_unit - 1) { \
101 mask = ~((~(type) 0) << (__start % ts)); \
102 if (end % ts) \
103 mask |= (~(type) 0) << (end % ts); \
104 cmask = (type) __v << (__start % ts); \
105 cmask &= ~mask; \
106 __ptr[this_unit] &= mask; \
107 __ptr[this_unit] |= cmask; \
108 break; \
109 } \
110 if (__start % ts) { \
111 cshift = __start % ts; \
112 mask = ~((~(type) 0) << cshift); \
113 cmask = (type) __v << cshift; \
114 cmask &= ~mask; \
115 __ptr[this_unit] &= mask; \
116 __ptr[this_unit] |= cmask; \
117 __v = _ja_piecewise_rshift(__v, ts - cshift); \
118 __start += ts - cshift; \
119 this_unit++; \
120 } \
121 for (; this_unit < end_unit - 1; this_unit++) { \
122 __ptr[this_unit] = (type) __v; \
123 __v = _ja_piecewise_rshift(__v, ts); \
124 __start += ts; \
125 } \
126 if (end % ts) { \
127 mask = (~(type) 0) << (end % ts); \
128 cmask = (type) __v; \
129 cmask &= ~mask; \
130 __ptr[this_unit] &= mask; \
131 __ptr[this_unit] |= cmask; \
132 } else \
133 __ptr[this_unit] = (type) __v; \
134} while (0)
135
136#define _ja_bitfield_write_be(_ptr, type, _start, _length, _v) \
137do { \
138 typeof(_v) __v = (_v); \
139 type *__ptr = (void *) (_ptr); \
140 unsigned long __start = (_start), __length = (_length); \
141 type mask, cmask; \
142 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
143 unsigned long start_unit, end_unit, this_unit; \
144 unsigned long end, cshift; /* cshift is "complement shift" */ \
145 \
146 if (!__length) \
147 break; \
148 \
149 end = __start + __length; \
150 start_unit = __start / ts; \
151 end_unit = (end + (ts - 1)) / ts; \
152 \
153 /* Trim v high bits */ \
154 if (__length < sizeof(__v) * CHAR_BIT) \
155 __v &= ~((~(typeof(__v)) 0) << __length); \
156 \
157 /* We can now append v with a simple "or", shift it piece-wise */ \
158 this_unit = end_unit - 1; \
159 if (start_unit == end_unit - 1) { \
160 mask = ~((~(type) 0) << ((ts - (end % ts)) % ts)); \
161 if (__start % ts) \
162 mask |= (~((type) 0)) << (ts - (__start % ts)); \
163 cmask = (type) __v << ((ts - (end % ts)) % ts); \
164 cmask &= ~mask; \
165 __ptr[this_unit] &= mask; \
166 __ptr[this_unit] |= cmask; \
167 break; \
168 } \
169 if (end % ts) { \
170 cshift = end % ts; \
171 mask = ~((~(type) 0) << (ts - cshift)); \
172 cmask = (type) __v << (ts - cshift); \
173 cmask &= ~mask; \
174 __ptr[this_unit] &= mask; \
175 __ptr[this_unit] |= cmask; \
176 __v = _ja_piecewise_rshift(__v, cshift); \
177 end -= cshift; \
178 this_unit--; \
179 } \
180 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
181 __ptr[this_unit] = (type) __v; \
182 __v = _ja_piecewise_rshift(__v, ts); \
183 end -= ts; \
184 } \
185 if (__start % ts) { \
186 mask = (~(type) 0) << (ts - (__start % ts)); \
187 cmask = (type) __v; \
188 cmask &= ~mask; \
189 __ptr[this_unit] &= mask; \
190 __ptr[this_unit] |= cmask; \
191 } else \
192 __ptr[this_unit] = (type) __v; \
193} while (0)
194
195/*
196 * ja_bitfield_write - write integer to a bitfield in native endianness
197 * ja_bitfield_write_le - write integer to a bitfield in little endian
198 * ja_bitfield_write_be - write integer to a bitfield in big endian
199 */
200
201#if (BYTE_ORDER == LITTLE_ENDIAN)
202
203#define ja_bitfield_write(ptr, type, _start, _length, _v) \
204 _ja_bitfield_write_le(ptr, type, _start, _length, _v)
205
206#define ja_bitfield_write_le(ptr, type, _start, _length, _v) \
207 _ja_bitfield_write_le(ptr, type, _start, _length, _v)
208
209#define ja_bitfield_write_be(ptr, type, _start, _length, _v) \
210 _ja_bitfield_write_be(ptr, unsigned char, _start, _length, _v)
211
212#elif (BYTE_ORDER == BIG_ENDIAN)
213
214#define ja_bitfield_write(ptr, type, _start, _length, _v) \
215 _ja_bitfield_write_be(ptr, type, _start, _length, _v)
216
217#define ja_bitfield_write_le(ptr, type, _start, _length, _v) \
218 _ja_bitfield_write_le(ptr, unsigned char, _start, _length, _v)
219
220#define ja_bitfield_write_be(ptr, type, _start, _length, _v) \
221 _ja_bitfield_write_be(ptr, type, _start, _length, _v)
222
223#else /* (BYTE_ORDER == PDP_ENDIAN) */
224
225#error "Byte order not supported"
226
227#endif
228
229#define _ja_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
230do { \
231 typeof(*(_vptr)) *__vptr = (_vptr); \
232 typeof(*__vptr) __v; \
233 type *__ptr = (void *) (_ptr); \
234 unsigned long __start = (_start), __length = (_length); \
235 type mask, cmask; \
236 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
237 unsigned long start_unit, end_unit, this_unit; \
238 unsigned long end, cshift; /* cshift is "complement shift" */ \
239 \
240 if (!__length) { \
241 *__vptr = 0; \
242 break; \
243 } \
244 \
245 end = __start + __length; \
246 start_unit = __start / ts; \
247 end_unit = (end + (ts - 1)) / ts; \
248 \
249 this_unit = end_unit - 1; \
250 if (_ja_is_signed_type(typeof(__v)) \
251 && (__ptr[this_unit] & ((type) 1 << ((end % ts ? : ts) - 1)))) \
252 __v = ~(typeof(__v)) 0; \
253 else \
254 __v = 0; \
255 if (start_unit == end_unit - 1) { \
256 cmask = __ptr[this_unit]; \
257 cmask >>= (__start % ts); \
258 if ((end - __start) % ts) { \
259 mask = ~((~(type) 0) << (end - __start)); \
260 cmask &= mask; \
261 } \
262 __v = _ja_piecewise_lshift(__v, end - __start); \
263 __v |= _ja_unsigned_cast(typeof(__v), cmask); \
264 *__vptr = __v; \
265 break; \
266 } \
267 if (end % ts) { \
268 cshift = end % ts; \
269 mask = ~((~(type) 0) << cshift); \
270 cmask = __ptr[this_unit]; \
271 cmask &= mask; \
272 __v = _ja_piecewise_lshift(__v, cshift); \
273 __v |= _ja_unsigned_cast(typeof(__v), cmask); \
274 end -= cshift; \
275 this_unit--; \
276 } \
277 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
278 __v = _ja_piecewise_lshift(__v, ts); \
279 __v |= _ja_unsigned_cast(typeof(__v), __ptr[this_unit]);\
280 end -= ts; \
281 } \
282 if (__start % ts) { \
283 mask = ~((~(type) 0) << (ts - (__start % ts))); \
284 cmask = __ptr[this_unit]; \
285 cmask >>= (__start % ts); \
286 cmask &= mask; \
287 __v = _ja_piecewise_lshift(__v, ts - (__start % ts)); \
288 __v |= _ja_unsigned_cast(typeof(__v), cmask); \
289 } else { \
290 __v = _ja_piecewise_lshift(__v, ts); \
291 __v |= _ja_unsigned_cast(typeof(__v), __ptr[this_unit]);\
292 } \
293 *__vptr = __v; \
294} while (0)
295
296#define _ja_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
297do { \
298 typeof(*(_vptr)) *__vptr = (_vptr); \
299 typeof(*__vptr) __v; \
300 type *__ptr = (void *) (_ptr); \
301 unsigned long __start = (_start), __length = (_length); \
302 type mask, cmask; \
303 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
304 unsigned long start_unit, end_unit, this_unit; \
305 unsigned long end, cshift; /* cshift is "complement shift" */ \
306 \
307 if (!__length) { \
308 *__vptr = 0; \
309 break; \
310 } \
311 \
312 end = __start + __length; \
313 start_unit = __start / ts; \
314 end_unit = (end + (ts - 1)) / ts; \
315 \
316 this_unit = start_unit; \
317 if (_ja_is_signed_type(typeof(__v)) \
318 && (__ptr[this_unit] & ((type) 1 << (ts - (__start % ts) - 1)))) \
319 __v = ~(typeof(__v)) 0; \
320 else \
321 __v = 0; \
322 if (start_unit == end_unit - 1) { \
323 cmask = __ptr[this_unit]; \
324 cmask >>= (ts - (end % ts)) % ts; \
325 if ((end - __start) % ts) { \
326 mask = ~((~(type) 0) << (end - __start)); \
327 cmask &= mask; \
328 } \
329 __v = _ja_piecewise_lshift(__v, end - __start); \
330 __v |= _ja_unsigned_cast(typeof(__v), cmask); \
331 *__vptr = __v; \
332 break; \
333 } \
334 if (__start % ts) { \
335 cshift = __start % ts; \
336 mask = ~((~(type) 0) << (ts - cshift)); \
337 cmask = __ptr[this_unit]; \
338 cmask &= mask; \
339 __v = _ja_piecewise_lshift(__v, ts - cshift); \
340 __v |= _ja_unsigned_cast(typeof(__v), cmask); \
341 __start += ts - cshift; \
342 this_unit++; \
343 } \
344 for (; this_unit < end_unit - 1; this_unit++) { \
345 __v = _ja_piecewise_lshift(__v, ts); \
346 __v |= _ja_unsigned_cast(typeof(__v), __ptr[this_unit]);\
347 __start += ts; \
348 } \
349 if (end % ts) { \
350 mask = ~((~(type) 0) << (end % ts)); \
351 cmask = __ptr[this_unit]; \
352 cmask >>= ts - (end % ts); \
353 cmask &= mask; \
354 __v = _ja_piecewise_lshift(__v, end % ts); \
355 __v |= _ja_unsigned_cast(typeof(__v), cmask); \
356 } else { \
357 __v = _ja_piecewise_lshift(__v, ts); \
358 __v |= _ja_unsigned_cast(typeof(__v), __ptr[this_unit]);\
359 } \
360 *__vptr = __v; \
361} while (0)
362
363/*
364 * ja_bitfield_read - read integer from a bitfield in native endianness
365 * ja_bitfield_read_le - read integer from a bitfield in little endian
366 * ja_bitfield_read_be - read integer from a bitfield in big endian
367 */
368
369#if (BYTE_ORDER == LITTLE_ENDIAN)
370
371#define ja_bitfield_read(_ptr, type, _start, _length, _vptr) \
372 _ja_bitfield_read_le(_ptr, type, _start, _length, _vptr)
373
374#define ja_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
375 _ja_bitfield_read_le(_ptr, type, _start, _length, _vptr)
376
377#define ja_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
378 _ja_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr)
379
380#elif (BYTE_ORDER == BIG_ENDIAN)
381
382#define ja_bitfield_read(_ptr, type, _start, _length, _vptr) \
383 _ja_bitfield_read_be(_ptr, type, _start, _length, _vptr)
384
385#define ja_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
386 _ja_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr)
387
388#define ja_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
389 _ja_bitfield_read_be(_ptr, type, _start, _length, _vptr)
390
391#else /* (BYTE_ORDER == PDP_ENDIAN) */
392
393#error "Byte order not supported"
394
395#endif
396
397#endif /* _URCU_RCUJA_BITFIELD_H */
This page took 0.036216 seconds and 4 git commands to generate.