1/* Test assembler support for --enable-profiling=instrument.
2
3Copyright 2002, 2003 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include "gmp.h"
23#include "gmp-impl.h"
24#include "longlong.h"
25#include "tests.h"
26
27
28#if WANT_PROFILING_INSTRUMENT
29
30/* This program exercises each mpn routine that might be implemented in
31   assembler.  It ensures the __cyg_profile_func_enter and exit calls have
32   come out right, and that in the x86 code "ret_internal" is correctly used
33   for PIC setups.  */
34
35
36/* Changes to enter_seen done by __cyg_profile_func_enter are essentially
37   unknown to the optimizer, so must use volatile.  */
38volatile int  enter_seen;
39
40/* Dummy used to stop various calls going dead. */
41unsigned long  notdead;
42
43const char     *name = "<none>";
44int  old_ncall;
45
46struct {
47  void  *this_fn;
48  void  *call_site;
49} call[100];
50int  ncall;
51
52
53void __cyg_profile_func_enter __GMP_PROTO ((void *this_fn, void *call_site))
54     __attribute__ ((no_instrument_function));
55
56void
57__cyg_profile_func_enter (void *this_fn, void *call_site)
58{
59#if 0
60  printf ("%24s %p %p\n", name, this_fn, call_site);
61#endif
62  ASSERT_ALWAYS (ncall >= 0);
63  ASSERT_ALWAYS (ncall <= numberof (call));
64
65  if (ncall >= numberof (call))
66    {
67      printf ("__cyg_profile_func_enter: oops, call stack full, from %s\n", name);
68      abort ();
69    }
70
71  enter_seen = 1;
72  call[ncall].this_fn = this_fn;
73  call[ncall].call_site = call_site;
74  ncall++;
75}
76
77void __cyg_profile_func_exit __GMP_PROTO ((void *this_fn, void *call_site))
78     __attribute__ ((no_instrument_function));
79
80void
81__cyg_profile_func_exit  (void *this_fn, void *call_site)
82{
83  ASSERT_ALWAYS (ncall >= 0);
84  ASSERT_ALWAYS (ncall <= numberof (call));
85
86  if (ncall == 0)
87    {
88      printf ("__cyg_profile_func_exit: call stack empty, from %s\n", name);
89      abort ();
90    }
91
92  ncall--;
93  if (this_fn != call[ncall].this_fn || call_site != call[ncall].call_site)
94    {
95      printf ("__cyg_profile_func_exit: unbalanced this_fn/call_site from %s\n", name);
96      printf ("  this_fn got  %p\n", this_fn);
97      printf ("          want %p\n", call[ncall].this_fn);
98      printf ("  call_site got  %p\n", call_site);
99      printf ("            want %p\n", call[ncall].call_site);
100      abort ();
101    }
102}
103
104
105void
106pre (const char *str)
107{
108  name = str;
109  enter_seen = 0;
110  old_ncall = ncall;
111}
112
113void
114post (void)
115{
116  if (! enter_seen)
117    {
118      printf ("did not reach __cyg_profile_func_enter from %s\n", name);
119      abort ();
120    }
121
122  if (ncall != old_ncall)
123    {
124      printf ("unbalance enter/exit calls from %s\n", name);
125      printf ("  ncall     %d\n", ncall);
126      printf ("  old_ncall %d\n", old_ncall);
127      abort ();
128    }
129}
130
131void
132check (void)
133{
134  mp_limb_t  wp[100], xp[100], yp[100];
135  mp_size_t  size = 100;
136
137  refmpn_zero (xp, size);
138  refmpn_zero (yp, size);
139  refmpn_zero (wp, size);
140
141  pre ("mpn_add_n");
142  mpn_add_n (wp, xp, yp, size);
143  post ();
144
145#if HAVE_NATIVE_mpn_add_nc
146  pre ("mpn_add_nc");
147  mpn_add_nc (wp, xp, yp, size, CNST_LIMB(0));
148  post ();
149#endif
150
151#if HAVE_NATIVE_mpn_addlsh1_n
152  pre ("mpn_addlsh1_n");
153  mpn_addlsh1_n (wp, xp, yp, size);
154  post ();
155#endif
156
157#if HAVE_NATIVE_mpn_and_n
158  pre ("mpn_and_n");
159  mpn_and_n (wp, xp, yp, size);
160  post ();
161#endif
162
163#if HAVE_NATIVE_mpn_andn_n
164  pre ("mpn_andn_n");
165  mpn_andn_n (wp, xp, yp, size);
166  post ();
167#endif
168
169  pre ("mpn_addmul_1");
170  mpn_addmul_1 (wp, xp, size, yp[0]);
171  post ();
172
173#if HAVE_NATIVE_mpn_addmul_1c
174  pre ("mpn_addmul_1c");
175  mpn_addmul_1c (wp, xp, size, yp[0], CNST_LIMB(0));
176  post ();
177#endif
178
179#if HAVE_NATIVE_mpn_com
180  pre ("mpn_com");
181  mpn_com (wp, xp, size);
182  post ();
183#endif
184
185#if HAVE_NATIVE_mpn_copyd
186  pre ("mpn_copyd");
187  mpn_copyd (wp, xp, size);
188  post ();
189#endif
190
191#if HAVE_NATIVE_mpn_copyi
192  pre ("mpn_copyi");
193  mpn_copyi (wp, xp, size);
194  post ();
195#endif
196
197  pre ("mpn_divexact_1");
198  mpn_divexact_1 (wp, xp, size, CNST_LIMB(123));
199  post ();
200
201  pre ("mpn_divexact_by3c");
202  mpn_divexact_by3c (wp, xp, size, CNST_LIMB(0));
203  post ();
204
205  pre ("mpn_divrem_1");
206  mpn_divrem_1 (wp, (mp_size_t) 0, xp, size, CNST_LIMB(123));
207  post ();
208
209#if HAVE_NATIVE_mpn_divrem_1c
210  pre ("mpn_divrem_1c");
211  mpn_divrem_1c (wp, (mp_size_t) 0, xp, size, CNST_LIMB(123), CNST_LIMB(122));
212  post ();
213#endif
214
215  pre ("mpn_gcd_1");
216  xp[0] |= 1;
217  notdead += (unsigned long) mpn_gcd_1 (xp, size, CNST_LIMB(123));
218  post ();
219
220  pre ("mpn_hamdist");
221  notdead += mpn_hamdist (xp, yp, size);
222  post ();
223
224#if HAVE_NATIVE_mpn_ior_n
225  pre ("mpn_ior_n");
226  mpn_ior_n (wp, xp, yp, size);
227  post ();
228#endif
229
230#if HAVE_NATIVE_mpn_iorn_n
231  pre ("mpn_iorn_n");
232  mpn_iorn_n (wp, xp, yp, size);
233  post ();
234#endif
235
236  pre ("mpn_lshift");
237  mpn_lshift (wp, xp, size, 1);
238  post ();
239
240  pre ("mpn_mod_1");
241  notdead += mpn_mod_1 (xp, size, CNST_LIMB(123));
242  post ();
243
244#if HAVE_NATIVE_mpn_mod_1c
245  pre ("mpn_mod_1c");
246  notdead += mpn_mod_1c (xp, size, CNST_LIMB(123), CNST_LIMB(122));
247  post ();
248#endif
249
250#if GMP_NUMB_BITS % 4 == 0
251  pre ("mpn_mod_34lsub1");
252  notdead += mpn_mod_34lsub1 (xp, size);
253  post ();
254#endif
255
256  pre ("mpn_modexact_1_odd");
257  notdead += mpn_modexact_1_odd (xp, size, CNST_LIMB(123));
258  post ();
259
260  pre ("mpn_modexact_1c_odd");
261  notdead += mpn_modexact_1c_odd (xp, size, CNST_LIMB(123), CNST_LIMB(456));
262  post ();
263
264  pre ("mpn_mul_1");
265  mpn_mul_1 (wp, xp, size, yp[0]);
266  post ();
267
268#if HAVE_NATIVE_mpn_mul_1c
269  pre ("mpn_mul_1c");
270  mpn_mul_1c (wp, xp, size, yp[0], CNST_LIMB(0));
271  post ();
272#endif
273
274#if HAVE_NATIVE_mpn_mul_2
275  pre ("mpn_mul_2");
276  mpn_mul_2 (wp, xp, size-1, yp);
277  post ();
278#endif
279
280  pre ("mpn_mul_basecase");
281  mpn_mul_basecase (wp, xp, (mp_size_t) 3, yp, (mp_size_t) 3);
282  post ();
283
284#if HAVE_NATIVE_mpn_nand_n
285  pre ("mpn_nand_n");
286  mpn_nand_n (wp, xp, yp, size);
287  post ();
288#endif
289
290#if HAVE_NATIVE_mpn_nior_n
291  pre ("mpn_nior_n");
292  mpn_nior_n (wp, xp, yp, size);
293  post ();
294#endif
295
296  pre ("mpn_popcount");
297  notdead += mpn_popcount (xp, size);
298  post ();
299
300  pre ("mpn_preinv_mod_1");
301  notdead += mpn_preinv_mod_1 (xp, size, GMP_NUMB_MAX,
302                               refmpn_invert_limb (GMP_NUMB_MAX));
303  post ();
304
305#if USE_PREINV_DIVREM_1 || HAVE_NATIVE_mpn_preinv_divrem_1
306  pre ("mpn_preinv_divrem_1");
307  mpn_preinv_divrem_1 (wp, (mp_size_t) 0, xp, size, GMP_NUMB_MAX,
308                       refmpn_invert_limb (GMP_NUMB_MAX), 0);
309  post ();
310#endif
311
312#if HAVE_NATIVE_mpn_rsh1add_n
313  pre ("mpn_rsh1add_n");
314  mpn_rsh1add_n (wp, xp, yp, size);
315  post ();
316#endif
317
318#if HAVE_NATIVE_mpn_rsh1sub_n
319  pre ("mpn_rsh1sub_n");
320  mpn_rsh1sub_n (wp, xp, yp, size);
321  post ();
322#endif
323
324  pre ("mpn_rshift");
325  mpn_rshift (wp, xp, size, 1);
326  post ();
327
328  pre ("mpn_sqr_basecase");
329  mpn_sqr_basecase (wp, xp, (mp_size_t) 3);
330  post ();
331
332  pre ("mpn_submul_1");
333  mpn_submul_1 (wp, xp, size, yp[0]);
334  post ();
335
336#if HAVE_NATIVE_mpn_submul_1c
337  pre ("mpn_submul_1c");
338  mpn_submul_1c (wp, xp, size, yp[0], CNST_LIMB(0));
339  post ();
340#endif
341
342  pre ("mpn_sub_n");
343  mpn_sub_n (wp, xp, yp, size);
344  post ();
345
346#if HAVE_NATIVE_mpn_sub_nc
347  pre ("mpn_sub_nc");
348  mpn_sub_nc (wp, xp, yp, size, CNST_LIMB(0));
349  post ();
350#endif
351
352#if HAVE_NATIVE_mpn_sublsh1_n
353  pre ("mpn_sublsh1_n");
354  mpn_sublsh1_n (wp, xp, yp, size);
355  post ();
356#endif
357
358#if HAVE_NATIVE_mpn_udiv_qrnnd
359  pre ("mpn_udiv_qrnnd");
360  mpn_udiv_qrnnd (&wp[0], CNST_LIMB(122), xp[0], CNST_LIMB(123));
361  post ();
362#endif
363
364#if HAVE_NATIVE_mpn_udiv_qrnnd_r
365  pre ("mpn_udiv_qrnnd_r");
366  mpn_udiv_qrnnd (CNST_LIMB(122), xp[0], CNST_LIMB(123), &wp[0]);
367  post ();
368#endif
369
370#if HAVE_NATIVE_mpn_umul_ppmm
371  pre ("mpn_umul_ppmm");
372  mpn_umul_ppmm (&wp[0], xp[0], yp[0]);
373  post ();
374#endif
375
376#if HAVE_NATIVE_mpn_umul_ppmm_r
377  pre ("mpn_umul_ppmm_r");
378  mpn_umul_ppmm_r (&wp[0], xp[0], yp[0]);
379  post ();
380#endif
381
382#if HAVE_NATIVE_mpn_xor_n
383  pre ("mpn_xor_n");
384  mpn_xor_n (wp, xp, yp, size);
385  post ();
386#endif
387
388#if HAVE_NATIVE_mpn_xnor_n
389  pre ("mpn_xnor_n");
390  mpn_xnor_n (wp, xp, yp, size);
391  post ();
392#endif
393}
394
395
396int
397main (void)
398{
399  tests_start ();
400
401  check ();
402
403  tests_end ();
404  exit (0);
405}
406
407
408#else /* ! WANT_PROFILING_INSTRUMENT */
409
410int
411main (void)
412{
413  exit (0);
414}
415
416#endif
417