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