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>