Home | History | Annotate | Line # | Download | only in tune
many.pl revision 1.1.1.2
      1 #! /usr/bin/perl -w
      2 
      3 # Copyright 2000-2002 Free Software Foundation, Inc.
      4 #
      5 #  This file is part of the GNU MP Library.
      6 #
      7 #  The GNU MP Library is free software; you can redistribute it and/or modify
      8 #  it under the terms of either:
      9 #
     10 #    * the GNU Lesser General Public License as published by the Free
     11 #      Software Foundation; either version 3 of the License, or (at your
     12 #      option) any later version.
     13 #
     14 #  or
     15 #
     16 #    * the GNU General Public License as published by the Free Software
     17 #      Foundation; either version 2 of the License, or (at your option) any
     18 #      later version.
     19 #
     20 #  or both in parallel, as here.
     21 #
     22 #  The GNU MP Library is distributed in the hope that it will be useful, but
     23 #  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     24 #  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     25 #  for more details.
     26 #
     27 #  You should have received copies of the GNU General Public License and the
     28 #  GNU Lesser General Public License along with the GNU MP Library.  If not,
     29 #  see https://www.gnu.org/licenses/.
     30 
     31 
     32 # Usage:  cd $builddir/tune
     33 #	  perl $srcdir/tune/many.pl [-t] <files/dirs>...
     34 #
     35 # Output: speed-many.c
     36 #         try-many.c
     37 #         Makefile.many
     38 #
     39 # Make alternate versions of various mpn routines available for measuring
     40 # and testing.
     41 #
     42 # The $srcdir and $builddir in the invocation above just means the script
     43 # lives in the tune source directory, but should be run in the tune build
     44 # directory.  When not using a separate object directory this just becomes
     45 #
     46 #	cd tune
     47 #	perl many.pl [-t] <files/dirs>...
     48 #
     49 #
     50 # SINGLE FILES
     51 #
     52 # Suppose $HOME/newcode/mul_1_experiment.asm is a new implementation of
     53 # mpn_mul_1, then
     54 #
     55 #	cd $builddir/tune
     56 #	perl $srcdir/tune/many.pl $HOME/newcode/mul_1_experiment.asm
     57 #
     58 # will produce rules and renaming so that a speed program incorporating it
     59 # can be built,
     60 #
     61 #	make -f Makefile.many speed-many
     62 #
     63 # then for example it can be compared to the standard mul_1,
     64 #
     65 #	./speed-many -s 1-30 mpn_mul_1 mpn_mul_1_experiment
     66 #
     67 # An expanded try program can be used to check correctness,
     68 #
     69 #	make -f Makefile.many try-many
     70 #
     71 # and run
     72 #
     73 #	./try-many mpn_mul_1_experiment
     74 #
     75 # Files can be ".c", ".S" or ".asm".  ".s" files can't be used because they
     76 # don't get any preprocessing so there's no way to do renaming of their
     77 # functions.
     78 #
     79 #
     80 # WHOLE DIRECTORIES
     81 #
     82 # If a directory is given, then all files in it will be made available.
     83 # For example,
     84 #
     85 #	cd $builddir/tune
     86 #	perl $srcdir/tune/many.pl $HOME/newcode
     87 #
     88 # Each file should have a suffix, like "_experiment" above.
     89 #
     90 #
     91 # MPN DIRECTORIES
     92 #
     93 # mpn directories from the GMP source tree can be included, and this is a
     94 # convenient way to compare multiple implementations suiting different chips
     95 # in a CPU family.  For example the following would make all x86 routines
     96 # available,
     97 #
     98 #	cd $builddir/tune
     99 #	perl $srcdir/tune/many.pl `find $srcdir/mpn/x86 -type d`
    100 #
    101 # On a new x86 chip a comparison could then be made to see how existing code
    102 # runs.  For example,
    103 #
    104 #	make -f Makefile.many speed-many
    105 #	./speed-many -s 1-30 -c \
    106 #		mpn_add_n_x86 mpn_add_n_pentium mpn_add_n_k6 mpn_add_n_k7
    107 #
    108 # Files in "mpn" subdirectories don't need the "_experiment" style suffix
    109 # described above, instead a suffix is constructed from the subdirectory.
    110 # For example "mpn/x86/k7/mmx/mod_1.asm" will generate a function
    111 # mpn_mod_1_k7_mmx.  The rule is to take the last directory name after the
    112 # "mpn", or the last two if there's three or more.  (Check the generated
    113 # speed-many.c if in doubt.)
    114 #
    115 #
    116 # GENERIC C
    117 #
    118 # The mpn/generic directory can be included too, just like any processor
    119 # specific directory.  This is a good way to compare assembler and generic C
    120 # implementations.  For example,
    121 #
    122 #	cd $builddir/tune
    123 #	perl $srcdir/tune/many.pl $srcdir/mpn/generic
    124 #
    125 # or if just a few routines are of interest, then for example
    126 #
    127 #	cd $builddir/tune
    128 #	perl $srcdir/tune/many.pl \
    129 #		$srcdir/mpn/generic/lshift.c \
    130 #		$srcdir/mpn/generic/mod_1.c \
    131 #		$srcdir/mpn/generic/aorsmul_1.c
    132 #
    133 # giving mpn_lshift_generic etc.
    134 #
    135 #
    136 # TESTS/DEVEL PROGRAMS
    137 #
    138 # Makefile.many also has rules to build the tests/devel programs with suitable
    139 # renaming, and with some parameters for correctness or speed.  This is less
    140 # convenient than the speed and try programs, but provides an independent
    141 # check.  For example,
    142 #
    143 #	make -f Makefile.many tests_mul_1_experimental
    144 #	./tests_mul_1_experimental
    145 #
    146 # and for speed
    147 #
    148 #	make -f Makefile.many tests_mul_1_experimental_sp
    149 #	./tests_mul_1_experimental_sp
    150 #
    151 # Not all the programs support speed measuring, in which case only the
    152 # correctness test will be useful.
    153 #
    154 # The parameters for repetitions and host clock speed are -D defines.  Some
    155 # defaults are provided at the end of Makefile.many, but probably these will
    156 # want to be overridden.  For example,
    157 #
    158 #	rm tests_mul_1_experimental.o
    159 #	make -f Makefile.many \
    160 #	   CFLAGS_TESTS="-DSIZE=50 -DTIMES=1000 -DRANDOM -DCLOCK=175000000" \
    161 #	   tests_mul_1_experimental
    162 #	./tests_mul_1_experimental
    163 #
    164 #
    165 # OTHER NOTES
    166 #
    167 # The mappings of file names to functions, and the macros to then use for
    168 # speed measuring etc are driven by @table below.  The scheme isn't
    169 # completely general, it's only got as many variations as have been needed
    170 # so far.
    171 #
    172 # Some functions are only made available in speed-many, or others only in
    173 # try-many.  An @table entry speed=>none means no speed measuring is
    174 # available, or try=>none no try program testing.  These can be removed
    175 # if/when the respective programs get the necessary support.
    176 #
    177 # If a file has "1c" or "nc" carry-in entrypoints, they're renamed and made
    178 # available too.  These are recognised from PROLOGUE or MULFUNC_PROLOGUE in
    179 # .S and .asm files, or from a line starting with "mpn_foo_1c" in a .c file
    180 # (possibly via a #define), and on that basis are entirely optional.  This
    181 # entrypoint matching is done for the standard entrypoints too, but it would
    182 # be very unusual to have for instance a mul_1c without a mul_1.
    183 #
    184 # Some mpz files are recognized.  For example an experimental copy of
    185 # mpz/powm.c could be included as powm_new.c and would be called
    186 # mpz_powm_new.  So far only speed measuring is available for these.
    187 #
    188 # For the ".S" and ".asm" files, both PIC and non-PIC objects are built.
    189 # The PIC functions have a "_pic" suffix, for example "mpn_mod_1_k7_mmx_pic".
    190 # This can be ignored for routines that don't differ for PIC, or for CPUs
    191 # where everything is PIC anyway.
    192 #
    193 # K&R compilers are supported via the same ansi2knr mechanism used by
    194 # automake, though it's hard to believe anyone will have much interest in
    195 # measuring a compiler so old that it doesn't even have an ANSI mode.
    196 #
    197 # The "-t" option can be used to print a trace of the files found and what's
    198 # done with them.  A great deal of obscure output is produced, but it can
    199 # indicate where or why some files aren't being recognised etc.  For
    200 # example,
    201 #
    202 #	cd $builddir/tune
    203 #	perl $srcdir/tune/many.pl -t $HOME/newcode/add_n_weird.asm
    204 #
    205 # In general, when including new code, all that's really necessary is that
    206 # it will compile or assemble under the current configuration.  It's fine if
    207 # some code doesn't actually run due to bugs, or to needing a newer CPU or
    208 # whatever, simply don't ask for the offending routines when invoking
    209 # speed-many or try-many, or don't try to run them on sizes they don't yet
    210 # support, or whatever.
    211 #
    212 #
    213 # CPU SPECIFICS
    214 #
    215 # x86 - All the x86 code will assemble on any system, but code for newer
    216 #       chips might not run on older chips.  Expect SIGILLs from new
    217 #       instructions on old chips.
    218 #
    219 #       A few "new" instructions, like cmov for instance, are done as macros
    220 #       and will generate some equivalent plain i386 code when HAVE_HOST_CPU
    221 #       in config.m4 indicates an old CPU.  It won't run fast, but it does
    222 #       make it possible to test correctness.
    223 #
    224 #
    225 # INTERNALS
    226 #
    227 # The nonsense involving $ENV is some hooks used during development to add
    228 # additional functions temporarily.
    229 #
    230 #
    231 # FUTURE
    232 #
    233 # Maybe the C files should be compiled pic and non-pic too.  Wait until
    234 # there's a difference that might be of interest.
    235 #
    236 # Warn if a file provides no functions.
    237 #
    238 # Allow mpz and mpn files of the same name.  Currently the mpn fib2_ui
    239 # matching hides the mpz version of that.  Will need to check the file
    240 # contents to see which it is.  Would be worth allowing an "mpz_" or "mpn_"
    241 # prefix on the filenames to have working versions of both in one directory.
    242 #
    243 #
    244 # LIMITATIONS
    245 #
    246 # Some of the command lines can become very long when a lot of files are
    247 # included.  If this is a problem on a given system the only suggestion is
    248 # to run many.pl for just those that are actually wanted at a particular
    249 # time.
    250 #
    251 # DOS 8.3 or SysV 14 char filesystems won't work, since the long filenames
    252 # generated will almost certainly fail to be unique.
    253 
    254 
    255 use strict;
    256 use File::Basename;
    257 use Getopt::Std;
    258 
    259 my %opt;
    260 getopts('t', \%opt);
    261 
    262 my @DIRECTORIES = @ARGV;
    263 if (defined $ENV{directories}) { push @DIRECTORIES, @{$ENV{directories}} }
    264 
    265 
    266 # regexp - matched against the start of the filename.  If a grouping "(...)"
    267 #          is present then only the first such part is used.
    268 #
    269 # mulfunc - filenames to be generated from a multi-function file.
    270 #
    271 # funs - functions provided by the file, defaulting to the filename with mpn
    272 #          (or mpX).
    273 #
    274 # mpX - prefix like "mpz", defaulting to "mpn".
    275 #
    276 # ret - return value type.
    277 #
    278 # args, args_<fun> - arguments for the given function.  If an args_<fun> is
    279 #          set then it's used, otherwise plain args is used.  "mp_limb_t
    280 #          carry" is appended for carry-in variants.
    281 #
    282 # try - try.c TYPE_ to use, defaulting to TYPE_fun with the function name
    283 #          in upper case.  "C" is appended for carry-in variants.  Can be
    284 #          'none' for no try program entry.
    285 #
    286 # speed - SPEED_ROUTINE_ to use, handled like "try".
    287 #
    288 # speed_flags - SPEED_ROUTINE_ to use, handled like "try".
    289 
    290 
    291 my @table =
    292     (
    293      {
    294        'regexp'=> 'add_n|sub_n|addlsh1_n|sublsh1_n|rsh1add_n|rsh1sub_n',
    295        'ret'   => 'mp_limb_t',
    296        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
    297        'speed' => 'SPEED_ROUTINE_MPN_BINARY_N',
    298        'speed_flags'=> 'FLAG_R_OPTIONAL',
    299      },
    300      {
    301        'regexp'=> 'aors_n',
    302        'mulfunc'=> ['add_n','sub_n'],
    303        'ret'   => 'mp_limb_t',
    304        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
    305        'speed' => 'SPEED_ROUTINE_MPN_BINARY_N',
    306        'speed_flags'=> 'FLAG_R_OPTIONAL',
    307      },
    308 
    309      {
    310        'regexp'=> 'addmul_1|submul_1',
    311        'ret'   => 'mp_limb_t',
    312        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_limb_t mult',
    313        'speed' => 'SPEED_ROUTINE_MPN_UNARY_1',
    314        'speed_flags'=> 'FLAG_R',
    315      },
    316      {
    317        'regexp'=> 'aorsmul_1',
    318        'mulfunc'=> ['addmul_1','submul_1'],
    319        'ret'   => 'mp_limb_t',
    320        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_limb_t mult',
    321        'speed' => 'SPEED_ROUTINE_MPN_UNARY_1',
    322        'speed_flags'=> 'FLAG_R',
    323      },
    324 
    325      {
    326        'regexp'=> 'addmul_2|submul_2',
    327        'ret'   => 'mp_limb_t',
    328        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
    329        'speed' => 'SPEED_ROUTINE_MPN_UNARY_2',
    330        'speed_flags'=> 'FLAG_R_OPTIONAL',
    331        'try-minsize' => 2,
    332      },
    333      {
    334        'regexp'=> 'addmul_3|submul_3',
    335        'ret'   => 'mp_limb_t',
    336        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
    337        'speed' => 'SPEED_ROUTINE_MPN_UNARY_3',
    338        'speed_flags'=> 'FLAG_R_OPTIONAL',
    339        'try-minsize' => 3,
    340      },
    341      {
    342        'regexp'=> 'addmul_4|submul_4',
    343        'ret'   => 'mp_limb_t',
    344        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
    345        'speed' => 'SPEED_ROUTINE_MPN_UNARY_4',
    346        'speed_flags'=> 'FLAG_R_OPTIONAL',
    347        'try-minsize' => 4,
    348      },
    349      {
    350        'regexp'=> 'addmul_5|submul_5',
    351        'ret'   => 'mp_limb_t',
    352        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
    353        'speed' => 'SPEED_ROUTINE_MPN_UNARY_5',
    354        'speed_flags'=> 'FLAG_R_OPTIONAL',
    355        'try-minsize' => 5,
    356      },
    357      {
    358        'regexp'=> 'addmul_6|submul_6',
    359        'ret'   => 'mp_limb_t',
    360        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
    361        'speed' => 'SPEED_ROUTINE_MPN_UNARY_6',
    362        'speed_flags'=> 'FLAG_R_OPTIONAL',
    363        'try-minsize' => 6,
    364      },
    365      {
    366        'regexp'=> 'addmul_7|submul_7',
    367        'ret'   => 'mp_limb_t',
    368        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
    369        'speed' => 'SPEED_ROUTINE_MPN_UNARY_7',
    370        'speed_flags'=> 'FLAG_R_OPTIONAL',
    371        'try-minsize' => 7,
    372      },
    373      {
    374        'regexp'=> 'addmul_8|submul_8',
    375        'ret'   => 'mp_limb_t',
    376        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
    377        'speed' => 'SPEED_ROUTINE_MPN_UNARY_8',
    378        'speed_flags'=> 'FLAG_R_OPTIONAL',
    379        'try-minsize' => 8,
    380      },
    381 
    382      {
    383        'regexp'=> 'add_n_sub_n',
    384        'ret'   => 'mp_limb_t',
    385        'args'  => 'mp_ptr sum, mp_ptr diff, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
    386        'speed_flags'=> 'FLAG_R_OPTIONAL',
    387      },
    388 
    389      {
    390        'regexp'=> 'com|copyi|copyd',
    391        'ret'   => 'void',
    392        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size',
    393        'speed' => 'SPEED_ROUTINE_MPN_COPY',
    394      },
    395 
    396      {
    397        'regexp'=> 'dive_1',
    398        'funs'  => ['divexact_1'],
    399        'ret'   => 'void',
    400        'args'  => 'mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor',
    401        'speed_flags'=> 'FLAG_R',
    402      },
    403      {
    404        'regexp'=> 'diveby3',
    405        'funs'  => ['divexact_by3c'],
    406        'ret'   => 'mp_limb_t',
    407        'args'  => 'mp_ptr dst, mp_srcptr src, mp_size_t size',
    408        'carrys'=> [''],
    409        'speed' => 'SPEED_ROUTINE_MPN_COPY',
    410      },
    411 
    412      # mpn_preinv_divrem_1 is an optional extra entrypoint
    413      {
    414        'regexp'=> 'divrem_1',
    415        'funs'  => ['divrem_1', 'preinv_divrem_1'],
    416        'ret'   => 'mp_limb_t',
    417        'args_divrem_1' => 'mp_ptr rp, mp_size_t xsize, mp_srcptr sp, mp_size_t size, mp_limb_t divisor',
    418        'args_preinv_divrem_1' => 'mp_ptr rp, mp_size_t xsize, mp_srcptr sp, mp_size_t size, mp_limb_t divisor, mp_limb_t inverse, unsigned shift',
    419        'speed_flags'=> 'FLAG_R',
    420        'speed_suffixes' => ['f'],
    421      },
    422      {
    423        'regexp'=> 'pre_divrem_1',
    424        'funs'  => ['preinv_divrem_1'],
    425        'ret'   => 'mp_limb_t',
    426        'args'  => 'mp_ptr qp, mp_size_t qxn, mp_srcptr ap, mp_size_t asize, mp_limb_t divisor, mp_limb_t inverse, int shift',
    427        'speed_flags' => 'FLAG_R',
    428      },
    429 
    430      {
    431        'regexp'=> 'divrem_2',
    432        'ret'   => 'mp_limb_t',
    433        'args'  => 'mp_ptr qp, mp_size_t qxn, mp_srcptr np, mp_size_t nsize, mp_srcptr dp',
    434        'try'   => 'none',
    435      },
    436 
    437      {
    438        'regexp'=> 'sb_divrem_mn',
    439        'ret'   => 'mp_limb_t',
    440        'args'  => 'mp_ptr qp, mp_ptr np, mp_size_t nsize, mp_srcptr dp, mp_size_t dsize',
    441        'speed' => 'SPEED_ROUTINE_MPN_DC_DIVREM_SB',
    442        'try-minsize' => 3,
    443      },
    444      {
    445        'regexp'=> 'tdiv_qr',
    446        'ret'   => 'void',
    447        'args'  => 'mp_ptr qp, mp_size_t qxn, mp_ptr np, mp_size_t nsize, mp_srcptr dp, mp_size_t dsize',
    448        'speed' => 'none',
    449      },
    450 
    451      {
    452        'regexp'=> 'get_str',
    453        'ret'   => 'size_t',
    454        'args'  => 'unsigned char *str, int base, mp_ptr mptr, mp_size_t msize',
    455        'speed_flags' => 'FLAG_R_OPTIONAL',
    456        'try'   => 'none',
    457      },
    458      {
    459        'regexp'=> 'set_str',
    460        'ret'   => 'mp_size_t',
    461        'args'  => 'mp_ptr xp, const unsigned char *str, size_t str_len, int base',
    462        'speed_flags' => 'FLAG_R_OPTIONAL',
    463        'try'   => 'none',
    464      },
    465 
    466      {
    467        'regexp'=> 'fac_ui',
    468        'mpX'   => 'mpz',
    469        'ret'   => 'void',
    470        'args'  => 'mpz_ptr r, unsigned long n',
    471        'speed_flags' => 'FLAG_NODATA',
    472        'try'   => 'none',
    473      },
    474 
    475      {
    476        'regexp'=> 'fib2_ui',
    477        'ret'   => 'void',
    478        'args'  => 'mp_ptr fp, mp_ptr f1p, unsigned long n',
    479        'rename'=> ['__gmp_fib_table'],
    480        'speed_flags' => 'FLAG_NODATA',
    481        'try'   => 'none',
    482      },
    483      {
    484        'regexp'=> 'fib_ui',
    485        'mpX'   => 'mpz',
    486        'ret'   => 'void',
    487        'args'  => 'mpz_ptr fn, unsigned long n',
    488        'speed_flags' => 'FLAG_NODATA',
    489        'try'   => 'none',
    490      },
    491      {
    492        'regexp'=> 'fib2_ui',
    493        'mpX'   => 'mpz',
    494        'ret'   => 'void',
    495        'args'  => 'mpz_ptr fn, mpz_ptr fnsub1, unsigned long n',
    496        'speed_flags' => 'FLAG_NODATA',
    497        'try'   => 'none',
    498      },
    499 
    500      {
    501        'regexp'=> 'lucnum_ui',
    502        'mpX'   => 'mpz',
    503        'ret'   => 'void',
    504        'args'  => 'mpz_ptr ln, unsigned long n',
    505        'speed_flags' => 'FLAG_NODATA',
    506        'try'   => 'none',
    507      },
    508      {
    509        'regexp'=> 'lucnum2_ui',
    510        'mpX'   => 'mpz',
    511        'ret'   => 'void',
    512        'args'  => 'mpz_ptr ln, mpz_ptr lnsub1, unsigned long n',
    513        'speed_flags' => 'FLAG_NODATA',
    514        'try'   => 'none',
    515      },
    516 
    517      {
    518        'regexp'=> 'gcd_1',
    519        'ret'   => 'mp_limb_t',
    520        'args'  => 'mp_ptr xp, mp_size_t xsize, mp_limb_t y',
    521        'speed_flags'=> 'FLAG_R_OPTIONAL',
    522        'speed_suffixes' => ['N'],
    523      },
    524      {
    525        'regexp'=> '(gcd)(?!(_1|ext|_finda))',
    526        'ret'   => 'mp_size_t',
    527        'args'  => 'mp_ptr gp, mp_ptr up, mp_size_t usize, mp_ptr vp, mp_size_t vsize',
    528      },
    529      {
    530        'regexp'=> 'gcd_finda',
    531        'ret'   => 'mp_limb_t',
    532        'args'  => 'mp_srcptr cp',
    533      },
    534 
    535 
    536      {
    537        'regexp'=> 'jacobi',
    538        'funs'  => ['jacobi', 'legendre', 'kronecker'],
    539        'mpX'   => 'mpz',
    540        'ret'   => 'int',
    541        'args'  => 'mpz_srcptr a, mpz_srcptr b',
    542        'try-legendre' => 'TYPE_MPZ_JACOBI',
    543      },
    544      {
    545        'regexp'=> 'jacbase',
    546        'funs'  => ['jacobi_base'],
    547        'ret'   => 'mp_limb_t',
    548        'args'  => 'mp_limb_t a, mp_limb_t b, int bit1',
    549        'speed' => 'SPEED_ROUTINE_MPN_JACBASE',
    550        'try'   => 'none',
    551      },
    552 
    553      {
    554        'regexp'=> 'logops_n',
    555        'mulfunc'=> ['and_n','andn_n','nand_n','ior_n','iorn_n','nior_n','xor_n','xnor_n'],
    556        'ret'   => 'void',
    557        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
    558        'speed' => 'SPEED_ROUTINE_MPN_BINARY_N',
    559      },
    560 
    561      {
    562        'regexp'=> '[lr]shift',
    563        'ret'   => 'mp_limb_t',
    564        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, unsigned shift',
    565        'speed' => 'SPEED_ROUTINE_MPN_UNARY_1',
    566        'speed_flags'=> 'FLAG_R',
    567      },
    568 
    569      # mpn_preinv_mod_1 is an optional extra entrypoint
    570      {
    571        'regexp'=> '(mod_1)(?!_rs)',
    572        'funs'  => ['mod_1','preinv_mod_1'],
    573        'ret'   => 'mp_limb_t',
    574        'args_mod_1'       => 'mp_srcptr xp, mp_size_t size, mp_limb_t divisor',
    575        'args_preinv_mod_1'=> 'mp_srcptr xp, mp_size_t size, mp_limb_t divisor, mp_limb_t inverse',
    576        'speed_flags'=> 'FLAG_R',
    577      },
    578      {
    579        'regexp'=> 'pre_mod_1',
    580        'funs'  => ['preinv_mod_1'],
    581        'ret'   => 'mp_limb_t',
    582        'args'  => 'mp_srcptr xp, mp_size_t size, mp_limb_t divisor, mp_limb_t inverse',
    583        'speed_flags'=> 'FLAG_R',
    584      },
    585      {
    586        'regexp'=> 'mod_34lsub1',
    587        'ret'   => 'mp_limb_t',
    588        'args'  => 'mp_srcptr src, mp_size_t len',
    589      },
    590      {
    591        'regexp'=> 'invert_limb',
    592        'ret'   => 'mp_limb_t',
    593        'args'  => 'mp_limb_t divisor',
    594        'speed_flags'=> 'FLAG_R_OPTIONAL',
    595        'try'   => 'none',
    596      },
    597 
    598      {
    599        # not for use with hppa reversed argument versions of mpn_umul_ppmm
    600        'regexp'=> 'udiv',
    601        'funs'  => ['udiv_qrnnd','udiv_qrnnd_r'],
    602        'ret'   => 'mp_limb_t',
    603        'args_udiv_qrnnd'   => 'mp_limb_t *, mp_limb_t, mp_limb_t, mp_limb_t',
    604        'args_udiv_qrnnd_r' => 'mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t *',
    605        'speed' => 'none',
    606        'try-minsize' => 2,
    607      },
    608 
    609      {
    610        'regexp'=> 'mode1o',
    611        'funs'  => ['modexact_1_odd'],
    612        'ret'   => 'mp_limb_t',
    613        'args'  => 'mp_srcptr src, mp_size_t size, mp_limb_t divisor',
    614        'speed_flags'=> 'FLAG_R',
    615      },
    616      {
    617        'regexp'=> 'modlinv',
    618        'funs'  => ['modlimb_invert'],
    619        'ret'   => 'mp_limb_t',
    620        'args'  => 'mp_limb_t v',
    621        'carrys'=> [''],
    622        'try'   => 'none',
    623      },
    624 
    625      {
    626        'regexp'=> 'mul_1',
    627        'ret'   => 'mp_limb_t',
    628        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_limb_t mult',
    629        'speed' => 'SPEED_ROUTINE_MPN_UNARY_1',
    630        'speed_flags'=> 'FLAG_R',
    631      },
    632      {
    633        'regexp'=> 'mul_2',
    634        'ret'   => 'mp_limb_t',
    635        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr mult',
    636        'speed' => 'SPEED_ROUTINE_MPN_UNARY_2',
    637        'speed_flags'=> 'FLAG_R',
    638      },
    639 
    640      {
    641        'regexp'=> 'mul_basecase',
    642        'ret'   => 'void',
    643        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t xsize, mp_srcptr yp, mp_size_t ysize',
    644        'speed_flags' => 'FLAG_R_OPTIONAL | FLAG_RSIZE',
    645      },
    646      {
    647        'regexp'=> '(mul_n)[_.]',
    648        'ret'   => 'void',
    649        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
    650        'rename'=> ['kara_mul_n','kara_sqr_n','toom3_mul_n','toom3_sqr_n'],
    651      },
    652      {
    653        'regexp'=> 'umul',
    654        'funs'  => ['umul_ppmm','umul_ppmm_r'],
    655        'ret'   => 'mp_limb_t',
    656        'args_umul_ppmm'   => 'mp_limb_t *lowptr, mp_limb_t m1, mp_limb_t m2',
    657        'args_umul_ppmm_r' => 'mp_limb_t m1, mp_limb_t m2, mp_limb_t *lowptr',
    658        'speed' => 'none',
    659        'try-minsize' => 3,
    660      },
    661 
    662 
    663      {
    664        'regexp'=> 'popham',
    665        'mulfunc'=> ['popcount','hamdist'],
    666        'ret'   => 'unsigned long',
    667        'args_popcount'=> 'mp_srcptr xp, mp_size_t size',
    668        'args_hamdist' => 'mp_srcptr xp, mp_srcptr yp, mp_size_t size',
    669      },
    670      {
    671        'regexp'=> 'popcount',
    672        'ret'   => 'unsigned long',
    673        'args'  => 'mp_srcptr xp, mp_size_t size',
    674      },
    675      {
    676        'regexp'=> 'hamdist',
    677        'ret'   => 'unsigned long',
    678        'args'  => 'mp_srcptr xp, mp_srcptr yp, mp_size_t size',
    679        # extra renaming to support sharing a data table with mpn_popcount
    680        'rename'=> ['popcount'],
    681      },
    682 
    683      {
    684        'regexp'=> 'sqr_basecase',
    685        'ret'   => 'void',
    686        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size',
    687        'speed' => 'SPEED_ROUTINE_MPN_SQR',
    688        'try'   => 'TYPE_SQR',
    689      },
    690      {
    691        'regexp'=> 'sqr_diagonal',
    692        'ret'   => 'void',
    693        'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size',
    694        'try'   => 'none',
    695      },
    696 
    697      {
    698        'regexp'=> 'sqrtrem',
    699        'ret'   => 'mp_size_t',
    700        'args'  => 'mp_ptr root, mp_ptr rem, mp_srcptr src, mp_size_t size',
    701        'try'   => 'none',
    702      },
    703 
    704      {
    705        'regexp'=> 'cntlz',
    706        'funs'  => ['count_leading_zeros'],
    707        'ret'   => 'unsigned',
    708        'args'  => 'mp_limb_t',
    709        'macro-before' => "#undef COUNT_LEADING_ZEROS_0",
    710        'macro-speed'  =>
    711 '#ifdef COUNT_LEADING_ZEROS_0
    712 #define COUNT_LEADING_ZEROS_0_ALLOWED   1
    713 #else
    714 #define COUNT_LEADING_ZEROS_0_ALLOWED   0
    715 #endif
    716   SPEED_ROUTINE_COUNT_ZEROS_A (1, COUNT_LEADING_ZEROS_0_ALLOWED);
    717   $fun (c, n);
    718   SPEED_ROUTINE_COUNT_ZEROS_B ()',
    719        'speed_flags'=> 'FLAG_R_OPTIONAL',
    720        'try'   => 'none',
    721      },
    722      {
    723        'regexp'=> 'cnttz',
    724        'funs'  => ['count_trailing_zeros'],
    725        'ret'   => 'unsigned',
    726        'args'  => 'mp_limb_t',
    727        'macro-speed' => '
    728   SPEED_ROUTINE_COUNT_ZEROS_A (0, 0);
    729   $fun (c, n);
    730   SPEED_ROUTINE_COUNT_ZEROS_B ()',
    731        'speed_flags' => 'FLAG_R_OPTIONAL',
    732        'try'   => 'none',
    733      },
    734 
    735      {
    736        'regexp'=> 'zero',
    737        'ret'   => 'void',
    738        'args'  => 'mp_ptr ptr, mp_size_t size',
    739      },
    740 
    741      {
    742        'regexp'=> '(powm)(?!_ui)',
    743        'mpX'   => 'mpz',
    744        'ret'   => 'void',
    745        'args'  => 'mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m',
    746        'try'   => 'none',
    747      },
    748      {
    749        'regexp'=> 'powm_ui',
    750        'mpX'   => 'mpz',
    751        'ret'   => 'void',
    752        'args'  => 'mpz_ptr r, mpz_srcptr b, unsigned long e, mpz_srcptr m',
    753        'try'   => 'none',
    754      },
    755 
    756      # special for use during development
    757      {
    758        'regexp'=> 'back',
    759        'funs'  => ['back_to_back'],
    760        'ret'   => 'void',
    761        'args'  => 'void',
    762        'pic'   => 'no',
    763        'try'   => 'none',
    764        'speed_flags'=> 'FLAG_NODATA',
    765      },
    766      );
    767 
    768 if (defined $ENV{table2}) {
    769   my @newtable = @{$ENV{table2}};
    770   push @newtable, @table;
    771   @table = @newtable;
    772 }
    773 
    774 
    775 my %pictable =
    776     (
    777      'yes' => {
    778        'suffix' =>  '_pic',
    779        'asmflags'=> '$(ASMFLAGS_PIC)',
    780        'cflags' =>  '$(CFLAGS_PIC)',
    781      },
    782      'no' => {
    783        'suffix' =>  '',
    784        'asmflags'=> '',
    785        'cflags' =>  '',
    786      },
    787      );
    788 
    789 
    790 my $builddir = $ENV{builddir};
    791 $builddir = "." if (! defined $builddir);
    792 
    793 my $top_builddir = "${builddir}/..";
    794 
    795 
    796 open(MAKEFILE, "<${builddir}/Makefile")
    797   or die "Cannot open ${builddir}/Makefile: $!\n"
    798        . "Is this a tune build directory?";
    799 my ($srcdir, $top_srcdir);
    800 while (<MAKEFILE>) {
    801   if (/^srcdir = (.*)/) {     $srcdir = $1;     }
    802   if (/^top_srcdir = (.*)/) { $top_srcdir = $1; }
    803 }
    804 die "Cannot find \$srcdir in Makefile\n" if (! defined $srcdir);
    805 die "Cannot find \$top_srcdir in Makefile\n" if (! defined $top_srcdir);
    806 print "srcdir $srcdir\n" if $opt{'t'};
    807 print "top_srcdir $top_srcdir\n" if $opt{'t'};
    808 close(MAKEFILE);
    809 
    810 
    811 open(SPEED, ">speed-many.c") or die;
    812 print SPEED
    813 "/* speed-many.c generated by many.pl - DO NOT EDIT, CHANGES WILL BE LOST */
    814 
    815 ";
    816 my $SPEED_EXTRA_ROUTINES = "#define SPEED_EXTRA_ROUTINES \\\n";
    817 my $SPEED_EXTRA_PROTOS = "#define SPEED_EXTRA_PROTOS \\\n";
    818 my $SPEED_CODE = "";
    819 
    820 open(TRY, ">try-many.c") or die;
    821 print TRY
    822     "/* try-many.c generated by many.pl - DO NOT EDIT, CHANGES WILL BE LOST */\n" .
    823     "\n";
    824 my $TRY_EXTRA_ROUTINES = "#define EXTRA_ROUTINES \\\n";
    825 my $TRY_EXTRA_PROTOS = "#define EXTRA_PROTOS \\\n";
    826 
    827 open(FD,"<${top_builddir}/libtool") or die "Cannot open \"${top_builddir}/libtool\": $!\n";
    828 my $pic_flag;
    829 while (<FD>) {
    830   if (/^pic_flag="?([^"]*)"?$/) {
    831     $pic_flag=$1;
    832     last;
    833   }
    834 }
    835 close FD;
    836 if (! defined $pic_flag) {
    837   die "Cannot find pic_flag in ${top_builddir}/libtool";
    838 }
    839 
    840 my $CFLAGS_PIC = $pic_flag;
    841 
    842 my $ASMFLAGS_PIC = "";
    843 foreach (split /[ \t]/, $pic_flag) {
    844   if (/^-D/) {
    845     $ASMFLAGS_PIC .= " " . $_;
    846   }
    847 }
    848 
    849 open(MAKEFILE, ">Makefile.many") or die;
    850 print MAKEFILE
    851     "# Makefile.many generated by many.pl - DO NOT EDIT, CHANGES WILL BE LOST\n" .
    852     "\n" .
    853     "all: speed-many try-many\n" .
    854     "\n" .
    855     "#--------- begin included copy of basic Makefile ----------\n" .
    856     "\n";
    857 open(FD,"<${builddir}/Makefile") or die "Cannot open \"${builddir}/Makefile\": $!\n";
    858 print MAKEFILE <FD>;
    859 close FD;
    860 print MAKEFILE
    861     "\n" .
    862     "#--------- end included copy of basic Makefile ----------\n" .
    863     "\n" .
    864     "CFLAGS_PIC = $CFLAGS_PIC\n" .
    865     "ASMFLAGS_PIC = $ASMFLAGS_PIC\n" .
    866     "\n";
    867 
    868 my $CLEAN="";
    869 my $MANY_OBJS="";
    870 
    871 
    872 sub print_ansi2knr {
    873   my ($base,$file,$includes) = @_;
    874   if (! defined $file)     { $file = "$base.c"; }
    875   if (! defined $includes) { $includes = ""; }
    876 
    877   print MAKEFILE <<EOF;
    878 ${base}_.c: $file \$(ANSI2KNR)
    879 	\$(CPP) \$(DEFS) \$(INCLUDES) $includes \$(AM_CPPFLAGS) \$(CPPFLAGS) $file | sed 's/^# \([0-9]\)/#line \\1/' | \$(ANSI2KNR) >${base}_.c
    880 
    881 EOF
    882 }
    883 
    884 
    885 # Spawning a glob is a touch slow when there's lots of files.
    886 my @files = ();
    887 foreach my $dir (@DIRECTORIES) {
    888   print "dir $dir\n" if $opt{'t'};
    889   if (-f $dir) {
    890     push @files,$dir;
    891   } else {
    892     if (! opendir DD,$dir) {
    893       print "Cannot open $dir: $!\n";
    894     } else {
    895       push @files, map {$_="$dir/$_"} grep /\.(c|asm|S|h)$/, readdir DD;
    896       closedir DD;
    897     }
    898   }
    899 }
    900 @files = sort @files;
    901 print "@files ",join(" ",@files),"\n" if $opt{'t'};
    902 
    903 my $count_files = 0;
    904 my $count_functions = 0;
    905 my %seen_obj;
    906 my %seen_file;
    907 
    908 foreach my $file_full (@files) {
    909   if (! -f $file_full) {
    910     print "Not a file: $file_full\n";
    911     next;
    912   }
    913   if (defined $seen_file{$file_full}) {
    914     print "Skipping duplicate file: $file_full\n";
    915     next;
    916   }
    917   $seen_file{$file_full} = 1;
    918 
    919   my ($FILE,$path,$lang) = fileparse($file_full,"\.[a-zA-Z]+");
    920   $path =~ s/\/$//;
    921   print "file $FILE path $path lang $lang\n" if $opt{'t'};
    922 
    923   my @pic_choices;
    924   if ($lang eq '.asm')  { @pic_choices=('no','yes'); }
    925   elsif ($lang eq '.c') { @pic_choices=('no'); }
    926   elsif ($lang eq '.S') { @pic_choices=('no','yes'); }
    927   elsif ($lang eq '.h') { @pic_choices=('no'); }
    928   else { next };
    929 
    930   my ($t, $file_match);
    931   foreach my $p (@table) {
    932     # print " ",$p->{'regexp'},"\n" if $opt{'t'};
    933     if ($FILE =~ "^($p->{'regexp'})") {
    934       $t = $p;
    935       $file_match = $1;
    936       $file_match = $2 if defined $2;
    937       last;
    938     }
    939   }
    940   next if ! defined $t;
    941   print "match $t->{'regexp'} $FILE ($file_full)\n" if $opt{'t'};
    942 
    943   if (! open FD,"<$file_full") { print "Can't open $file_full: $!\n"; next }
    944   my @file_contents = <FD>;
    945   close FD;
    946 
    947   my $objs;
    948   if (defined $t->{'mulfunc'}) { $objs = $t->{'mulfunc'}; }
    949   else                         { $objs = [$file_match]; }
    950   print "objs @$objs\n" if $opt{'t'};
    951 
    952   my $ret = $t->{'ret'};
    953   if (! defined $ret && $lang eq '.h') { $ret = ''; }
    954   if (! defined $ret) { die "$FILE return type not defined\n" };
    955   print "ret $ret\n" if $opt{'t'};
    956 
    957   my $mpX = $t->{'mpX'};
    958   if (! defined $mpX) { $mpX = ($lang eq '.h' ? '' : 'mpn'); }
    959   $mpX = "${mpX}_" if $mpX ne '';
    960   print "mpX $mpX\n" if $opt{'t'};
    961 
    962   my $carrys;
    963   if (defined $t->{'carrys'}) { $carrys = $t->{'carrys'}; }
    964   else                        { $carrys = ['','c'];       }
    965   print "carrys $carrys @$carrys\n" if $opt{'t'};
    966 
    967   # some restriction functions are implemented, but they're not very useful
    968   my $restriction='';
    969 
    970   my $suffix;
    971   if ($FILE =~ ("${file_match}_(.+)")) {
    972     $suffix = $1;
    973   } elsif ($path =~ /\/mp[zn]\/(.*)$/) {
    974     # derive the suffix from the path
    975     $suffix = $1;
    976     $suffix =~ s/\//_/g;
    977     # use last directory name, or if there's 3 or more then the last two
    978     if ($suffix =~ /([^_]*_)+([^_]+_[^_]+)$/) {
    979       $suffix = $2;
    980     } elsif ($suffix =~ /([^_]*_)*([^_]+)$/) {
    981       $suffix = $2;
    982     }
    983   } else {
    984     die "Can't determine suffix for: $file_full (path $path)\n";
    985   }
    986   print "suffix $suffix\n" if $opt{'t'};
    987 
    988   $count_files++;
    989 
    990   foreach my $obj (@{$objs}) {
    991     print "obj $obj\n" if $opt{'t'};
    992 
    993     my $obj_with_suffix = "${obj}_$suffix";
    994     if (defined $seen_obj{$obj_with_suffix}) {
    995       print "Skipping duplicate object: $obj_with_suffix\n";
    996       print "   first from: $seen_obj{$obj_with_suffix}\n";
    997       print "   now from:   $file_full\n";
    998       next;
    999     }
   1000     $seen_obj{$obj_with_suffix} = $file_full;
   1001 
   1002     my $funs = $t->{'funs'};
   1003     $funs = [$obj] if ! defined $funs;
   1004     print "funs @$funs\n" if $opt{'t'};
   1005 
   1006     if (defined $t->{'pic'}) { @pic_choices = ('no'); }
   1007 
   1008     foreach my $pic (map {$pictable{$_}} @pic_choices) {
   1009       print "pic $pic->{'suffix'}\n" if $opt{'t'};
   1010 
   1011       my $objbase = "${obj}_$suffix$pic->{'suffix'}";
   1012       print "objbase $objbase\n" if $opt{'t'};
   1013 
   1014       if ($path !~ "." && -f "${objbase}.c") {
   1015 	die "Already have ${objbase}.c";
   1016       }
   1017 
   1018       my $tmp_file = "tmp-$objbase.c";
   1019 
   1020       my $renaming;
   1021       foreach my $fun (@{$funs}) {
   1022         if ($mpX eq 'mpn_' && $lang eq '.c') {
   1023           $renaming .= "\t\t-DHAVE_NATIVE_mpn_$fun=1 \\\n";
   1024         }
   1025 
   1026         # The carry-in variant is with a "c" appended, unless there's a "_1"
   1027         # somewhere, eg. "modexact_1_odd", in which case that becomes "_1c".
   1028 	my $fun_carry = $fun;
   1029 	if (! ($fun_carry =~ s/_1/_1c/)) { $fun_carry = "${fun}c"; }
   1030 
   1031 	$renaming .=
   1032 	    "\t\t-D__g$mpX$fun=$mpX${fun}_$suffix$pic->{'suffix'} \\\n" .
   1033 	    "\t\t-D__g$mpX$fun_carry=$mpX${fun_carry}_$suffix$pic->{'suffix'} \\\n";
   1034       }
   1035       foreach my $r (@{$t->{'rename'}}) {
   1036 	if ($r =~ /^__gmp/) {
   1037 	  $renaming .= "\\\n" .
   1038 	      "\t\t-D$r=${r}_$suffix$pic->{'suffix'}";
   1039 	} else {
   1040 	  $renaming .= "\\\n" .
   1041 	      "\t\t-D__g$mpX$r=$mpX${r}_$suffix$pic->{'suffix'}";
   1042 	}
   1043       }
   1044       print "renaming $renaming\n" if $opt{'t'};
   1045 
   1046       print MAKEFILE "\n";
   1047       if ($lang eq '.asm') {
   1048 	print MAKEFILE
   1049 	    "$objbase.o: $file_full \$(ASM_HEADERS)\n" .
   1050 	    "	\$(M4) \$(M4FLAGS) -DOPERATION_$obj $pic->{'asmflags'} \\\n" .
   1051   	    "$renaming" .
   1052 	    "		$file_full >tmp-$objbase.s\n" .
   1053             "	\$(CCAS) \$(COMPILE_FLAGS) $pic->{'cflags'} tmp-$objbase.s -o $objbase.o\n" .
   1054             "	\$(RM_TMP) tmp-$objbase.s\n";
   1055 	$MANY_OBJS .= " $objbase.o";
   1056 
   1057       } elsif ($lang eq '.c') {
   1058 	print MAKEFILE
   1059 	    "$objbase.o: $file_full\n" .
   1060 	    "	\$(COMPILE) -DOPERATION_$obj $pic->{'cflags'} \\\n" .
   1061   	    "$renaming" .
   1062 	    "		-c $file_full -o $objbase.o\n";
   1063 	print_ansi2knr($objbase,
   1064 		       $file_full,
   1065 		       " -DOPERATION_$obj\\\n$renaming\t\t");
   1066 	$MANY_OBJS .= " $objbase\$U.o";
   1067 
   1068       } elsif ($lang eq '.S') {
   1069 	print MAKEFILE
   1070 	    "$objbase.o: $file_full\n" .
   1071             "	\$(COMPILE) -g $pic->{'asmflags'} \\\n" .
   1072   	    "$renaming" .
   1073             "	-c $file_full -o $objbase.o\n";
   1074 	$MANY_OBJS .= " $objbase.o";
   1075 
   1076       } elsif ($lang eq '.h') {
   1077 	print MAKEFILE
   1078 	    "$objbase.o: tmp-$objbase.c $file_full\n" .
   1079 	    "	\$(COMPILE) -DOPERATION_$obj $pic->{'cflags'} \\\n" .
   1080   	    "$renaming" .
   1081 	    "		-c tmp-$objbase.c -o $objbase.o\n";
   1082 	print_ansi2knr($objbase,
   1083 		       "tmp-$objbase.c",
   1084 		       " -DOPERATION_$obj\\\n$renaming\t\t");
   1085 	$MANY_OBJS .= " $objbase\$U.o";
   1086 
   1087         $CLEAN .= " tmp-$objbase.c";
   1088 	open(TMP_C,">tmp-$objbase.c")
   1089 	    or die "Can't create tmp-$objbase.c: $!\n";
   1090 	print TMP_C
   1091 "/* tmp-$objbase.c generated by many.pl - DO NOT EDIT, CHANGES WILL BE LOST */
   1092 
   1093 #include \"gmp.h\"
   1094 #include \"gmp-impl.h\"
   1095 #include \"longlong.h\"
   1096 #include \"speed.h\"
   1097 
   1098 ";
   1099       }
   1100 
   1101       my $tests_program = "$top_srcdir/tests/devel/$obj.c";
   1102       if (-f $tests_program) {
   1103 	$tests_program = "\$(top_srcdir)/tests/devel/$obj.c";
   1104 	print_ansi2knr("tests_${objbase}",
   1105 		       $tests_program,
   1106 		       "\\\n$renaming\t\t\$(CFLAGS_TESTS_SP)");
   1107 	print_ansi2knr("tests_${objbase}_sp",
   1108 		       $tests_program,
   1109 		       "\\\n$renaming\t\t\$(CFLAGS_TESTS_SP)");
   1110 
   1111 	print MAKEFILE <<EOF;
   1112 tests_$objbase.o: $tests_program
   1113 	\$(COMPILE) \$(CFLAGS_TESTS) \\
   1114 $renaming		-c $tests_program -o tests_$objbase.o
   1115 
   1116 tests_$objbase: $objbase\$U.o tests_$objbase\$U.o ../libgmp.la
   1117 	\$(LINK) tests_$objbase\$U.o $objbase\$U.o ../libgmp.la -o tests_$objbase
   1118 
   1119 tests_${objbase}_sp.o: $tests_program
   1120 	\$(COMPILE) \$(CFLAGS_TESTS_SP) \\
   1121 $renaming		-c $tests_program -o tests_${objbase}_sp.o
   1122 
   1123 tests_${objbase}_sp: $objbase\$U.o tests_${objbase}_sp\$U.o ../libgmp.la
   1124 	\$(LINK) tests_${objbase}_sp\$U.o $objbase\$U.o ../libgmp.la -o tests_${objbase}_sp
   1125 
   1126 EOF
   1127         $CLEAN .= " tests_$objbase tests_${objbase}_sp";
   1128       }
   1129 
   1130       foreach my $fun (@{$funs}) {
   1131 	print "fun $fun\n" if $opt{'t'};
   1132 
   1133 	if ($lang eq '.h') {
   1134           my $macro_before = $t->{'macro_before'};
   1135           $macro_before = "" if ! defined $macro_before;
   1136 	  print TMP_C
   1137 "$macro_before
   1138 #undef $fun
   1139 #include \"$file_full\"
   1140 
   1141 ";
   1142 	}
   1143 
   1144 	my $args = $t->{"args_$fun"};
   1145 	if (! defined $args) { $args = $t->{'args'}; }
   1146 	if (! defined $args) { die "Need args for $fun\n"; }
   1147 	print "args $args\n" if $opt{'t'};
   1148 
   1149 	foreach my $carry (@$carrys) {
   1150 	  print "carry $carry\n" if $opt{'t'};
   1151 
   1152 	  my $fun_carry = $fun;
   1153 	  if (! ($fun_carry =~ s/_1/_1$carry/)) { $fun_carry = "$fun$carry"; }
   1154           print "fun_carry $fun_carry\n" if $opt{'t'};
   1155 
   1156 	  if ($lang =~ /\.(asm|S)/
   1157 	      && ! grep(m"PROLOGUE\((.* )?$mpX$fun_carry[ ,)]",@file_contents)) {
   1158 	    print "no PROLOGUE $mpX$fun_carry\n" if $opt{'t'};
   1159 	    next;
   1160 	  }
   1161 	  if ($lang eq '.c'
   1162 	      && ! grep(m"^(#define FUNCTION\s+)?$mpX$fun_carry\W", @file_contents)) {
   1163 	    print "no mention of $mpX$fun_carry\n" if $opt{'t'};
   1164 	    next;
   1165 	  }
   1166 	  if ($lang eq '.h'
   1167 	      && ! grep(m"^#define $fun_carry\W", @file_contents)) {
   1168 	    print "no mention of #define $fun_carry\n" if $opt{'t'};
   1169 	    next;
   1170 	  }
   1171 
   1172 	  $count_functions++;
   1173 
   1174 	  my $carryarg;
   1175 	  if (defined $t->{'carryarg'}) { $carryarg = $t->{'carryarg'}; }
   1176 	  if ($carry eq '')             { $carryarg = ''; }
   1177 	  else                          { $carryarg = ', mp_limb_t carry'; }
   1178 	  print "carryarg $carryarg\n" if $opt{'t'};
   1179 
   1180 	  my $funfull="$mpX${fun_carry}_$suffix$pic->{'suffix'}";
   1181 	  print "funfull $funfull\n" if $opt{'t'};
   1182 
   1183 	  if ($lang ne '.h') {
   1184 	    my $proto = "$t->{'ret'} $funfull _PROTO (($args$carryarg)); \\\n";
   1185 	    $SPEED_EXTRA_PROTOS .= $proto;
   1186 	    $TRY_EXTRA_PROTOS .= $proto;
   1187 	  }
   1188 
   1189 	  my $try_type = $t->{"try-$fun"};
   1190 	  $try_type = $t->{'try'} if ! defined $try_type;
   1191 	  if (! defined $try_type) {
   1192 	    if ($mpX eq 'mpn_') {
   1193 	      $try_type = "TYPE_\U$fun_carry";
   1194 	    } else {
   1195 	      $try_type = "TYPE_\U$mpX\U$fun_carry";
   1196 	    }
   1197 	  }
   1198 	  print "try_type $try_type\n" if $opt{'t'};
   1199 
   1200 	  my $try_minsize = $t->{'try-minsize'};
   1201 	  if (defined $try_minsize) {
   1202 	    $try_minsize = ", " . $try_minsize;
   1203 	  } else {
   1204 	    $try_minsize = "";
   1205 	  }
   1206 	  print "try_minsize $try_minsize\n" if $opt{'t'};
   1207 
   1208 	  if ($try_type ne 'none') {
   1209 	    $TRY_EXTRA_ROUTINES .=
   1210 		"  { TRY($mpX${fun_carry}_$suffix$pic->{'suffix'}), $try_type$try_minsize }, \\\n";
   1211 	  }
   1212 
   1213 	  my $speed_flags = $t->{'speed_flags'};
   1214 	  $speed_flags = '0' if ! defined $speed_flags;
   1215 	  print "speed_flags $speed_flags\n" if $opt{'t'};
   1216 
   1217 	  my $speed_routine = $t->{'speed'};
   1218 	  $speed_routine = "SPEED_ROUTINE_\U$mpX\U$fun"
   1219 	      if !defined $speed_routine;
   1220 	  if (! ($speed_routine =~ s/_1/_1\U$carry/)) {
   1221 	    $speed_routine = "$speed_routine\U$carry";
   1222 	  }
   1223 	  print "speed_routine $speed_routine\n" if $opt{'t'};
   1224 
   1225 	  my @speed_suffixes = ();
   1226 	  push (@speed_suffixes, '') if $speed_routine ne 'none';
   1227 	  push (@speed_suffixes, @{$t->{'speed_suffixes'}})
   1228 	      if defined $t->{'speed_suffixes'};
   1229 
   1230           my $macro_speed = $t->{'macro-speed'};
   1231           $macro_speed = "$speed_routine ($fun_carry)" if ! defined $macro_speed;
   1232           $macro_speed =~ s/\$fun/$fun_carry/g;
   1233 
   1234 	  foreach my $S (@speed_suffixes) {
   1235 	    my $Sfunfull="$mpX${fun_carry}${S}_$suffix$pic->{'suffix'}";
   1236 
   1237 	    $SPEED_EXTRA_PROTOS .=
   1238 	      "double speed_$Sfunfull _PROTO ((struct speed_params *s)); \\\n";
   1239 	    $SPEED_EXTRA_ROUTINES .=
   1240 	      "  { \"$Sfunfull\", speed_$Sfunfull, $speed_flags }, \\\n";
   1241 	    if ($lang eq '.h') {
   1242               print TMP_C
   1243 "double
   1244 speed_$Sfunfull (struct speed_params *s)
   1245 {
   1246 $macro_speed
   1247 }
   1248 
   1249 ";
   1250             } else {
   1251 	      $SPEED_CODE .=
   1252 	        "double\n" .
   1253 	        "speed_$Sfunfull (struct speed_params *s)\n" .
   1254                 "{\n" .
   1255                 "$restriction" .
   1256 	        "  $speed_routine\U$S\E ($funfull)\n" .
   1257                 "}\n";
   1258             }
   1259 	  }
   1260 	}
   1261       }
   1262     }
   1263   }
   1264 }
   1265 
   1266 
   1267 print SPEED $SPEED_EXTRA_PROTOS . "\n";
   1268 print SPEED $SPEED_EXTRA_ROUTINES . "\n";
   1269 if (defined $ENV{speedinc}) { print SPEED $ENV{speedinc} . "\n"; }
   1270 print SPEED
   1271     "#include \"speed.c\"\n" .
   1272     "\n";
   1273 print SPEED $SPEED_CODE;
   1274 
   1275 print TRY $TRY_EXTRA_ROUTINES . "\n";
   1276 print TRY $TRY_EXTRA_PROTOS . "\n";
   1277 my $tryinc = "";
   1278 if (defined $ENV{tryinc}) {
   1279   $tryinc = $ENV{tryinc};
   1280   print TRY "#include \"$tryinc\"\n";
   1281 }
   1282 print "tryinc $tryinc\n" if $opt{'t'};
   1283 print TRY
   1284     "#include \"try.c\"\n" .
   1285     "\n";
   1286 
   1287 my $extra_libraries = "";
   1288 if (defined $ENV{extra_libraries}) { $extra_libraries = $ENV{extra_libraries};}
   1289 
   1290 my $trydeps = "";
   1291 if (defined $ENV{trydeps}) { $trydeps = $ENV{trydeps}; }
   1292 $trydeps .= " $tryinc";
   1293 print "trydeps $trydeps\n" if $opt{'t'};
   1294 
   1295 print MAKEFILE <<EOF;
   1296 
   1297 MANY_OBJS = $MANY_OBJS
   1298 MANY_CLEAN = \$(MANY_OBJS) \\
   1299 	speed-many.c speed-many\$U.o speed-many\$(EXEEXT) \\
   1300 	try-many.c try-many\$U.o try-many \\
   1301 	$CLEAN
   1302 MANY_DISTCLEAN = Makefile.many
   1303 
   1304 speed-many: \$(MANY_OBJS) speed-many\$U.o libspeed.la $extra_libraries
   1305 	\$(LINK) \$(LDFLAGS) speed-many\$U.o \$(MANY_OBJS) \$(LDADD) \$(LIBS) $extra_libraries
   1306 
   1307 try-many: \$(MANY_OBJS) try-many\$U.o libspeed.la $extra_libraries
   1308 	\$(LINK) \$(LDFLAGS) try-many\$U.o \$(MANY_OBJS)  \$(LDADD) \$(LIBS) $extra_libraries
   1309 
   1310 try-many.o: try-many.c \$(top_srcdir)/tests/devel/try.c $trydeps
   1311 	\$(COMPILE) -I\$(top_srcdir)/tests/devel -c try-many.c
   1312 
   1313 EOF
   1314 
   1315 print_ansi2knr("speed-many");
   1316 print_ansi2knr("try-many",
   1317 	       "\$(top_srcdir)/tests/devel/try.c",
   1318 	       "-I\$(top_srcdir)/tests/devel");
   1319 
   1320 print MAKEFILE <<EOF;
   1321 RM_TMP = rm -f
   1322 CFLAGS_TESTS = -DSIZE=50 -DTIMES=1 -DRANDOM -DCLOCK=333000000
   1323 CFLAGS_TESTS_SP = -DSIZE=1024 -DNOCHECK -DOPS=200000000 -DCLOCK=333000000
   1324 EOF
   1325 
   1326 close MAKEFILE or die;
   1327 
   1328 print "Total $count_files files, $count_functions functions\n";
   1329 
   1330 
   1331 
   1332 # Local variables:
   1333 # perl-indent-level: 2
   1334 # End:
   1335