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

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

unix.superglobalmegacorp.com

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