|
|
1.1 root 1: #! /bin/sh
2:
1.1.1.2 ! root 3: # $Id: memory-auto.sh,v 1.2 2010/02/15 15:16:28 fredette Exp $
1.1 root 4:
5: # libtme/memory-auto.sh - automatically generates C code for
6: # memory support:
7:
8: #
9: # Copyright (c) 2005, 2006 Matt Fredette
10: # All rights reserved.
11: #
12: # Redistribution and use in source and binary forms, with or without
13: # modification, are permitted provided that the following conditions
14: # are met:
15: # 1. Redistributions of source code must retain the above copyright
16: # notice, this list of conditions and the following disclaimer.
17: # 2. Redistributions in binary form must reproduce the above copyright
18: # notice, this list of conditions and the following disclaimer in the
19: # documentation and/or other materials provided with the distribution.
20: # 3. All advertising materials mentioning features or use of this software
21: # must display the following acknowledgement:
22: # This product includes software developed by Matt Fredette.
23: # 4. The name of the author may not be used to endorse or promote products
24: # derived from this software without specific prior written permission.
25: #
26: # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27: # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28: # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29: # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
30: # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31: # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32: # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34: # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35: # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: # POSSIBILITY OF SUCH DAMAGE.
37: #
38:
39: header=false
40:
41: for option
42: do
43: case $option in
44: --header) header=true ;;
45: esac
46: done
47:
48: PROG=`basename $0`
49: cat <<EOF
50: /* automatically generated by $PROG, do not edit! */
51:
52: /*
53: * Copyright (c) 2005, 2006 Matt Fredette
54: * All rights reserved.
55: *
56: * Redistribution and use in source and binary forms, with or without
57: * modification, are permitted provided that the following conditions
58: * are met:
59: * 1. Redistributions of source code must retain the above copyright
60: * notice, this list of conditions and the following disclaimer.
61: * 2. Redistributions in binary form must reproduce the above copyright
62: * notice, this list of conditions and the following disclaimer in the
63: * documentation and/or other materials provided with the distribution.
64: * 3. All advertising materials mentioning features or use of this software
65: * must display the following acknowledgement:
66: * This product includes software developed by Matt Fredette.
67: * 4. The name of the author may not be used to endorse or promote products
68: * derived from this software without specific prior written permission.
69: *
70: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
71: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
72: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
73: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
74: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
75: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
76: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
77: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
78: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
79: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
80: * POSSIBILITY OF SUCH DAMAGE.
81: */
82: EOF
83:
84: if $header; then :; else
85: cat <<EOF
86:
87: /* includes: */
88: #include <tme/memory.h>
89:
90: EOF
91: fi
92: cat <<EOF
93:
1.1.1.2 ! root 94: _TME_RCSID("\$Id: memory-auto.sh,v 1.2 2010/02/15 15:16:28 fredette Exp $");
1.1 root 95: EOF
96: if $header; then
97: cat <<EOF
98:
99: /* macros: */
100:
101: /* the plain partial read internal macro: */
102: #define _tme_memory_read(type_whole, type_part, mem, offset) \\
103: (((type_whole) \\
104: *((_tme_const type_part *) \\
105: (_tme_cast_pointer_const(tme_uint8_t *, type_whole *, mem) \\
106: + (offset)))) \\
107: << (8 * (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG \\
108: ? (sizeof(type_whole) \\
109: - ((offset) + sizeof(type_part))) \\
110: : (offset))))
111:
112: /* the plain partial write internal macro: */
113: #define _tme_memory_write(type_whole, type_part, mem, offset, x) \\
114: do { \\
115: *((type_part *) \\
116: (_tme_cast_pointer(tme_uint8_t *, type_whole *, mem) \\
117: + (offset))) \\
1.1.1.2 ! root 118: = (type_part) \\
! 119: (((type_whole) (x)) \\
1.1 root 120: >> (8 * (TME_ENDIAN_NATIVE == TME_ENDIAN_BIG \\
121: ? (sizeof(type_whole) \\
122: - ((offset) + sizeof(type_part))) \\
123: : (offset)))); \\
124: } while (/* CONSTCOND */ 0)
125:
126: /* this tests bits in a memory address: */
127: #define _tme_memory_address_test(mem, bits, align_min) \\
128: (((bits) & ~((align_min - 1))) & ((unsigned long) (mem)))
129:
130: /* this returns a mask of all-bits-one in given type: */
131: #define _tme_memory_type_mask(type, shift) \\
132: ((type) ((((type) 0) - ((type) 1)) shift))
133:
134: EOF
135: fi
136:
137: # the different sizes we handle, and the smallest size that we have to
138: # wrap in an ifdef:
139: #
140: sizes='8 16 32 64'
141: size_ifdef=64
142:
143: # the largest possible host boundary that we will consider:
144: #
145: host_boundary_largest=64
146:
147: # permute for the different sizes:
148: #
149: for size in ${sizes}; do
150:
151: # we don't need bus eight-bit read and write slow functions:
152: #
153: if test ${size} = 8; then continue; fi
154:
155: if test `expr ${size} \>= ${size_ifdef}` = 1; then
156: echo ""
157: echo "#ifdef TME_HAVE_INT${size}_T"
158: fi
159:
160: # emit the bus read and write slow functions:
161: #
162: for op in read write; do
163:
164: # dispatch on the operation:
165: #
166: if test ${op} = read; then
167: op_return_type="tme_uint${size}_t"
168: op_cap=READ
169: op_const="_tme_const "
170: op_proto_operand=
171: op_operand=
172: else
173: op_return_type=void
174: op_cap=WRITE
175: op_const=
176: op_proto_operand=", tme_uint${size}_t"
177: op_operand="${op_proto_operand} x"
178: fi
179:
180: # if we're making the header, just emit a prototype:
181: #
182: if $header; then
183: echo ""
184: echo "/* the bus ${size}-bit ${op} slow function: */"
185: echo "${op_return_type} tme_memory_bus_${op}${size} _TME_P((${op_const}tme_shared tme_uint${size}_t *${op_proto_operand}, tme_rwlock_t *, unsigned int, unsigned int));"
186: continue
187: fi
188:
189: echo ""
190: echo "/* undefine the macro version of tme_memory_bus_${op}${size}: */"
191: echo "#undef tme_memory_bus_${op}${size}"
192: echo ""
193: echo "/* the bus ${size}-bit ${op} slow function: */"
194: echo ${op_return_type}
195: echo "tme_memory_bus_${op}${size}(${op_const}tme_shared tme_uint${size}_t *mem${op_operand}, tme_rwlock_t *rwlock, unsigned int align_min, unsigned int bus_boundary)"
196: echo "{"
197: echo " const unsigned int host_boundary = TME_MEMORY_BUS_BOUNDARY;"
198: echo " unsigned int size_skip;"
199: echo " unsigned int size_done;"
200: if test ${op} = read; then
201: echo " tme_uint${size}_t x;"
202: fi
203:
204: # emit the locals for the possible host boundaries:
205: #
206: host_boundary=${host_boundary_largest}
207: while test ${host_boundary} != 4; do
208: if test `expr ${host_boundary} \>= ${size_ifdef}` = 1; then
209: echo "#ifdef TME_HAVE_INT${host_boundary}_T"
210: fi
211: echo " ${op_const}tme_shared tme_uint${host_boundary}_t *parts${host_boundary};"
212: echo " tme_uint${host_boundary}_t part${host_boundary};"
213: if test ${op} = write; then
214: echo " tme_uint${host_boundary}_t part${host_boundary}_cmp;"
215: fi
216: if test `expr ${host_boundary} \>= ${size_ifdef}` = 1; then
217: echo "#endif /* TME_HAVE_INT${host_boundary}_T */"
218: fi
219: host_boundary=`expr ${host_boundary} / 2`
220: done
221: echo ""
222: echo -n " assert (bus_boundary != 0 && bus_boundary <= host_boundary);"
223:
224: # loop over the possible host boundaries:
225: #
226: host_boundary=${host_boundary_largest}
227: while test ${host_boundary} != 4; do
228:
229: # calculate the worst number of host boundaries that an
230: # access of this size could cross:
231: #
232: host_boundaries_worst=`expr ${size} - 16`
233: host_boundaries_worst=`expr ${host_boundaries_worst} / ${host_boundary}`
234: host_boundaries_worst=`expr ${host_boundaries_worst} + 1`
235:
236: # open this host boundary:
237: #
238: if test ${host_boundary} != 8; then
239: if test `expr ${host_boundary} \>= ${size_ifdef}` = 1; then
240: echo ""
241: echo ""
242: echo "#ifdef TME_HAVE_INT${host_boundary}_T"
243: echo ""
244: echo -n " "
245: fi
246: echo -n " if (host_boundary == sizeof(tme_uint${host_boundary}_t))"
247: fi
248: echo " {"
249:
250: echo ""
251: echo " /* prepare to ${op} the first ${host_boundary}-bit part of the memory: */"
252: echo " parts${host_boundary} = (${op_const}tme_shared tme_uint${host_boundary}_t *) (((unsigned long) mem) & (((unsigned long) 0) - (${host_boundary} / 8)));"
253: echo " size_skip = (((unsigned int) (unsigned long) mem) % (${host_boundary} / 8)) * 8;"
254: echo " size_done = 0;"
255:
256: echo ""
257: echo " /* ${op} the first ${host_boundary}-bit part of the memory: */"
258:
259: # emit two accesses. if the worst number of boundaries
260: # that this access could cross is one, the second access
261: # is inside an if, else it's in a for loop:
262: #
263: indent0=
264: size_done=0
265: size_skip=size_skip
266: access_or=
267: while true; do
268:
269: # read this memory part:
270: #
271: echo "${indent0} part${host_boundary} = tme_memory_atomic_read${host_boundary}(parts${host_boundary}, rwlock, sizeof(tme_uint${host_boundary}_t));"
272:
273: # if this is a read:
274: #
275: if test ${op} = read; then
276:
277: echo ""
278: echo "${indent0} /* on a little-endian host, we shift off the skip"
279: echo "${indent0} data on the right, and shift the remaining data"
280: echo "${indent0} up into position in the result: */"
281: echo "${indent0} if (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE) {"
282: echo "${indent0} x ${access_or}= (((tme_uint${size}_t) (part${host_boundary} >> ${size_skip})) << ${size_done});"
283: echo "${indent0} }"
284: echo ""
285: echo "${indent0} /* on a big-endian host, we shift off the skip data"
286: echo "${indent0} on the left, and shift the remaining data down"
287: echo "${indent0} into position in the result: */"
288: #
289: # NB: on a big-endian host, because the skip data
290: # is on the left, the type of what we shift
291: # depends on how this host boundary size compares
292: # to the access size:
293: #
294: echo "${indent0} else {"
295: echo -n "${indent0} x ${access_or}= "
296: if test `expr ${host_boundary} \> ${size}` = 1; then
297: echo "((part${host_boundary} << ${size_skip}) >> ((${host_boundary} - ${size}) + ${size_done}));"
298: else
299: echo "((((tme_uint${size}_t) part${host_boundary}) << ((${size} - ${host_boundary}) + ${size_skip})) >> ${size_done});"
300: fi
301: echo "${indent0} }"
302:
303: # otherwise, this is a write:
304: #
305: else
306:
307: # start the compare-and-exchange do loop:
308: #
309: echo "${indent0} do {"
310: echo "${indent0} part${host_boundary}_cmp = part${host_boundary};"
311: echo ""
312: echo "${indent0} /* on a little-endian host, we clear with zeroes"
313: echo "${indent0} shifted up past the skip data, and then we"
314: echo "${indent0} insert the data shifted up past the skip data: */"
315: echo "${indent0} if (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE) {"
316: echo "${indent0} part${host_boundary} &= (_tme_memory_type_mask(tme_uint${host_boundary}_t, + 0) ^ (((tme_uint${host_boundary}_t) _tme_memory_type_mask(tme_uint${size}_t, << ${size_done})) << ${size_skip}));"
317: echo "${indent0} part${host_boundary} |= (((tme_uint${host_boundary}_t) x) << ${size_skip});"
318: echo "${indent0} }"
319: echo ""
320: echo "${indent0} /* on a big-endian host, we clear with zeroes"
321: echo "${indent0} shifted down past the skip data, and then we"
322: echo "${indent0} insert the data shifted down past the skip data: */"
323: #
324: # NB: on a big-endian host, because the skip data
325: # is on the left, exactly how we shift depends on
326: # how this host boundary size compares to the
327: # access size:
328: #
329: echo "${indent0} else {"
330: if test `expr ${host_boundary} \> ${size}` = 1; then
331: echo "${indent0} part${host_boundary} &= ~((((tme_uint${host_boundary}_t) _tme_memory_type_mask(tme_uint${size}_t, + 0)) << ((${host_boundary} - ${size}) + ${size_done})) >> ${size_skip});"
332: echo "${indent0} part${host_boundary} |= ((((tme_uint${host_boundary}_t) x) << (${host_boundary} - ${size})) >> ${size_skip});"
333: else
334: echo "${indent0} part${host_boundary} &= ~(_tme_memory_type_mask(tme_uint${host_boundary}_t, << ${size_done}) >> ${size_skip});"
335: echo "${indent0} part${host_boundary} |= (x >> ((${size} - ${host_boundary}) + ${size_skip}));"
336: fi
337: echo "${indent0} }"
338: echo ""
339: echo "${indent0} /* loop until we can atomically update this part: */"
340: echo "${indent0} part${host_boundary} = tme_memory_atomic_cx${host_boundary}(parts${host_boundary}, part${host_boundary}_cmp, part${host_boundary}, rwlock, sizeof(tme_uint${host_boundary}_t));"
341: echo "${indent0} } while (part${host_boundary} != part${host_boundary}_cmp);"
342: if test ${host_boundaries_worst} != 1 || test ${size_skip} != 0; then
343: echo "${indent0} if (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE) {"
344: echo "${indent0} x >>= (${host_boundary} - ${size_skip});"
345: echo "${indent0} }"
346: echo "${indent0} else {"
347: echo "${indent0} x <<= (${host_boundary} - ${size_skip});"
348: echo "${indent0} }"
349: fi
350: fi
351:
352: # if this was the first access:
353: #
354: if test ${size_done} = 0; then
355:
356: echo " size_done = ${host_boundary} - size_skip;"
357: size_done=size_done
358: size_skip=0
359: access_or='|'
360:
361: # if the worst number of boundaries that this
362: # access could cross is more than one, we will do
363: # the remaining accesses in a loop, otherwise we
364: # will do one more access, if necessary:
365: #
366: if test ${host_boundaries_worst} = 1; then
367: access_if=true
368: else
369: access_if=false
370:
371: # as an optimization, writes of full parts are
372: # done directly:
373: #
374: if test ${op} = write; then
375: if test `expr ${host_boundary} \< ${size}` = 1; then
376: echo ""
377: if test ${host_boundaries_worst} = 2; then
378: echo " /* try to write one full ${host_boundary}-bit part of memory: */"
379: echo -n " if (__tme_predict_true(size_done <= (${size} - ${host_boundary})))"
380: else
381: echo " /* write as many full ${host_boundary}-bit parts of the memory as we can: */"
382: echo -n " for (; size_done <= (${size} - ${host_boundary}); )"
383: fi
384: echo " {"
385: echo ""
386: echo " /* make a boundary: */"
387: echo " tme_memory_barrier(mem, (${size} / 8), TME_MEMORY_BARRIER_${op_cap}_BEFORE_${op_cap});"
388: echo ""
389: echo " /* write a full ${host_boundary}-bit part of memory: */"
390: echo " part${host_boundary} = (x >> ((TME_ENDIAN_NATIVE == TME_ENDIAN_BIG) * (${size} - ${host_boundary})));"
391: echo " parts${host_boundary}++;"
392: echo " tme_memory_atomic_write${host_boundary}(parts${host_boundary}, part${host_boundary}, rwlock, sizeof(tme_uint${host_boundary}_t));"
393: echo " size_done += ${host_boundary};"
394: echo " if (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE) {"
395: echo " x >>= ${host_boundary};"
396: echo " }"
397: echo " else {"
398: echo " x <<= ${host_boundary};"
399: echo " }"
400: echo " }"
401: access_if=true
402: fi
403: fi
404: fi
405: echo ""
406: if $access_if; then
407: echo " /* ${op} at most one remaining ${host_boundary}-bit part of the memory: */"
408: echo -n " if (__tme_predict_false(size_done < ${size}))"
409: else
410: echo " /* ${op} any remaining ${host_boundary}-bit parts of the memory: */"
411: echo -n " for (; size_done < ${size}; size_done += ${host_boundary})"
412: fi
413: echo " {"
414:
415: echo ""
416: echo " /* make a boundary: */"
417: echo " tme_memory_barrier(mem, (${size} / 8), TME_MEMORY_BARRIER_${op_cap}_BEFORE_${op_cap});"
418: echo ""
419: echo " /* ${op} the next ${host_boundary}-bit part of the memory: */"
420: echo " parts${host_boundary}++;"
421: indent0=" "
422:
423: # otherwise, this was the loop or second access:
424: #
425: else
426: echo " }"
427: break
428: fi
429:
430: done
431:
432: echo " }"
433:
434: # close this host boundary:
435: #
436: if test ${host_boundary} != 8; then
437: echo ""
438: echo -n " else"
439: if test `expr ${host_boundary} \>= ${size_ifdef}` = 1; then
440: echo ""
441: echo ""
442: echo -n "#endif /* TME_HAVE_INT${host_boundary}_T */"
443: if test ${host_boundary} = ${size_ifdef}; then
444: echo ""
445: echo ""
446: echo -n " "
447: fi
448: fi
449: fi
450:
451: # advance:
452: #
453: host_boundary=`expr ${host_boundary} / 2`
454: done
455: if test ${op} = read; then
456: echo ""
457: echo " /* return the value read: */"
458: echo " return (x);"
459: fi
460: echo "}"
461: done
462:
463: if test `expr ${size} \>= ${size_ifdef}` = 1; then
464: echo ""
465: echo "#endif /* TME_HAVE_INT${size}_T */"
466: fi
467:
468: done
469:
470: # emit the bus read and write buffer functions:
471: #
472: for op in read write; do
473:
474: # dispatch on the operation:
475: #
476: if test ${op} = read; then
477: op_cap=READ
478: op_rwlock=rd
479: op_const_mem="_tme_const "
480: op_const_buffer=
481: op_audit_mem=
482: op_audit_buffer=_tme_audit_pointer
483: op_memcpy="(buffer), ((_tme_const tme_uint8_t *) (mem))"
484: op_copy="*buffer = *part_buffer"
485: else
486: op_cap=WRITE
487: op_rwlock=wr
488: op_const_mem=
489: op_const_buffer="_tme_const "
490: op_audit_mem=_tme_audit_pointer_shared
491: op_audit_buffer=_tme_audit_pointer_const
492: op_memcpy="(tme_uint8_t *) (mem), (buffer)"
493: op_copy="*part_buffer = *buffer"
494: fi
495:
496: # if we're making the header:
497: #
498: if $header; then
499:
500: echo ""
501: echo "/* the bus ${op} buffer function and default macro implementation: */"
502:
503: # emit the prototype:
504: #
505: echo "void tme_memory_bus_${op}_buffer _TME_P((${op_const_mem}tme_shared tme_uint8_t *, ${op_const_buffer}tme_uint8_t *, unsigned long, tme_rwlock_t *, unsigned int, unsigned int));"
506:
507: # emit the default macro definition:
508: #
509: echo "#define tme_memory_bus_${op}_buffer(mem, buffer, count, rwlock, align_min, bus_boundary) \\"
510: echo " do { \\"
511: echo " if (TME_THREADS_COOPERATIVE) { \\"
512: echo " memcpy(${op_memcpy}, (count)); \\"
513: echo " } \\"
514: echo " else { \\"
515: echo " tme_memory_bus_${op}_buffer(((${op_const_mem}tme_shared tme_uint8_t *) ${op_audit_mem}(mem)), ((${op_const_buffer}tme_uint8_t *) ${op_audit_buffer}(buffer)), (count), (rwlock), (align_min), (bus_boundary)); \\"
516: echo " } \\"
517: echo " } while (/* CONSTCOND */ 0)"
518:
519: continue
520: fi
521:
522: # start the function:
523: #
524: echo ""
525: echo "/* undefine the macro version of tme_memory_bus_${op}_buffer: */"
526: echo "#undef tme_memory_bus_${op}_buffer"
527: echo ""
528: echo "/* the bus ${op} buffer function: */"
529: echo "void"
530: echo "tme_memory_bus_${op}_buffer(${op_const_mem}tme_shared tme_uint8_t *mem, ${op_const_buffer}tme_uint8_t *buffer, unsigned long count, tme_rwlock_t *rwlock, unsigned int align_min, unsigned int bus_boundary)"
531: echo "{"
532: echo " const unsigned int host_boundary = TME_MEMORY_BUS_BOUNDARY;"
533: echo " ${op_const_mem}tme_uint8_t *part_buffer;"
534: echo " unsigned int count_done;"
535: echo " unsigned int count_misaligned;"
536: echo " unsigned int bits_misaligned;"
537:
538: # emit the locals for the possible host boundaries:
539: #
540: host_boundary=${host_boundary_largest}
541: while test ${host_boundary} != 4; do
542: if test `expr ${host_boundary} \>= ${size_ifdef}` = 1; then
543: echo "#ifdef TME_HAVE_INT${host_boundary}_T"
544: fi
1.1.1.2 ! root 545: echo " ${op_const_mem}tme_shared tme_uint${host_boundary}_t *parts${host_boundary};"
1.1 root 546: echo " tme_uint${host_boundary}_t part${host_boundary}_buffer;"
547: echo " tme_uint${host_boundary}_t part${host_boundary};"
548: echo " tme_uint${host_boundary}_t part${host_boundary}_next;"
549: if test ${op} = write; then
550: echo " tme_uint${host_boundary}_t part${host_boundary}_mask;"
551: echo " tme_uint${host_boundary}_t part${host_boundary}_cmp;"
552: fi
553: if test `expr ${host_boundary} \>= ${size_ifdef}` = 1; then
554: echo "#endif /* TME_HAVE_INT${host_boundary}_T */"
555: fi
556: host_boundary=`expr ${host_boundary} / 2`
557: done
558: echo ""
559: echo " assert (count != 0);"
560: echo " assert (bus_boundary != 0);"
561:
562: echo ""
563: echo " /* if we are locking for all memory accesses, lock memory"
564: echo " around a memcpy: */"
565: echo " if (TME_MEMORY_ALIGNMENT_ATOMIC(TME_MEMORY_TYPE_COMMON) == 0) {"
566: echo " tme_rwlock_${op_rwlock}lock(rwlock);"
567: echo " memcpy(${op_memcpy}, (count));"
568: echo " tme_rwlock_unlock(rwlock);"
569: echo " }"
570: echo ""
571: echo " /* otherwise, if the emulated bus boundary is greater than the"
572: echo " host's bus boundary, we are forced to stop all other threads"
573: echo " around a memcpy: */"
574: echo " else if (__tme_predict_false(bus_boundary == 0"
575: echo " || bus_boundary > host_boundary)) {"
576: echo " tme_thread_suspend_others();"
577: echo " memcpy(${op_memcpy}, (count) + (0 && align_min));"
578: echo " tme_thread_resume_others();"
579: echo " }"
580:
581: # loop over the possible host boundaries:
582: #
583: host_boundary=${host_boundary_largest}
584: indent0=
585: while test ${host_boundary} != 4; do
586:
587: # open this host boundary:
588: #
589: if test `expr ${host_boundary} \>= ${size_ifdef}` = 1; then
590: echo ""
591: echo "#ifdef TME_HAVE_INT${host_boundary}_T"
592: fi
593: echo ""
594: echo -n " else"
595: if test ${host_boundary} != 8; then
596: echo -n " if (host_boundary == sizeof(tme_uint${host_boundary}_t))"
597: fi
598: echo " {"
599:
600: if test ${op} = write; then
601: op_part_read="tme_memory_read${host_boundary}((const tme_uint${host_boundary}_t *) buffer, sizeof(tme_uint${host_boundary}_t))"
602: op_part_write="tme_memory_atomic_write${host_boundary}(parts${host_boundary}, part${host_boundary}, rwlock, sizeof(tme_uint${host_boundary}_t))"
603: else
604: op_part_read="tme_memory_atomic_read${host_boundary}(parts${host_boundary}, rwlock, sizeof(tme_uint${host_boundary}_t))"
605: op_part_write="tme_memory_write${host_boundary}((tme_uint${host_boundary}_t *) buffer, part${host_boundary}, sizeof(tme_uint${host_boundary}_t))"
606: fi
607:
608: echo ""
609: echo " /* make a ${host_boundary}-bit pointer to the memory: */"
1.1.1.2 ! root 610: echo " parts${host_boundary} = (${op_const_mem}tme_shared tme_uint${host_boundary}_t *) mem;"
1.1 root 611: echo ""
612: echo " /* if this pointer is not ${host_boundary}-bit aligned: */"
613: echo " if (__tme_predict_false((((unsigned long) parts${host_boundary}) % sizeof(tme_uint${host_boundary}_t)) != 0)) {"
614: echo ""
615: echo " /* get the misalignment from the previous ${host_boundary}-bit boundary: */"
616: echo " count_misaligned = ((unsigned long) parts${host_boundary}) % sizeof(tme_uint${host_boundary}_t);"
617: echo ""
618: echo " /* truncate this pointer to the previous ${host_boundary}-bit boundary: */"
1.1.1.2 ! root 619: echo " parts${host_boundary} = (${op_const_mem}tme_shared tme_uint${host_boundary}_t *) (((unsigned long) parts${host_boundary}) & (((unsigned long) 0) - sizeof(tme_uint${host_boundary}_t)));"
1.1 root 620: echo ""
621: echo " /* get the number of bytes to ${op} in the first ${host_boundary}-bit memory part: */"
622: echo " count_done = sizeof(tme_uint${host_boundary}_t) - count_misaligned;"
623: echo " if (__tme_predict_false(count_done > count)) {"
624: echo " count_done = count;"
625: echo " }"
626:
627: if test ${op} = write; then
628: echo ""
629: echo " /* make a mask that clears for the data to write in the"
630: echo " first ${host_boundary}-bit memory part: */"
631: echo " part${host_boundary}_mask = 1;"
632: echo " part${host_boundary}_mask = (part${host_boundary}_mask << (count_done * 8)) - 1;"
633: echo " part${host_boundary}_mask"
634: echo " <<= (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE"
635: echo " ? (count_misaligned * 8)"
636: echo " : (${host_boundary} - ((count_misaligned + count_done) * 8)));"
637: echo " part${host_boundary}_mask = ~part${host_boundary}_mask;"
638: echo ""
639: echo " /* copy from the buffer the bytes to write in the first"
640: echo " ${host_boundary}-bit memory part: */"
641: echo " part${host_boundary}_buffer = 0;"
642: else
643: echo ""
644: echo " /* read the first ${host_boundary}-bit memory part: */"
645: echo " part${host_boundary}_buffer = ${op_part_read};"
646: echo " parts${host_boundary}++;"
647: echo ""
648: echo " /* copy to the buffer the bytes to read in the first"
649: echo " ${host_boundary}-bit memory part: */"
650: fi
651: echo " part_buffer = ((tme_uint8_t *) &part${host_boundary}_buffer) + count_misaligned;"
652: echo " count -= count_done;"
653: echo " do {"
654: echo " ${op_copy};"
655: echo " part_buffer++;"
656: echo " buffer++;"
657: echo " } while (--count_done != 0);"
658:
659: if test ${op} = write; then
660: echo ""
661: echo " /* compare-and-exchange the first ${host_boundary}-bit memory part: */"
662: echo " part${host_boundary} = ${op_part_read};"
663: echo " do {"
664: echo " part${host_boundary}_cmp = part${host_boundary};"
665: echo " part${host_boundary} = (part${host_boundary} & part${host_boundary}_mask) | part${host_boundary}_buffer;"
666: echo " part${host_boundary} = tme_memory_atomic_cx${host_boundary}(parts${host_boundary}, part${host_boundary}_cmp, part${host_boundary}, rwlock, sizeof(tme_uint${host_boundary}_t));"
667: echo " } while (part${host_boundary} != part${host_boundary}_cmp);"
668: echo " parts${host_boundary}++;"
669: fi
670: echo " }"
671:
672: echo ""
673: echo " /* if we have full ${host_boundary}-bit parts to ${op}: */"
674: echo " if (__tme_predict_true(count >= sizeof(tme_uint${host_boundary}_t))) {"
675: echo ""
676: echo " /* if the buffer is ${host_boundary}-bit aligned: */"
677: echo " if (__tme_predict_true((((unsigned long) buffer) % sizeof(tme_uint${host_boundary}_t)) == 0)) {"
678: echo ""
679: echo " /* ${op} full ${host_boundary}-bit parts without shifting: */"
680: echo " do {"
681: echo " part${host_boundary} = ${op_part_read};"
682: echo " ${op_part_write};"
683: echo ""
684: echo " /* advance: */"
685: echo " parts${host_boundary}++;"
686: echo " buffer += sizeof(tme_uint${host_boundary}_t);"
687: echo " count -= sizeof(tme_uint${host_boundary}_t);"
688: echo " } while (count >= sizeof(tme_uint${host_boundary}_t));"
689: echo " }"
690: echo ""
691: echo " /* otherwise, the buffer is not ${host_boundary}-bit aligned: */"
692: echo " else {"
693: echo ""
694: echo " /* get the misalignment to the next ${host_boundary}-bit boundary: */"
695: echo " count_misaligned = (sizeof(tme_uint${host_boundary}_t) - ((unsigned int) (unsigned long) buffer)) % sizeof(tme_uint${host_boundary}_t);"
696: if test ${op} = write; then
697: echo ""
698: echo " /* copy from the buffer until it is aligned: */"
699: echo " part${host_boundary}_buffer = 0;"
700: else
701: echo ""
702: echo " /* read the next ${host_boundary}-bit memory part: */"
703: echo " part${host_boundary}_buffer = ${op_part_read};"
704: echo " parts${host_boundary}++;"
705: echo ""
706: echo " /* copy to the buffer until it is aligned: */"
707: fi
708: echo " part_buffer = ((${op_const_mem}tme_uint8_t *) &part${host_boundary}_buffer);"
709: echo " count_done = count_misaligned;"
710: echo " count -= count_misaligned;"
711: echo " do {"
712: echo " ${op_copy};"
713: echo " part_buffer++;"
714: echo " buffer++;"
715: echo " } while (--count_done != 0);"
716:
717: echo ""
718: echo " /* ${op} full ${host_boundary}-bit words with shifting: */"
719: echo " bits_misaligned = count_misaligned * 8;"
720: if test ${op} = write; then
721: op_shift=bits_misaligned
722: op_shift_next="(${host_boundary} - bits_misaligned)"
723: echo " part${host_boundary} = part${host_boundary}_buffer;"
724: else
725: op_shift="(${host_boundary} - bits_misaligned)"
726: op_shift_next=bits_misaligned
727: echo " part${host_boundary}"
728: echo " = (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE"
729: echo " ? (part${host_boundary}_buffer >> ${op_shift_next})"
730: echo " : (part${host_boundary}_buffer << ${op_shift_next}));"
731: fi
732: echo " for (; count >= sizeof(tme_uint${host_boundary}_t); ) {"
733: echo " part${host_boundary}_next = ${op_part_read};"
734: echo " if (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE) {"
735: echo " part${host_boundary} |= (part${host_boundary}_next << ${op_shift});"
736: echo " ${op_part_write};"
737: echo " part${host_boundary} = (part${host_boundary}_next >> ${op_shift_next});"
738: echo " }"
739: echo " else {"
740: echo " part${host_boundary} |= (part${host_boundary}_next >> ${op_shift});"
741: echo " ${op_part_write};"
742: echo " part${host_boundary} = (part${host_boundary}_next << ${op_shift_next});"
743: echo " }"
744: echo ""
745: echo " /* advance: */"
746: echo " parts${host_boundary}++;"
747: echo " buffer += sizeof(tme_uint${host_boundary}_t);"
748: echo " count -= sizeof(tme_uint${host_boundary}_t);"
749: echo " }"
750:
751: echo ""
752: echo " /* calculate how many more bytes there are to ${op} in this"
753: echo " ${host_boundary}-bit memory part: */"
754: echo " count_done = sizeof(tme_uint${host_boundary}_t) - count_misaligned;"
755: echo " part${host_boundary}_buffer = part${host_boundary};"
756: if test ${op} = write; then
757: echo ""
758: echo " /* if we can't write one more full ${host_boundary}-bit memory part: */"
759: echo " if (count_done > count) {"
760: echo ""
761: echo " /* we will reread this data to write below: */"
762: echo " buffer -= count_misaligned;"
763: echo " count += count_misaligned;"
764: echo " }"
765: echo ""
766: echo " /* otherwise, we can write one more full ${host_boundary}-bit memory part: */"
767: echo " else {"
768: echo ""
769: echo " /* copy from the buffer until we have the full ${host_boundary}-bit part: */"
770: echo " part_buffer = ((${op_const_mem}tme_uint8_t *) &part${host_boundary}_buffer) + count_misaligned;"
771: echo " count -= count_done;"
772: echo " do {"
773: echo " ${op_copy};"
774: echo " part_buffer++;"
775: echo " buffer++;"
776: echo " } while (--count_done != 0);"
777: echo ""
778: echo " /* write the last full ${host_boundary}-bit memory part: */"
779: echo " part${host_boundary} = part${host_boundary}_buffer;"
780: echo " ${op_part_write};"
781: echo " }"
782: else
783: echo ""
784: echo " /* copy to the buffer the remaining bytes in this ${host_boundary}-bit part: */"
785: echo " if (count_done > count) {"
786: echo " count_done = count;"
787: echo " }"
788: echo " part_buffer = ((${op_const_mem}tme_uint8_t *) &part${host_boundary}_buffer);"
789: echo " count -= count_done;"
790: echo " do {"
791: echo " ${op_copy};"
792: echo " part_buffer++;"
793: echo " buffer++;"
794: echo " } while (--count_done != 0);"
795: fi
796: echo " }"
797: echo " }"
798:
799: echo ""
800: echo " /* if we still have bytes to ${op}: */"
801: echo " if (__tme_predict_false(count > 0)) {"
802: echo ""
803: echo " /* we must have less than a full ${host_boundary}-bit part to ${op}: */"
804: echo " assert (count < sizeof(tme_uint${host_boundary}_t));"
805: if test ${op} = write; then
806: echo ""
807: echo " /* make a mask that clears for the data to write in the last"
808: echo " ${host_boundary}-bit memory part: */"
809: echo " part${host_boundary}_mask"
810: echo " = (TME_ENDIAN_NATIVE == TME_ENDIAN_LITTLE"
811: echo " ? _tme_memory_type_mask(tme_uint${host_boundary}_t, << (count * 8))"
812: echo " : _tme_memory_type_mask(tme_uint${host_boundary}_t, >> (count * 8)));"
813: echo ""
814: echo " /* copy from the buffer the bytes to write in the last"
815: echo " ${host_boundary}-bit memory part: */"
816: echo " part${host_boundary}_buffer = 0;"
817: else
818: echo ""
819: echo " /* read the last ${host_boundary}-bit memory part: */"
820: echo " part${host_boundary}_buffer = ${op_part_read};"
821: echo ""
822: echo " /* copy to the buffer the bytes to read in the first"
823: echo " ${host_boundary}-bit memory part: */"
824: fi
825: echo " part_buffer = ((${op_const_mem}tme_uint8_t *) &part${host_boundary}_buffer);"
826: echo " count_done = count;"
827: echo " do {"
828: echo " ${op_copy};"
829: echo " part_buffer++;"
830: echo " buffer++;"
831: echo " } while (--count_done != 0);"
832: if test ${op} = write; then
833: echo ""
834: echo " /* compare-and-exchange the last ${host_boundary}-bit memory part: */"
835: echo " part${host_boundary} = ${op_part_read};"
836: echo " do {"
837: echo " part${host_boundary}_cmp = part${host_boundary};"
838: echo " part${host_boundary} = (part${host_boundary} & part${host_boundary}_mask) | part${host_boundary}_buffer;"
839: echo " part${host_boundary} = tme_memory_atomic_cx${host_boundary}(parts${host_boundary}, part${host_boundary}_cmp, part${host_boundary}, rwlock, sizeof(tme_uint${host_boundary}_t));"
840: echo " } while (part${host_boundary} != part${host_boundary}_cmp);"
841: fi
842: echo " }"
843:
844: # close this host boundary:
845: #
846: echo ""
847: echo " }"
848: if test `expr ${host_boundary} \>= ${size_ifdef}` = 1; then
849: echo ""
850: echo "#endif /* TME_HAVE_INT${host_boundary}_T */"
851: fi
852:
853: # advance:
854: #
855: host_boundary=`expr ${host_boundary} / 2`
856: done
857:
858: echo "}"
859: done
860:
861: # permute for the different sizes:
862: #
863: for size in ${sizes}; do
864:
865: if test `expr ${size} \>= ${size_ifdef}` = 1; then
866: echo ""
867: echo "#ifdef TME_HAVE_INT${size}_T"
868: fi
869:
870: # permute for the different types of memory read and write macros.
871: # all of these macros work with memory of any alignment, but for
872: # best performance they accept the minimum alignment of the memory
873: # known at compile time.
874: #
875: # the "plain" macros are used to read and write memory that is not
876: # shared.
877: #
878: # the "atomic" macros are used to read and write memory that is
879: # shared. the total read or write is always atomic.
880: #
881: # the "bus" macros are used to read and write memory that is
882: # shared, with the access split across the given bus boundary into
883: # atomic partials.
884: #
885: for type_user in plain atomic bus; do
886:
887: # permute over read and write:
888: #
889: for op in read write; do
890:
891: # these macros are for the header file, and there are
892: # hand-coded macros for 8-bit values:
893: #
894: if $header; then :; else continue; fi
895: if test ${size} = 8; then continue; fi
896:
897: # characterize this macro:
898: #
899: type="_${type_user}"
900: type_lock=", lock"
901: type_part=_atomic
902: type_bus_boundary=
903: case ${type_user} in
904: plain)
905: type=
906: type_lock=
907: type_part=
908: ;;
909: bus)
910: type_bus_boundary=", bus_boundary"
911: ;;
912: esac
913: if test ${op} = read; then
914: op_x=
915: op_open=" ( \\"
916: op_indent0=" "
917: op_indent1=${op_indent0}
918: op_then="${op_indent1}? \\"
919: op_else_if="${op_indent1}: \\"
920: op_else=${op_else_if}
921: op_indent2="${op_indent1} "
922: op_semi=
923: op_close=" )"
924: else
925: op_x=", x"
926: op_open=" do { \\@ if \\"
927: op_indent0=" "
928: op_indent1=${op_indent0}
929: op_then=" { \\"
930: op_else_if=" } \\@ else if \\"
931: op_else=" } \\@ else \\@${op_then}"
932: op_indent2=" "
933: op_semi=';'
934: op_close=" } \\@ } while (/* CONSTCOND */ 0)"
935: fi
936:
937: # start the macro:
938: #
939: echo ""
940: echo "/* the default ${size}-bit memory ${type_user} ${op} macro: */"
941: echo "#define tme_memory${type}_${op}${size}(mem${op_x}${type_lock}, align_min${type_bus_boundary}) \\"
942: echo "${op_open}" | tr '@' '\n'
943:
944: # dispatch on the macro type:
945: #
946: case ${type_user} in
947:
948: plain)
949: echo "${op_indent0}/* if we know at compile time that the memory is aligned \\"
950: echo "${op_indent0} enough to ${op} directly, do the single direct ${op}. \\"
951: echo "${op_indent0}\\"
952: echo "${op_indent0} otherwise, if we know at compile time that the memory \\"
953: echo "${op_indent0} is less aligned than the smallest acceptable parts size, \\"
954: echo "${op_indent0} test if the memory is aligned enough to ${op} directly, \\"
955: echo "${op_indent0} and do the single direct ${op} if it is: */ \\"
956: echo "${op_indent0}(__tme_predict_true((_TME_ALIGNOF_INT${size}_T == 1 \\"
957: echo "${op_indent0} || (align_min) >= _TME_ALIGNOF_INT${size}_T) \\"
958: echo "${op_indent0} || ((align_min) < TME_MEMORY_ALIGNMENT_ACCEPT(tme_uint${size}_t) \\"
959: echo "${op_indent0} && _tme_memory_address_test(mem, _TME_ALIGNOF_INT${size}_T - 1, align_min) == 0))) \\"
960: echo "${op_then}"
961: echo "${op_indent2}_tme_memory_${op}(tme_uint${size}_t, tme_uint${size}_t, mem, 0${op_x})${op_semi} \\"
962:
963: # loop over the possible part sizes:
964: #
965: size_part=8
966: while test ${size_part} != ${size}; do
967:
968: # at this point, we know that the memory is at
969: # least aligned to the part size:
970: #
971:
972: # if this is the last possible part size:
973: #
974: if test `expr ${size_part} \* 2` = ${size}; then
975:
976: # we will just access all parts of this size:
977: #
978: echo "${op_else}" | tr '@' '\n'
979:
980: # otherwise, this is not the last possible part
981: # size:
982: #
983: else
984:
985: # if we know at compile time that accessing
986: # all parts of this size is acceptable over
987: # further testing of the address, and the
988: # memory is not more aligned than this part
989: # size, we will just access all parts of this
990: # size:
991: #
992: echo "${op_else_if}" | tr '@' '\n'
993: echo "${op_indent1}((TME_MEMORY_ALIGNMENT_ACCEPT(tme_uint${size}_t) <= sizeof(tme_uint${size_part}_t)) \\"
994: echo "${op_indent1} && ((align_min) <= sizeof(tme_uint${size_part}_t))) \\"
995: echo "${op_then}"
996: fi
997:
998: # we always emit one set of partial accesses, all
999: # of this part size.
1000: #
1001: # then, if this isn't the last possible part size,
1002: # we test if the address is aligned only to this
1003: # part size. if it is, we emit a second set of partial
1004: # accesses, to transfer this part size, some number
1005: # of parts of the next part size, and one part of this
1006: # part size:
1007: #
1008: size_now=${size_part}
1009: misaligned=false
1010: while true; do
1011: size_done=0
1012: while test ${size_done} != ${size}; do
1013:
1014: # emit one partial transfer:
1015: #
1016: echo -n "${op_indent2}"
1017: op_delim=${op_semi}
1018: if test ${op} = read; then
1019: if test ${size_done} = 0; then echo -n '('; else echo -n ' | '; fi
1020: if test `expr ${size_done} + ${size_now}` = ${size}; then op_delim=')'; fi
1021: fi
1022: echo "_tme_memory${type}_${op}(tme_uint${size}_t, tme_uint${size_now}_t, mem, (${size_done} / 8)${op_x})${op_delim} \\"
1023:
1024: # advance:
1025: #
1026: size_done=`expr ${size_done} + ${size_now}`
1027: size_now=`expr ${size} - ${size_done}`
1028: if test `expr ${size_now} \> ${size_part}` = 1; then
1029: size_now=${size_part}
1030: fi
1031: done
1032:
1033: # if we have already done the misaligned set,
1034: # stop now:
1035: #
1036: if ${misaligned}; then
1037: break
1038: fi
1039: misaligned=true
1040:
1041: # advance to test and do the misaligned set:
1042: #
1043: size_now=${size_part}
1044: size_part=`expr ${size_part} \* 2`
1045: if test ${size_part} = ${size}; then
1046: break
1047: fi
1048: echo "${op_else_if}" | tr '@' '\n'
1049: echo "${op_indent1}(_tme_memory_address_test(mem, sizeof(tme_uint${size_now}_t), align_min) != 0) \\"
1050: echo "${op_then}"
1051: done
1052: done
1053: ;;
1054:
1055: atomic)
1.1.1.2 ! root 1056: echo "${op_indent0}/* if threads are cooperative, do a plain ${op}: */ \\"
! 1057: echo "${op_indent0}(TME_THREADS_COOPERATIVE) \\"
! 1058: echo "${op_then}"
! 1059: echo -n "${op_indent2}tme_memory_${op}${size}("
! 1060: # this strips off the tme_shared qualifier:
! 1061: #
! 1062: if test ${op} = read; then
! 1063: echo -n "(_tme_const tme_uint${size}_t *) _tme_audit_type(mem, tme_uint${size}_t *)"
! 1064: else
! 1065: echo -n "(tme_uint${size}_t *) _tme_cast_pointer_shared(tme_uint${size}_t *, tme_uint${size}_t *, mem)"
! 1066: fi
! 1067: echo "${op_x}, align_min)${op_semi} \\"
! 1068:
! 1069: echo "${op_indent1}/* otherwise, if we aren't locking for all memory accesses, and we can \\"
! 1070: echo "${op_indent1} make direct ${size}-bit accesses, and this memory is aligned \\"
! 1071: echo "${op_indent1} enough to make a single direct atomic access, do the single \\"
! 1072: echo "${op_indent1} direct atomic ${op}: */ \\"
! 1073: echo "${op_else_if}" | tr '@' '\n'
! 1074: echo "${op_indent1}(__tme_predict_true(TME_MEMORY_ALIGNMENT_ATOMIC(TME_MEMORY_TYPE_COMMON) != 0 \\"
! 1075: echo "${op_indent1} && TME_MEMORY_ALIGNMENT_ATOMIC(tme_uint${size}_t) != 0 \\"
! 1076: echo "${op_indent1} && _tme_memory_address_test(mem, TME_MEMORY_ALIGNMENT_ATOMIC(tme_uint${size}_t) - 1, align_min) == 0)) \\"
1.1 root 1077: echo "${op_then}"
1078: echo "${op_indent2}(*_tme_audit_type(mem, tme_uint${size}_t *)) \\"
1079: if test ${op} = write; then
1080: echo "${op_indent2} = (x); \\"
1081: fi
1082: echo "${op_indent1}/* otherwise, we must do a slow indirect atomic ${op}: */ \\"
1083: echo "${op_else}" | tr '@' '\n'
1084: echo "${op_indent2}tme_memory${type}_${op}${size}(mem${op_x}${type_lock}, align_min)${op_semi} \\"
1085: ;;
1086:
1087: bus)
1088: echo "${op_indent0}/* if threads are cooperative, do a plain ${op}: */ \\"
1089: echo "${op_indent0}(TME_THREADS_COOPERATIVE) \\"
1090: echo "${op_then}"
1091: echo -n "${op_indent2}tme_memory_${op}${size}("
1092: # this strips off the tme_shared qualifier:
1093: #
1094: if test ${op} = read; then
1095: echo -n "(_tme_const tme_uint${size}_t *) _tme_audit_type(mem, tme_uint${size}_t *)"
1096: else
1097: echo -n "(tme_uint${size}_t *) _tme_cast_pointer_shared(tme_uint${size}_t *, tme_uint${size}_t *, mem)"
1098: fi
1099: echo "${op_x}, align_min)${op_semi} \\"
1100:
1101: echo "${op_indent1}/* otherwise, if we aren't locking for all memory accesses, the \\"
1102: echo "${op_indent1} host supports misaligned ${size}-bit accesses, the host's bus \\"
1103: echo "${op_indent1} boundary is greater than or equal to the emulated bus \\"
1104: echo "${op_indent1} boundary, and this memory is aligned enough, do a single \\"
1105: echo "${op_indent1} direct bus ${op}: */ \\"
1106: echo "${op_else_if}" | tr '@' '\n'
1107: echo "${op_indent1}(__tme_predict_true(TME_MEMORY_ALIGNMENT_ATOMIC(TME_MEMORY_TYPE_COMMON) != 0 \\"
1108: echo "${op_indent1} && _TME_ALIGNOF_INT${size}_T < sizeof(tme_uint${size}_t) \\"
1109: echo "${op_indent1} && TME_MEMORY_BUS_BOUNDARY >= (bus_boundary) \\"
1110: echo "${op_indent1} && _tme_memory_address_test(mem, _TME_ALIGNOF_INT${size}_T - 1, align_min) == 0)) \\"
1111: echo "${op_then}"
1112: echo "${op_indent2}(*_tme_audit_type(mem, tme_uint${size}_t *)) \\"
1113: if test ${op} = write; then
1114: echo "${op_indent2} = (x); \\"
1115: fi
1116:
1117: echo "${op_indent1}/* otherwise, if we're locking for all memory accesses, or \\"
1118: echo "${op_indent1} if this memory must cross at least one host bus boundary \\"
1119: echo "${op_indent1} and the host bus boundary is less than the emulated bus \\"
1120: echo "${op_indent1} boundary, do a slow indirect atomic ${op}: */ \\"
1121: echo "${op_else_if}" | tr '@' '\n'
1122: echo "${op_indent1}(__tme_predict_false(TME_MEMORY_ALIGNMENT_ATOMIC(TME_MEMORY_TYPE_COMMON) == 0 \\"
1123: echo "${op_indent1} || (sizeof(tme_uint${size}_t) > TME_MEMORY_BUS_BOUNDARY \\"
1124: echo "${op_indent1} && TME_MEMORY_BUS_BOUNDARY < (bus_boundary)))) \\"
1125: echo "${op_then}"
1126: echo "${op_indent2}tme_memory_atomic_${op}${size}(mem${op_x}, lock, align_min)${op_semi} \\"
1127:
1128: echo "${op_indent1}/* otherwise, if the memory is not larger than the emulated \\"
1129: echo "${op_indent1} bus boundary, or if size-alignment would mean an atomic \\"
1130: echo "${op_indent1} host access and it is size-aligned, do a single atomic \\"
1131: echo "${op_indent1} ${op}, which may be direct or slow: */ \\"
1132: echo "${op_else_if}" | tr '@' '\n'
1133: echo "${op_indent1}(__tme_predict_true((sizeof(tme_uint${size}_t) <= (bus_boundary) \\"
1134: echo "${op_indent1} || (TME_MEMORY_ALIGNMENT_ATOMIC(tme_uint${size}_t) != 0 \\"
1135: echo "${op_indent1} && TME_MEMORY_ALIGNMENT_ATOMIC(tme_uint${size}_t) <= sizeof(tme_uint${size}_t))) \\"
1136: echo "${op_indent1} && _tme_memory_address_test(mem, sizeof(tme_uint${size}_t) - 1, align_min) == 0)) \\"
1137: echo "${op_then}"
1138: echo "${op_indent2}tme_memory_atomic_${op}${size}(mem${op_x}, lock, sizeof(tme_uint${size}_t))${op_semi} \\"
1139: echo "${op_indent1}/* otherwise, we must do a slow bus ${op}: */ \\"
1140: echo "${op_else}" | tr '@' '\n'
1141: echo "${op_indent2}tme_memory${type}_${op}${size}(mem${op_x}${type_lock}, align_min, bus_boundary)${op_semi} \\"
1142: ;;
1143:
1144: esac
1145:
1146: # close this macro:
1147: #
1148: echo "${op_close}" | tr '@' '\n'
1149: done
1150: done
1151:
1152: echo ""
1153: echo "/* the ${size}-bit atomic operations: */"
1154:
1155: # the atomic operations. NB that cx, read, and write are
1156: # deliberately at the end and in that order, to allow all earlier
1157: # default implementations to still use any host CPU-specific cx,
1158: # read and write macros:
1159: #
1160: for op in add sub mul div and or xor not neg xchg cx read write; do
1161:
1162: # dispatch on the operation. NB that we don't need to
1163: # generate 8-bit atomic read and write operations:
1164: #
1165: op_rval="tme_uint${size}_t"
1166: op_const=
1167: op_proto_operand=", tme_uint${size}_t"
1168: op_operand=operand
1169: op_from=to
1170: op_operator=
1171: op_operation=
1172: op_indent=
1173: case ${op} in
1174: read)
1175: if test ${size} = 8; then continue; fi
1176: op_const="_tme_const "
1177: op_from=from
1178: op_proto_operand=
1179: ;;
1180: write)
1181: if test ${size} = 8; then continue; fi
1182: op_rval=void
1183: op_operand=value_written
1184: ;;
1185: cx)
1186: op_proto_operand=", tme_uint${size}_t, tme_uint${size}_t"
1187: op_operand=value_written
1188: op_indent=" "
1189: ;;
1190: add) op_operator='+' ;;
1191: sub) op_operator='-' ;;
1192: mul) op_operator='*' ;;
1193: div) op_operator='/' ;;
1194: and) op_operator='&' ;;
1195: or) op_operator='|' ;;
1196: xor) op_operator='^' ;;
1197: not) op_operation='~value_read' ; op_proto_operand= ;;
1198: neg) op_operation='0 - value_read' ; op_proto_operand= ;;
1199: xchg) op_operand=value_written
1200: esac
1201: if test "x${op_operator}" != x; then
1202: op_operation="value_read ${op_operator} ${op_operand}"
1203: fi
1204:
1205: # if we're making the header, just emit a prototype:
1206: #
1207: if $header; then
1208: echo "${op_rval} tme_memory_atomic_${op}${size} _TME_P((${op_const}tme_shared tme_uint${size}_t *${op_proto_operand}, tme_rwlock_t *, unsigned int));"
1209: continue
1210: fi
1211:
1212: echo ""
1213: echo "/* undefine any macro version of tme_memory_atomic_${op}${size}: */"
1214: echo "#undef tme_memory_atomic_${op}${size}"
1215: echo ""
1216: echo "/* the ${size}-bit atomic ${op} function: */"
1217: echo "${op_rval}"
1218: echo "tme_memory_atomic_${op}${size}(${op_const}tme_shared tme_uint${size}_t *memory,"
1219: if test ${op} = cx; then
1220: echo " tme_uint${size}_t value_cmp,"
1221: fi
1222: if test "x${op_proto_operand}" != x; then
1223: echo " tme_uint${size}_t ${op_operand},"
1224: fi
1225: echo " tme_rwlock_t *rwlock,"
1226: echo " unsigned int align_min)"
1227: echo "{"
1228: if test ${op} != write; then
1229: echo " tme_uint${size}_t value_read;"
1230: fi
1231: if test "x${op_operation}" != x; then
1232: echo " tme_uint${size}_t value_written;"
1233: fi
1234: if test ${op} = read || test ${op} = write || test ${op} = cx; then :; else
1235: echo " tme_uint${size}_t value_read_verify;"
1236: fi
1237: echo ""
1238: echo " /* if we can't make direct accesses at all, all atomic"
1239: echo " accesses must be done under lock. (when threads are"
1240: echo " cooperative the actual locking isn't needed): */"
1241: echo " if (TME_MEMORY_ALIGNMENT_ATOMIC(TME_MEMORY_TYPE_COMMON) == 0) {"
1242: echo " if (!TME_THREADS_COOPERATIVE) {"
1243: if test ${op} = read; then
1244: echo " tme_rwlock_rdlock(rwlock);"
1245: else
1246: echo " tme_rwlock_wrlock(rwlock);"
1247: fi
1248: echo " }"
1249: if test ${op} != write; then
1250: echo " value_read = tme_memory_read${size}((_tme_const tme_uint${size}_t *) memory, align_min);"
1251: fi
1252: if test ${op} = cx; then
1253: echo " if (value_read == value_cmp) {"
1254: fi
1255: if test "x${op_operation}" != x; then
1256: echo " value_written = ${op_operation};"
1257: fi
1258: if test ${op} != read; then
1259: echo "${op_indent} tme_memory_write${size}((tme_uint${size}_t *) memory, value_written, align_min);"
1260: fi
1261: if test "x${op_indent}" != x; then
1262: echo " }"
1263: fi
1264: echo " if (!TME_THREADS_COOPERATIVE) {"
1265: echo " tme_rwlock_unlock(rwlock);"
1266: echo " }"
1267: echo " }"
1268: echo ""
1269: echo " /* otherwise, threads are not cooperative and this host CPU"
1270: echo " can make atomic accesses to at least the most common memory"
1271: echo " size."
1272: echo ""
1273: echo " in that case, the only reason this function should get"
1274: echo " called is if the host CPU can't do an atomic ${size}-bit"
1275: echo " ${op} at all, or if it can't do it at this alignment."
1276: if test ${op} = read || test ${op} = write || test ${op} = cx; then
1277: echo ""
1278: echo " we assume that these problematic atomic ${op}s are rare,"
1279: echo " and to emulate them we simply stop all other threads while"
1280: echo " doing the ${op}: */"
1281: echo " else {"
1282: echo " tme_thread_suspend_others();"
1283: if test ${op} != write; then
1284: echo " value_read = tme_memory_read${size}((_tme_const tme_uint${size}_t *) memory, align_min);"
1285: fi
1286: if test ${op} = cx; then
1287: echo " if (value_read == value_cmp) {"
1288: fi
1289: if test ${op} != read; then
1290: echo "${op_indent} tme_memory_write${size}((tme_uint${size}_t *) memory, value_written, align_min);"
1291: fi
1292: if test "x${op_indent}" != x; then
1293: echo " }"
1294: fi
1295: echo " tme_thread_resume_others();"
1296: echo " }"
1297: else
1298: echo ""
1299: echo " we emulate the atomic ${size}-bit ${op} with a compare-and-exchange: */"
1300: echo " else {"
1301: echo ""
1302: echo " /* do an atomic read of the memory: */"
1303: echo " value_read = tme_memory_atomic_read${size}(memory, rwlock, align_min);"
1304: echo ""
1305: echo " /* spin the ${op} in a compare-and-exchange loop: */"
1306: echo " for (;;) {"
1307: if test "x${op_operation}" != x; then
1308: echo ""
1309: echo " /* make the value to write: */"
1310: echo " value_written = ${op_operation};"
1311: fi
1312: echo ""
1313: echo " /* try the compare-and-exchange: */"
1314: echo " value_read_verify = tme_memory_atomic_cx${size}(memory, value_read, value_written, rwlock, align_min);"
1315: echo ""
1316: echo " /* if the compare-and-exchange failed: */"
1317: echo " if (__tme_predict_false(value_read_verify != value_read)) {"
1318: echo ""
1319: echo " /* loop with the new value read from the memory: */"
1320: echo " value_read = value_read_verify;"
1321: echo " continue;"
1322: echo " }"
1323: echo ""
1324: echo " /* stop now: */"
1325: echo " break;"
1326: echo " }"
1327: echo " }"
1328: fi
1329: if test ${op} != write; then
1330: echo ""
1331: echo " /* return the value read: */"
1332: echo " return (value_read);"
1333: fi
1334: echo "}"
1335: done
1336:
1337: if test `expr ${size} \>= ${size_ifdef}` = 1; then
1338: echo ""
1339: echo "#endif /* TME_HAVE_INT${size}_T */"
1340: fi
1341:
1342: done
1343:
1344: # done:
1345: #
1346: exit 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.