(root)/
gmp-6.3.0/
tests/
mpn/
t-fat.c
       1  /* Test fat binary setups.
       2  
       3  Copyright 2003, 2012 Free Software Foundation, Inc.
       4  
       5  This file is part of the GNU MP Library test suite.
       6  
       7  The GNU MP Library test suite is free software; you can redistribute it
       8  and/or modify it under the terms of the GNU General Public License as
       9  published by the Free Software Foundation; either version 3 of the License,
      10  or (at your option) any later version.
      11  
      12  The GNU MP Library test suite is distributed in the hope that it will be
      13  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
      14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
      15  Public License for more details.
      16  
      17  You should have received a copy of the GNU General Public License along with
      18  the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
      19  
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include <string.h>
      23  
      24  #include "gmp-impl.h"
      25  #include "longlong.h"
      26  #include "tests.h"
      27  
      28  
      29  /* In this program we're aiming to pick up certain subtle problems that
      30     might creep into a fat binary.
      31  
      32     1. We want to ensure the application entry point routines like
      33        __gmpn_add_n dispatch to the correct field of __gmpn_cpuvec.
      34  
      35        Note that these routines are not exercised as a side effect of other
      36        tests (eg. the mpz routines).  Internally the fields of __gmpn_cpuvec
      37        are used directly, so we need to write test code explicitly calling
      38        the mpn functions, like an application will have.
      39  
      40     2. We want to ensure the initial __gmpn_cpuvec data has the initializer
      41        function pointers in the correct fields, and that those initializer
      42        functions dispatch to their correct corresponding field once
      43        initialization has been done.
      44  
      45        Only one of the initializer routines executes in a normal program,
      46        since that routine sets all the pointers to actual mpn functions.  We
      47        forcibly reset __gmpn_cpuvec so we can run each.
      48  
      49     In both cases for the above, the data put through the functions is
      50     nothing special, just enough to verify that for instance an add_n is
      51     really doing an add_n and has not for instance mistakenly gone to sub_n
      52     or something.
      53  
      54     The loop around each test will exercise the initializer routine on the
      55     first iteration, and the dispatcher routine on the second.
      56  
      57     If the dispatcher and/or initializer routines are generated mechanically
      58     via macros (eg. mpn/x86/fat/fat_entry.asm) then there shouldn't be too
      59     much risk of them going wrong, provided the structure layout is correctly
      60     expressed.  But if they're in C then it's good to guard against typos in
      61     what is rather repetitive code.  The initializer data for __gmpn_cpuvec
      62     in fat.c is always done by hand and is likewise a bit repetitive.  */
      63  
      64  
      65  /* dummies when not a fat binary */
      66  #if ! WANT_FAT_BINARY
      67  struct cpuvec_t {
      68    int  dummy;
      69  };
      70  struct cpuvec_t __gmpn_cpuvec;
      71  #define ITERATE_FAT_THRESHOLDS()  do { } while (0)
      72  #endif
      73  
      74  /* saved from program startup */
      75  struct cpuvec_t  initial_cpuvec;
      76  
      77  void
      78  check_functions (void)
      79  {
      80    mp_limb_t  wp[2], xp[2], yp[2], r;
      81    int  i;
      82  
      83    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
      84    for (i = 0; i < 2; i++)
      85      {
      86        xp[0] = 123;
      87        yp[0] = 456;
      88        mpn_add_n (wp, xp, yp, (mp_size_t) 1);
      89        ASSERT_ALWAYS (wp[0] == 579);
      90      }
      91  
      92    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
      93    for (i = 0; i < 2; i++)
      94      {
      95        xp[0] = 123;
      96        wp[0] = 456;
      97        r = mpn_addmul_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(2));
      98        ASSERT_ALWAYS (wp[0] == 702);
      99        ASSERT_ALWAYS (r == 0);
     100      }
     101  
     102  #if HAVE_NATIVE_mpn_copyd
     103    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     104    for (i = 0; i < 2; i++)
     105      {
     106        xp[0] = 123;
     107        xp[1] = 456;
     108        mpn_copyd (xp+1, xp, (mp_size_t) 1);
     109        ASSERT_ALWAYS (xp[1] == 123);
     110      }
     111  #endif
     112  
     113  #if HAVE_NATIVE_mpn_copyi
     114    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     115    for (i = 0; i < 2; i++)
     116      {
     117        xp[0] = 123;
     118        xp[1] = 456;
     119        mpn_copyi (xp, xp+1, (mp_size_t) 1);
     120        ASSERT_ALWAYS (xp[0] == 456);
     121      }
     122  #endif
     123  
     124    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     125    for (i = 0; i < 2; i++)
     126      {
     127        xp[0] = 1605;
     128        mpn_divexact_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(5));
     129        ASSERT_ALWAYS (wp[0] == 321);
     130      }
     131  
     132    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     133    for (i = 0; i < 2; i++)
     134      {
     135        xp[0] = 1296;
     136        r = mpn_divexact_by3c (wp, xp, (mp_size_t) 1, CNST_LIMB(0));
     137        ASSERT_ALWAYS (wp[0] == 432);
     138        ASSERT_ALWAYS (r == 0);
     139      }
     140  
     141    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     142    for (i = 0; i < 2; i++)
     143      {
     144        xp[0] = 287;
     145        r = mpn_divrem_1 (wp, (mp_size_t) 1, xp, (mp_size_t) 1, CNST_LIMB(7));
     146        ASSERT_ALWAYS (wp[1] == 41);
     147        ASSERT_ALWAYS (wp[0] == 0);
     148        ASSERT_ALWAYS (r == 0);
     149      }
     150  
     151    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     152    for (i = 0; i < 2; i++)
     153      {
     154        xp[0] = 12;
     155        r = mpn_gcd_1 (xp, (mp_size_t) 1, CNST_LIMB(9));
     156        ASSERT_ALWAYS (r == 3);
     157      }
     158  
     159    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     160    for (i = 0; i < 2; i++)
     161      {
     162        xp[0] = 0x1001;
     163        mpn_lshift (wp, xp, (mp_size_t) 1, 1);
     164        ASSERT_ALWAYS (wp[0] == 0x2002);
     165      }
     166  
     167    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     168    for (i = 0; i < 2; i++)
     169      {
     170        xp[0] = 14;
     171        r = mpn_mod_1 (xp, (mp_size_t) 1, CNST_LIMB(4));
     172        ASSERT_ALWAYS (r == 2);
     173      }
     174  
     175  #if (GMP_NUMB_BITS % 4) == 0
     176    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     177    for (i = 0; i < 2; i++)
     178      {
     179        int  bits = (GMP_NUMB_BITS / 4) * 3;
     180        mp_limb_t  mod = (CNST_LIMB(1) << bits) - 1;
     181        mp_limb_t  want = GMP_NUMB_MAX % mod;
     182        xp[0] = GMP_NUMB_MAX;
     183        r = mpn_mod_34lsub1 (xp, (mp_size_t) 1);
     184        ASSERT_ALWAYS (r % mod == want);
     185      }
     186  #endif
     187  
     188    /*   DECL_modexact_1c_odd ((*modexact_1c_odd)); */
     189  
     190    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     191    for (i = 0; i < 2; i++)
     192      {
     193        xp[0] = 14;
     194        r = mpn_mul_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(4));
     195        ASSERT_ALWAYS (wp[0] == 56);
     196        ASSERT_ALWAYS (r == 0);
     197      }
     198  
     199    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     200    for (i = 0; i < 2; i++)
     201      {
     202        xp[0] = 5;
     203        yp[0] = 7;
     204        mpn_mul_basecase (wp, xp, (mp_size_t) 1, yp, (mp_size_t) 1);
     205        ASSERT_ALWAYS (wp[0] == 35);
     206        ASSERT_ALWAYS (wp[1] == 0);
     207      }
     208  
     209    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     210    for (i = 0; i < 2; i++)
     211      {
     212        xp[0] = 5;
     213        yp[0] = 7;
     214        mpn_mullo_basecase (wp, xp, yp, (mp_size_t) 1);
     215        ASSERT_ALWAYS (wp[0] == 35);
     216      }
     217  
     218  #if HAVE_NATIVE_mpn_preinv_divrem_1 && GMP_NAIL_BITS == 0
     219    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     220    for (i = 0; i < 2; i++)
     221      {
     222        xp[0] = 0x101;
     223        r = mpn_preinv_divrem_1 (wp, (mp_size_t) 1, xp, (mp_size_t) 1,
     224                                 GMP_LIMB_HIGHBIT,
     225                                 refmpn_invert_limb (GMP_LIMB_HIGHBIT), 0);
     226        ASSERT_ALWAYS (wp[0] == 0x202);
     227        ASSERT_ALWAYS (wp[1] == 0);
     228        ASSERT_ALWAYS (r == 0);
     229      }
     230  #endif
     231  
     232  #if GMP_NAIL_BITS == 0
     233    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     234    for (i = 0; i < 2; i++)
     235      {
     236        xp[0] = GMP_LIMB_HIGHBIT+123;
     237        r = mpn_preinv_mod_1 (xp, (mp_size_t) 1, GMP_LIMB_HIGHBIT,
     238                              refmpn_invert_limb (GMP_LIMB_HIGHBIT));
     239        ASSERT_ALWAYS (r == 123);
     240      }
     241  #endif
     242  
     243    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     244    for (i = 0; i < 2; i++)
     245      {
     246        xp[0] = 0x8008;
     247        mpn_rshift (wp, xp, (mp_size_t) 1, 1);
     248        ASSERT_ALWAYS (wp[0] == 0x4004);
     249      }
     250  
     251    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     252    for (i = 0; i < 2; i++)
     253      {
     254        xp[0] = 5;
     255        mpn_sqr_basecase (wp, xp, (mp_size_t) 1);
     256        ASSERT_ALWAYS (wp[0] == 25);
     257        ASSERT_ALWAYS (wp[1] == 0);
     258      }
     259  
     260    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     261    for (i = 0; i < 2; i++)
     262      {
     263        xp[0] = 999;
     264        yp[0] = 666;
     265        mpn_sub_n (wp, xp, yp, (mp_size_t) 1);
     266        ASSERT_ALWAYS (wp[0] == 333);
     267      }
     268  
     269    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
     270    for (i = 0; i < 2; i++)
     271      {
     272        xp[0] = 123;
     273        wp[0] = 456;
     274        r = mpn_submul_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(2));
     275        ASSERT_ALWAYS (wp[0] == 210);
     276        ASSERT_ALWAYS (r == 0);
     277      }
     278  }
     279  
     280  /* Expect the first use of each fat threshold to invoke the necessary
     281     initialization.  */
     282  void
     283  check_thresholds (void)
     284  {
     285  #define ITERATE(name,field)                                             \
     286    do {                                                                  \
     287      __gmpn_cpuvec_initialized = 0;					\
     288      memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));   \
     289      ASSERT_ALWAYS (name != 0);                                          \
     290      ASSERT_ALWAYS (name == __gmpn_cpuvec.field);                        \
     291      ASSERT_ALWAYS (__gmpn_cpuvec_initialized);                          \
     292    } while (0)
     293  
     294    ITERATE_FAT_THRESHOLDS ();
     295  }
     296  
     297  
     298  int
     299  main (void)
     300  {
     301    memcpy (&initial_cpuvec, &__gmpn_cpuvec, sizeof (__gmpn_cpuvec));
     302  
     303    tests_start ();
     304  
     305    check_functions ();
     306    check_thresholds ();
     307  
     308    tests_end ();
     309    exit (0);
     310  }