Annotation of OpenXM_contrib/gmp/mpn/tests/try.c, Revision 1.1
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:
! 973: case TRY_TYPE_POPCOUNT:
! 974: e->retval = CALLING_CONVENTIONS (function) (e->s[0].p, size);
! 975: break;
! 976: case TRY_TYPE_HAMDIST:
! 977: e->retval = CALLING_CONVENTIONS (function) (e->s[0].p, e->s[1].p, size);
! 978: break;
! 979:
! 980: default:
! 981: printf ("Unknown routine type 0x%X\n", tr->flag);
! 982: abort ();
! 983: break;
! 984: }
! 985: }
! 986:
! 987:
! 988: void
! 989: pointer_setup (struct each_t *e)
! 990: {
! 991: int i, j;
! 992:
! 993: if (tr->flag & TRY_DOUBLE_DST)
! 994: dsize = 2*size;
! 995: else if (tr->flag & (TRY_SIZE2|TRY_XSIZE))
! 996: dsize = size+size2;
! 997: else
! 998: dsize = size;
! 999:
! 1000: /* establish e->d[].p destinations */
! 1001: for (i = 0; i < numberof (e->d); i++)
! 1002: {
! 1003: mp_size_t offset = 0;
! 1004:
! 1005: /* possible room for overlapping sources */
! 1006: for (j = 0; j < numberof (overlap->s); j++)
! 1007: if (overlap->s[j] == i)
! 1008: offset = MAX (offset, s[j].align);
! 1009:
! 1010: if (d[i].high)
! 1011: {
! 1012: e->d[i].p = e->d[i].region.ptr + e->d[i].region.size
! 1013: - dsize - d[i].align;
! 1014: if (tr->flag & TRY_OVERLAP_LOW_TO_HIGH)
! 1015: e->d[i].p -= offset;
! 1016: }
! 1017: else
! 1018: {
! 1019: e->d[i].p = e->d[i].region.ptr + d[i].align;
! 1020: if (tr->flag & TRY_OVERLAP_HIGH_TO_LOW)
! 1021: e->d[i].p += offset;
! 1022: }
! 1023: }
! 1024:
! 1025: /* establish e->s[].p sources */
! 1026: for (i = 0; i < numberof (s); i++)
! 1027: {
! 1028: int o = overlap->s[i];
! 1029: switch (o) {
! 1030: case -1:
! 1031: /* no overlap */
! 1032: e->s[i].p = s[i].p;
! 1033: break;
! 1034: case 0:
! 1035: case 1:
! 1036: /* overlap with d[o] */
! 1037: if (tr->flag & TRY_OVERLAP_HIGH_TO_LOW)
! 1038: e->s[i].p = e->d[o].p - s[i].align;
! 1039: else if (tr->flag & TRY_OVERLAP_LOW_TO_HIGH)
! 1040: e->s[i].p = e->d[o].p + s[i].align;
! 1041: else if (tr->flag & TRY_XSIZE)
! 1042: e->s[i].p = e->d[o].p + size2;
! 1043: else
! 1044: e->s[i].p = e->d[o].p;
! 1045: break;
! 1046: default:
! 1047: abort();
! 1048: break;
! 1049: }
! 1050: }
! 1051: }
! 1052:
! 1053:
! 1054: void
! 1055: try_one (void)
! 1056: {
! 1057: int i;
! 1058:
! 1059: if (option_spinner)
! 1060: spinner();
! 1061: spinner_count++;
! 1062:
! 1063: trap_location = TRAP_SETUPS;
! 1064:
! 1065: for (i = 0; i < numberof (s); i++)
! 1066: {
! 1067: if (s[i].high)
! 1068: s[i].p = s[i].region.ptr + s[i].region.size - SRC_SIZE(i) - s[i].align;
! 1069: else
! 1070: s[i].p = s[i].region.ptr + s[i].align;
! 1071: }
! 1072:
! 1073: pointer_setup (&ref);
! 1074: pointer_setup (&fun);
! 1075:
! 1076: if (tr->flag & TRY_DST0_INIT)
! 1077: {
! 1078: t_random (s[1].region.ptr, dsize);
! 1079: MPN_COPY (fun.d[0].p, s[1].region.ptr, dsize);
! 1080: MPN_COPY (ref.d[0].p, s[1].region.ptr, dsize);
! 1081: }
! 1082: else if (tr->flag & TRY_DST0)
! 1083: {
! 1084: refmpn_fill (ref.d[0].p, dsize, DEADVAL);
! 1085: refmpn_fill (fun.d[0].p, dsize, DEADVAL);
! 1086: }
! 1087: for (i = 1; i < numberof (d); i++)
! 1088: {
! 1089: if (!(tr->flag & TRY_DST(i)))
! 1090: continue;
! 1091:
! 1092: refmpn_fill (ref.d[i].p, dsize, DEADVAL);
! 1093: refmpn_fill (fun.d[i].p, dsize, DEADVAL);
! 1094: }
! 1095:
! 1096: ref.retval = 0x04152637;
! 1097: fun.retval = 0x8C9DAEBF;
! 1098:
! 1099: for (i = 0; i < numberof (s); i++)
! 1100: {
! 1101: if (!(tr->flag & TRY_SRC(i)))
! 1102: continue;
! 1103:
! 1104: mprotect_region (&s[i].region, PROT_READ|PROT_WRITE);
! 1105: t_random (s[i].p, SRC_SIZE(i));
! 1106:
! 1107: if (tr->flag & TRY_SRC1_GCDDATA)
! 1108: {
! 1109: /* s[1] no more bits than s[0] */
! 1110: if (i == 1 && size2 == size)
! 1111: s[1].p[size-1] &= refmpn_msbone_mask (s[0].p[size-1]);
! 1112:
! 1113: /* normalized */
! 1114: s[i].p[SRC_SIZE(i)-1] += (s[i].p[SRC_SIZE(i)-1] == 0);
! 1115:
! 1116: /* odd */
! 1117: s[i].p[0] |= 1;
! 1118: }
! 1119:
! 1120: mprotect_region (&s[i].region, PROT_READ);
! 1121:
! 1122: if (ref.s[i].p != s[i].p)
! 1123: {
! 1124: MPN_COPY (ref.s[i].p, s[i].p, SRC_SIZE(i));
! 1125: MPN_COPY (fun.s[i].p, s[i].p, SRC_SIZE(i));
! 1126: }
! 1127: }
! 1128:
! 1129: /* special requirement of divmod_1c,divrem_1c,mod_1c */
! 1130: if (tr->flag == TRY_TYPE_DIVMOD_1C
! 1131: || tr->flag == TRY_TYPE_DIVREM_1C
! 1132: || tr->flag == TRY_TYPE_MOD_1C)
! 1133: carry %= divisor;
! 1134:
! 1135: if (option_print)
! 1136: print_all();
! 1137:
! 1138: trap_location = TRAP_REF;
! 1139: call (&ref, tr->ref.function);
! 1140: trap_location = TRAP_FUN;
! 1141: call (&fun, tr->fun.function);
! 1142: trap_location = TRAP_NOWHERE;
! 1143:
! 1144: compare ();
! 1145: }
! 1146:
! 1147:
! 1148: #define SIZE_ITERATION \
! 1149: for (size = MAX3 (option_firstsize, \
! 1150: tr->minsize, \
! 1151: (tr->flag & TRY_SIZE_ZERO) ? 0 : 1); \
! 1152: size <= option_lastsize; \
! 1153: size++)
! 1154:
! 1155: #define SIZE2_FIRST \
! 1156: (option_firstsize2 != 0 ? option_firstsize2 \
! 1157: : tr->flag & TRY_SIZE2 ? 1 \
! 1158: : tr->flag & TRY_XSIZE ? 0 \
! 1159: : 0)
! 1160: #define SIZE2_LAST \
! 1161: (tr->flag & TRY_SIZE2 ? size \
! 1162: : tr->flag & TRY_XSIZE ? XSIZE_COUNT-1 \
! 1163: : 0)
! 1164:
! 1165: #define SIZE2_ITERATION \
! 1166: for (size2 = SIZE2_FIRST; size2 <= SIZE2_LAST; size2++)
! 1167:
! 1168: #define ALIGN_COUNT(cond) ((cond) ? ALIGNMENTS : 1)
! 1169: #define ALIGN_ITERATION(w,n,cond) \
! 1170: for (w[n].align = 0; w[n].align < ALIGN_COUNT(cond); w[n].align++)
! 1171:
! 1172: #define HIGH_LIMIT(cond) ((cond) != 0)
! 1173: #define HIGH_COUNT(cond) (HIGH_LIMIT (cond) + 1)
! 1174: #define HIGH_ITERATION(w,n,cond) \
! 1175: for (w[n].high = 0; w[n].high <= HIGH_LIMIT(cond); w[n].high++)
! 1176:
! 1177: #define SHIFT_LIMIT \
! 1178: ((unsigned long) ((tr->flag & TRY_SHIFT) ? BITS_PER_MP_LIMB-1 : 1))
! 1179:
! 1180: #define SHIFT_ITERATION \
! 1181: for (shift = 1; shift <= SHIFT_LIMIT; shift++)
! 1182:
! 1183:
! 1184: void
! 1185: try_many (void)
! 1186: {
! 1187: int i;
! 1188:
! 1189: {
! 1190: unsigned long total = 1;
! 1191:
! 1192: total *= option_repetitions;
! 1193: total *= option_lastsize;
! 1194: if (tr->flag & TRY_SIZE2) total *= (option_lastsize+1)/2;
! 1195: if (tr->flag & TRY_XSIZE) total *= XSIZE_COUNT;
! 1196:
! 1197: total *= SHIFT_LIMIT;
! 1198: total *= MULTIPLIER_COUNT;
! 1199: total *= DIVISOR_COUNT;
! 1200: total *= CARRY_COUNT;
! 1201: total *= T_RAND_COUNT;
! 1202:
! 1203: total *= HIGH_COUNT (tr->flag & TRY_DST0);
! 1204: total *= HIGH_COUNT (tr->flag & TRY_DST1);
! 1205: total *= HIGH_COUNT (tr->flag & TRY_SRC0);
! 1206: total *= HIGH_COUNT (tr->flag & TRY_SRC1);
! 1207:
! 1208: total *= ALIGN_COUNT (tr->flag & TRY_DST0);
! 1209: total *= ALIGN_COUNT (tr->flag & TRY_DST1);
! 1210: total *= ALIGN_COUNT (tr->flag & TRY_SRC0);
! 1211: total *= ALIGN_COUNT (tr->flag & TRY_SRC1);
! 1212:
! 1213: total *= OVERLAP_COUNT;
! 1214:
! 1215: printf ("%s %lu\n", tr->fun.name, total);
! 1216: }
! 1217:
! 1218: spinner_count = 0;
! 1219:
! 1220: for (i = 0; i < option_repetitions; i++)
! 1221: SIZE_ITERATION
! 1222: SIZE2_ITERATION
! 1223:
! 1224: SHIFT_ITERATION
! 1225: MULTIPLIER_ITERATION
! 1226: DIVISOR_ITERATION
! 1227: CARRY_ITERATION /* must be after divisor */
! 1228: T_RAND_ITERATION
! 1229:
! 1230: HIGH_ITERATION(d,0, tr->flag & TRY_DST0)
! 1231: HIGH_ITERATION(d,1, tr->flag & TRY_DST1)
! 1232: HIGH_ITERATION(s,0, tr->flag & TRY_SRC0)
! 1233: HIGH_ITERATION(s,1, tr->flag & TRY_SRC1)
! 1234:
! 1235: ALIGN_ITERATION(d,0, tr->flag & TRY_DST0)
! 1236: ALIGN_ITERATION(d,1, tr->flag & TRY_DST1)
! 1237: ALIGN_ITERATION(s,0, tr->flag & TRY_SRC0)
! 1238: ALIGN_ITERATION(s,1, tr->flag & TRY_SRC1)
! 1239:
! 1240: OVERLAP_ITERATION
! 1241: try_one();
! 1242:
! 1243: printf("\n");
! 1244: }
! 1245:
! 1246:
! 1247: /* Usually print_all() doesn't show much, but it might give a hint as to
! 1248: where the function was up to when it died. */
! 1249: void
! 1250: trap (int sig)
! 1251: {
! 1252: const char *name = "noname";
! 1253:
! 1254: switch (sig) {
! 1255: case SIGILL: name = "SIGILL"; break;
! 1256: #ifdef SIGBUS
! 1257: case SIGBUS: name = "SIGBUS"; break;
! 1258: #endif
! 1259: case SIGSEGV: name = "SIGSEGV"; break;
! 1260: case SIGFPE: name = "SIGFPE"; break;
! 1261: }
! 1262:
! 1263: printf ("\n\nSIGNAL TRAP: %s\n", name);
! 1264:
! 1265: switch (trap_location) {
! 1266: case TRAP_REF:
! 1267: printf (" in reference function: %s\n", tr->ref.name);
! 1268: break;
! 1269: case TRAP_FUN:
! 1270: printf (" in test function: %s\n", tr->fun.name);
! 1271: print_all ();
! 1272: break;
! 1273: case TRAP_SETUPS:
! 1274: printf (" in parameter setups\n");
! 1275: print_all ();
! 1276: break;
! 1277: default:
! 1278: printf (" somewhere unknown\n");
! 1279: break;
! 1280: }
! 1281: exit (1);
! 1282: }
! 1283:
! 1284:
! 1285: void
! 1286: try_init (void)
! 1287: {
! 1288: #if HAVE_GETPAGESIZE
! 1289: /* Prefer getpagesize() over sysconf(), since on SunOS 4 sysconf() doesn't
! 1290: know _SC_PAGESIZE. */
! 1291: pagesize = getpagesize ();
! 1292: #else
! 1293: #if HAVE_SYSCONF
! 1294: if ((pagesize = sysconf (_SC_PAGESIZE)) == -1)
! 1295: {
! 1296: /* According to the linux man page, sysconf doesn't set errno */
! 1297: fprintf (stderr, "Cannot get sysconf _SC_PAGESIZE\n");
! 1298: exit (1);
! 1299: }
! 1300: #else
! 1301: Error, error, cannot get page size
! 1302: #endif
! 1303: #endif
! 1304:
! 1305: printf ("pagesize is 0x%lX bytes\n", pagesize);
! 1306:
! 1307: signal (SIGILL, trap);
! 1308: #ifdef SIGBUS
! 1309: signal (SIGBUS, trap);
! 1310: #endif
! 1311: signal (SIGSEGV, trap);
! 1312: signal (SIGFPE, trap);
! 1313:
! 1314: {
! 1315: int i;
! 1316:
! 1317: for (i = 0; i < numberof (s); i++)
! 1318: {
! 1319: malloc_region (&s[i].region, 2*option_lastsize+ALIGNMENTS-1);
! 1320: printf ("s[%d] %p to %p (0x%lX bytes)\n",
! 1321: i, s[i].region.ptr,
! 1322: s[i].region.ptr + s[i].region.size,
! 1323: s[i].region.size * BYTES_PER_MP_LIMB);
! 1324: }
! 1325:
! 1326: #define INIT_EACH(e,es) \
! 1327: for (i = 0; i < numberof (e.d); i++) \
! 1328: { \
! 1329: malloc_region (&e.d[i].region, 2*option_lastsize+ALIGNMENTS-1); \
! 1330: printf ("%s d[%d] %p to %p (0x%lX bytes)\n", \
! 1331: es, i, e.d[i].region.ptr, \
! 1332: e.d[i].region.ptr + e.d[i].region.size, \
! 1333: e.d[i].region.size * BYTES_PER_MP_LIMB); \
! 1334: }
! 1335:
! 1336: INIT_EACH(ref, "ref");
! 1337: INIT_EACH(fun, "fun");
! 1338: }
! 1339: }
! 1340:
! 1341: int
! 1342: strmatch_wild (const char *pattern, const char *str)
! 1343: {
! 1344: size_t plen, slen;
! 1345:
! 1346: /* wildcard at start */
! 1347: if (pattern[0] == '*')
! 1348: {
! 1349: pattern++;
! 1350: plen = strlen (pattern);
! 1351: slen = strlen (str);
! 1352: return (plen == 0
! 1353: || (slen >= plen && memcmp (pattern, str+slen-plen, plen) == 0));
! 1354: }
! 1355:
! 1356: /* wildcard at end */
! 1357: plen = strlen (pattern);
! 1358: if (plen >= 1 && pattern[plen-1] == '*')
! 1359: return (memcmp (pattern, str, plen-1) == 0);
! 1360:
! 1361: /* no wildcards */
! 1362: return (strcmp (pattern, str) == 0);
! 1363: }
! 1364:
! 1365: void
! 1366: try_name (const char *name)
! 1367: {
! 1368: int found = 0;
! 1369: int i;
! 1370:
! 1371: for (i = 0; i < numberof (try_array); i++)
! 1372: {
! 1373: if (strmatch_wild (name, try_array[i].fun.name))
! 1374: {
! 1375: tr = &try_array[i];
! 1376: try_many ();
! 1377: found = 1;
! 1378: }
! 1379: }
! 1380:
! 1381: if (!found)
! 1382: {
! 1383: printf ("%s unknown\n", name);
! 1384: /* exit (1); */
! 1385: }
! 1386: }
! 1387:
! 1388:
! 1389: void
! 1390: usage (const char *prog)
! 1391: {
! 1392: int col = 0;
! 1393: int i;
! 1394:
! 1395: printf ("Usage: %s [options] function...\n\
! 1396: -1 use limb data 1,2,3,etc\n\
! 1397: -9 use limb data all 0xFF..FFs\n\
! 1398: -a zeros use limb data all zeros\n\
! 1399: -a ffs use limb data all 0xFF..FFs (same as -9)\n\
! 1400: -a 2fd use data 0x2FFF...FFFD\n\
! 1401: -p print each case tried (try this if seg faulting)\n\
! 1402: -R seed random numbers from time()\n\
! 1403: -r reps set repetitions (default %d)\n\
! 1404: -S seed randomize from given seed\n\
! 1405: -s size starting size to test\n\
! 1406: -s s1-s2 range of sizes to test\n\
! 1407: -W don't show the spinner (use this in gdb)\n\
! 1408: -z disable mprotect() redzones\n\
! 1409: Default data is mpn_random() and mpn_random2().\n\
! 1410: \n\
! 1411: Functions that can be tested:\n\
! 1412: ", prog, DEFAULT_REPETITIONS);
! 1413:
! 1414: for (i = 0; i < numberof (try_array); i++)
! 1415: {
! 1416: if (col + 1 + strlen (try_array[i].fun.name) > 79)
! 1417: {
! 1418: printf ("\n");
! 1419: col = 0;
! 1420: }
! 1421: printf (" %s", try_array[i].fun.name);
! 1422: col += 1 + strlen (try_array[i].fun.name);
! 1423: }
! 1424: printf ("\n");
! 1425:
! 1426: exit(1);
! 1427: }
! 1428:
! 1429:
! 1430: int
! 1431: main (int argc, char *argv[])
! 1432: {
! 1433: int i;
! 1434:
! 1435: /* unbuffered output */
! 1436: setbuf (stdout, NULL);
! 1437: setbuf (stderr, NULL);
! 1438:
! 1439: /* always trace in hex, upper-case so can paste into bc */
! 1440: mp_trace_base = -16;
! 1441:
! 1442: {
! 1443: unsigned seed = 123;
! 1444: int opt;
! 1445:
! 1446: while ((opt = getopt(argc, argv, "19a:pRr:S:s:Wz")) != EOF)
! 1447: {
! 1448: switch (opt) {
! 1449: case '1':
! 1450: /* use limb data values 1, 2, 3, ... etc */
! 1451: option_data = DATA_SEQ;
! 1452: break;
! 1453: case '9':
! 1454: /* use limb data values 0xFFF...FFF always */
! 1455: option_data = DATA_FFS;
! 1456: break;
! 1457: case 'a':
! 1458: if (strcmp (optarg, "zeros") == 0) option_data = DATA_ZEROS;
! 1459: else if (strcmp (optarg, "seq") == 0) option_data = DATA_SEQ;
! 1460: else if (strcmp (optarg, "ffs") == 0) option_data = DATA_FFS;
! 1461: else if (strcmp (optarg, "2fd") == 0) option_data = DATA_2FD;
! 1462: else
! 1463: {
! 1464: fprintf (stderr, "unrecognised data option: %s\n", optarg);
! 1465: exit (1);
! 1466: }
! 1467: break;
! 1468: case 'p':
! 1469: option_print = 1;
! 1470: break;
! 1471: case 'R':
! 1472: /* randomize */
! 1473: seed = time (NULL);
! 1474: break;
! 1475: case 'r':
! 1476: option_repetitions = atoi (optarg);
! 1477: break;
! 1478: case 's':
! 1479: {
! 1480: char *p;
! 1481: option_firstsize = atoi (optarg);
! 1482: if ((p = strchr (optarg, '-')) != NULL)
! 1483: option_lastsize = atoi (p+1);
! 1484: }
! 1485: break;
! 1486: case 'S':
! 1487: /* -S <size> sets the starting size for the second of a two size
! 1488: routine (like mpn_mul_basecase) */
! 1489: option_firstsize2 = atoi (optarg);
! 1490: break;
! 1491: case 'W':
! 1492: /* use this when running in the debugger */
! 1493: option_spinner = 0;
! 1494: break;
! 1495: case 'z':
! 1496: /* disable redzones */
! 1497: option_redzones = 0;
! 1498: break;
! 1499: case '?':
! 1500: usage (argv[0]);
! 1501: break;
! 1502: }
! 1503: }
! 1504:
! 1505: srandom (seed);
! 1506: }
! 1507:
! 1508: try_init();
! 1509:
! 1510: if (argc <= optind)
! 1511: usage (argv[0]);
! 1512:
! 1513: for (i = optind; i < argc; i++)
! 1514: try_name (argv[i]);
! 1515:
! 1516: return 0;
! 1517: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>