[BACK]Return to try.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpn / tests

Annotation of OpenXM_contrib/gmp/mpn/tests/try.c, Revision 1.1.1.2

1.1       maekawa     1: /* Run some tests on various mpn routines.
                      2:
                      3:    THIS IS A TEST PROGRAM USED ONLY FOR DEVELOPMENT.  IT'S ALMOST CERTAIN TO
                      4:    BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE VERSIONS OF GMP.  */
                      5:
                      6: /*
                      7: Copyright (C) 2000 Free Software Foundation, Inc.
                      8:
                      9: This file is part of the GNU MP Library.
                     10:
                     11: The GNU MP Library is free software; you can redistribute it and/or modify
                     12: it under the terms of the GNU Lesser General Public License as published by
                     13: the Free Software Foundation; either version 2.1 of the License, or (at your
                     14: option) any later version.
                     15:
                     16: The GNU MP Library is distributed in the hope that it will be useful, but
                     17: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     18: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
                     19: License for more details.
                     20:
                     21: You should have received a copy of the GNU Lesser General Public License
                     22: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
                     23: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
                     24: MA 02111-1307, USA.
                     25: */
                     26:
                     27:
                     28: /* Usage: try [options] <function>...
                     29:
                     30:    For example, "./try mpn_add_n" to run tests of that function.
                     31:
                     32:    Combinations of alignments and overlaps are tested, with redzones above
                     33:    or below the destinations, and with the sources write-protected.
                     34:
                     35:    The number of tests performed becomes ridiculously large with all the
                     36:    combinations, and for that reason this can't be a part of a "make check",
                     37:    it's meant only for development.  The code isn't very pretty either.
                     38:
                     39:    During development it can help to disable the redzones, since seeing the
                     40:    rest of the destination written can show where the wrong part is, or if
                     41:    the dst pointers are off by 1 or whatever.  The magic DEADVAL initial
                     42:    fill (see below) will show locations never written.
                     43:
                     44:    The -s option can be used to test only certain size operands, which is
                     45:    useful if some new code doesn't yet support say sizes less than the
                     46:    unrolling, or whatever.
                     47:
                     48:    When a problem occurs it'll of course be necessary to run the program
                     49:    under gdb to find out quite where, how and why it's going wrong.  Disable
                     50:    the spinner with the -W option when doing this, or single stepping won't
                     51:    work.  Using -1 to run with simple data can be useful.
                     52:
                     53:    New functions to test can be added by defining a TRY_TYPE_, adding an
                     54:    entry to try_array[] and adding a call to the call() function (if the
                     55:    type isn't already supported).  Extra TRY_TYPE_ bits can be easily added
                     56:    if necessary.
                     57:
                     58:
                     59:    Future:
                     60:
                     61:    Automatically detect gdb and disable the spinner timer (use -W for now).
                     62:
                     63:    Make a way to re-run a failing case in the debugger.  Have an option to
                     64:    snapshot each test case before it's run so the data is available if a
                     65:    segv occurs.  (This should be more reliable than the current print_all()
                     66:    in the signal handler.)
                     67:
                     68:    When alignment means a dst isn't hard against the redzone, check the
                     69:    space in between remains unchanged.
                     70:
                     71:    See if the 80x86 debug registers can do redzones on byte boundaries.
                     72:
                     73:    When a source overlaps a destination, don't run both s[i].high 0 and 1,
                     74:    as s[i].high has no effect.  Maybe encode s[i].high into overlap->s[i].
                     75:
                     76:    When partial overlaps aren't done, don't loop over source alignments
                     77:    during overlaps.
                     78:
                     79: */
                     80:
                     81:
                     82: /* always do assertion checking */
                     83: #define WANT_ASSERT 1
                     84:
                     85: #include "config.h"
                     86:
                     87: #if HAVE_GETOPT_H
                     88: #include <getopt.h>  /* for getopt_long() */
                     89: #endif
                     90: #include <limits.h>
                     91: #include <signal.h>
                     92: #include <stdio.h>
                     93: #include <stdlib.h>
                     94: #include <string.h>
                     95: #include <time.h>
                     96: #include <unistd.h>
                     97: #include <sys/mman.h>
                     98:
                     99: #include "gmp.h"
                    100: #include "gmp-impl.h"
                    101:
                    102: #include "ref.h"
                    103: #include "try.h"
                    104:
                    105: #if HAVE_SPA_EXTRAS
                    106: #include "spa-out.asm.h"
                    107: #endif
                    108:
                    109: #if !HAVE_DECL_OPTARG
                    110: extern char *optarg;
                    111: extern int optind, opterr;
                    112: #endif
                    113:
                    114:
                    115: #define DEFAULT_REPETITIONS  10
                    116:
                    117: int  option_repetitions = DEFAULT_REPETITIONS;
                    118: int  option_spinner = 1;
                    119: int  option_redzones = 1;
                    120: int  option_firstsize = 0;
                    121: int  option_lastsize = 500;
                    122: int  option_firstsize2 = 0;
                    123:
                    124: #define ALIGNMENTS          4
                    125: #define OVERLAPS            4
                    126: #define CARRY_RANDOMS       5
                    127: #define MULTIPLIER_RANDOMS  5
                    128: #define DIVISOR_RANDOMS     5
                    129: #define XSIZE_COUNT         4
                    130:
                    131: int  option_print = 0;
                    132:
                    133: #define DATA_TRAND  0
                    134: #define DATA_ZEROS  1
                    135: #define DATA_SEQ    2
                    136: #define DATA_FFS    3
                    137: #define DATA_2FD    4
                    138: int  option_data = DATA_TRAND;
                    139:
                    140:
                    141: mp_size_t  pagesize;
                    142: #define PAGESIZE_LIMBS  (pagesize / BYTES_PER_MP_LIMB)
                    143:
                    144: /* must be a multiple of the page size */
                    145: #define REDZONE_BYTES   (pagesize * 16)
                    146: #define REDZONE_LIMBS   (REDZONE_BYTES / BYTES_PER_MP_LIMB)
                    147:
                    148:
                    149: #define MAX3(x,y,z)   (MAX (x, MAX (y, z)))
                    150:
                    151: #if BITS_PER_MP_LIMB == 32
                    152: #define DEADVAL  CNST_LIMB(0xDEADBEEF)
                    153: #else
                    154: #define DEADVAL  CNST_LIMB(0xDEADBEEFBADDCAFE)
                    155: #endif
                    156:
                    157:
                    158: #define TRY_RETVAL           (1<<0)
                    159: #define TRY_SIZE2            (1<<1)
                    160: #define TRY_SHIFT            (1<<2)
                    161: #define TRY_CARRYBIT         (1<<3)
                    162: #define TRY_CARRY3           (1<<4)
                    163: #define TRY_CARRY4           (1<<4)
                    164: #define TRY_CARRYLIMB        (1<<5)
                    165: #define TRY_MULTIPLIER       (1<<6)
                    166: #define TRY_DIVISOR          (1<<7)
                    167: #define TRY_DOUBLE_DST       (1<<8)
                    168: #define TRY_DST0_INIT        (1<<9)
                    169: #define TRY_XSIZE            (1<<10)
                    170: #define TRY_SIZE_ZERO        (1<<11)
                    171: #define TRY_DST_SIZE_RETVAL  (1<<12)
                    172: #define TRY_SRC1_GCDDATA     (1<<13)
                    173:
                    174: #define TRY_OVERLAP_LOW_TO_HIGH  (1<<15) /* Default is allow full overlap. */
                    175: #define TRY_OVERLAP_HIGH_TO_LOW  (1<<16)
                    176: #define TRY_OVERLAP_NONE         (1<<17)
                    177: #define TRY_OVERLAP_NOTSRCS      (1<<18)
                    178:
                    179: #define TRY_SRC0        (1<<20)
                    180: #define TRY_SRC1        (TRY_SRC0 << 1)
                    181:
                    182: #define TRY_DST0        (1<<24)
                    183: #define TRY_DST1        (TRY_DST0 << 1)
                    184:
                    185:
                    186: #define TRY_SRC(n)      (TRY_SRC0 << (n))
                    187: #define TRY_DST(n)      (TRY_DST0 << (n))
                    188:
                    189: #define TRY_CARRYANY  (TRY_CARRYBIT | TRY_CARRY3 | TRY_CARRY4 | TRY_CARRYLIMB)
                    190:
                    191:
                    192: #define TRY_TYPE_AORS_N      (TRY_RETVAL | TRY_DST0 | TRY_SRC0 | TRY_SRC1)
                    193: #define TRY_TYPE_AORS_NC     (TRY_TYPE_AORS_N | TRY_CARRYBIT)
                    194:
                    195: #define TRY_TYPE_AORSMUL_1   (TRY_TYPE_MUL_1  | TRY_DST0_INIT)
                    196: #define TRY_TYPE_AORSMUL_1C  (TRY_TYPE_MUL_1C | TRY_DST0_INIT)
                    197:
                    198: #define TRY_TYPE_LOGOPS_N    (TRY_DST0 | TRY_SRC0 | TRY_SRC1)
                    199:
                    200: #define TRY_TYPE_ADDSUB_N \
                    201:   (TRY_RETVAL | TRY_DST0 | TRY_DST1 | TRY_SRC0 | TRY_SRC1)
                    202: #define TRY_TYPE_ADDSUB_NC \
                    203:   (TRY_TYPE_ADDSUB_N | TRY_CARRY4)
                    204:
                    205: #define TRY_TYPE_COPYI \
                    206:   (TRY_DST0 | TRY_SRC0 | TRY_OVERLAP_LOW_TO_HIGH | TRY_SIZE_ZERO)
                    207: #define TRY_TYPE_COPYD \
                    208:   (TRY_DST0 | TRY_SRC0 | TRY_OVERLAP_HIGH_TO_LOW | TRY_SIZE_ZERO)
                    209: #define TRY_TYPE_COM_N   (TRY_DST0 | TRY_SRC0)
                    210:
                    211: #define TRY_TYPE_MOD_1   (TRY_RETVAL | TRY_SRC0 | TRY_DIVISOR | TRY_SIZE_ZERO)
                    212: #define TRY_TYPE_MOD_1C       (TRY_TYPE_MOD_1 | TRY_CARRYLIMB)
                    213: #define TRY_TYPE_DIVMOD_1     (TRY_TYPE_MOD_1  | TRY_DST0)
                    214: #define TRY_TYPE_DIVMOD_1C    (TRY_TYPE_MOD_1C | TRY_DST0)
                    215: #define TRY_TYPE_DIVREM_1     (TRY_TYPE_DIVMOD_1  | TRY_XSIZE)
                    216: #define TRY_TYPE_DIVREM_1C    (TRY_TYPE_DIVMOD_1C | TRY_XSIZE)
                    217: #define TRY_TYPE_MOD_1_RSHIFT (TRY_RETVAL | TRY_SRC0 | TRY_SHIFT | TRY_DIVISOR)
                    218:
                    219: #define TRY_TYPE_DIVEXACT_BY3   (TRY_RETVAL | TRY_DST0 | TRY_SRC0)
                    220: #define TRY_TYPE_DIVEXACT_BY3C  (TRY_TYPE_DIVEXACT_BY3 | TRY_CARRY3)
                    221:
                    222: #define TRY_TYPE_GCD_1   (TRY_RETVAL | TRY_SRC0 | TRY_DIVISOR)
                    223: #define TRY_TYPE_GCD                                            \
                    224:   (TRY_RETVAL | TRY_DST0 | TRY_SRC0 | TRY_SRC1 | TRY_SIZE2      \
                    225:    | TRY_DST_SIZE_RETVAL | TRY_OVERLAP_NOTSRCS | TRY_SRC1_GCDDATA)
                    226:
                    227: #define TRY_TYPE_MUL_1   (TRY_RETVAL | TRY_DST0 | TRY_SRC0 | TRY_MULTIPLIER)
                    228: #define TRY_TYPE_MUL_1C  (TRY_TYPE_MUL_1 | TRY_CARRYLIMB)
                    229:
                    230: #define TRY_TYPE_MUL_BASECASE \
                    231:   (TRY_DST0 | TRY_SRC0 | TRY_SRC1 | TRY_SIZE2 | TRY_OVERLAP_NONE)
                    232: #define TRY_TYPE_MUL_N \
                    233:   (TRY_DST0 | TRY_SRC0 | TRY_SRC1 | TRY_DOUBLE_DST | TRY_OVERLAP_NONE)
                    234: #define TRY_TYPE_SQR \
                    235:   (TRY_DST0 | TRY_SRC0 | TRY_DOUBLE_DST | TRY_OVERLAP_NONE)
                    236:
                    237: #define TRY_TYPE_RSHIFT \
                    238:   (TRY_RETVAL | TRY_DST0 | TRY_SRC0 | TRY_SHIFT | TRY_OVERLAP_LOW_TO_HIGH)
                    239: #define TRY_TYPE_LSHIFT \
                    240:   (TRY_RETVAL | TRY_DST0 | TRY_SRC0 | TRY_SHIFT | TRY_OVERLAP_HIGH_TO_LOW)
                    241:
                    242: #define TRY_TYPE_POPCOUNT   (TRY_RETVAL | TRY_SRC0 | TRY_SIZE_ZERO)
                    243: #define TRY_TYPE_HAMDIST    (TRY_TYPE_POPCOUNT | TRY_SRC1)
                    244:
                    245:
                    246: /* The following are macros if there's no native versions, so wrap them in
                    247:    functions that can be in try_array[]. */
                    248:
                    249: void
                    250: MPN_COPY_INCR_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
                    251: { MPN_COPY_INCR (rp, sp, size); }
                    252:
                    253: void
                    254: MPN_COPY_DECR_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
                    255: { MPN_COPY_DECR (rp, sp, size); }
                    256:
                    257: void
                    258: mpn_com_n_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
                    259: { mpn_com_n (rp, sp, size); }
                    260:
                    261: void
                    262: mpn_and_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
                    263: { mpn_and_n (rp, s1, s2, size); }
                    264:
                    265: void
                    266: mpn_andn_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
                    267: { mpn_andn_n (rp, s1, s2, size); }
                    268:
                    269: void
                    270: mpn_nand_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
                    271: { mpn_nand_n (rp, s1, s2, size); }
                    272:
                    273: void
                    274: mpn_ior_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
                    275: { mpn_ior_n (rp, s1, s2, size); }
                    276:
                    277: void
                    278: mpn_iorn_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
                    279: { mpn_iorn_n (rp, s1, s2, size); }
                    280:
                    281: void
                    282: mpn_nior_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
                    283: { mpn_nior_n (rp, s1, s2, size); }
                    284:
                    285: void
                    286: mpn_xor_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
                    287: { mpn_xor_n (rp, s1, s2, size); }
                    288:
                    289: void
                    290: mpn_xnor_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
                    291: { mpn_xnor_n (rp, s1, s2, size); }
                    292:
                    293: void
                    294: mpn_divexact_by3_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
                    295: { mpn_divexact_by3 (rp, sp, size); }
                    296:
                    297:
                    298: struct try_t {
                    299:   struct try_one_t {
                    300:     tryfun_t    function;
                    301:     const char  *name;
                    302:   } ref, fun;
                    303:   int         flag;
                    304:   mp_size_t   minsize;
                    305: };
                    306:
                    307: #if HAVE_STRINGIZE
                    308: #define TRY(fun)        { (tryfun_t) fun,       #fun }
                    309: #define TRY_FUNFUN(fun) { (tryfun_t) fun##_fun, #fun }
                    310: #else
                    311: #define TRY(fun)        { (tryfun_t) fun,         "fun" }
                    312: #define TRY_FUNFUN(fun) { (tryfun_t) fun/**/_fun, "fun" }
                    313: #endif
                    314:
                    315: struct try_t try_array[] = {
                    316:   { TRY(refmpn_add_n),     TRY(mpn_add_n),     TRY_TYPE_AORS_N  },
                    317:   { TRY(refmpn_sub_n),     TRY(mpn_sub_n),     TRY_TYPE_AORS_N  },
                    318: #if HAVE_NATIVE_mpn_add_nc
                    319:   { TRY(refmpn_add_nc),    TRY(mpn_add_nc),    TRY_TYPE_AORS_NC },
                    320: #endif
                    321: #if HAVE_NATIVE_mpn_sub_nc
                    322:   { TRY(refmpn_sub_nc),    TRY(mpn_sub_nc),    TRY_TYPE_AORS_NC },
                    323: #endif
                    324:
                    325:   { TRY(refmpn_addmul_1),  TRY(mpn_addmul_1),  TRY_TYPE_AORSMUL_1  },
                    326:   { TRY(refmpn_submul_1),  TRY(mpn_submul_1),  TRY_TYPE_AORSMUL_1  },
                    327: #if HAVE_NATIVE_mpn_addmul_1c
                    328:   { TRY(refmpn_addmul_1c), TRY(mpn_addmul_1c), TRY_TYPE_AORSMUL_1C },
                    329: #endif
                    330: #if HAVE_NATIVE_mpn_submul_1c
                    331:   { TRY(refmpn_submul_1c), TRY(mpn_submul_1c), TRY_TYPE_AORSMUL_1C },
                    332: #endif
                    333:
                    334:   { TRY(refmpn_com_n),    TRY_FUNFUN(mpn_com_n),  TRY_TYPE_COM_N },
                    335:
                    336:   { TRY(refmpn_copyi),    TRY_FUNFUN(MPN_COPY_INCR), TRY_TYPE_COPYI },
                    337:   { TRY(refmpn_copyd),    TRY_FUNFUN(MPN_COPY_DECR), TRY_TYPE_COPYD },
                    338:
                    339:   { TRY(refmpn_and_n),    TRY_FUNFUN(mpn_and_n),  TRY_TYPE_LOGOPS_N },
                    340:   { TRY(refmpn_andn_n),   TRY_FUNFUN(mpn_andn_n), TRY_TYPE_LOGOPS_N },
                    341:   { TRY(refmpn_nand_n),   TRY_FUNFUN(mpn_nand_n), TRY_TYPE_LOGOPS_N },
                    342:   { TRY(refmpn_ior_n),    TRY_FUNFUN(mpn_ior_n),  TRY_TYPE_LOGOPS_N },
                    343:   { TRY(refmpn_iorn_n),   TRY_FUNFUN(mpn_iorn_n), TRY_TYPE_LOGOPS_N },
                    344:   { TRY(refmpn_nior_n),   TRY_FUNFUN(mpn_nior_n), TRY_TYPE_LOGOPS_N },
                    345:   { TRY(refmpn_xor_n),    TRY_FUNFUN(mpn_xor_n),  TRY_TYPE_LOGOPS_N },
                    346:   { TRY(refmpn_xnor_n),   TRY_FUNFUN(mpn_xnor_n), TRY_TYPE_LOGOPS_N },
                    347:
                    348:   { TRY(refmpn_divrem_1),     TRY(mpn_divrem_1),     TRY_TYPE_DIVREM_1 },
                    349:   { TRY(refmpn_mod_1),        TRY(mpn_mod_1),        TRY_TYPE_MOD_1 },
                    350:   { TRY(refmpn_mod_1_rshift), TRY(mpn_mod_1_rshift), TRY_TYPE_MOD_1_RSHIFT },
                    351: #if HAVE_NATIVE_mpn_divrem_1c
                    352:   { TRY(refmpn_divrem_1c),    TRY(mpn_divrem_1c),    TRY_TYPE_DIVREM_1C },
                    353: #endif
                    354: #if HAVE_NATIVE_mpn_mod_1c
                    355:   { TRY(refmpn_mod_1c),       TRY(mpn_mod_1c),       TRY_TYPE_MOD_1C },
                    356: #endif
                    357:   { TRY(refmpn_divexact_by3), TRY_FUNFUN(mpn_divexact_by3),
                    358:                                                      TRY_TYPE_DIVEXACT_BY3 },
                    359:   { TRY(refmpn_divexact_by3c),TRY(mpn_divexact_by3c),TRY_TYPE_DIVEXACT_BY3C },
                    360:
                    361:   { TRY(refmpn_mul_1),    TRY(mpn_mul_1),      TRY_TYPE_MUL_1 },
                    362: #if HAVE_NATIVE_mpn_mul_1c
                    363:   { TRY(refmpn_mul_1c),   TRY(mpn_mul_1c),     TRY_TYPE_MUL_1C },
                    364: #endif
                    365:
                    366:   { TRY(refmpn_rshift),   TRY(mpn_rshift),     TRY_TYPE_RSHIFT },
                    367:   { TRY(refmpn_lshift),   TRY(mpn_lshift),     TRY_TYPE_LSHIFT },
                    368:
                    369:
                    370:   { TRY(refmpn_mul_basecase), TRY(mpn_mul_basecase), TRY_TYPE_MUL_BASECASE },
                    371:   { TRY(refmpn_sqr),          TRY(mpn_sqr_basecase), TRY_TYPE_SQR },
                    372:
                    373:   { TRY(refmpn_mul_basecase), TRY(mpn_mul),    TRY_TYPE_MUL_BASECASE },
                    374:   { TRY(refmpn_mul_n),        TRY(mpn_mul_n),  TRY_TYPE_MUL_N },
                    375:   { TRY(refmpn_sqr),          TRY(mpn_sqr_n),  TRY_TYPE_SQR },
                    376:
                    377:   { TRY(refmpn_gcd_1),    TRY(mpn_gcd_1),      TRY_TYPE_GCD_1 },
                    378:   { TRY(refmpn_gcd),      TRY(mpn_gcd),        TRY_TYPE_GCD   },
                    379:
                    380:   { TRY(refmpn_popcount), TRY(mpn_popcount),   TRY_TYPE_POPCOUNT },
                    381:   { TRY(refmpn_hamdist),  TRY(mpn_hamdist),    TRY_TYPE_HAMDIST },
                    382:
                    383: #if 0
                    384:   /* need wrapper functions since they take workspace arguments */
                    385:   { TRY(refmpn_mul_n), TRY_FUNFUN(mpn_kara_mul_n),  TRY_TYPE_MUL_N,
                    386:                                                       MPN_KARA_MINSIZE},
                    387:   { TRY(refmpn_sqr),   TRY_FUNFUN(mpn_kara_sqr_n),  TRY_TYPE_SQR,
                    388:                                                       MPN_KARA_MINSIZE},
                    389:   { TRY(refmpn_mul_n), TRY_FUNFUN(mpn_toom3_mul_n), TRY_TYPE_MUL_N,
                    390:                                                       MPN_TOOM3_MINSIZE},
                    391:   { TRY(refmpn_sqr),   TRY_FUNFUN(mpn_toom3_sqr_n), TRY_TYPE_SQR,
                    392:                                                       MPN_TOOM3_MINSIZE },
                    393: #endif
                    394:
                    395: #if HAVE_SPA_EXTRAS
                    396: #include "spa-out.t-table.i"
                    397: #endif
                    398: };
                    399:
                    400: struct try_t *tr = &try_array[0];
                    401:
                    402:
                    403: struct region_t {
                    404:   mp_ptr     ptr;
                    405:   mp_size_t  size;
                    406: };
                    407:
                    408:
                    409: #define TRAP_NOWHERE 0
                    410: #define TRAP_REF     1
                    411: #define TRAP_FUN     2
                    412: #define TRAP_SETUPS  3
                    413: int trap_location = TRAP_NOWHERE;
                    414:
                    415:
                    416: /* Find least significant limb position where p1,size and p2,size differ.  */
                    417: mp_size_t
                    418: mpn_diff_lowest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
                    419: {
                    420:   mp_size_t  i;
                    421:
                    422:   for (i = 0; i < size; i++)
                    423:     if (p1[i] != p2[i])
                    424:       return i;
                    425:
                    426:   /* no differences */
                    427:   return -1;
                    428: }
                    429:
                    430:
                    431: /* Find most significant limb position where p1,size and p2,size differ.  */
                    432: mp_size_t
                    433: mpn_diff_highest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
                    434: {
                    435:   mp_size_t  i;
                    436:
                    437:   for (i = size-1; i >= 0; i--)
                    438:     if (p1[i] != p2[i])
                    439:       return i;
                    440:
                    441:   /* no differences */
                    442:   return -1;
                    443: }
                    444:
                    445:
                    446: /* Return p advanced to the next multiple of "align" bytes.  "align" must be
                    447:    a power of 2.  Care is taken not to assume sizeof(int)==sizeof(pointer).  */
                    448: void *
                    449: align_pointer (void *p, size_t align)
                    450: {
                    451:   unsigned  d;
                    452:   d = ((unsigned) p) & (align-1);
                    453:   d = (d != 0 ? align-d : 0);
                    454:   return (void *) (((char *) p) + d);
                    455: }
                    456:
                    457: /* malloc n limbs on a multiple of m bytes boundary */
                    458: mp_ptr
                    459: malloc_limbs_aligned (size_t n, size_t m)
                    460: {
                    461:   return (mp_ptr) align_pointer (refmpn_malloc_limbs (n + m-1), m);
                    462: }
                    463:
                    464: void
                    465: mprotect_maybe (void *addr, size_t len, int prot)
                    466: {
                    467:   if (!option_redzones)
                    468:     return;
                    469:
                    470:   if (mprotect (addr, len, prot) != 0)
                    471:     {
                    472:       fprintf (stderr, "Cannot mprotect %p 0x%X 0x%X\n", addr, len, prot);
                    473:       exit (1);
                    474:     }
                    475: }
                    476:
                    477: /* round "a" up to a multiple of "m" */
                    478: size_t
                    479: round_up_multiple (size_t a, size_t m)
                    480: {
                    481:   unsigned long  r;
                    482:
                    483:   r = a % m;
                    484:   if (r == 0)
                    485:     return a;
                    486:   else
                    487:     return a + (m - r);
                    488: }
                    489:
                    490: void
                    491: malloc_region (struct region_t *r, mp_size_t n)
                    492: {
                    493:   mp_ptr  p;
                    494:
                    495:   ASSERT ((pagesize % BYTES_PER_MP_LIMB) == 0);
                    496:
                    497:   r->size = round_up_multiple (n, PAGESIZE_LIMBS);
                    498:   p = malloc_limbs_aligned (r->size + REDZONE_LIMBS*2, pagesize);
                    499:   mprotect_maybe (p, REDZONE_BYTES, PROT_NONE);
                    500:
                    501:   r->ptr = p + REDZONE_LIMBS;
                    502:   mprotect_maybe (r->ptr + r->size, REDZONE_BYTES, PROT_NONE);
                    503: }
                    504:
                    505: void
                    506: mprotect_region (const struct region_t *r, int prot)
                    507: {
                    508:   mprotect_maybe (r->ptr, r->size, prot);
                    509: }
                    510:
                    511:
                    512: #define NUM_SOURCES  2
                    513: #define NUM_DESTS    2
                    514:
                    515: struct source_t {
                    516:   struct region_t  region;
                    517:   int        high;
                    518:   mp_size_t  align;
                    519:   mp_ptr     p;
                    520: };
                    521:
                    522: struct source_t  s[NUM_SOURCES];
                    523:
                    524: struct dest_t {
                    525:   int        high;
                    526:   mp_size_t  align;
                    527: };
                    528:
                    529: struct dest_t  d[NUM_SOURCES];
                    530:
                    531: struct source_each_t {
                    532:   mp_ptr     p;
                    533: };
                    534:
                    535: struct dest_each_t {
                    536:   struct region_t  region;
                    537:   mp_ptr     p;
                    538: };
                    539:
                    540: mp_size_t  size;
                    541: mp_size_t  size2;
                    542: mp_size_t  dsize;
                    543: unsigned long   shift;
                    544:
                    545: struct each_t {
                    546:   const char  *name;
                    547:   struct dest_each_t    d[numberof(d)];
                    548:   struct source_each_t  s[numberof(s)];
                    549:   mp_limb_t  retval;
                    550: };
                    551:
                    552: struct each_t  ref = { "Ref" };
                    553: struct each_t  fun = { "Fun" };
                    554:
                    555: #define SRC_SIZE(n) \
                    556:   ((n) == 1 && (tr->flag & (TRY_SIZE2|TRY_XSIZE)) ? size2 : size)
                    557:
                    558:
                    559: /* First four entries must be 0,1,2,3 for TRY_CARRYBIT, TRY_CARRY3, and
                    560:    TRY_CARRY4 */
                    561: mp_limb_t  carry_array[] = {
                    562:   0, 1, 2, 3,
                    563:   4,
                    564:   (mp_limb_t) 1 << 8,
                    565:   (mp_limb_t) 1 << 16,
                    566:   (mp_limb_t) -1
                    567: };
                    568: mp_limb_t  carry;
                    569: int        carry_index;
                    570:
                    571: #define CARRY_COUNT                                                     \
                    572:   ((tr->flag & TRY_CARRYBIT) ? 2                                        \
                    573:    : (tr->flag & TRY_CARRY3) ? 3                                        \
                    574:    : (tr->flag & TRY_CARRY4) ? 4                                        \
                    575:    : (tr->flag & TRY_CARRYLIMB) ? numberof(carry_array) + CARRY_RANDOMS \
                    576:    : 1)
                    577:
                    578: #define MPN_RANDOM_ALT(index,dst,size) \
                    579:   (((index) & 1) ? mpn_random (dst, size) : mpn_random2 (dst, size))
                    580:
                    581: /* The dummy value after MPN_RANDOM_ALT ensures both sides of the ":" have
                    582:    the same type */
                    583: #define CARRY_ITERATION                                                 \
                    584:   for (carry_index = 0;                                                 \
                    585:        (carry_index < numberof (carry_array)                            \
                    586:         ? (carry = carry_array[carry_index])                            \
                    587:         : (MPN_RANDOM_ALT (carry_index, &carry, 1), (mp_limb_t) 0)),    \
                    588:        carry_index < CARRY_COUNT;                                       \
                    589:        carry_index++)
                    590:
                    591:
                    592: mp_limb_t  multiplier_array[] = {
                    593:   0, 1, 2, 3,
                    594:   (mp_limb_t) 1 << 8,
                    595:   (mp_limb_t) 1 << 16,
                    596:   (mp_limb_t) -3,
                    597:   (mp_limb_t) -2,
                    598:   (mp_limb_t) -1,
                    599: };
                    600: mp_limb_t  multiplier;
                    601: int        multiplier_index;
                    602:
                    603: mp_limb_t  divisor_array[] = {
                    604:   1, 2, 3,
                    605:   (mp_limb_t) 1 << 8,
                    606:   (mp_limb_t) 1 << 16,
                    607:   (mp_limb_t) -3,
                    608:   (mp_limb_t) -2,
                    609:   (mp_limb_t) -1,
                    610: };
                    611:
                    612: mp_limb_t  divisor;
                    613: int        divisor_index;
                    614:
                    615: /* The dummy value after MPN_RANDOM_ALT ensures both sides of the ":" have
                    616:    the same type */
                    617: #define ARRAY_ITERATION(var, index, limit, array, randoms, cond)        \
                    618:   for (index = 0;                                                       \
                    619:        (index < numberof (array)                                        \
                    620:         ? CAST_TO_VOID (var = array[index])                             \
                    621:         : (MPN_RANDOM_ALT (index, &var, 1), (mp_limb_t) 0)),            \
                    622:        index < limit;                                                   \
                    623:        index++)
                    624:
                    625: #define MULTIPLIER_COUNT                                \
                    626:   ((tr->flag & TRY_MULTIPLIER)                          \
                    627:     ? numberof (multiplier_array) + MULTIPLIER_RANDOMS  \
                    628:     : 1)
                    629:
                    630: #define MULTIPLIER_ITERATION                                            \
                    631:   ARRAY_ITERATION(multiplier, multiplier_index, MULTIPLIER_COUNT,       \
                    632:                   multiplier_array, MULTIPLIER_RANDOMS, TRY_MULTIPLIER)
                    633:
                    634: #define DIVISOR_COUNT                           \
                    635:   ((tr->flag & TRY_DIVISOR)                    \
                    636:    ? numberof (divisor_array) + DIVISOR_RANDOMS \
                    637:    : 1)
                    638:
                    639: #define DIVISOR_ITERATION                                               \
                    640:   ARRAY_ITERATION(divisor, divisor_index, DIVISOR_COUNT, divisor_array, \
                    641:                   DIVISOR_RANDOMS, TRY_DIVISOR)
                    642:
                    643:
                    644: /* overlap_array[].s[i] is where s[i] should be, 0 or 1 means overlapping
                    645:    d[0] or d[1] respectively, -1 means a separate (write-protected)
                    646:    location. */
                    647:
                    648: struct overlap_t {
                    649:   int  s[NUM_SOURCES];
                    650: } overlap_array[] = {
                    651:   { { -1, -1 } },
                    652:   { {  0, -1 } },
                    653:   { { -1,  0 } },
                    654:   { {  0,  0 } },
                    655:   { {  1, -1 } },
                    656:   { { -1,  1 } },
                    657:   { {  1,  1 } },
                    658:   { {  0,  1 } },
                    659:   { {  1,  0 } },
                    660: };
                    661:
                    662: struct overlap_t  *overlap, *overlap_limit;
                    663:
                    664: #define OVERLAP_COUNT                   \
                    665:   (tr->flag & TRY_OVERLAP_NONE ? 1      \
                    666:    : tr->flag & TRY_OVERLAP_NOTSRCS ? 3 \
                    667:    : tr->flag & TRY_DST1 ? 9            \
                    668:    : tr->flag & TRY_SRC1 ? 4            \
                    669:    : tr->flag & TRY_DST0 ? 2            \
                    670:    : 1)
                    671:
                    672: #define OVERLAP_ITERATION                               \
                    673:   for (overlap = &overlap_array[0],                     \
                    674:     overlap_limit = &overlap_array[OVERLAP_COUNT];      \
                    675:     overlap < overlap_limit;                            \
                    676:     overlap++)
                    677:
                    678:
                    679: #define T_RAND_COUNT  2
                    680: int  t_rand;
                    681:
                    682: void
                    683: t_random (mp_ptr ptr, mp_size_t n)
                    684: {
                    685:   if (size == 0)
                    686:     return;
                    687:
                    688:   switch (option_data) {
                    689:   case DATA_TRAND:
                    690:     switch (t_rand) {
                    691:     case 0: mpn_random (ptr, n); break;
                    692:     case 1: mpn_random2 (ptr, n); break;
                    693:     default: abort();
                    694:     }
                    695:     break;
                    696:   case DATA_SEQ:
                    697:     {
                    698:       static mp_limb_t  counter = 0;
                    699:       mp_size_t  i;
                    700:       for (i = 0; i < n; i++)
                    701:         ptr[i] = ++counter;
                    702:     }
                    703:     break;
                    704:   case DATA_ZEROS:
                    705:     refmpn_fill (ptr, n, (mp_limb_t) 0);
                    706:     break;
                    707:   case DATA_FFS:
                    708:     refmpn_fill (ptr, n, (mp_limb_t) -1);
                    709:     break;
                    710:   case DATA_2FD:
                    711:     /* Special value 0x2FFF...FFFD, which divided by 3 gives 0xFFF...FFF,
                    712:        inducing the q1_ff special case in the mul-by-inverse part of some
                    713:        versions of divrem_1 and mod_1. */
                    714:     refmpn_fill (ptr, n, (mp_limb_t) -1);
                    715:     ptr[n-1] = 2;
                    716:     ptr[0] -= 2;
                    717:     break;
                    718:
                    719:   default:
                    720:     abort();
                    721:   }
                    722: }
                    723: #define T_RAND_ITERATION \
                    724:   for (t_rand = 0; t_rand < T_RAND_COUNT; t_rand++)
                    725:
                    726:
                    727: void
                    728: print_each (const struct each_t *e)
                    729: {
                    730:   int  i;
                    731:
                    732:   printf ("%s %s\n", e->name, e == &ref ? tr->ref.name : tr->fun.name);
                    733:   if (tr->flag & TRY_RETVAL)
                    734:     printf ("   retval %08lX\n", e->retval);
                    735:
                    736:   for (i = 0; i < numberof (e->d); i++)
                    737:     {
                    738:       if (tr->flag & TRY_DST(i))
                    739:         {
                    740:           mpn_tracen ("   d[%d]", i, e->d[i].p, dsize);
                    741:           printf ("        located %p\n", e->d[i].p);
                    742:         }
                    743:     }
                    744:
                    745:   for (i = 0; i < numberof (e->s); i++)
                    746:     if (tr->flag & TRY_SRC(i))
                    747:       printf ("   s[%d] located %p\n", i, e->s[i].p);
                    748: }
                    749:
                    750: void
                    751: print_all (void)
                    752: {
                    753:   int  i;
                    754:
                    755:   printf ("\n");
                    756:   printf ("size  %ld\n", size);
                    757:   if (tr->flag & (TRY_SIZE2|TRY_XSIZE))
                    758:     printf ("size2 %ld\n", size2);
                    759:   if (dsize != size)
                    760:     printf ("dsize %ld\n", dsize);
                    761:   if (tr->flag & TRY_MULTIPLIER)
                    762:     printf ("   multiplier 0x%lX\n", multiplier);
                    763:   if (tr->flag & TRY_DIVISOR)
                    764:     printf ("   divisor 0x%lX\n", divisor);
                    765:   if (tr->flag & TRY_SHIFT)
                    766:     printf ("   shift %lu\n", shift);
                    767:   if (tr->flag & TRY_CARRYANY)
                    768:     printf ("   carry %lX\n", carry);
                    769:
                    770:   for (i = 0; i < numberof (d); i++)
                    771:     if (tr->flag & TRY_DST(i))
                    772:       printf ("   d[%d] %s, align %ld\n",
                    773:               i, d[i].high ? "high" : "low", d[i].align);
                    774:
                    775:   for (i = 0; i < numberof (s); i++)
                    776:     {
                    777:       if (tr->flag & TRY_SRC(i))
                    778:         {
                    779:           printf ("   s[%d] %s, align %ld, ",
                    780:                   i, s[i].high ? "high" : "low", s[i].align);
                    781:           switch (overlap->s[i]) {
                    782:           case -1:
                    783:             printf ("no overlap\n");
                    784:             break;
                    785:           default:
                    786:             printf ("==d[%d]%s\n",
                    787:                     overlap->s[i],
                    788:                     tr->flag & TRY_OVERLAP_LOW_TO_HIGH ? "+a"
                    789:                     : tr->flag & TRY_OVERLAP_HIGH_TO_LOW ? "-a"
                    790:                     : "");
                    791:             break;
                    792:           }
                    793:           mpn_tracen ("   s[%d]", i, s[i].p, SRC_SIZE(i));
                    794:         }
                    795:     }
                    796:
                    797:   if (tr->flag & TRY_DST0_INIT)
                    798:     mpn_trace ("   d[0]", s[1].region.ptr, size);
                    799:
                    800:   print_each (&ref);
                    801:   print_each (&fun);
                    802: }
                    803:
                    804: void
                    805: compare (void)
                    806: {
                    807:   int  error = 0;
                    808:   int  i;
                    809:
                    810:   if ((tr->flag & TRY_RETVAL) && ref.retval != fun.retval)
                    811:     {
                    812:       printf ("Different return values\n");
                    813:       error = 1;
                    814:     }
                    815:
                    816:   if (! CALLING_CONVENTIONS_CHECK ())
                    817:     error = 1;
                    818:
                    819:   if (tr->flag & TRY_DST_SIZE_RETVAL)
                    820:     dsize = ref.retval;
                    821:
                    822:   for (i = 0; i < numberof (ref.d); i++)
                    823:     {
                    824:       if (!(tr->flag & TRY_DST(i)))
                    825:         continue;
                    826:
                    827:       if (dsize != 0 && refmpn_cmp (ref.d[i].p, fun.d[i].p, dsize) != 0)
                    828:         {
                    829:           printf ("Different d[%d] data results, low diff at %ld, high diff at %ld\n",
                    830:                   i,
                    831:                   mpn_diff_lowest (ref.d[i].p, fun.d[i].p, dsize),
                    832:                   mpn_diff_highest (ref.d[i].p, fun.d[i].p, dsize));
                    833:           error = 1;
                    834:         }
                    835:     }
                    836:
                    837:   if (error)
                    838:     {
                    839:       print_all();
                    840:       abort();
                    841:     }
                    842: }
                    843:
                    844: void
                    845: call (struct each_t *e, tryfun_t function)
                    846: {
                    847:   switch (tr->flag) {
                    848:   case TRY_TYPE_AORS_N:
                    849:     e->retval = CALLING_CONVENTIONS (function)
                    850:       (e->d[0].p, e->s[0].p, e->s[1].p, size);
                    851:     break;
                    852:   case TRY_TYPE_AORS_NC:
                    853:     e->retval = CALLING_CONVENTIONS (function)
                    854:       (e->d[0].p, e->s[0].p, e->s[1].p, size, carry);
                    855:     break;
                    856:
                    857:   case TRY_TYPE_LOGOPS_N:
                    858:     CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, e->s[1].p, size);
                    859:     break;
                    860:
                    861:   case TRY_TYPE_ADDSUB_N:
                    862:     e->retval = CALLING_CONVENTIONS (function)
                    863:       (e->d[0].p, e->d[1].p, e->s[0].p, e->s[1].p, size);
                    864:     break;
                    865:   case TRY_TYPE_ADDSUB_NC:
                    866:     e->retval = CALLING_CONVENTIONS (function)
                    867:       (e->d[0].p, e->d[1].p, e->s[0].p, e->s[1].p, size, carry);
                    868:     break;
                    869:
                    870:   case TRY_TYPE_COPYI:
                    871:   case TRY_TYPE_COPYD:
                    872:   case TRY_TYPE_COM_N:
                    873:     CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size);
                    874:     break;
                    875:
                    876:   case TRY_TYPE_DIVEXACT_BY3:
                    877:     e->retval = CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size);
                    878:     break;
                    879:   case TRY_TYPE_DIVEXACT_BY3C:
                    880:     e->retval = CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size,
                    881:                                                 carry);
                    882:     break;
                    883:
                    884:   case TRY_TYPE_DIVMOD_1:
                    885:     e->retval = CALLING_CONVENTIONS (function)
                    886:       (e->d[0].p, e->s[0].p, size, divisor);
                    887:     break;
                    888:   case TRY_TYPE_DIVMOD_1C:
                    889:     e->retval = CALLING_CONVENTIONS (function)
                    890:       (e->d[0].p, e->s[0].p, size, divisor, carry);
                    891:     break;
                    892:   case TRY_TYPE_DIVREM_1:
                    893:     e->retval = CALLING_CONVENTIONS (function)
                    894:       (e->d[0].p, size2, e->s[0].p, size, divisor);
                    895:     break;
                    896:   case TRY_TYPE_DIVREM_1C:
                    897:     e->retval = CALLING_CONVENTIONS (function)
                    898:       (e->d[0].p, size2, e->s[0].p, size, divisor, carry);
                    899:     break;
                    900:   case TRY_TYPE_MOD_1:
                    901:     e->retval = CALLING_CONVENTIONS (function)
                    902:       (e->s[0].p, size, divisor);
                    903:     break;
                    904:   case TRY_TYPE_MOD_1C:
                    905:     e->retval = CALLING_CONVENTIONS (function)
                    906:       (e->s[0].p, size, divisor, carry);
                    907:     break;
                    908:   case TRY_TYPE_MOD_1_RSHIFT:
                    909:     e->retval = CALLING_CONVENTIONS (function)
                    910:       (e->s[0].p, size, shift, divisor);
                    911:     break;
                    912:
                    913:   case TRY_TYPE_GCD_1:
                    914:     /* Must have a non-zero src, but this probably isn't the best way to do
                    915:        it. */
                    916:     if (refmpn_zero_p (e->s[0].p, size))
                    917:       e->retval = 0;
                    918:     else
                    919:       e->retval = CALLING_CONVENTIONS (function) (e->s[0].p, size, divisor);
                    920:     break;
                    921:
                    922:   case TRY_TYPE_GCD:
                    923:     /* Sources are destroyed, so they're saved and replaced, but a general
                    924:        approach to this might be better.  Note that it's still e->s[0].p and
                    925:        e->s[1].p that are passed, to get the desired alignments. */
                    926:     {
                    927:       mp_ptr  s0 = refmpn_malloc_limbs (size);
                    928:       mp_ptr  s1 = refmpn_malloc_limbs (size2);
                    929:       refmpn_copyi (s0, e->s[0].p, size);
                    930:       refmpn_copyi (s1, e->s[1].p, size2);
                    931:
                    932:       mprotect_region (&s[0].region, PROT_READ|PROT_WRITE);
                    933:       mprotect_region (&s[1].region, PROT_READ|PROT_WRITE);
                    934:       e->retval = CALLING_CONVENTIONS (function) (e->d[0].p,
                    935:                                                   e->s[0].p, size,
                    936:                                                   e->s[1].p, size2);
                    937:       refmpn_copyi (e->s[0].p, s0, size);
                    938:       refmpn_copyi (e->s[1].p, s1, size2);
                    939:       free (s0);
                    940:       free (s1);
                    941:     }
                    942:     break;
                    943:
                    944:   case TRY_TYPE_MUL_1:
                    945:   case TRY_TYPE_AORSMUL_1:
                    946:     e->retval = CALLING_CONVENTIONS (function)
                    947:       (e->d[0].p, e->s[0].p, size, multiplier);
                    948:     break;
                    949:   case TRY_TYPE_MUL_1C:
                    950:   case TRY_TYPE_AORSMUL_1C:
                    951:     /* TRY_TYPE_AORSMUL_1C same */
                    952:     e->retval = CALLING_CONVENTIONS (function)
                    953:       (e->d[0].p, e->s[0].p, size, multiplier, carry);
                    954:     break;
                    955:
                    956:   case TRY_TYPE_MUL_BASECASE:
                    957:     CALLING_CONVENTIONS (function)
                    958:       (e->d[0].p, e->s[0].p, size, e->s[1].p, size2);
                    959:     break;
                    960:   case TRY_TYPE_MUL_N:
                    961:     CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, e->s[1].p, size);
                    962:     break;
                    963:   case TRY_TYPE_SQR:
                    964:     CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size);
                    965:     break;
                    966:
                    967:   case TRY_TYPE_LSHIFT:
                    968:   case TRY_TYPE_RSHIFT:
                    969:     e->retval = CALLING_CONVENTIONS (function)
                    970:       (e->d[0].p, e->s[0].p, size, shift);
                    971:     break;
                    972:
1.1.1.2 ! maekawa   973:     /* The two casts here are necessary for _LONG_LONG_LIMB.  They might not
        !           974:        be enough if some actual calling conventions checking is implemented
        !           975:        on such a system.  */
1.1       maekawa   976:   case TRY_TYPE_POPCOUNT:
1.1.1.2 ! maekawa   977:     e->retval = (* (unsigned long (*)(ANYARGS))
        !           978:                   CALLING_CONVENTIONS (function)) (e->s[0].p, size);
1.1       maekawa   979:     break;
                    980:   case TRY_TYPE_HAMDIST:
1.1.1.2 ! maekawa   981:     e->retval = (* (unsigned long (*)(ANYARGS))
        !           982:                  CALLING_CONVENTIONS (function)) (e->s[0].p, e->s[1].p, size);
1.1       maekawa   983:     break;
                    984:
                    985:   default:
                    986:     printf ("Unknown routine type 0x%X\n", tr->flag);
                    987:     abort ();
                    988:     break;
                    989:   }
                    990: }
                    991:
                    992:
                    993: void
                    994: pointer_setup (struct each_t *e)
                    995: {
                    996:   int  i, j;
                    997:
                    998:   if (tr->flag & TRY_DOUBLE_DST)
                    999:     dsize = 2*size;
                   1000:   else if (tr->flag & (TRY_SIZE2|TRY_XSIZE))
                   1001:     dsize = size+size2;
                   1002:   else
                   1003:     dsize = size;
                   1004:
                   1005:   /* establish e->d[].p destinations */
                   1006:   for (i = 0; i < numberof (e->d); i++)
                   1007:     {
                   1008:       mp_size_t  offset = 0;
                   1009:
                   1010:       /* possible room for overlapping sources */
                   1011:       for (j = 0; j < numberof (overlap->s); j++)
                   1012:         if (overlap->s[j] == i)
                   1013:           offset = MAX (offset, s[j].align);
                   1014:
                   1015:       if (d[i].high)
                   1016:         {
                   1017:           e->d[i].p = e->d[i].region.ptr + e->d[i].region.size
                   1018:             - dsize - d[i].align;
                   1019:           if (tr->flag & TRY_OVERLAP_LOW_TO_HIGH)
                   1020:             e->d[i].p -= offset;
                   1021:         }
                   1022:       else
                   1023:         {
                   1024:           e->d[i].p = e->d[i].region.ptr + d[i].align;
                   1025:           if (tr->flag & TRY_OVERLAP_HIGH_TO_LOW)
                   1026:             e->d[i].p += offset;
                   1027:         }
                   1028:     }
                   1029:
                   1030:   /* establish e->s[].p sources */
                   1031:   for (i = 0; i < numberof (s); i++)
                   1032:     {
                   1033:       int  o = overlap->s[i];
                   1034:       switch (o) {
                   1035:       case -1:
                   1036:         /* no overlap */
                   1037:         e->s[i].p = s[i].p;
                   1038:         break;
                   1039:       case 0:
                   1040:       case 1:
                   1041:         /* overlap with d[o] */
                   1042:         if (tr->flag & TRY_OVERLAP_HIGH_TO_LOW)
                   1043:           e->s[i].p = e->d[o].p - s[i].align;
                   1044:         else if (tr->flag & TRY_OVERLAP_LOW_TO_HIGH)
                   1045:           e->s[i].p = e->d[o].p + s[i].align;
                   1046:         else if (tr->flag & TRY_XSIZE)
                   1047:           e->s[i].p = e->d[o].p + size2;
                   1048:         else
                   1049:           e->s[i].p = e->d[o].p;
                   1050:         break;
                   1051:       default:
                   1052:         abort();
                   1053:         break;
                   1054:       }
                   1055:     }
                   1056: }
                   1057:
                   1058:
                   1059: void
                   1060: try_one (void)
                   1061: {
                   1062:   int  i;
                   1063:
                   1064:   if (option_spinner)
                   1065:     spinner();
                   1066:   spinner_count++;
                   1067:
                   1068:   trap_location = TRAP_SETUPS;
                   1069:
                   1070:   for (i = 0; i < numberof (s); i++)
                   1071:     {
                   1072:       if (s[i].high)
                   1073:         s[i].p = s[i].region.ptr + s[i].region.size - SRC_SIZE(i) - s[i].align;
                   1074:       else
                   1075:         s[i].p = s[i].region.ptr + s[i].align;
                   1076:     }
                   1077:
                   1078:   pointer_setup (&ref);
                   1079:   pointer_setup (&fun);
                   1080:
                   1081:   if (tr->flag & TRY_DST0_INIT)
                   1082:     {
                   1083:       t_random (s[1].region.ptr, dsize);
                   1084:       MPN_COPY (fun.d[0].p, s[1].region.ptr, dsize);
                   1085:       MPN_COPY (ref.d[0].p, s[1].region.ptr, dsize);
                   1086:     }
                   1087:   else if (tr->flag & TRY_DST0)
                   1088:     {
                   1089:       refmpn_fill (ref.d[0].p, dsize, DEADVAL);
                   1090:       refmpn_fill (fun.d[0].p, dsize, DEADVAL);
                   1091:     }
                   1092:   for (i = 1; i < numberof (d); i++)
                   1093:     {
                   1094:       if (!(tr->flag & TRY_DST(i)))
                   1095:         continue;
                   1096:
                   1097:       refmpn_fill (ref.d[i].p, dsize, DEADVAL);
                   1098:       refmpn_fill (fun.d[i].p, dsize, DEADVAL);
                   1099:     }
                   1100:
                   1101:   ref.retval = 0x04152637;
                   1102:   fun.retval = 0x8C9DAEBF;
                   1103:
                   1104:   for (i = 0; i < numberof (s); i++)
                   1105:     {
                   1106:       if (!(tr->flag & TRY_SRC(i)))
                   1107:         continue;
                   1108:
                   1109:       mprotect_region (&s[i].region, PROT_READ|PROT_WRITE);
                   1110:       t_random (s[i].p, SRC_SIZE(i));
                   1111:
                   1112:       if (tr->flag & TRY_SRC1_GCDDATA)
                   1113:         {
                   1114:           /* s[1] no more bits than s[0] */
                   1115:           if (i == 1 && size2 == size)
                   1116:             s[1].p[size-1] &= refmpn_msbone_mask (s[0].p[size-1]);
                   1117:
                   1118:           /* normalized */
                   1119:           s[i].p[SRC_SIZE(i)-1] += (s[i].p[SRC_SIZE(i)-1] == 0);
                   1120:
                   1121:           /* odd */
                   1122:           s[i].p[0] |= 1;
                   1123:         }
                   1124:
                   1125:       mprotect_region (&s[i].region, PROT_READ);
                   1126:
                   1127:       if (ref.s[i].p != s[i].p)
                   1128:         {
                   1129:           MPN_COPY (ref.s[i].p, s[i].p, SRC_SIZE(i));
                   1130:           MPN_COPY (fun.s[i].p, s[i].p, SRC_SIZE(i));
                   1131:         }
                   1132:     }
                   1133:
                   1134:   /* special requirement of divmod_1c,divrem_1c,mod_1c */
                   1135:   if (tr->flag == TRY_TYPE_DIVMOD_1C
                   1136:       || tr->flag == TRY_TYPE_DIVREM_1C
                   1137:       || tr->flag == TRY_TYPE_MOD_1C)
                   1138:     carry %= divisor;
                   1139:
                   1140:   if (option_print)
                   1141:     print_all();
                   1142:
                   1143:   trap_location = TRAP_REF;
                   1144:   call (&ref, tr->ref.function);
                   1145:   trap_location = TRAP_FUN;
                   1146:   call (&fun, tr->fun.function);
                   1147:   trap_location = TRAP_NOWHERE;
                   1148:
                   1149:   compare ();
                   1150: }
                   1151:
                   1152:
                   1153: #define SIZE_ITERATION                                          \
                   1154:   for (size = MAX3 (option_firstsize,                           \
                   1155:                     tr->minsize,                                \
                   1156:                     (tr->flag & TRY_SIZE_ZERO) ? 0 : 1);        \
                   1157:        size <= option_lastsize;                                 \
                   1158:        size++)
                   1159:
                   1160: #define SIZE2_FIRST                             \
                   1161:   (option_firstsize2 != 0 ? option_firstsize2   \
                   1162:    : tr->flag & TRY_SIZE2 ? 1                   \
                   1163:    : tr->flag & TRY_XSIZE ? 0                   \
                   1164:    : 0)
                   1165: #define SIZE2_LAST                              \
                   1166:   (tr->flag & TRY_SIZE2 ? size                  \
                   1167:    : tr->flag & TRY_XSIZE ? XSIZE_COUNT-1       \
                   1168:    : 0)
                   1169:
                   1170: #define SIZE2_ITERATION \
                   1171:   for (size2 = SIZE2_FIRST; size2 <= SIZE2_LAST; size2++)
                   1172:
                   1173: #define ALIGN_COUNT(cond)  ((cond) ? ALIGNMENTS : 1)
                   1174: #define ALIGN_ITERATION(w,n,cond) \
                   1175:   for (w[n].align = 0; w[n].align < ALIGN_COUNT(cond); w[n].align++)
                   1176:
                   1177: #define HIGH_LIMIT(cond)  ((cond) != 0)
                   1178: #define HIGH_COUNT(cond)  (HIGH_LIMIT (cond) + 1)
                   1179: #define HIGH_ITERATION(w,n,cond) \
                   1180:   for (w[n].high = 0; w[n].high <= HIGH_LIMIT(cond); w[n].high++)
                   1181:
                   1182: #define SHIFT_LIMIT \
                   1183:   ((unsigned long) ((tr->flag & TRY_SHIFT) ? BITS_PER_MP_LIMB-1 : 1))
                   1184:
                   1185: #define SHIFT_ITERATION \
                   1186:   for (shift = 1; shift <= SHIFT_LIMIT; shift++)
                   1187:
                   1188:
                   1189: void
                   1190: try_many (void)
                   1191: {
                   1192:   int   i;
                   1193:
                   1194:   {
                   1195:     unsigned long  total = 1;
                   1196:
                   1197:     total *= option_repetitions;
                   1198:     total *= option_lastsize;
                   1199:     if (tr->flag & TRY_SIZE2) total *= (option_lastsize+1)/2;
                   1200:     if (tr->flag & TRY_XSIZE) total *= XSIZE_COUNT;
                   1201:
                   1202:     total *= SHIFT_LIMIT;
                   1203:     total *= MULTIPLIER_COUNT;
                   1204:     total *= DIVISOR_COUNT;
                   1205:     total *= CARRY_COUNT;
                   1206:     total *= T_RAND_COUNT;
                   1207:
                   1208:     total *= HIGH_COUNT (tr->flag & TRY_DST0);
                   1209:     total *= HIGH_COUNT (tr->flag & TRY_DST1);
                   1210:     total *= HIGH_COUNT (tr->flag & TRY_SRC0);
                   1211:     total *= HIGH_COUNT (tr->flag & TRY_SRC1);
                   1212:
                   1213:     total *= ALIGN_COUNT (tr->flag & TRY_DST0);
                   1214:     total *= ALIGN_COUNT (tr->flag & TRY_DST1);
                   1215:     total *= ALIGN_COUNT (tr->flag & TRY_SRC0);
                   1216:     total *= ALIGN_COUNT (tr->flag & TRY_SRC1);
                   1217:
                   1218:     total *= OVERLAP_COUNT;
                   1219:
                   1220:     printf ("%s %lu\n", tr->fun.name, total);
                   1221:   }
                   1222:
                   1223:   spinner_count = 0;
                   1224:
                   1225:   for (i = 0; i < option_repetitions; i++)
                   1226:     SIZE_ITERATION
                   1227:       SIZE2_ITERATION
                   1228:
                   1229:       SHIFT_ITERATION
                   1230:       MULTIPLIER_ITERATION
                   1231:       DIVISOR_ITERATION
                   1232:       CARRY_ITERATION /* must be after divisor */
                   1233:       T_RAND_ITERATION
                   1234:
                   1235:       HIGH_ITERATION(d,0, tr->flag & TRY_DST0)
                   1236:       HIGH_ITERATION(d,1, tr->flag & TRY_DST1)
                   1237:       HIGH_ITERATION(s,0, tr->flag & TRY_SRC0)
                   1238:       HIGH_ITERATION(s,1, tr->flag & TRY_SRC1)
                   1239:
                   1240:       ALIGN_ITERATION(d,0, tr->flag & TRY_DST0)
                   1241:       ALIGN_ITERATION(d,1, tr->flag & TRY_DST1)
                   1242:       ALIGN_ITERATION(s,0, tr->flag & TRY_SRC0)
                   1243:       ALIGN_ITERATION(s,1, tr->flag & TRY_SRC1)
                   1244:
                   1245:       OVERLAP_ITERATION
                   1246:       try_one();
                   1247:
                   1248:   printf("\n");
                   1249: }
                   1250:
                   1251:
                   1252: /* Usually print_all() doesn't show much, but it might give a hint as to
                   1253:    where the function was up to when it died. */
                   1254: void
                   1255: trap (int sig)
                   1256: {
                   1257:   const char *name = "noname";
                   1258:
                   1259:   switch (sig) {
                   1260:   case SIGILL:  name = "SIGILL";  break;
                   1261: #ifdef SIGBUS
                   1262:   case SIGBUS:  name = "SIGBUS";  break;
                   1263: #endif
                   1264:   case SIGSEGV: name = "SIGSEGV"; break;
                   1265:   case SIGFPE:  name = "SIGFPE";  break;
                   1266:   }
                   1267:
                   1268:   printf ("\n\nSIGNAL TRAP: %s\n", name);
                   1269:
                   1270:   switch (trap_location) {
                   1271:   case TRAP_REF:
                   1272:     printf ("  in reference function: %s\n", tr->ref.name);
                   1273:     break;
                   1274:   case TRAP_FUN:
                   1275:     printf ("  in test function: %s\n", tr->fun.name);
                   1276:     print_all ();
                   1277:     break;
                   1278:   case TRAP_SETUPS:
                   1279:     printf ("  in parameter setups\n");
                   1280:     print_all ();
                   1281:     break;
                   1282:   default:
                   1283:     printf ("  somewhere unknown\n");
                   1284:     break;
                   1285:   }
                   1286:   exit (1);
                   1287: }
                   1288:
                   1289:
                   1290: void
                   1291: try_init (void)
                   1292: {
                   1293: #if HAVE_GETPAGESIZE
                   1294:   /* Prefer getpagesize() over sysconf(), since on SunOS 4 sysconf() doesn't
                   1295:      know _SC_PAGESIZE. */
                   1296:   pagesize = getpagesize ();
                   1297: #else
                   1298: #if HAVE_SYSCONF
                   1299:   if ((pagesize = sysconf (_SC_PAGESIZE)) == -1)
                   1300:     {
                   1301:       /* According to the linux man page, sysconf doesn't set errno */
                   1302:       fprintf (stderr, "Cannot get sysconf _SC_PAGESIZE\n");
                   1303:       exit (1);
                   1304:     }
                   1305: #else
                   1306: Error, error, cannot get page size
                   1307: #endif
                   1308: #endif
                   1309:
                   1310:   printf ("pagesize is 0x%lX bytes\n", pagesize);
                   1311:
                   1312:   signal (SIGILL,  trap);
                   1313: #ifdef SIGBUS
                   1314:   signal (SIGBUS,  trap);
                   1315: #endif
                   1316:   signal (SIGSEGV, trap);
                   1317:   signal (SIGFPE,  trap);
                   1318:
                   1319:   {
                   1320:     int  i;
                   1321:
                   1322:     for (i = 0; i < numberof (s); i++)
                   1323:       {
                   1324:         malloc_region (&s[i].region, 2*option_lastsize+ALIGNMENTS-1);
                   1325:         printf ("s[%d] %p to %p (0x%lX bytes)\n",
                   1326:                 i, s[i].region.ptr,
                   1327:                 s[i].region.ptr + s[i].region.size,
                   1328:                 s[i].region.size * BYTES_PER_MP_LIMB);
                   1329:       }
                   1330:
                   1331: #define INIT_EACH(e,es)                                                 \
                   1332:     for (i = 0; i < numberof (e.d); i++)                                \
                   1333:       {                                                                 \
                   1334:         malloc_region (&e.d[i].region, 2*option_lastsize+ALIGNMENTS-1); \
                   1335:         printf ("%s d[%d] %p to %p (0x%lX bytes)\n",                    \
                   1336:                 es, i, e.d[i].region.ptr,                               \
                   1337:                 e.d[i].region.ptr + e.d[i].region.size,                 \
                   1338:                 e.d[i].region.size * BYTES_PER_MP_LIMB);                \
                   1339:       }
                   1340:
                   1341:     INIT_EACH(ref, "ref");
                   1342:     INIT_EACH(fun, "fun");
                   1343:   }
                   1344: }
                   1345:
                   1346: int
                   1347: strmatch_wild (const char *pattern, const char *str)
                   1348: {
                   1349:   size_t  plen, slen;
                   1350:
                   1351:   /* wildcard at start */
                   1352:   if (pattern[0] == '*')
                   1353:     {
                   1354:       pattern++;
                   1355:       plen = strlen (pattern);
                   1356:       slen = strlen (str);
                   1357:       return (plen == 0
                   1358:               || (slen >= plen && memcmp (pattern, str+slen-plen, plen) == 0));
                   1359:     }
                   1360:
                   1361:   /* wildcard at end */
                   1362:   plen = strlen (pattern);
                   1363:   if (plen >= 1 && pattern[plen-1] == '*')
                   1364:     return (memcmp (pattern, str, plen-1) == 0);
                   1365:
                   1366:   /* no wildcards */
                   1367:   return (strcmp (pattern, str) == 0);
                   1368: }
                   1369:
                   1370: void
                   1371: try_name (const char *name)
                   1372: {
                   1373:   int  found = 0;
                   1374:   int  i;
                   1375:
                   1376:   for (i = 0; i < numberof (try_array); i++)
                   1377:     {
                   1378:       if (strmatch_wild (name, try_array[i].fun.name))
                   1379:         {
                   1380:           tr = &try_array[i];
                   1381:           try_many ();
                   1382:           found = 1;
                   1383:         }
                   1384:     }
                   1385:
                   1386:   if (!found)
                   1387:     {
                   1388:       printf ("%s unknown\n", name);
                   1389:       /* exit (1); */
                   1390:     }
                   1391: }
                   1392:
                   1393:
                   1394: void
                   1395: usage (const char *prog)
                   1396: {
                   1397:   int  col = 0;
                   1398:   int  i;
                   1399:
                   1400:   printf ("Usage: %s [options] function...\n\
                   1401:     -1        use limb data 1,2,3,etc\n\
                   1402:     -9        use limb data all 0xFF..FFs\n\
                   1403:     -a zeros  use limb data all zeros\n\
                   1404:     -a ffs    use limb data all 0xFF..FFs (same as -9)\n\
                   1405:     -a 2fd    use data 0x2FFF...FFFD\n\
                   1406:     -p        print each case tried (try this if seg faulting)\n\
                   1407:     -R        seed random numbers from time()\n\
                   1408:     -r reps   set repetitions (default %d)\n\
                   1409:     -S seed   randomize from given seed\n\
                   1410:     -s size   starting size to test\n\
                   1411:     -s s1-s2  range of sizes to test\n\
                   1412:     -W        don't show the spinner (use this in gdb)\n\
                   1413:     -z        disable mprotect() redzones\n\
                   1414: Default data is mpn_random() and mpn_random2().\n\
                   1415: \n\
                   1416: Functions that can be tested:\n\
                   1417: ", prog, DEFAULT_REPETITIONS);
                   1418:
                   1419:   for (i = 0; i < numberof (try_array); i++)
                   1420:     {
                   1421:       if (col + 1 + strlen (try_array[i].fun.name) > 79)
                   1422:         {
                   1423:           printf ("\n");
                   1424:           col = 0;
                   1425:         }
                   1426:       printf (" %s", try_array[i].fun.name);
                   1427:       col += 1 + strlen (try_array[i].fun.name);
                   1428:     }
                   1429:   printf ("\n");
                   1430:
                   1431:   exit(1);
                   1432: }
                   1433:
                   1434:
                   1435: int
                   1436: main (int argc, char *argv[])
                   1437: {
                   1438:   int  i;
                   1439:
                   1440:   /* unbuffered output */
                   1441:   setbuf (stdout, NULL);
                   1442:   setbuf (stderr, NULL);
                   1443:
                   1444:   /* always trace in hex, upper-case so can paste into bc */
                   1445:   mp_trace_base = -16;
                   1446:
                   1447:   {
                   1448:     unsigned  seed = 123;
                   1449:     int   opt;
                   1450:
                   1451:     while ((opt = getopt(argc, argv, "19a:pRr:S:s:Wz")) != EOF)
                   1452:       {
                   1453:         switch (opt) {
                   1454:         case '1':
                   1455:           /* use limb data values 1, 2, 3, ... etc */
                   1456:           option_data = DATA_SEQ;
                   1457:           break;
                   1458:         case '9':
                   1459:           /* use limb data values 0xFFF...FFF always */
                   1460:           option_data = DATA_FFS;
                   1461:           break;
                   1462:         case 'a':
                   1463:           if (strcmp (optarg, "zeros") == 0)     option_data = DATA_ZEROS;
                   1464:           else if (strcmp (optarg, "seq") == 0)  option_data = DATA_SEQ;
                   1465:           else if (strcmp (optarg, "ffs") == 0)  option_data = DATA_FFS;
                   1466:           else if (strcmp (optarg, "2fd") == 0)  option_data = DATA_2FD;
                   1467:           else
                   1468:             {
                   1469:               fprintf (stderr, "unrecognised data option: %s\n", optarg);
                   1470:               exit (1);
                   1471:             }
                   1472:           break;
                   1473:         case 'p':
                   1474:           option_print = 1;
                   1475:           break;
                   1476:         case 'R':
                   1477:           /* randomize */
                   1478:          seed = time (NULL);
                   1479:           break;
                   1480:         case 'r':
                   1481:          option_repetitions = atoi (optarg);
                   1482:           break;
                   1483:         case 's':
                   1484:           {
                   1485:             char  *p;
                   1486:             option_firstsize = atoi (optarg);
                   1487:             if ((p = strchr (optarg, '-')) != NULL)
                   1488:               option_lastsize = atoi (p+1);
                   1489:           }
                   1490:           break;
                   1491:         case 'S':
                   1492:           /* -S <size> sets the starting size for the second of a two size
                   1493:              routine (like mpn_mul_basecase) */
                   1494:          option_firstsize2 = atoi (optarg);
                   1495:           break;
                   1496:         case 'W':
                   1497:           /* use this when running in the debugger */
                   1498:           option_spinner = 0;
                   1499:           break;
                   1500:         case 'z':
                   1501:           /* disable redzones */
                   1502:           option_redzones = 0;
                   1503:           break;
                   1504:         case '?':
                   1505:           usage (argv[0]);
                   1506:           break;
                   1507:         }
                   1508:       }
                   1509:
                   1510:     srandom (seed);
                   1511:   }
                   1512:
                   1513:   try_init();
                   1514:
                   1515:   if (argc <= optind)
                   1516:     usage (argv[0]);
                   1517:
                   1518:   for (i = optind; i < argc; i++)
                   1519:     try_name (argv[i]);
                   1520:
                   1521:   return 0;
                   1522: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>