github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tune/many.pl (about)

     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: