xref: /netbsd-src/external/lgpl3/gmp/dist/tests/mpn/t-fat.c (revision 72c7faa4dbb41dbb0238d6b4a109da0d4b236dd4)
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
check_functions(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
check_thresholds(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
main(void)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 }
311