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