blob: 4e7101785ec3c5f265f3dadc5c158756931af384 [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/* Test fat binary setups.
2
3Copyright 2003, 2012 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the 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
67struct cpuvec_t {
68 int dummy;
69};
70struct cpuvec_t __gmpn_cpuvec;
71#define ITERATE_FAT_THRESHOLDS() do { } while (0)
72#endif
73
74/* saved from program startup */
75struct cpuvec_t initial_cpuvec;
76
77void
78check_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. */
282void
283check_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
298int
299main (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}