]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/libgcc2.c
Daily bump.
[thirdparty/gcc.git] / gcc / libgcc2.c
CommitLineData
203b91b9
RS
1/* More subroutines needed by GCC output code on some machines. */
2/* Compile this one with gcc. */
5d0e6486
AO
3/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
4 2000, 2001 Free Software Foundation, Inc.
203b91b9
RS
5
6This file is part of GNU CC.
7
8GNU CC is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
f7af368f
JL
13In addition to the permissions in the GNU General Public License, the
14Free Software Foundation gives you unlimited permission to link the
15compiled version of this file into combinations with other programs,
16and to distribute those combinations without any restriction coming
17from the use of this file. (The General Public License restrictions
18do apply in other respects; for example, they cover modification of
19the file, and distribution when not linked into a combine
20executable.)
21
203b91b9
RS
22GNU CC is distributed in the hope that it will be useful,
23but WITHOUT ANY WARRANTY; without even the implied warranty of
24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25GNU General Public License for more details.
26
27You should have received a copy of the GNU General Public License
28along with GNU CC; see the file COPYING. If not, write to
a35311b0
RK
29the Free Software Foundation, 59 Temple Place - Suite 330,
30Boston, MA 02111-1307, USA. */
203b91b9 31
203b91b9
RS
32/* It is incorrect to include config.h here, because this file is being
33 compiled for the target, and hence definitions concerning only the host
34 do not apply. */
35
0dadecf6 36#include "tconfig.h"
2e39bdbe 37#include "tsystem.h"
2467749d 38
bfe655f9 39#include "machmode.h"
203b91b9
RS
40
41/* Don't use `fancy_abort' here even if config.h says to use it. */
42#ifdef abort
43#undef abort
44#endif
45
299b83b7 46#include "libgcc2.h"
203b91b9
RS
47\f
48#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
49#if defined (L_divdi3) || defined (L_moddi3)
50static inline
51#endif
3d2adde6
CC
52DWtype
53__negdi2 (DWtype u)
54{
55 DWunion w;
56 DWunion uu;
57
58 uu.ll = u;
59
60 w.s.low = -uu.s.low;
61 w.s.high = -uu.s.high - ((UWtype) w.s.low > 0);
62
63 return w.ll;
64}
65#endif
91ce572a
CC
66
67#ifdef L_addvsi3
66f77154
MH
68Wtype
69__addvsi3 (Wtype a, Wtype b)
91ce572a 70{
66f77154 71 Wtype w;
91ce572a
CC
72
73 w = a + b;
74
75 if (b >= 0 ? w < a : w > a)
76 abort ();
77
78 return w;
79}
3d2adde6 80#endif
91ce572a
CC
81\f
82#ifdef L_addvdi3
66f77154
MH
83DWtype
84__addvdi3 (DWtype a, DWtype b)
91ce572a 85{
66f77154 86 DWtype w;
91ce572a
CC
87
88 w = a + b;
89
90 if (b >= 0 ? w < a : w > a)
91 abort ();
92
93 return w;
94}
95#endif
96\f
97#ifdef L_subvsi3
66f77154
MH
98Wtype
99__subvsi3 (Wtype a, Wtype b)
91ce572a
CC
100{
101#ifdef L_addvsi3
102 return __addvsi3 (a, (-b));
103#else
66f77154 104 DWtype w;
91ce572a
CC
105
106 w = a - b;
107
108 if (b >= 0 ? w > a : w < a)
109 abort ();
110
111 return w;
112#endif
113}
114#endif
115\f
116#ifdef L_subvdi3
66f77154
MH
117DWtype
118__subvdi3 (DWtype a, DWtype b)
91ce572a
CC
119{
120#ifdef L_addvdi3
121 return (a, (-b));
122#else
66f77154 123 DWtype w;
91ce572a
CC
124
125 w = a - b;
126
127 if (b >= 0 ? w > a : w < a)
128 abort ();
129
130 return w;
131#endif
132}
133#endif
134\f
135#ifdef L_mulvsi3
66f77154
MH
136Wtype
137__mulvsi3 (Wtype a, Wtype b)
91ce572a 138{
66f77154 139 DWtype w;
91ce572a
CC
140
141 w = a * b;
142
3cf37281 143 if (((a >= 0) == (b >= 0)) ? w < 0 : w > 0)
91ce572a
CC
144 abort ();
145
146 return w;
147}
148#endif
149\f
150#ifdef L_negvsi2
66f77154
MH
151Wtype
152__negvsi2 (Wtype a)
91ce572a 153{
66f77154 154 Wtype w;
91ce572a
CC
155
156 w = -a;
157
158 if (a >= 0 ? w > 0 : w < 0)
159 abort ();
160
161 return w;
162}
163#endif
164\f
165#ifdef L_negvdi2
66f77154
MH
166DWtype
167__negvdi2 (DWtype a)
91ce572a 168{
66f77154 169 DWtype w;
91ce572a
CC
170
171 w = -a;
172
173 if (a >= 0 ? w > 0 : w < 0)
174 abort ();
175
176 return w;
177}
178#endif
179\f
180#ifdef L_absvsi2
66f77154
MH
181Wtype
182__absvsi2 (Wtype a)
91ce572a 183{
66f77154 184 Wtype w = a;
91ce572a
CC
185
186 if (a < 0)
187#ifdef L_negvsi2
188 w = __negvsi2 (a);
189#else
190 w = -a;
191
192 if (w < 0)
193 abort ();
194#endif
195
196 return w;
197}
198#endif
199\f
200#ifdef L_absvdi2
66f77154
MH
201DWtype
202__absvdi2 (DWtype a)
91ce572a 203{
66f77154 204 DWtype w = a;
91ce572a
CC
205
206 if (a < 0)
207#ifdef L_negvsi2
208 w = __negvsi2 (a);
209#else
210 w = -a;
211
212 if (w < 0)
213 abort ();
214#endif
215
216 return w;
217}
218#endif
219\f
220#ifdef L_mulvdi3
66f77154
MH
221DWtype
222__mulvdi3 (DWtype u, DWtype v)
91ce572a 223{
66f77154 224 DWtype w;
91ce572a
CC
225
226 w = u * v;
227
3d2adde6 228 if (((u >= 0) == (v >= 0)) ? w < 0 : w > 0)
91ce572a
CC
229 abort ();
230
231 return w;
232}
233#endif
234\f
203b91b9 235
37ef1054
RK
236/* Unless shift functions are defined whith full ANSI prototypes,
237 parameter b will be promoted to int if word_type is smaller than an int. */
203b91b9 238#ifdef L_lshrdi3
996ed075
JJ
239DWtype
240__lshrdi3 (DWtype u, word_type b)
203b91b9 241{
996ed075 242 DWunion w;
b799cfc3 243 word_type bm;
996ed075 244 DWunion uu;
203b91b9
RS
245
246 if (b == 0)
247 return u;
248
249 uu.ll = u;
250
996ed075 251 bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
203b91b9
RS
252 if (bm <= 0)
253 {
254 w.s.high = 0;
6da9c622 255 w.s.low = (UWtype) uu.s.high >> -bm;
203b91b9
RS
256 }
257 else
258 {
6da9c622
RK
259 UWtype carries = (UWtype) uu.s.high << bm;
260
261 w.s.high = (UWtype) uu.s.high >> b;
262 w.s.low = ((UWtype) uu.s.low >> b) | carries;
203b91b9
RS
263 }
264
265 return w.ll;
266}
267#endif
268
269#ifdef L_ashldi3
996ed075
JJ
270DWtype
271__ashldi3 (DWtype u, word_type b)
203b91b9 272{
996ed075 273 DWunion w;
b799cfc3 274 word_type bm;
996ed075 275 DWunion uu;
203b91b9
RS
276
277 if (b == 0)
278 return u;
279
280 uu.ll = u;
281
996ed075 282 bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
203b91b9
RS
283 if (bm <= 0)
284 {
285 w.s.low = 0;
6da9c622 286 w.s.high = (UWtype) uu.s.low << -bm;
203b91b9
RS
287 }
288 else
289 {
6da9c622
RK
290 UWtype carries = (UWtype) uu.s.low >> bm;
291
292 w.s.low = (UWtype) uu.s.low << b;
293 w.s.high = ((UWtype) uu.s.high << b) | carries;
203b91b9
RS
294 }
295
296 return w.ll;
297}
298#endif
299
300#ifdef L_ashrdi3
996ed075
JJ
301DWtype
302__ashrdi3 (DWtype u, word_type b)
203b91b9 303{
996ed075 304 DWunion w;
b799cfc3 305 word_type bm;
996ed075 306 DWunion uu;
203b91b9
RS
307
308 if (b == 0)
309 return u;
310
311 uu.ll = u;
312
996ed075 313 bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
203b91b9
RS
314 if (bm <= 0)
315 {
316 /* w.s.high = 1..1 or 0..0 */
996ed075 317 w.s.high = uu.s.high >> (sizeof (Wtype) * BITS_PER_UNIT - 1);
203b91b9
RS
318 w.s.low = uu.s.high >> -bm;
319 }
320 else
321 {
6da9c622
RK
322 UWtype carries = (UWtype) uu.s.high << bm;
323
203b91b9 324 w.s.high = uu.s.high >> b;
6da9c622 325 w.s.low = ((UWtype) uu.s.low >> b) | carries;
203b91b9
RS
326 }
327
328 return w.ll;
329}
330#endif
331\f
aa66bd06 332#ifdef L_ffsdi2
996ed075
JJ
333DWtype
334__ffsdi2 (DWtype u)
aa66bd06 335{
d6eacd48
RH
336 DWunion uu;
337 UWtype word, count, add;
338
aa66bd06 339 uu.ll = u;
d6eacd48
RH
340 if (uu.s.low != 0)
341 word = uu.s.low, add = 0;
342 else if (uu.s.high != 0)
343 word = uu.s.high, add = BITS_PER_UNIT * sizeof (Wtype);
344 else
345 return 0;
346
347 count_trailing_zeros (count, word);
348 return count + add + 1;
aa66bd06
RS
349}
350#endif
351\f
203b91b9 352#ifdef L_muldi3
996ed075
JJ
353DWtype
354__muldi3 (DWtype u, DWtype v)
203b91b9 355{
996ed075
JJ
356 DWunion w;
357 DWunion uu, vv;
203b91b9
RS
358
359 uu.ll = u,
360 vv.ll = v;
361
362 w.ll = __umulsidi3 (uu.s.low, vv.s.low);
996ed075
JJ
363 w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high
364 + (UWtype) uu.s.high * (UWtype) vv.s.low);
203b91b9
RS
365
366 return w.ll;
367}
368#endif
369\f
3904131a 370#ifdef L_udiv_w_sdiv
ce13d15f 371#if defined (sdiv_qrnnd)
996ed075
JJ
372UWtype
373__udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d)
431b1ee0 374{
996ed075
JJ
375 UWtype q, r;
376 UWtype c0, c1, b1;
431b1ee0 377
996ed075 378 if ((Wtype) d >= 0)
431b1ee0 379 {
996ed075 380 if (a1 < d - a1 - (a0 >> (W_TYPE_SIZE - 1)))
431b1ee0
TG
381 {
382 /* dividend, divisor, and quotient are nonnegative */
383 sdiv_qrnnd (q, r, a1, a0, d);
384 }
385 else
386 {
387 /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
996ed075 388 sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (W_TYPE_SIZE - 1));
431b1ee0
TG
389 /* Divide (c1*2^32 + c0) by d */
390 sdiv_qrnnd (q, r, c1, c0, d);
391 /* Add 2^31 to quotient */
996ed075 392 q += (UWtype) 1 << (W_TYPE_SIZE - 1);
431b1ee0
TG
393 }
394 }
395 else
396 {
397 b1 = d >> 1; /* d/2, between 2^30 and 2^31 - 1 */
398 c1 = a1 >> 1; /* A/2 */
996ed075 399 c0 = (a1 << (W_TYPE_SIZE - 1)) + (a0 >> 1);
431b1ee0
TG
400
401 if (a1 < b1) /* A < 2^32*b1, so A/2 < 2^31*b1 */
402 {
403 sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
404
405 r = 2*r + (a0 & 1); /* Remainder from A/(2*b1) */
406 if ((d & 1) != 0)
407 {
408 if (r >= q)
409 r = r - q;
410 else if (q - r <= d)
411 {
412 r = r - q + d;
413 q--;
414 }
415 else
416 {
417 r = r - q + 2*d;
418 q -= 2;
419 }
420 }
421 }
422 else if (c1 < b1) /* So 2^31 <= (A/2)/b1 < 2^32 */
423 {
424 c1 = (b1 - 1) - c1;
425 c0 = ~c0; /* logical NOT */
426
427 sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
428
429 q = ~q; /* (A/2)/b1 */
430 r = (b1 - 1) - r;
431
432 r = 2*r + (a0 & 1); /* A/(2*b1) */
433
434 if ((d & 1) != 0)
435 {
436 if (r >= q)
437 r = r - q;
438 else if (q - r <= d)
439 {
440 r = r - q + d;
441 q--;
442 }
443 else
444 {
445 r = r - q + 2*d;
446 q -= 2;
447 }
448 }
449 }
450 else /* Implies c1 = b1 */
451 { /* Hence a1 = d - 1 = 2*b1 - 1 */
452 if (a0 >= -d)
453 {
454 q = -1;
455 r = a0 + d;
456 }
457 else
458 {
459 q = -2;
460 r = a0 + 2*d;
461 }
462 }
463 }
464
465 *rp = r;
466 return q;
467}
ce13d15f
RK
468#else
469/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv. */
996ed075
JJ
470UWtype
471__udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)),
472 UWtype a1 __attribute__ ((__unused__)),
473 UWtype a0 __attribute__ ((__unused__)),
474 UWtype d __attribute__ ((__unused__)))
081f5e7e
KG
475{
476 return 0;
477}
ce13d15f 478#endif
431b1ee0
TG
479#endif
480\f
536bfcd0
RK
481#if (defined (L_udivdi3) || defined (L_divdi3) || \
482 defined (L_umoddi3) || defined (L_moddi3))
483#define L_udivmoddi4
484#endif
485
d6eacd48
RH
486#ifdef L_clz
487const UQItype __clz_tab[] =
203b91b9
RS
488{
489 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
490 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
491 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
492 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
493 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
494 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
495 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
496 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
497};
d6eacd48
RH
498#endif
499
500#ifdef L_udivmoddi4
203b91b9 501
536bfcd0
RK
502#if (defined (L_udivdi3) || defined (L_divdi3) || \
503 defined (L_umoddi3) || defined (L_moddi3))
504static inline
505#endif
996ed075
JJ
506UDWtype
507__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
203b91b9 508{
996ed075
JJ
509 DWunion ww;
510 DWunion nn, dd;
511 DWunion rr;
512 UWtype d0, d1, n0, n1, n2;
513 UWtype q0, q1;
514 UWtype b, bm;
203b91b9
RS
515
516 nn.ll = n;
517 dd.ll = d;
518
519 d0 = dd.s.low;
520 d1 = dd.s.high;
521 n0 = nn.s.low;
522 n1 = nn.s.high;
523
524#if !UDIV_NEEDS_NORMALIZATION
525 if (d1 == 0)
526 {
527 if (d0 > n1)
528 {
529 /* 0q = nn / 0D */
530
531 udiv_qrnnd (q0, n0, n1, n0, d0);
532 q1 = 0;
533
534 /* Remainder in n0. */
535 }
536 else
537 {
538 /* qq = NN / 0d */
539
540 if (d0 == 0)
541 d0 = 1 / d0; /* Divide intentionally by zero. */
542
543 udiv_qrnnd (q1, n1, 0, n1, d0);
544 udiv_qrnnd (q0, n0, n1, n0, d0);
545
546 /* Remainder in n0. */
547 }
548
549 if (rp != 0)
550 {
551 rr.s.low = n0;
552 rr.s.high = 0;
553 *rp = rr.ll;
554 }
555 }
556
557#else /* UDIV_NEEDS_NORMALIZATION */
558
559 if (d1 == 0)
560 {
561 if (d0 > n1)
562 {
563 /* 0q = nn / 0D */
564
565 count_leading_zeros (bm, d0);
566
567 if (bm != 0)
568 {
569 /* Normalize, i.e. make the most significant bit of the
570 denominator set. */
571
572 d0 = d0 << bm;
996ed075 573 n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
203b91b9
RS
574 n0 = n0 << bm;
575 }
576
577 udiv_qrnnd (q0, n0, n1, n0, d0);
578 q1 = 0;
579
580 /* Remainder in n0 >> bm. */
581 }
582 else
583 {
584 /* qq = NN / 0d */
585
586 if (d0 == 0)
587 d0 = 1 / d0; /* Divide intentionally by zero. */
588
589 count_leading_zeros (bm, d0);
590
591 if (bm == 0)
592 {
593 /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
594 conclude (the most significant bit of n1 is set) /\ (the
595 leading quotient digit q1 = 1).
596
597 This special case is necessary, not an optimization.
996ed075 598 (Shifts counts of W_TYPE_SIZE are undefined.) */
203b91b9
RS
599
600 n1 -= d0;
601 q1 = 1;
602 }
603 else
604 {
605 /* Normalize. */
606
996ed075 607 b = W_TYPE_SIZE - bm;
203b91b9
RS
608
609 d0 = d0 << bm;
610 n2 = n1 >> b;
611 n1 = (n1 << bm) | (n0 >> b);
612 n0 = n0 << bm;
613
614 udiv_qrnnd (q1, n1, n2, n1, d0);
615 }
616
0f41302f 617 /* n1 != d0... */
203b91b9
RS
618
619 udiv_qrnnd (q0, n0, n1, n0, d0);
620
621 /* Remainder in n0 >> bm. */
622 }
623
624 if (rp != 0)
625 {
626 rr.s.low = n0 >> bm;
627 rr.s.high = 0;
628 *rp = rr.ll;
629 }
630 }
631#endif /* UDIV_NEEDS_NORMALIZATION */
632
633 else
634 {
635 if (d1 > n1)
636 {
637 /* 00 = nn / DD */
638
639 q0 = 0;
640 q1 = 0;
641
642 /* Remainder in n1n0. */
643 if (rp != 0)
644 {
645 rr.s.low = n0;
646 rr.s.high = n1;
647 *rp = rr.ll;
648 }
649 }
650 else
651 {
652 /* 0q = NN / dd */
653
654 count_leading_zeros (bm, d1);
655 if (bm == 0)
656 {
657 /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
658 conclude (the most significant bit of n1 is set) /\ (the
659 quotient digit q0 = 0 or 1).
660
661 This special case is necessary, not an optimization. */
662
663 /* The condition on the next line takes advantage of that
664 n1 >= d1 (true due to program flow). */
665 if (n1 > d1 || n0 >= d0)
666 {
667 q0 = 1;
668 sub_ddmmss (n1, n0, n1, n0, d1, d0);
669 }
670 else
671 q0 = 0;
672
673 q1 = 0;
674
675 if (rp != 0)
676 {
677 rr.s.low = n0;
678 rr.s.high = n1;
679 *rp = rr.ll;
680 }
681 }
682 else
683 {
996ed075 684 UWtype m1, m0;
203b91b9
RS
685 /* Normalize. */
686
996ed075 687 b = W_TYPE_SIZE - bm;
203b91b9
RS
688
689 d1 = (d1 << bm) | (d0 >> b);
690 d0 = d0 << bm;
691 n2 = n1 >> b;
692 n1 = (n1 << bm) | (n0 >> b);
693 n0 = n0 << bm;
694
695 udiv_qrnnd (q0, n1, n2, n1, d1);
696 umul_ppmm (m1, m0, q0, d0);
697
698 if (m1 > n1 || (m1 == n1 && m0 > n0))
699 {
700 q0--;
701 sub_ddmmss (m1, m0, m1, m0, d1, d0);
702 }
703
704 q1 = 0;
705
706 /* Remainder in (n1n0 - m1m0) >> bm. */
707 if (rp != 0)
708 {
709 sub_ddmmss (n1, n0, n1, n0, m1, m0);
710 rr.s.low = (n1 << b) | (n0 >> bm);
711 rr.s.high = n1 >> bm;
712 *rp = rr.ll;
713 }
714 }
715 }
716 }
717
718 ww.s.low = q0;
719 ww.s.high = q1;
720 return ww.ll;
721}
722#endif
723
724#ifdef L_divdi3
996ed075
JJ
725DWtype
726__divdi3 (DWtype u, DWtype v)
203b91b9 727{
b799cfc3 728 word_type c = 0;
996ed075
JJ
729 DWunion uu, vv;
730 DWtype w;
203b91b9
RS
731
732 uu.ll = u;
733 vv.ll = v;
734
735 if (uu.s.high < 0)
736 c = ~c,
737 uu.ll = __negdi2 (uu.ll);
738 if (vv.s.high < 0)
739 c = ~c,
740 vv.ll = __negdi2 (vv.ll);
741
996ed075 742 w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
203b91b9
RS
743 if (c)
744 w = __negdi2 (w);
745
746 return w;
747}
748#endif
749
750#ifdef L_moddi3
996ed075
JJ
751DWtype
752__moddi3 (DWtype u, DWtype v)
203b91b9 753{
b799cfc3 754 word_type c = 0;
996ed075
JJ
755 DWunion uu, vv;
756 DWtype w;
203b91b9
RS
757
758 uu.ll = u;
759 vv.ll = v;
760
761 if (uu.s.high < 0)
762 c = ~c,
763 uu.ll = __negdi2 (uu.ll);
764 if (vv.s.high < 0)
765 vv.ll = __negdi2 (vv.ll);
766
767 (void) __udivmoddi4 (uu.ll, vv.ll, &w);
768 if (c)
769 w = __negdi2 (w);
770
771 return w;
772}
773#endif
774
775#ifdef L_umoddi3
996ed075
JJ
776UDWtype
777__umoddi3 (UDWtype u, UDWtype v)
203b91b9 778{
996ed075 779 UDWtype w;
203b91b9
RS
780
781 (void) __udivmoddi4 (u, v, &w);
782
783 return w;
784}
785#endif
786
787#ifdef L_udivdi3
996ed075
JJ
788UDWtype
789__udivdi3 (UDWtype n, UDWtype d)
203b91b9 790{
996ed075 791 return __udivmoddi4 (n, d, (UDWtype *) 0);
203b91b9
RS
792}
793#endif
794\f
795#ifdef L_cmpdi2
4be7c28f 796word_type
996ed075 797__cmpdi2 (DWtype a, DWtype b)
203b91b9 798{
996ed075 799 DWunion au, bu;
203b91b9
RS
800
801 au.ll = a, bu.ll = b;
802
803 if (au.s.high < bu.s.high)
804 return 0;
805 else if (au.s.high > bu.s.high)
806 return 2;
996ed075 807 if ((UWtype) au.s.low < (UWtype) bu.s.low)
203b91b9 808 return 0;
996ed075 809 else if ((UWtype) au.s.low > (UWtype) bu.s.low)
203b91b9
RS
810 return 2;
811 return 1;
812}
813#endif
814
815#ifdef L_ucmpdi2
4be7c28f 816word_type
996ed075 817__ucmpdi2 (DWtype a, DWtype b)
203b91b9 818{
996ed075 819 DWunion au, bu;
203b91b9
RS
820
821 au.ll = a, bu.ll = b;
822
996ed075 823 if ((UWtype) au.s.high < (UWtype) bu.s.high)
203b91b9 824 return 0;
996ed075 825 else if ((UWtype) au.s.high > (UWtype) bu.s.high)
203b91b9 826 return 2;
996ed075 827 if ((UWtype) au.s.low < (UWtype) bu.s.low)
203b91b9 828 return 0;
996ed075 829 else if ((UWtype) au.s.low > (UWtype) bu.s.low)
203b91b9
RS
830 return 2;
831 return 1;
832}
833#endif
834\f
eaa4b44c 835#if defined(L_fixunstfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
996ed075
JJ
836#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
837#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
ab495388 838
996ed075 839DWtype
6da9c622 840__fixunstfDI (TFtype a)
ab495388
RS
841{
842 TFtype b;
996ed075 843 UDWtype v;
ab495388
RS
844
845 if (a < 0)
846 return 0;
847
848 /* Compute high word of result, as a flonum. */
849 b = (a / HIGH_WORD_COEFF);
996ed075 850 /* Convert that to fixed (but not to DWtype!),
ab495388 851 and shift it into the high word. */
996ed075 852 v = (UWtype) b;
ab495388
RS
853 v <<= WORD_SIZE;
854 /* Remove high part from the TFtype, leaving the low part as flonum. */
855 a -= (TFtype)v;
996ed075 856 /* Convert that to fixed (but not to DWtype!) and add it in.
ab495388
RS
857 Sometimes A comes out negative. This is significant, since
858 A has more bits than a long int does. */
859 if (a < 0)
996ed075 860 v -= (UWtype) (- a);
ab495388 861 else
996ed075 862 v += (UWtype) a;
ab495388
RS
863 return v;
864}
865#endif
866
eaa4b44c 867#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
996ed075 868DWtype
37ef1054 869__fixtfdi (TFtype a)
ab495388
RS
870{
871 if (a < 0)
6da9c622
RK
872 return - __fixunstfDI (-a);
873 return __fixunstfDI (a);
ab495388
RS
874}
875#endif
876
eaa4b44c 877#if defined(L_fixunsxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
996ed075
JJ
878#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
879#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
e0799b34 880
996ed075 881DWtype
6da9c622 882__fixunsxfDI (XFtype a)
e0799b34
RS
883{
884 XFtype b;
996ed075 885 UDWtype v;
e0799b34
RS
886
887 if (a < 0)
888 return 0;
889
890 /* Compute high word of result, as a flonum. */
891 b = (a / HIGH_WORD_COEFF);
996ed075 892 /* Convert that to fixed (but not to DWtype!),
e0799b34 893 and shift it into the high word. */
996ed075 894 v = (UWtype) b;
e0799b34
RS
895 v <<= WORD_SIZE;
896 /* Remove high part from the XFtype, leaving the low part as flonum. */
897 a -= (XFtype)v;
996ed075 898 /* Convert that to fixed (but not to DWtype!) and add it in.
e0799b34
RS
899 Sometimes A comes out negative. This is significant, since
900 A has more bits than a long int does. */
901 if (a < 0)
996ed075 902 v -= (UWtype) (- a);
e0799b34 903 else
996ed075 904 v += (UWtype) a;
e0799b34
RS
905 return v;
906}
907#endif
908
eaa4b44c 909#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
996ed075 910DWtype
37ef1054 911__fixxfdi (XFtype a)
e0799b34
RS
912{
913 if (a < 0)
6da9c622
RK
914 return - __fixunsxfDI (-a);
915 return __fixunsxfDI (a);
e0799b34
RS
916}
917#endif
918
203b91b9 919#ifdef L_fixunsdfdi
996ed075
JJ
920#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
921#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
203b91b9 922
996ed075 923DWtype
6da9c622 924__fixunsdfDI (DFtype a)
203b91b9 925{
ab495388 926 DFtype b;
996ed075 927 UDWtype v;
203b91b9
RS
928
929 if (a < 0)
930 return 0;
931
932 /* Compute high word of result, as a flonum. */
933 b = (a / HIGH_WORD_COEFF);
996ed075 934 /* Convert that to fixed (but not to DWtype!),
203b91b9 935 and shift it into the high word. */
996ed075 936 v = (UWtype) b;
203b91b9 937 v <<= WORD_SIZE;
ab495388
RS
938 /* Remove high part from the DFtype, leaving the low part as flonum. */
939 a -= (DFtype)v;
996ed075 940 /* Convert that to fixed (but not to DWtype!) and add it in.
203b91b9
RS
941 Sometimes A comes out negative. This is significant, since
942 A has more bits than a long int does. */
943 if (a < 0)
996ed075 944 v -= (UWtype) (- a);
203b91b9 945 else
996ed075 946 v += (UWtype) a;
203b91b9
RS
947 return v;
948}
949#endif
950
951#ifdef L_fixdfdi
996ed075 952DWtype
37ef1054 953__fixdfdi (DFtype a)
203b91b9
RS
954{
955 if (a < 0)
6da9c622
RK
956 return - __fixunsdfDI (-a);
957 return __fixunsdfDI (a);
203b91b9
RS
958}
959#endif
960
961#ifdef L_fixunssfdi
996ed075
JJ
962#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
963#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
203b91b9 964
996ed075 965DWtype
6da9c622 966__fixunssfDI (SFtype original_a)
203b91b9 967{
ab495388 968 /* Convert the SFtype to a DFtype, because that is surely not going
203b91b9 969 to lose any bits. Some day someone else can write a faster version
ab495388
RS
970 that avoids converting to DFtype, and verify it really works right. */
971 DFtype a = original_a;
972 DFtype b;
996ed075 973 UDWtype v;
203b91b9
RS
974
975 if (a < 0)
976 return 0;
977
978 /* Compute high word of result, as a flonum. */
979 b = (a / HIGH_WORD_COEFF);
996ed075 980 /* Convert that to fixed (but not to DWtype!),
203b91b9 981 and shift it into the high word. */
996ed075 982 v = (UWtype) b;
203b91b9 983 v <<= WORD_SIZE;
ab495388 984 /* Remove high part from the DFtype, leaving the low part as flonum. */
6da9c622 985 a -= (DFtype) v;
996ed075 986 /* Convert that to fixed (but not to DWtype!) and add it in.
203b91b9
RS
987 Sometimes A comes out negative. This is significant, since
988 A has more bits than a long int does. */
989 if (a < 0)
996ed075 990 v -= (UWtype) (- a);
203b91b9 991 else
996ed075 992 v += (UWtype) a;
203b91b9
RS
993 return v;
994}
995#endif
996
997#ifdef L_fixsfdi
996ed075 998DWtype
ab495388 999__fixsfdi (SFtype a)
203b91b9
RS
1000{
1001 if (a < 0)
6da9c622
RK
1002 return - __fixunssfDI (-a);
1003 return __fixunssfDI (a);
203b91b9
RS
1004}
1005#endif
1006
eaa4b44c 1007#if defined(L_floatdixf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
996ed075
JJ
1008#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
1009#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
1010#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
e0799b34
RS
1011
1012XFtype
996ed075 1013__floatdixf (DWtype u)
e0799b34
RS
1014{
1015 XFtype d;
e0799b34 1016
996ed075 1017 d = (Wtype) (u >> WORD_SIZE);
e0799b34
RS
1018 d *= HIGH_HALFWORD_COEFF;
1019 d *= HIGH_HALFWORD_COEFF;
996ed075 1020 d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
e0799b34 1021
e5e809f4 1022 return d;
e0799b34
RS
1023}
1024#endif
1025
eaa4b44c 1026#if defined(L_floatditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
996ed075
JJ
1027#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
1028#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
1029#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
ab495388
RS
1030
1031TFtype
996ed075 1032__floatditf (DWtype u)
ab495388
RS
1033{
1034 TFtype d;
ab495388 1035
996ed075 1036 d = (Wtype) (u >> WORD_SIZE);
ab495388
RS
1037 d *= HIGH_HALFWORD_COEFF;
1038 d *= HIGH_HALFWORD_COEFF;
996ed075 1039 d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
ab495388 1040
e5e809f4 1041 return d;
ab495388
RS
1042}
1043#endif
1044
203b91b9 1045#ifdef L_floatdidf
996ed075
JJ
1046#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
1047#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
1048#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
203b91b9 1049
ab495388 1050DFtype
996ed075 1051__floatdidf (DWtype u)
203b91b9 1052{
ab495388 1053 DFtype d;
203b91b9 1054
996ed075 1055 d = (Wtype) (u >> WORD_SIZE);
203b91b9
RS
1056 d *= HIGH_HALFWORD_COEFF;
1057 d *= HIGH_HALFWORD_COEFF;
996ed075 1058 d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
203b91b9 1059
e5e809f4 1060 return d;
203b91b9
RS
1061}
1062#endif
1063
1064#ifdef L_floatdisf
996ed075
JJ
1065#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
1066#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
1067#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
1068#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
cac896d8
RK
1069
1070/* Define codes for all the float formats that we know of. Note
1071 that this is copied from real.h. */
1072
1073#define UNKNOWN_FLOAT_FORMAT 0
1074#define IEEE_FLOAT_FORMAT 1
1075#define VAX_FLOAT_FORMAT 2
1076#define IBM_FLOAT_FORMAT 3
1077
1078/* Default to IEEE float if not specified. Nearly all machines use it. */
1079#ifndef HOST_FLOAT_FORMAT
1080#define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT
1081#endif
1082
1083#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
d9e1ab8d
RK
1084#define DF_SIZE 53
1085#define SF_SIZE 24
cac896d8
RK
1086#endif
1087
1088#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
d9e1ab8d
RK
1089#define DF_SIZE 56
1090#define SF_SIZE 24
cac896d8
RK
1091#endif
1092
1093#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
d9e1ab8d
RK
1094#define DF_SIZE 56
1095#define SF_SIZE 24
d9e1ab8d 1096#endif
203b91b9 1097
ab495388 1098SFtype
996ed075 1099__floatdisf (DWtype u)
203b91b9 1100{
56b03d5f
RS
1101 /* Do the calculation in DFmode
1102 so that we don't lose any of the precision of the high word
1103 while multiplying it. */
1104 DFtype f;
203b91b9 1105
d9e1ab8d
RK
1106 /* Protect against double-rounding error.
1107 Represent any low-order bits, that might be truncated in DFmode,
1108 by a bit that won't be lost. The bit can go in anywhere below the
1109 rounding position of the SFmode. A fixed mask and bit position
1110 handles all usual configurations. It doesn't handle the case
1111 of 128-bit DImode, however. */
1112 if (DF_SIZE < DI_SIZE
1113 && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
1114 {
6da9c622 1115#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE))
996ed075
JJ
1116 if (! (- ((DWtype) 1 << DF_SIZE) < u
1117 && u < ((DWtype) 1 << DF_SIZE)))
d9e1ab8d 1118 {
6da9c622 1119 if ((UDWtype) u & (REP_BIT - 1))
d9e1ab8d
RK
1120 u |= REP_BIT;
1121 }
1122 }
996ed075 1123 f = (Wtype) (u >> WORD_SIZE);
203b91b9
RS
1124 f *= HIGH_HALFWORD_COEFF;
1125 f *= HIGH_HALFWORD_COEFF;
996ed075 1126 f += (UWtype) (u & (HIGH_WORD_COEFF - 1));
203b91b9 1127
e5e809f4 1128 return (SFtype) f;
203b91b9
RS
1129}
1130#endif
1131
eaa4b44c 1132#if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
3f3d2ec8
JW
1133/* Reenable the normal types, in case limits.h needs them. */
1134#undef char
1135#undef short
1136#undef int
1137#undef long
1138#undef unsigned
1139#undef float
1140#undef double
c07e26bd
RK
1141#undef MIN
1142#undef MAX
a99598c9 1143#include <limits.h>
e0799b34 1144
996ed075 1145UWtype
6da9c622 1146__fixunsxfSI (XFtype a)
e0799b34 1147{
5d0e6486
AO
1148 if (a >= - (DFtype) Wtype_MIN)
1149 return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
996ed075 1150 return (Wtype) a;
e0799b34
RS
1151}
1152#endif
1153
203b91b9 1154#ifdef L_fixunsdfsi
3f3d2ec8
JW
1155/* Reenable the normal types, in case limits.h needs them. */
1156#undef char
1157#undef short
1158#undef int
1159#undef long
1160#undef unsigned
1161#undef float
1162#undef double
c07e26bd
RK
1163#undef MIN
1164#undef MAX
a99598c9 1165#include <limits.h>
203b91b9 1166
996ed075 1167UWtype
6da9c622 1168__fixunsdfSI (DFtype a)
203b91b9 1169{
5d0e6486
AO
1170 if (a >= - (DFtype) Wtype_MIN)
1171 return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
996ed075 1172 return (Wtype) a;
203b91b9
RS
1173}
1174#endif
1175
1176#ifdef L_fixunssfsi
3f3d2ec8
JW
1177/* Reenable the normal types, in case limits.h needs them. */
1178#undef char
1179#undef short
1180#undef int
1181#undef long
1182#undef unsigned
1183#undef float
1184#undef double
c07e26bd
RK
1185#undef MIN
1186#undef MAX
a99598c9 1187#include <limits.h>
203b91b9 1188
996ed075 1189UWtype
6da9c622 1190__fixunssfSI (SFtype a)
203b91b9 1191{
5d0e6486
AO
1192 if (a >= - (SFtype) Wtype_MIN)
1193 return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
996ed075 1194 return (Wtype) a;
203b91b9
RS
1195}
1196#endif
1197\f
ab495388
RS
1198/* From here on down, the routines use normal data types. */
1199
1200#define SItype bogus_type
1201#define USItype bogus_type
1202#define DItype bogus_type
1203#define UDItype bogus_type
1204#define SFtype bogus_type
1205#define DFtype bogus_type
996ed075
JJ
1206#undef Wtype
1207#undef UWtype
1208#undef HWtype
1209#undef UHWtype
1210#undef DWtype
1211#undef UDWtype
ab495388
RS
1212
1213#undef char
1214#undef short
1215#undef int
1216#undef long
1217#undef unsigned
1218#undef float
1219#undef double
9bd23d2c
RS
1220\f
1221#ifdef L__gcc_bcmp
1222
1223/* Like bcmp except the sign is meaningful.
9faa82d8 1224 Result is negative if S1 is less than S2,
9bd23d2c
RS
1225 positive if S1 is greater, 0 if S1 and S2 are equal. */
1226
1227int
299b83b7 1228__gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size)
9bd23d2c
RS
1229{
1230 while (size > 0)
1231 {
78e33213 1232 unsigned char c1 = *s1++, c2 = *s2++;
9bd23d2c
RS
1233 if (c1 != c2)
1234 return c1 - c2;
1235 size--;
1236 }
1237 return 0;
1238}
ab495388 1239
3fe68d0a
ZW
1240#endif
1241\f
1242/* __eprintf used to be used by GCC's private version of <assert.h>.
1243 We no longer provide that header, but this routine remains in libgcc.a
1244 for binary backward compatibility. Note that it is not included in
1245 the shared version of libgcc. */
1246#ifdef L_eprintf
1247#ifndef inhibit_libc
1248
1249#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
1250#include <stdio.h>
1251
1252void
1253__eprintf (const char *string, const char *expression,
1254 unsigned int line, const char *filename)
1255{
1256 fprintf (stderr, string, expression, line, filename);
1257 fflush (stderr);
1258 abort ();
1259}
1260
1261#endif
203b91b9
RS
1262#endif
1263
1264#ifdef L_bb
203b91b9 1265
b2aec5c0
JH
1266#if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
1267typedef long gcov_type;
1268#else
1269typedef long long gcov_type;
1270#endif
1271
1272
92832bb5 1273/* Structure emitted by -a */
203b91b9
RS
1274struct bb
1275{
92832bb5
MM
1276 long zero_word;
1277 const char *filename;
b2aec5c0 1278 gcov_type *counts;
92832bb5
MM
1279 long ncounts;
1280 struct bb *next;
1281 const unsigned long *addresses;
1282
1283 /* Older GCC's did not emit these fields. */
1284 long nwords;
1285 const char **functions;
1286 const long *line_nums;
1287 const char **filenames;
90b4a764 1288 char *flags;
203b91b9
RS
1289};
1290
92832bb5
MM
1291#ifdef BLOCK_PROFILER_CODE
1292BLOCK_PROFILER_CODE
1293#else
c7544ff7 1294#ifndef inhibit_libc
92832bb5
MM
1295
1296/* Simple minded basic block profiling output dumper for
9faa82d8 1297 systems that don't provide tcov support. At present,
92832bb5
MM
1298 it requires atexit and stdio. */
1299
ebd41309 1300#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
92832bb5 1301#include <stdio.h>
757e6639 1302char *ctime PARAMS ((const time_t *));
203b91b9 1303
8b7677be 1304#include "gbl-ctors.h"
65f7a653 1305#include "gcov-io.h"
ac957f13 1306#include <string.h>
e09d24ff
R
1307#ifdef TARGET_HAS_F_SETLKW
1308#include <fcntl.h>
1309#include <errno.h>
1310#endif
92832bb5 1311
7e6f1890 1312static struct bb *bb_head;
92832bb5 1313
e8f38d1a
DN
1314static int num_digits (long value, int base) __attribute__ ((const));
1315
92832bb5
MM
1316/* Return the number of digits needed to print a value */
1317/* __inline__ */ static int num_digits (long value, int base)
203b91b9 1318{
92832bb5
MM
1319 int minus = (value < 0 && base != 16);
1320 unsigned long v = (minus) ? -value : value;
1321 int ret = minus;
203b91b9 1322
92832bb5
MM
1323 do
1324 {
1325 v /= base;
1326 ret++;
1327 }
1328 while (v);
1329
1330 return ret;
203b91b9
RS
1331}
1332
92832bb5
MM
1333void
1334__bb_exit_func (void)
1335{
65f7a653 1336 FILE *da_file, *file;
92832bb5 1337 long time_value;
65f7a653
DE
1338 int i;
1339
1340 if (bb_head == 0)
1341 return;
1342
1343 i = strlen (bb_head->filename) - 3;
1344
1345 if (!strcmp (bb_head->filename+i, ".da"))
1346 {
1347 /* Must be -fprofile-arcs not -a.
1348 Dump data in a form that gcov expects. */
1349
1350 struct bb *ptr;
1351
1352 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
1353 {
e09d24ff
R
1354 int firstchar;
1355
1356 /* Make sure the output file exists -
1357 but don't clobber exiting data. */
1358 if ((da_file = fopen (ptr->filename, "a")) != 0)
1359 fclose (da_file);
1360
1361 /* Need to re-open in order to be able to write from the start. */
1362 da_file = fopen (ptr->filename, "r+b");
1363 /* Some old systems might not allow the 'b' mode modifier.
1364 Therefore, try to open without it. This can lead to a race
1365 condition so that when you delete and re-create the file, the
1366 file might be opened in text mode, but then, you shouldn't
1367 delete the file in the first place. */
1368 if (da_file == 0)
1369 da_file = fopen (ptr->filename, "r+");
1370 if (da_file == 0)
1371 {
1372 fprintf (stderr, "arc profiling: Can't open output file %s.\n",
1373 ptr->filename);
1374 continue;
1375 }
1376
1377 /* After a fork, another process might try to read and/or write
1378 the same file simultanously. So if we can, lock the file to
1379 avoid race conditions. */
1380#if defined (TARGET_HAS_F_SETLKW)
1381 {
1382 struct flock s_flock;
1383
1384 s_flock.l_type = F_WRLCK;
1385 s_flock.l_whence = SEEK_SET;
1386 s_flock.l_start = 0;
1387 s_flock.l_len = 1;
1388 s_flock.l_pid = getpid ();
1389
1390 while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
1391 && errno == EINTR);
1392 }
1393#endif
1394
1395 /* If the file is not empty, and the number of counts in it is the
1396 same, then merge them in. */
1397 firstchar = fgetc (da_file);
1398 if (firstchar == EOF)
1399 {
1400 if (ferror (da_file))
1401 {
1402 fprintf (stderr, "arc profiling: Can't read output file ");
1403 perror (ptr->filename);
1404 }
1405 }
1406 else
65f7a653
DE
1407 {
1408 long n_counts = 0;
65f7a653 1409
e09d24ff
R
1410 if (ungetc (firstchar, da_file) == EOF)
1411 rewind (da_file);
65f7a653
DE
1412 if (__read_long (&n_counts, da_file, 8) != 0)
1413 {
1414 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
1415 ptr->filename);
1416 continue;
1417 }
1418
1419 if (n_counts == ptr->ncounts)
1420 {
1421 int i;
1422
1423 for (i = 0; i < n_counts; i++)
1424 {
b2aec5c0 1425 gcov_type v = 0;
65f7a653 1426
b2aec5c0 1427 if (__read_gcov_type (&v, da_file, 8) != 0)
65f7a653
DE
1428 {
1429 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
1430 ptr->filename);
1431 break;
1432 }
1433 ptr->counts[i] += v;
1434 }
1435 }
1436
65f7a653
DE
1437 }
1438
e09d24ff
R
1439 rewind (da_file);
1440
956d6950 1441 /* ??? Should first write a header to the file. Preferably, a 4 byte
65f7a653
DE
1442 magic number, 4 bytes containing the time the program was
1443 compiled, 4 bytes containing the last modification time of the
1444 source file, and 4 bytes indicating the compiler options used.
1445
1446 That way we can easily verify that the proper source/executable/
1447 data file combination is being used from gcov. */
1448
b2aec5c0 1449 if (__write_gcov_type (ptr->ncounts, da_file, 8) != 0)
65f7a653
DE
1450 {
1451
1452 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
1453 ptr->filename);
1454 }
1455 else
1456 {
1457 int j;
b2aec5c0 1458 gcov_type *count_ptr = ptr->counts;
65f7a653
DE
1459 int ret = 0;
1460 for (j = ptr->ncounts; j > 0; j--)
1461 {
b2aec5c0 1462 if (__write_gcov_type (*count_ptr, da_file, 8) != 0)
65f7a653
DE
1463 {
1464 ret=1;
1465 break;
1466 }
1467 count_ptr++;
1468 }
1469 if (ret)
1470 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
1471 ptr->filename);
1472 }
1473
1474 if (fclose (da_file) == EOF)
1475 fprintf (stderr, "arc profiling: Error closing output file %s.\n",
1476 ptr->filename);
1477 }
1478
1479 return;
1480 }
1481
1482 /* Must be basic block profiling. Emit a human readable output file. */
1483
1484 file = fopen ("bb.out", "a");
92832bb5
MM
1485
1486 if (!file)
1487 perror ("bb.out");
1488
1489 else
1490 {
1491 struct bb *ptr;
1492
1493 /* This is somewhat type incorrect, but it avoids worrying about
1494 exactly where time.h is included from. It should be ok unless
90b4a764 1495 a void * differs from other pointer formats, or if sizeof (long)
92832bb5
MM
1496 is < sizeof (time_t). It would be nice if we could assume the
1497 use of rationale standards here. */
1498
90b4a764 1499 time ((void *) &time_value);
92832bb5
MM
1500 fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
1501
1502 /* We check the length field explicitly in order to allow compatibility
1503 with older GCC's which did not provide it. */
1504
0f41302f 1505 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
92832bb5
MM
1506 {
1507 int i;
3e7d8ef1 1508 int func_p = (ptr->nwords >= (long) sizeof (struct bb)
65f7a653
DE
1509 && ptr->nwords <= 1000
1510 && ptr->functions);
92832bb5
MM
1511 int line_p = (func_p && ptr->line_nums);
1512 int file_p = (func_p && ptr->filenames);
65f7a653 1513 int addr_p = (ptr->addresses != 0);
92832bb5
MM
1514 long ncounts = ptr->ncounts;
1515 long cnt_max = 0;
1516 long line_max = 0;
1517 long addr_max = 0;
1518 int file_len = 0;
1519 int func_len = 0;
1520 int blk_len = num_digits (ncounts, 10);
1521 int cnt_len;
1522 int line_len;
1523 int addr_len;
1524
1525 fprintf (file, "File %s, %ld basic blocks \n\n",
1526 ptr->filename, ncounts);
1527
1528 /* Get max values for each field. */
1529 for (i = 0; i < ncounts; i++)
1530 {
1531 const char *p;
1532 int len;
1533
1534 if (cnt_max < ptr->counts[i])
1535 cnt_max = ptr->counts[i];
1536
3e7d8ef1 1537 if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
92832bb5
MM
1538 addr_max = ptr->addresses[i];
1539
1540 if (line_p && line_max < ptr->line_nums[i])
1541 line_max = ptr->line_nums[i];
1542
1543 if (func_p)
1544 {
1545 p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
1546 len = strlen (p);
1547 if (func_len < len)
1548 func_len = len;
1549 }
1550
1551 if (file_p)
1552 {
1553 p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
1554 len = strlen (p);
1555 if (file_len < len)
1556 file_len = len;
1557 }
1558 }
1559
1560 addr_len = num_digits (addr_max, 16);
1561 cnt_len = num_digits (cnt_max, 10);
1562 line_len = num_digits (line_max, 10);
1563
1564 /* Now print out the basic block information. */
1565 for (i = 0; i < ncounts; i++)
1566 {
1567 fprintf (file,
65f7a653 1568 " Block #%*d: executed %*ld time(s)",
92832bb5 1569 blk_len, i+1,
65f7a653
DE
1570 cnt_len, ptr->counts[i]);
1571
1572 if (addr_p)
1573 fprintf (file, " address= 0x%.*lx", addr_len,
1574 ptr->addresses[i]);
92832bb5
MM
1575
1576 if (func_p)
3cca99e8 1577 fprintf (file, " function= %-*s", func_len,
92832bb5
MM
1578 (ptr->functions[i]) ? ptr->functions[i] : "<none>");
1579
1580 if (line_p)
1d42e1b7 1581 fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
92832bb5
MM
1582
1583 if (file_p)
3cca99e8 1584 fprintf (file, " file= %s",
92832bb5
MM
1585 (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
1586
1587 fprintf (file, "\n");
1588 }
1589
1590 fprintf (file, "\n");
1591 fflush (file);
1592 }
1593
1594 fprintf (file, "\n\n");
1595 fclose (file);
1596 }
1597}
1598
1599void
1600__bb_init_func (struct bb *blocks)
1601{
1602 /* User is supposed to check whether the first word is non-0,
0f41302f 1603 but just in case.... */
92832bb5
MM
1604
1605 if (blocks->zero_word)
1606 return;
1607
92832bb5
MM
1608 /* Initialize destructor. */
1609 if (!bb_head)
c063dc98 1610 atexit (__bb_exit_func);
92832bb5
MM
1611
1612 /* Set up linked list. */
1613 blocks->zero_word = 1;
1614 blocks->next = bb_head;
1615 bb_head = blocks;
1616}
1617
e09d24ff
R
1618/* Called before fork or exec - write out profile information gathered so
1619 far and reset it to zero. This avoids duplication or loss of the
1620 profile information gathered so far. */
1621void
1622__bb_fork_func (void)
1623{
1624 struct bb *ptr;
1625
1626 __bb_exit_func ();
1627 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
1628 {
1629 long i;
1630 for (i = ptr->ncounts - 1; i >= 0; i--)
1631 ptr->counts[i] = 0;
1632 }
1633}
1634
90b4a764
RK
1635#ifndef MACHINE_STATE_SAVE
1636#define MACHINE_STATE_SAVE(ID)
1637#endif
1638#ifndef MACHINE_STATE_RESTORE
1639#define MACHINE_STATE_RESTORE(ID)
1640#endif
1641
0f41302f 1642/* Number of buckets in hashtable of basic block addresses. */
90b4a764
RK
1643
1644#define BB_BUCKETS 311
1645
0f41302f 1646/* Maximum length of string in file bb.in. */
90b4a764
RK
1647
1648#define BBINBUFSIZE 500
1649
90b4a764
RK
1650struct bb_edge
1651{
1652 struct bb_edge *next;
1653 unsigned long src_addr;
1654 unsigned long dst_addr;
1655 unsigned long count;
1656};
1657
1658enum bb_func_mode
1659{
1660 TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
1661};
1662
1663struct bb_func
1664{
1665 struct bb_func *next;
1666 char *funcname;
1667 char *filename;
1668 enum bb_func_mode mode;
1669};
1670
1671/* This is the connection to the outside world.
1672 The BLOCK_PROFILER macro must set __bb.blocks
0f41302f 1673 and __bb.blockno. */
90b4a764
RK
1674
1675struct {
1676 unsigned long blockno;
1677 struct bb *blocks;
1678} __bb;
1679
1680/* Vars to store addrs of source and destination basic blocks
0f41302f 1681 of a jump. */
90b4a764
RK
1682
1683static unsigned long bb_src = 0;
1684static unsigned long bb_dst = 0;
1685
0f41302f
MS
1686static FILE *bb_tracefile = (FILE *) 0;
1687static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
1688static struct bb_func *bb_func_head = (struct bb_func *) 0;
90b4a764
RK
1689static unsigned long bb_callcount = 0;
1690static int bb_mode = 0;
1691
0f41302f 1692static unsigned long *bb_stack = (unsigned long *) 0;
90b4a764
RK
1693static size_t bb_stacksize = 0;
1694
1695static int reported = 0;
1696
1697/* Trace modes:
1698Always : Print execution frequencies of basic blocks
1699 to file bb.out.
1700bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
1701bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
1702bb_mode & 4 != 0 : Cut call instructions from basic block flow.
1703bb_mode & 8 != 0 : Insert return instructions in basic block flow.
1704*/
1705
1706#ifdef HAVE_POPEN
1707
1708/*#include <sys/types.h>*/
1709#include <sys/stat.h>
1710/*#include <malloc.h>*/
1711
0f41302f 1712/* Commands executed by gopen. */
90b4a764
RK
1713
1714#define GOPENDECOMPRESS "gzip -cd "
1715#define GOPENCOMPRESS "gzip -c >"
1716
1717/* Like fopen but pipes through gzip. mode may only be "r" or "w".
1718 If it does not compile, simply replace gopen by fopen and delete
0f41302f 1719 '.gz' from any first parameter to gopen. */
90b4a764
RK
1720
1721static FILE *
37ef1054 1722gopen (char *fn, char *mode)
90b4a764
RK
1723{
1724 int use_gzip;
1725 char *p;
1726
1727 if (mode[1])
0f41302f 1728 return (FILE *) 0;
90b4a764
RK
1729
1730 if (mode[0] != 'r' && mode[0] != 'w')
0f41302f 1731 return (FILE *) 0;
90b4a764
RK
1732
1733 p = fn + strlen (fn)-1;
db3cf6fb
MS
1734 use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
1735 || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
90b4a764
RK
1736
1737 if (use_gzip)
1738 {
1739 if (mode[0]=='r')
1740 {
1741 FILE *f;
0f41302f
MS
1742 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1743 + sizeof (GOPENDECOMPRESS));
90b4a764
RK
1744 strcpy (s, GOPENDECOMPRESS);
1745 strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
1746 f = popen (s, mode);
1747 free (s);
1748 return f;
1749 }
1750
1751 else
1752 {
1753 FILE *f;
0f41302f
MS
1754 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1755 + sizeof (GOPENCOMPRESS));
90b4a764
RK
1756 strcpy (s, GOPENCOMPRESS);
1757 strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
1758 if (!(f = popen (s, mode)))
1759 f = fopen (s, mode);
1760 free (s);
1761 return f;
1762 }
1763 }
1764
1765 else
1766 return fopen (fn, mode);
1767}
1768
1769static int
37ef1054 1770gclose (FILE *f)
90b4a764
RK
1771{
1772 struct stat buf;
1773
920b13cc 1774 if (f != 0)
90b4a764
RK
1775 {
1776 if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
1777 return pclose (f);
1778
1779 return fclose (f);
1780 }
1781 return 0;
1782}
1783
1784#endif /* HAVE_POPEN */
1785
0f41302f 1786/* Called once per program. */
90b4a764
RK
1787
1788static void
3e7d8ef1 1789__bb_exit_trace_func (void)
90b4a764
RK
1790{
1791 FILE *file = fopen ("bb.out", "a");
1792 struct bb_func *f;
90b4a764
RK
1793 struct bb *b;
1794
1795 if (!file)
1796 perror ("bb.out");
1797
1798 if (bb_mode & 1)
1799 {
1800 if (!bb_tracefile)
1801 perror ("bbtrace");
1802 else
1803#ifdef HAVE_POPEN
1804 gclose (bb_tracefile);
1805#else
1806 fclose (bb_tracefile);
1807#endif /* HAVE_POPEN */
1808 }
1809
0f41302f 1810 /* Check functions in `bb.in'. */
90b4a764
RK
1811
1812 if (file)
1813 {
1814 long time_value;
1815 const struct bb_func *p;
1816 int printed_something = 0;
1817 struct bb *ptr;
1818 long blk;
1819
0f41302f 1820 /* This is somewhat type incorrect. */
90b4a764
RK
1821 time ((void *) &time_value);
1822
0f41302f 1823 for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
90b4a764 1824 {
0f41302f 1825 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
90b4a764 1826 {
51723711 1827 if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
90b4a764
RK
1828 continue;
1829 for (blk = 0; blk < ptr->ncounts; blk++)
1830 {
1831 if (!strcmp (p->funcname, ptr->functions[blk]))
1832 goto found;
1833 }
1834 }
1835
1836 if (!printed_something)
1837 {
1838 fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
1839 printed_something = 1;
1840 }
1841
1842 fprintf (file, "\tFunction %s", p->funcname);
1843 if (p->filename)
1844 fprintf (file, " of file %s", p->filename);
1845 fprintf (file, "\n" );
1846
1847found: ;
1848 }
1849
1850 if (printed_something)
1851 fprintf (file, "\n");
1852
1853 }
1854
1855 if (bb_mode & 2)
1856 {
1857 if (!bb_hashbuckets)
1858 {
1859 if (!reported)
1860 {
1861 fprintf (stderr, "Profiler: out of memory\n");
1862 reported = 1;
1863 }
1864 return;
1865 }
1866
1867 else if (file)
1868 {
1869 long time_value;
1870 int i;
1871 unsigned long addr_max = 0;
1872 unsigned long cnt_max = 0;
1873 int cnt_len;
1874 int addr_len;
1875
1876 /* This is somewhat type incorrect, but it avoids worrying about
1877 exactly where time.h is included from. It should be ok unless
1878 a void * differs from other pointer formats, or if sizeof (long)
1879 is < sizeof (time_t). It would be nice if we could assume the
1880 use of rationale standards here. */
1881
1882 time ((void *) &time_value);
1883 fprintf (file, "Basic block jump tracing");
1884
1885 switch (bb_mode & 12)
1886 {
1887 case 0:
1888 fprintf (file, " (with call)");
1889 break;
1890
1891 case 4:
0f41302f 1892 /* Print nothing. */
90b4a764
RK
1893 break;
1894
1895 case 8:
1896 fprintf (file, " (with call & ret)");
1897 break;
1898
1899 case 12:
1900 fprintf (file, " (with ret)");
1901 break;
1902 }
1903
1904 fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
1905
1906 for (i = 0; i < BB_BUCKETS; i++)
1907 {
1908 struct bb_edge *bucket = bb_hashbuckets[i];
1909 for ( ; bucket; bucket = bucket->next )
1910 {
1911 if (addr_max < bucket->src_addr)
1912 addr_max = bucket->src_addr;
1913 if (addr_max < bucket->dst_addr)
1914 addr_max = bucket->dst_addr;
1915 if (cnt_max < bucket->count)
1916 cnt_max = bucket->count;
1917 }
1918 }
1919 addr_len = num_digits (addr_max, 16);
1920 cnt_len = num_digits (cnt_max, 10);
1921
1922 for ( i = 0; i < BB_BUCKETS; i++)
1923 {
1924 struct bb_edge *bucket = bb_hashbuckets[i];
1925 for ( ; bucket; bucket = bucket->next )
1926 {
78a0d70c
ZW
1927 fprintf (file,
1928 "Jump from block 0x%.*lx to block 0x%.*lx executed %*lu time(s)\n",
90b4a764
RK
1929 addr_len, bucket->src_addr,
1930 addr_len, bucket->dst_addr,
1931 cnt_len, bucket->count);
1932 }
1933 }
1934
1935 fprintf (file, "\n");
1936
1937 }
1938 }
1939
1940 if (file)
1941 fclose (file);
1942
0f41302f 1943 /* Free allocated memory. */
90b4a764
RK
1944
1945 f = bb_func_head;
1946 while (f)
1947 {
1948 struct bb_func *old = f;
1949
1950 f = f->next;
1951 if (old->funcname) free (old->funcname);
1952 if (old->filename) free (old->filename);
1953 free (old);
1954 }
1955
1956 if (bb_stack)
1957 free (bb_stack);
1958
1959 if (bb_hashbuckets)
1960 {
1961 int i;
1962
1963 for (i = 0; i < BB_BUCKETS; i++)
1964 {
1965 struct bb_edge *old, *bucket = bb_hashbuckets[i];
1966
1967 while (bucket)
1968 {
1969 old = bucket;
1970 bucket = bucket->next;
1971 free (old);
1972 }
1973 }
1974 free (bb_hashbuckets);
1975 }
1976
1977 for (b = bb_head; b; b = b->next)
1978 if (b->flags) free (b->flags);
1979}
1980
0f41302f 1981/* Called once per program. */
90b4a764
RK
1982
1983static void
3e7d8ef1 1984__bb_init_prg (void)
90b4a764 1985{
90b4a764
RK
1986 FILE *file;
1987 char buf[BBINBUFSIZE];
1988 const char *p;
1989 const char *pos;
1990 enum bb_func_mode m;
c5c76735 1991 int i;
90b4a764 1992
90b4a764 1993 /* Initialize destructor. */
c063dc98 1994 atexit (__bb_exit_func);
90b4a764
RK
1995
1996 if (!(file = fopen ("bb.in", "r")))
1997 return;
1998
78a0d70c 1999 while(fgets (buf, BBINBUFSIZE, file) != 0)
90b4a764 2000 {
78a0d70c
ZW
2001 i = strlen (buf);
2002 if (buf[i] == '\n')
2003 buf[i--] = '\0';
2004
90b4a764
RK
2005 p = buf;
2006 if (*p == '-')
2007 {
2008 m = TRACE_OFF;
2009 p++;
2010 }
2011 else
2012 {
2013 m = TRACE_ON;
2014 }
2015 if (!strcmp (p, "__bb_trace__"))
2016 bb_mode |= 1;
2017 else if (!strcmp (p, "__bb_jumps__"))
2018 bb_mode |= 2;
2019 else if (!strcmp (p, "__bb_hidecall__"))
2020 bb_mode |= 4;
2021 else if (!strcmp (p, "__bb_showret__"))
2022 bb_mode |= 8;
2023 else
2024 {
0f41302f 2025 struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
90b4a764
RK
2026 if (f)
2027 {
2028 unsigned long l;
2029 f->next = bb_func_head;
51723711 2030 if ((pos = strchr (p, ':')))
90b4a764 2031 {
0f41302f 2032 if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
90b4a764
RK
2033 continue;
2034 strcpy (f->funcname, pos+1);
2035 l = pos-p;
0f41302f 2036 if ((f->filename = (char *) malloc (l+1)))
90b4a764
RK
2037 {
2038 strncpy (f->filename, p, l);
2039 f->filename[l] = '\0';
2040 }
2041 else
0f41302f 2042 f->filename = (char *) 0;
90b4a764
RK
2043 }
2044 else
2045 {
0f41302f 2046 if (!(f->funcname = (char *) malloc (strlen (p)+1)))
90b4a764
RK
2047 continue;
2048 strcpy (f->funcname, p);
0f41302f 2049 f->filename = (char *) 0;
90b4a764
RK
2050 }
2051 f->mode = m;
2052 bb_func_head = f;
2053 }
2054 }
2055 }
2056 fclose (file);
2057
2058#ifdef HAVE_POPEN
2059
2060 if (bb_mode & 1)
2061 bb_tracefile = gopen ("bbtrace.gz", "w");
2062
2063#else
2064
2065 if (bb_mode & 1)
2066 bb_tracefile = fopen ("bbtrace", "w");
2067
2068#endif /* HAVE_POPEN */
2069
2070 if (bb_mode & 2)
2071 {
2072 bb_hashbuckets = (struct bb_edge **)
2073 malloc (BB_BUCKETS * sizeof (struct bb_edge *));
2074 if (bb_hashbuckets)
c5c76735
JL
2075 /* Use a loop here rather than calling bzero to avoid having to
2076 conditionalize its existance. */
2077 for (i = 0; i < BB_BUCKETS; i++)
2078 bb_hashbuckets[i] = 0;
90b4a764
RK
2079 }
2080
2081 if (bb_mode & 12)
2082 {
2083 bb_stacksize = 10;
2084 bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
2085 }
2086
c063dc98
JM
2087 /* Initialize destructor. */
2088 atexit (__bb_exit_trace_func);
90b4a764
RK
2089}
2090
0f41302f 2091/* Called upon entering a basic block. */
90b4a764
RK
2092
2093void
3e7d8ef1 2094__bb_trace_func (void)
90b4a764
RK
2095{
2096 struct bb_edge *bucket;
2097
2098 MACHINE_STATE_SAVE("1")
2099
2100 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2101 goto skip;
2102
2103 bb_dst = __bb.blocks->addresses[__bb.blockno];
2104 __bb.blocks->counts[__bb.blockno]++;
2105
2106 if (bb_tracefile)
2107 {
2108 fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
2109 }
2110
2111 if (bb_hashbuckets)
2112 {
2113 struct bb_edge **startbucket, **oldnext;
2114
db3cf6fb
MS
2115 oldnext = startbucket
2116 = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
90b4a764
RK
2117 bucket = *startbucket;
2118
2119 for (bucket = *startbucket; bucket;
2120 oldnext = &(bucket->next), bucket = *oldnext)
2121 {
db3cf6fb
MS
2122 if (bucket->src_addr == bb_src
2123 && bucket->dst_addr == bb_dst)
90b4a764
RK
2124 {
2125 bucket->count++;
2126 *oldnext = bucket->next;
2127 bucket->next = *startbucket;
2128 *startbucket = bucket;
2129 goto ret;
2130 }
2131 }
2132
2133 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2134
2135 if (!bucket)
2136 {
2137 if (!reported)
2138 {
2139 fprintf (stderr, "Profiler: out of memory\n");
2140 reported = 1;
2141 }
2142 }
2143
2144 else
2145 {
2146 bucket->src_addr = bb_src;
2147 bucket->dst_addr = bb_dst;
2148 bucket->next = *startbucket;
2149 *startbucket = bucket;
2150 bucket->count = 1;
2151 }
2152 }
2153
2154ret:
2155 bb_src = bb_dst;
2156
2157skip:
2158 ;
2159
2160 MACHINE_STATE_RESTORE("1")
2161
2162}
2163
0f41302f 2164/* Called when returning from a function and `__bb_showret__' is set. */
90b4a764
RK
2165
2166static void
3e7d8ef1 2167__bb_trace_func_ret (void)
90b4a764
RK
2168{
2169 struct bb_edge *bucket;
2170
2171 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2172 goto skip;
2173
2174 if (bb_hashbuckets)
2175 {
2176 struct bb_edge **startbucket, **oldnext;
2177
db3cf6fb
MS
2178 oldnext = startbucket
2179 = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
90b4a764
RK
2180 bucket = *startbucket;
2181
2182 for (bucket = *startbucket; bucket;
2183 oldnext = &(bucket->next), bucket = *oldnext)
2184 {
db3cf6fb
MS
2185 if (bucket->src_addr == bb_dst
2186 && bucket->dst_addr == bb_src)
90b4a764
RK
2187 {
2188 bucket->count++;
2189 *oldnext = bucket->next;
2190 bucket->next = *startbucket;
2191 *startbucket = bucket;
2192 goto ret;
2193 }
2194 }
2195
2196 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2197
2198 if (!bucket)
2199 {
2200 if (!reported)
2201 {
2202 fprintf (stderr, "Profiler: out of memory\n");
2203 reported = 1;
2204 }
2205 }
2206
2207 else
2208 {
2209 bucket->src_addr = bb_dst;
2210 bucket->dst_addr = bb_src;
2211 bucket->next = *startbucket;
2212 *startbucket = bucket;
2213 bucket->count = 1;
2214 }
2215 }
2216
2217ret:
2218 bb_dst = bb_src;
2219
2220skip:
2221 ;
2222
2223}
2224
0f41302f 2225/* Called upon entering the first function of a file. */
90b4a764
RK
2226
2227static void
37ef1054 2228__bb_init_file (struct bb *blocks)
90b4a764
RK
2229{
2230
2231 const struct bb_func *p;
2232 long blk, ncounts = blocks->ncounts;
2233 const char **functions = blocks->functions;
2234
2235 /* Set up linked list. */
2236 blocks->zero_word = 1;
2237 blocks->next = bb_head;
2238 bb_head = blocks;
2239
2240 blocks->flags = 0;
db3cf6fb
MS
2241 if (!bb_func_head
2242 || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
90b4a764
RK
2243 return;
2244
2245 for (blk = 0; blk < ncounts; blk++)
2246 blocks->flags[blk] = 0;
2247
2248 for (blk = 0; blk < ncounts; blk++)
2249 {
2250 for (p = bb_func_head; p; p = p->next)
2251 {
db3cf6fb
MS
2252 if (!strcmp (p->funcname, functions[blk])
2253 && (!p->filename || !strcmp (p->filename, blocks->filename)))
90b4a764
RK
2254 {
2255 blocks->flags[blk] |= p->mode;
2256 }
2257 }
2258 }
2259
2260}
2261
0f41302f 2262/* Called when exiting from a function. */
90b4a764
RK
2263
2264void
3e7d8ef1 2265__bb_trace_ret (void)
90b4a764
RK
2266{
2267
2268 MACHINE_STATE_SAVE("2")
2269
2270 if (bb_callcount)
2271 {
2272 if ((bb_mode & 12) && bb_stacksize > bb_callcount)
2273 {
2274 bb_src = bb_stack[bb_callcount];
2275 if (bb_mode & 8)
2276 __bb_trace_func_ret ();
2277 }
2278
2279 bb_callcount -= 1;
2280 }
2281
2282 MACHINE_STATE_RESTORE("2")
2283
2284}
2285
0f41302f 2286/* Called when entering a function. */
90b4a764
RK
2287
2288void
37ef1054 2289__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
90b4a764
RK
2290{
2291 static int trace_init = 0;
2292
2293 MACHINE_STATE_SAVE("3")
2294
2295 if (!blocks->zero_word)
2296 {
2297 if (!trace_init)
2298 {
2299 trace_init = 1;
2300 __bb_init_prg ();
2301 }
2302 __bb_init_file (blocks);
2303 }
2304
2305 if (bb_callcount)
2306 {
2307
2308 bb_callcount += 1;
2309
2310 if (bb_mode & 12)
2311 {
2312 if (bb_callcount >= bb_stacksize)
2313 {
2314 size_t newsize = bb_callcount + 100;
2315
2316 bb_stack = (unsigned long *) realloc (bb_stack, newsize);
2317 if (! bb_stack)
2318 {
2319 if (!reported)
2320 {
2321 fprintf (stderr, "Profiler: out of memory\n");
2322 reported = 1;
2323 }
2324 bb_stacksize = 0;
2325 goto stack_overflow;
2326 }
2327 bb_stacksize = newsize;
2328 }
2329 bb_stack[bb_callcount] = bb_src;
2330
2331 if (bb_mode & 4)
2332 bb_src = 0;
2333
2334 }
2335
2336stack_overflow:;
2337
2338 }
2339
2340 else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
2341 {
2342 bb_callcount = 1;
2343 bb_src = 0;
2344
2345 if (bb_stack)
2346 bb_stack[bb_callcount] = bb_src;
2347 }
2348
2349 MACHINE_STATE_RESTORE("3")
2350}
2351
c7544ff7
RS
2352#endif /* not inhibit_libc */
2353#endif /* not BLOCK_PROFILER_CODE */
2354#endif /* L_bb */
203b91b9 2355\f
203b91b9
RS
2356#ifdef L_clear_cache
2357/* Clear part of an instruction cache. */
2358
2359#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
2360
2361void
139fa6f8
MM
2362__clear_cache (char *beg __attribute__((__unused__)),
2363 char *end __attribute__((__unused__)))
203b91b9 2364{
e1178973
KKT
2365#ifdef CLEAR_INSN_CACHE
2366 CLEAR_INSN_CACHE (beg, end);
2367#else
203b91b9
RS
2368#ifdef INSN_CACHE_SIZE
2369 static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
7e6f1890 2370 static int initialized;
203b91b9 2371 int offset;
b6422cca
RS
2372 void *start_addr
2373 void *end_addr;
3e7d8ef1 2374 typedef (*function_ptr) (void);
203b91b9
RS
2375
2376#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
2377 /* It's cheaper to clear the whole cache.
2378 Put in a series of jump instructions so that calling the beginning
2379 of the cache will clear the whole thing. */
2380
2381 if (! initialized)
2382 {
2383 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2384 & -INSN_CACHE_LINE_WIDTH);
2385 int end_ptr = ptr + INSN_CACHE_SIZE;
2386
2387 while (ptr < end_ptr)
2388 {
2389 *(INSTRUCTION_TYPE *)ptr
2390 = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
2391 ptr += INSN_CACHE_LINE_WIDTH;
2392 }
0f41302f 2393 *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
203b91b9
RS
2394
2395 initialized = 1;
2396 }
2397
2398 /* Call the beginning of the sequence. */
2399 (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2400 & -INSN_CACHE_LINE_WIDTH))
2401 ());
2402
2403#else /* Cache is large. */
2404
2405 if (! initialized)
2406 {
2407 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2408 & -INSN_CACHE_LINE_WIDTH);
2409
2410 while (ptr < (int) array + sizeof array)
2411 {
2412 *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
2413 ptr += INSN_CACHE_LINE_WIDTH;
2414 }
2415
2416 initialized = 1;
2417 }
2418
2419 /* Find the location in array that occupies the same cache line as BEG. */
2420
2421 offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
2422 start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
2423 & -INSN_CACHE_PLANE_SIZE)
2424 + offset);
2425
2426 /* Compute the cache alignment of the place to stop clearing. */
2427#if 0 /* This is not needed for gcc's purposes. */
2428 /* If the block to clear is bigger than a cache plane,
2429 we clear the entire cache, and OFFSET is already correct. */
2430 if (end < beg + INSN_CACHE_PLANE_SIZE)
2431#endif
2432 offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
2433 & -INSN_CACHE_LINE_WIDTH)
2434 & (INSN_CACHE_PLANE_SIZE - 1));
2435
2436#if INSN_CACHE_DEPTH > 1
2437 end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset;
2438 if (end_addr <= start_addr)
2439 end_addr += INSN_CACHE_PLANE_SIZE;
2440
2441 for (plane = 0; plane < INSN_CACHE_DEPTH; plane++)
2442 {
2443 int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE;
2444 int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE;
2445
2446 while (addr != stop)
2447 {
2448 /* Call the return instruction at ADDR. */
2449 ((function_ptr) addr) ();
2450
2451 addr += INSN_CACHE_LINE_WIDTH;
2452 }
2453 }
2454#else /* just one plane */
2455 do
2456 {
2457 /* Call the return instruction at START_ADDR. */
2458 ((function_ptr) start_addr) ();
2459
2460 start_addr += INSN_CACHE_LINE_WIDTH;
2461 }
2462 while ((start_addr % INSN_CACHE_SIZE) != offset);
2463#endif /* just one plane */
2464#endif /* Cache is large */
2465#endif /* Cache exists */
e1178973 2466#endif /* CLEAR_INSN_CACHE */
203b91b9
RS
2467}
2468
2469#endif /* L_clear_cache */
2470\f
2471#ifdef L_trampoline
2472
2473/* Jump to a trampoline, loading the static chain address. */
2474
b27d2bd5 2475#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN)
e3367a77 2476
3e7d8ef1
KG
2477long
2478getpagesize (void)
f5ea9817
RK
2479{
2480#ifdef _ALPHA_
2481 return 8192;
2482#else
2483 return 4096;
2484#endif
2485}
2486
d7ebf9ea 2487#ifdef __i386__
e4b15106
RK
2488extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
2489#endif
2490
272e2587
RK
2491int
2492mprotect (char *addr, int len, int prot)
f5ea9817
RK
2493{
2494 int np, op;
2495
272e2587
RK
2496 if (prot == 7)
2497 np = 0x40;
2498 else if (prot == 5)
2499 np = 0x20;
2500 else if (prot == 4)
2501 np = 0x10;
2502 else if (prot == 3)
2503 np = 0x04;
2504 else if (prot == 1)
2505 np = 0x02;
2506 else if (prot == 0)
2507 np = 0x01;
f5ea9817
RK
2508
2509 if (VirtualProtect (addr, len, np, &op))
2510 return 0;
2511 else
2512 return -1;
f5ea9817
RK
2513}
2514
b27d2bd5 2515#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
f5ea9817 2516
203b91b9
RS
2517#ifdef TRANSFER_FROM_TRAMPOLINE
2518TRANSFER_FROM_TRAMPOLINE
2519#endif
2520
c1381fd3
KKT
2521#if defined (NeXT) && defined (__MACH__)
2522
2523/* Make stack executable so we can call trampolines on stack.
2524 This is called from INITIALIZE_TRAMPOLINE in next.h. */
c5df463e
RK
2525#ifdef NeXTStep21
2526 #include <mach.h>
2527#else
2528 #include <mach/mach.h>
2529#endif
c1381fd3
KKT
2530
2531void
37ef1054 2532__enable_execute_stack (char *addr)
c1381fd3
KKT
2533{
2534 kern_return_t r;
2535 char *eaddr = addr + TRAMPOLINE_SIZE;
2536 vm_address_t a = (vm_address_t) addr;
2537
2538 /* turn on execute access on stack */
2539 r = vm_protect (task_self (), a, TRAMPOLINE_SIZE, FALSE, VM_PROT_ALL);
2540 if (r != KERN_SUCCESS)
2541 {
2542 mach_error("vm_protect VM_PROT_ALL", r);
2543 exit(1);
2544 }
2545
2546 /* We inline the i-cache invalidation for speed */
2547
2548#ifdef CLEAR_INSN_CACHE
2549 CLEAR_INSN_CACHE (addr, eaddr);
2550#else
2551 __clear_cache ((int) addr, (int) eaddr);
2552#endif
2553}
2554
2555#endif /* defined (NeXT) && defined (__MACH__) */
2556
203b91b9
RS
2557#ifdef __convex__
2558
2559/* Make stack executable so we can call trampolines on stack.
2560 This is called from INITIALIZE_TRAMPOLINE in convex.h. */
2561
2562#include <sys/mman.h>
2563#include <sys/vmparam.h>
2564#include <machine/machparam.h>
2565
2566void
3e7d8ef1 2567__enable_execute_stack (void)
203b91b9
RS
2568{
2569 int fp;
2570 static unsigned lowest = USRSTACK;
2571 unsigned current = (unsigned) &fp & -NBPG;
2572
2573 if (lowest > current)
2574 {
2575 unsigned len = lowest - current;
2576 mremap (current, &len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
2577 lowest = current;
2578 }
2579
0f41302f 2580 /* Clear instruction cache in case an old trampoline is in it. */
203b91b9
RS
2581 asm ("pich");
2582}
2583#endif /* __convex__ */
b335c2cc 2584
db87ec0b 2585#ifdef __sysV88__
0c8ae3d3 2586
0f41302f 2587/* Modified from the convex -code above. */
0c8ae3d3
RK
2588
2589#include <sys/param.h>
2590#include <errno.h>
2591#include <sys/m88kbcs.h>
2592
2593void
3e7d8ef1 2594__enable_execute_stack (void)
0c8ae3d3
RK
2595{
2596 int save_errno;
2597 static unsigned long lowest = USRSTACK;
2598 unsigned long current = (unsigned long) &save_errno & -NBPC;
2599
2600 /* Ignore errno being set. memctl sets errno to EINVAL whenever the
2601 address is seen as 'negative'. That is the case with the stack. */
2602
2603 save_errno=errno;
2604 if (lowest > current)
2605 {
2606 unsigned len=lowest-current;
2607 memctl(current,len,MCT_TEXT);
2608 lowest = current;
2609 }
2610 else
2611 memctl(current,NBPC,MCT_TEXT);
2612 errno=save_errno;
2613}
2614
db87ec0b 2615#endif /* __sysV88__ */
0c8ae3d3 2616
c85f7c16
JL
2617#ifdef __sysV68__
2618
2619#include <sys/signal.h>
2620#include <errno.h>
2621
2622/* Motorola forgot to put memctl.o in the libp version of libc881.a,
2623 so define it here, because we need it in __clear_insn_cache below */
3698f44e
MH
2624/* On older versions of this OS, no memctl or MCT_TEXT are defined;
2625 hence we enable this stuff only if MCT_TEXT is #define'd. */
c85f7c16 2626
3698f44e 2627#ifdef MCT_TEXT
c85f7c16
JL
2628asm("\n\
2629 global memctl\n\
2630memctl:\n\
2631 movq &75,%d0\n\
2632 trap &0\n\
2633 bcc.b noerror\n\
2634 jmp cerror%\n\
2635noerror:\n\
2636 movq &0,%d0\n\
2637 rts");
3698f44e 2638#endif
c85f7c16
JL
2639
2640/* Clear instruction cache so we can call trampolines on stack.
2641 This is called from FINALIZE_TRAMPOLINE in mot3300.h. */
2642
2643void
3e7d8ef1 2644__clear_insn_cache (void)
c85f7c16 2645{
3698f44e 2646#ifdef MCT_TEXT
c85f7c16
JL
2647 int save_errno;
2648
2649 /* Preserve errno, because users would be surprised to have
2650 errno changing without explicitly calling any system-call. */
2651 save_errno = errno;
2652
2653 /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache.
2654 No need to use an address derived from _start or %sp, as 0 works also. */
2655 memctl(0, 4096, MCT_TEXT);
2656 errno = save_errno;
3698f44e 2657#endif
c85f7c16
JL
2658}
2659
2660#endif /* __sysV68__ */
2661
b335c2cc
TW
2662#ifdef __pyr__
2663
98126ed6 2664#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
b335c2cc
TW
2665#include <stdio.h>
2666#include <sys/mman.h>
2667#include <sys/types.h>
2668#include <sys/param.h>
2669#include <sys/vmmac.h>
2670
2671/* Modified from the convex -code above.
0f41302f 2672 mremap promises to clear the i-cache. */
b335c2cc
TW
2673
2674void
3e7d8ef1 2675__enable_execute_stack (void)
b335c2cc
TW
2676{
2677 int fp;
2678 if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ,
2679 PROT_READ|PROT_WRITE|PROT_EXEC))
2680 {
2681 perror ("mprotect in __enable_execute_stack");
2682 fflush (stderr);
2683 abort ();
2684 }
2685}
2686#endif /* __pyr__ */
7d41c411
RK
2687
2688#if defined (sony_news) && defined (SYSTYPE_BSD)
2689
2690#include <stdio.h>
2691#include <sys/types.h>
2692#include <sys/param.h>
2693#include <syscall.h>
2694#include <machine/sysnews.h>
2695
2696/* cacheflush function for NEWS-OS 4.2.
2697 This function is called from trampoline-initialize code
2698 defined in config/mips/mips.h. */
2699
2700void
37ef1054 2701cacheflush (char *beg, int size, int flag)
7d41c411
RK
2702{
2703 if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
2704 {
2705 perror ("cache_flush");
2706 fflush (stderr);
2707 abort ();
2708 }
2709}
2710
2711#endif /* sony_news */
203b91b9
RS
2712#endif /* L_trampoline */
2713\f
cae21ae8 2714#ifndef __CYGWIN__
203b91b9
RS
2715#ifdef L__main
2716
2717#include "gbl-ctors.h"
c06cff95
RS
2718/* Some systems use __main in a way incompatible with its use in gcc, in these
2719 cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
2720 give the same symbol without quotes for an alternative entry point. You
0f41302f 2721 must define both, or neither. */
c06cff95
RS
2722#ifndef NAME__MAIN
2723#define NAME__MAIN "__main"
2724#define SYMBOL__MAIN __main
2725#endif
203b91b9 2726
fe1fd353
JM
2727#ifdef INIT_SECTION_ASM_OP
2728#undef HAS_INIT_SECTION
2729#define HAS_INIT_SECTION
2730#endif
2731
2732#if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
31cf0144
JM
2733
2734/* Some ELF crosses use crtstuff.c to provide __CTOR_LIST__, but use this
2735 code to run constructors. In that case, we need to handle EH here, too. */
2736
2737#ifdef EH_FRAME_SECTION
e4b776a6 2738#include "unwind-dw2-fde.h"
31cf0144
JM
2739extern unsigned char __EH_FRAME_BEGIN__[];
2740#endif
2741
203b91b9
RS
2742/* Run all the global destructors on exit from the program. */
2743
2744void
3e7d8ef1 2745__do_global_dtors (void)
203b91b9 2746{
89cf554b
RS
2747#ifdef DO_GLOBAL_DTORS_BODY
2748 DO_GLOBAL_DTORS_BODY;
2749#else
b40b9d93
MS
2750 static func_ptr *p = __DTOR_LIST__ + 1;
2751 while (*p)
2752 {
2753 p++;
2754 (*(p-1)) ();
2755 }
89cf554b 2756#endif
bf279c4e 2757#if defined (EH_FRAME_SECTION) && !defined (HAS_INIT_SECTION)
a4ebb0e6
GRK
2758 {
2759 static int completed = 0;
2760 if (! completed)
2761 {
2762 completed = 1;
2763 __deregister_frame_info (__EH_FRAME_BEGIN__);
2764 }
2765 }
31cf0144 2766#endif
203b91b9 2767}
68d69835 2768#endif
203b91b9 2769
fe1fd353 2770#ifndef HAS_INIT_SECTION
203b91b9
RS
2771/* Run all the global constructors on entry to the program. */
2772
203b91b9 2773void
3e7d8ef1 2774__do_global_ctors (void)
203b91b9 2775{
31cf0144
JM
2776#ifdef EH_FRAME_SECTION
2777 {
2778 static struct object object;
2779 __register_frame_info (__EH_FRAME_BEGIN__, &object);
2780 }
2781#endif
203b91b9 2782 DO_GLOBAL_CTORS_BODY;
a218d5ba 2783 atexit (__do_global_dtors);
203b91b9 2784}
fe1fd353 2785#endif /* no HAS_INIT_SECTION */
203b91b9 2786
fe1fd353 2787#if !defined (HAS_INIT_SECTION) || defined (INVOKE__main)
203b91b9
RS
2788/* Subroutine called automatically by `main'.
2789 Compiling a global function named `main'
2790 produces an automatic call to this function at the beginning.
2791
2792 For many systems, this routine calls __do_global_ctors.
2793 For systems which support a .init section we use the .init section
2794 to run __do_global_ctors, so we need not do anything here. */
2795
2796void
c06cff95 2797SYMBOL__MAIN ()
203b91b9
RS
2798{
2799 /* Support recursive calls to `main': run initializers just once. */
7e6f1890 2800 static int initialized;
203b91b9
RS
2801 if (! initialized)
2802 {
2803 initialized = 1;
2804 __do_global_ctors ();
2805 }
2806}
fe1fd353 2807#endif /* no HAS_INIT_SECTION or INVOKE__main */
203b91b9
RS
2808
2809#endif /* L__main */
cae21ae8 2810#endif /* __CYGWIN__ */
203b91b9 2811\f
ad38743d 2812#ifdef L_ctors
203b91b9
RS
2813
2814#include "gbl-ctors.h"
2815
2816/* Provide default definitions for the lists of constructors and
657be7af
JL
2817 destructors, so that we don't get linker errors. These symbols are
2818 intentionally bss symbols, so that gld and/or collect will provide
2819 the right values. */
203b91b9
RS
2820
2821/* We declare the lists here with two elements each,
657be7af
JL
2822 so that they are valid empty lists if no other definition is loaded.
2823
2824 If we are using the old "set" extensions to have the gnu linker
2825 collect ctors and dtors, then we __CTOR_LIST__ and __DTOR_LIST__
2826 must be in the bss/common section.
2827
2828 Long term no port should use those extensions. But many still do. */
b335c2cc 2829#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
657be7af 2830#if defined (ASM_OUTPUT_CONSTRUCTOR) || defined (USE_COLLECT2)
d15d0264
RS
2831func_ptr __CTOR_LIST__[2] = {0, 0};
2832func_ptr __DTOR_LIST__[2] = {0, 0};
657be7af
JL
2833#else
2834func_ptr __CTOR_LIST__[2];
2835func_ptr __DTOR_LIST__[2];
2836#endif
b335c2cc 2837#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
ad38743d
RS
2838#endif /* L_ctors */
2839\f
2840#ifdef L_exit
2841
2842#include "gbl-ctors.h"
203b91b9 2843
8b7677be 2844#ifdef NEED_ATEXIT
8b7677be 2845
f75e8946 2846#ifndef ON_EXIT
203b91b9 2847
8b7677be
RK
2848# include <errno.h>
2849
920b13cc 2850static func_ptr *atexit_chain = 0;
8b7677be
RK
2851static long atexit_chain_length = 0;
2852static volatile long last_atexit_chain_slot = -1;
2853
c063dc98
JM
2854int
2855atexit (func_ptr func)
8b7677be
RK
2856{
2857 if (++last_atexit_chain_slot == atexit_chain_length)
2858 {
2859 atexit_chain_length += 32;
2860 if (atexit_chain)
a25cea96
RK
2861 atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
2862 * sizeof (func_ptr));
8b7677be 2863 else
a25cea96
RK
2864 atexit_chain = (func_ptr *) malloc (atexit_chain_length
2865 * sizeof (func_ptr));
8b7677be
RK
2866 if (! atexit_chain)
2867 {
2868 atexit_chain_length = 0;
2869 last_atexit_chain_slot = -1;
2870 errno = ENOMEM;
2871 return (-1);
2872 }
2873 }
2874 atexit_chain[last_atexit_chain_slot] = func;
2875 return (0);
2876}
8b7677be 2877
3e7d8ef1
KG
2878extern void _cleanup (void);
2879extern void _exit (int) __attribute__ ((__noreturn__));
203b91b9
RS
2880
2881void
37ef1054 2882exit (int status)
203b91b9 2883{
8b7677be
RK
2884 if (atexit_chain)
2885 {
2886 for ( ; last_atexit_chain_slot-- >= 0; )
2887 {
2888 (*atexit_chain[last_atexit_chain_slot + 1]) ();
920b13cc 2889 atexit_chain[last_atexit_chain_slot + 1] = 0;
8b7677be
RK
2890 }
2891 free (atexit_chain);
920b13cc 2892 atexit_chain = 0;
8b7677be 2893 }
203b91b9
RS
2894#ifdef EXIT_BODY
2895 EXIT_BODY;
2896#else
2897 _cleanup ();
2898#endif
2899 _exit (status);
2900}
2901
f75e8946 2902#else /* ON_EXIT */
bceb30e7 2903
c063dc98
JM
2904/* Simple; we just need a wrapper for ON_EXIT. */
2905int
2906atexit (func_ptr func)
bceb30e7 2907{
c063dc98 2908 return ON_EXIT (func);
bceb30e7 2909}
c063dc98 2910
f75e8946 2911#endif /* ON_EXIT */
c063dc98 2912#endif /* NEED_ATEXIT */
203b91b9
RS
2913
2914#endif /* L_exit */