Annotation of tme/libtme/memory-auto.sh, revision 1.1.1.1

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         

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.