]> gcc.gnu.org Git - gcc.git/blame - gcc/libgcc2.c
Forgot to change this file.
[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. */
2398fb2a 3/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
757e6639 4 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
RS
1147{
1148 if (a >= - (DFtype) LONG_MIN)
996ed075
JJ
1149 return (Wtype) (a + LONG_MIN) - LONG_MIN;
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{
ab495388 1170 if (a >= - (DFtype) LONG_MIN)
996ed075
JJ
1171 return (Wtype) (a + LONG_MIN) - LONG_MIN;
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{
ab495388 1192 if (a >= - (SFtype) LONG_MIN)
996ed075
JJ
1193 return (Wtype) (a + LONG_MIN) - LONG_MIN;
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
9bd23d2c
RS
1240#endif
1241\f\f
2e06e616
RK
1242#ifdef L__dummy
1243void
3e7d8ef1 1244__dummy (void) {}
2e06e616
RK
1245#endif
1246
203b91b9
RS
1247#ifdef L_varargs
1248#ifdef __i860__
600032fc 1249#if defined(__svr4__) || defined(__alliant__)
203b91b9
RS
1250 asm (" .text");
1251 asm (" .align 4");
1252
27d21d32 1253/* The Alliant needs the added underscore. */
203b91b9
RS
1254 asm (".globl __builtin_saveregs");
1255asm ("__builtin_saveregs:");
27d21d32
RS
1256 asm (".globl ___builtin_saveregs");
1257asm ("___builtin_saveregs:");
1258
1259 asm (" andnot 0x0f,%sp,%sp"); /* round down to 16-byte boundary */
203b91b9
RS
1260 asm (" adds -96,%sp,%sp"); /* allocate stack space for reg save
1261 area and also for a new va_list
1262 structure */
1263 /* Save all argument registers in the arg reg save area. The
1264 arg reg save area must have the following layout (according
1265 to the svr4 ABI):
1266
1267 struct {
1268 union {
1269 float freg[8];
1270 double dreg[4];
1271 } float_regs;
1272 long ireg[12];
1273 };
1274 */
1275
1276 asm (" fst.q %f8, 0(%sp)"); /* save floating regs (f8-f15) */
1277 asm (" fst.q %f12,16(%sp)");
1278
1279 asm (" st.l %r16,32(%sp)"); /* save integer regs (r16-r27) */
1280 asm (" st.l %r17,36(%sp)");
1281 asm (" st.l %r18,40(%sp)");
1282 asm (" st.l %r19,44(%sp)");
1283 asm (" st.l %r20,48(%sp)");
1284 asm (" st.l %r21,52(%sp)");
1285 asm (" st.l %r22,56(%sp)");
1286 asm (" st.l %r23,60(%sp)");
1287 asm (" st.l %r24,64(%sp)");
1288 asm (" st.l %r25,68(%sp)");
1289 asm (" st.l %r26,72(%sp)");
1290 asm (" st.l %r27,76(%sp)");
1291
1292 asm (" adds 80,%sp,%r16"); /* compute the address of the new
1293 va_list structure. Put in into
1294 r16 so that it will be returned
1295 to the caller. */
1296
1297 /* Initialize all fields of the new va_list structure. This
1298 structure looks like:
1299
1300 typedef struct {
1301 unsigned long ireg_used;
1302 unsigned long freg_used;
1303 long *reg_base;
1304 long *mem_ptr;
1305 } va_list;
1306 */
1307
1308 asm (" st.l %r0, 0(%r16)"); /* nfixed */
1309 asm (" st.l %r0, 4(%r16)"); /* nfloating */
1310 asm (" st.l %sp, 8(%r16)"); /* __va_ctl points to __va_struct. */
1311 asm (" bri %r1"); /* delayed return */
1312 asm (" st.l %r28,12(%r16)"); /* pointer to overflow args */
1313
24e4939e 1314#else /* not __svr4__ */
6aadf9c2
RS
1315#if defined(__PARAGON__)
1316 /*
1317 * we'll use SVR4-ish varargs but need SVR3.2 assembler syntax,
1318 * and we stand a better chance of hooking into libraries
1319 * compiled by PGI. [andyp@ssd.intel.com]
1320 */
1321 asm (" .text");
1322 asm (" .align 4");
1323 asm (".globl __builtin_saveregs");
1324asm ("__builtin_saveregs:");
1325 asm (".globl ___builtin_saveregs");
1326asm ("___builtin_saveregs:");
1327
1328 asm (" andnot 0x0f,sp,sp"); /* round down to 16-byte boundary */
1329 asm (" adds -96,sp,sp"); /* allocate stack space for reg save
1330 area and also for a new va_list
1331 structure */
1332 /* Save all argument registers in the arg reg save area. The
1333 arg reg save area must have the following layout (according
1334 to the svr4 ABI):
1335
1336 struct {
1337 union {
1338 float freg[8];
1339 double dreg[4];
1340 } float_regs;
1341 long ireg[12];
1342 };
1343 */
1344
1345 asm (" fst.q f8, 0(sp)");
1346 asm (" fst.q f12,16(sp)");
1347 asm (" st.l r16,32(sp)");
1348 asm (" st.l r17,36(sp)");
1349 asm (" st.l r18,40(sp)");
1350 asm (" st.l r19,44(sp)");
1351 asm (" st.l r20,48(sp)");
1352 asm (" st.l r21,52(sp)");
1353 asm (" st.l r22,56(sp)");
1354 asm (" st.l r23,60(sp)");
1355 asm (" st.l r24,64(sp)");
1356 asm (" st.l r25,68(sp)");
1357 asm (" st.l r26,72(sp)");
1358 asm (" st.l r27,76(sp)");
1359
1360 asm (" adds 80,sp,r16"); /* compute the address of the new
1361 va_list structure. Put in into
1362 r16 so that it will be returned
1363 to the caller. */
1364
1365 /* Initialize all fields of the new va_list structure. This
1366 structure looks like:
1367
1368 typedef struct {
1369 unsigned long ireg_used;
1370 unsigned long freg_used;
1371 long *reg_base;
1372 long *mem_ptr;
1373 } va_list;
1374 */
1375
1376 asm (" st.l r0, 0(r16)"); /* nfixed */
1377 asm (" st.l r0, 4(r16)"); /* nfloating */
1378 asm (" st.l sp, 8(r16)"); /* __va_ctl points to __va_struct. */
1379 asm (" bri r1"); /* delayed return */
1380 asm (" st.l r28,12(r16)"); /* pointer to overflow args */
1381#else /* not __PARAGON__ */
203b91b9
RS
1382 asm (" .text");
1383 asm (" .align 4");
1384
1385 asm (".globl ___builtin_saveregs");
1386 asm ("___builtin_saveregs:");
1387 asm (" mov sp,r30");
1388 asm (" andnot 0x0f,sp,sp");
1389 asm (" adds -96,sp,sp"); /* allocate sufficient space on the stack */
1390
1391/* Fill in the __va_struct. */
1392 asm (" st.l r16, 0(sp)"); /* save integer regs (r16-r27) */
1393 asm (" st.l r17, 4(sp)"); /* int fixed[12] */
1394 asm (" st.l r18, 8(sp)");
1395 asm (" st.l r19,12(sp)");
1396 asm (" st.l r20,16(sp)");
1397 asm (" st.l r21,20(sp)");
1398 asm (" st.l r22,24(sp)");
1399 asm (" st.l r23,28(sp)");
1400 asm (" st.l r24,32(sp)");
1401 asm (" st.l r25,36(sp)");
1402 asm (" st.l r26,40(sp)");
1403 asm (" st.l r27,44(sp)");
1404
1405 asm (" fst.q f8, 48(sp)"); /* save floating regs (f8-f15) */
1406 asm (" fst.q f12,64(sp)"); /* int floating[8] */
1407
1408/* Fill in the __va_ctl. */
1409 asm (" st.l sp, 80(sp)"); /* __va_ctl points to __va_struct. */
1410 asm (" st.l r28,84(sp)"); /* pointer to more args */
1411 asm (" st.l r0, 88(sp)"); /* nfixed */
1412 asm (" st.l r0, 92(sp)"); /* nfloating */
1413
1414 asm (" adds 80,sp,r16"); /* return address of the __va_ctl. */
1415 asm (" bri r1");
1416 asm (" mov r30,sp");
1417 /* recover stack and pass address to start
1418 of data. */
6aadf9c2 1419#endif /* not __PARAGON__ */
24e4939e 1420#endif /* not __svr4__ */
203b91b9
RS
1421#else /* not __i860__ */
1422#ifdef __sparc__
b335c2cc
TW
1423 asm (".global __builtin_saveregs");
1424 asm ("__builtin_saveregs:");
203b91b9
RS
1425 asm (".global ___builtin_saveregs");
1426 asm ("___builtin_saveregs:");
b1166fae
RS
1427#ifdef NEED_PROC_COMMAND
1428 asm (".proc 020");
b335c2cc 1429#endif
203b91b9
RS
1430 asm ("st %i0,[%fp+68]");
1431 asm ("st %i1,[%fp+72]");
1432 asm ("st %i2,[%fp+76]");
1433 asm ("st %i3,[%fp+80]");
1434 asm ("st %i4,[%fp+84]");
1435 asm ("retl");
1436 asm ("st %i5,[%fp+88]");
b1166fae
RS
1437#ifdef NEED_TYPE_COMMAND
1438 asm (".type __builtin_saveregs,#function");
1439 asm (".size __builtin_saveregs,.-__builtin_saveregs");
1440#endif
203b91b9
RS
1441#else /* not __sparc__ */
1442#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
1443
1444 asm (" .text");
6003a6bf
JL
1445#ifdef __mips16
1446 asm (" .set nomips16");
1447#endif
203b91b9
RS
1448 asm (" .ent __builtin_saveregs");
1449 asm (" .globl __builtin_saveregs");
1450 asm ("__builtin_saveregs:");
1451 asm (" sw $4,0($30)");
1452 asm (" sw $5,4($30)");
1453 asm (" sw $6,8($30)");
1454 asm (" sw $7,12($30)");
1455 asm (" j $31");
1456 asm (" .end __builtin_saveregs");
0f41302f 1457#else /* not __mips__, etc. */
3bd4f3b8 1458
757e6639
RK
1459void * ATTRIBUTE_NORETURN
1460__builtin_saveregs ()
203b91b9
RS
1461{
1462 abort ();
1463}
3bd4f3b8 1464
203b91b9
RS
1465#endif /* not __mips__ */
1466#endif /* not __sparc__ */
1467#endif /* not __i860__ */
1468#endif
1469\f
1470#ifdef L_eprintf
c74d5583 1471#ifndef inhibit_libc
bba2431c 1472
203b91b9
RS
1473#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
1474#include <stdio.h>
1475/* This is used by the `assert' macro. */
1476void
37ef1054 1477__eprintf (const char *string, const char *expression,
10c301ac 1478 unsigned int line, const char *filename)
203b91b9
RS
1479{
1480 fprintf (stderr, string, expression, line, filename);
1481 fflush (stderr);
1482 abort ();
1483}
bba2431c
RS
1484
1485#endif
203b91b9
RS
1486#endif
1487
1488#ifdef L_bb
203b91b9 1489
92832bb5 1490/* Structure emitted by -a */
203b91b9
RS
1491struct bb
1492{
92832bb5
MM
1493 long zero_word;
1494 const char *filename;
1495 long *counts;
1496 long ncounts;
1497 struct bb *next;
1498 const unsigned long *addresses;
1499
1500 /* Older GCC's did not emit these fields. */
1501 long nwords;
1502 const char **functions;
1503 const long *line_nums;
1504 const char **filenames;
90b4a764 1505 char *flags;
203b91b9
RS
1506};
1507
92832bb5
MM
1508#ifdef BLOCK_PROFILER_CODE
1509BLOCK_PROFILER_CODE
1510#else
c7544ff7 1511#ifndef inhibit_libc
92832bb5
MM
1512
1513/* Simple minded basic block profiling output dumper for
9faa82d8 1514 systems that don't provide tcov support. At present,
92832bb5
MM
1515 it requires atexit and stdio. */
1516
ebd41309 1517#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
92832bb5 1518#include <stdio.h>
757e6639 1519char *ctime PARAMS ((const time_t *));
203b91b9 1520
8b7677be 1521#include "gbl-ctors.h"
65f7a653 1522#include "gcov-io.h"
ac957f13 1523#include <string.h>
e09d24ff
R
1524#ifdef TARGET_HAS_F_SETLKW
1525#include <fcntl.h>
1526#include <errno.h>
1527#endif
92832bb5 1528
7e6f1890 1529static struct bb *bb_head;
92832bb5 1530
e8f38d1a
DN
1531static int num_digits (long value, int base) __attribute__ ((const));
1532
92832bb5
MM
1533/* Return the number of digits needed to print a value */
1534/* __inline__ */ static int num_digits (long value, int base)
203b91b9 1535{
92832bb5
MM
1536 int minus = (value < 0 && base != 16);
1537 unsigned long v = (minus) ? -value : value;
1538 int ret = minus;
203b91b9 1539
92832bb5
MM
1540 do
1541 {
1542 v /= base;
1543 ret++;
1544 }
1545 while (v);
1546
1547 return ret;
203b91b9
RS
1548}
1549
92832bb5
MM
1550void
1551__bb_exit_func (void)
1552{
65f7a653 1553 FILE *da_file, *file;
92832bb5 1554 long time_value;
65f7a653
DE
1555 int i;
1556
1557 if (bb_head == 0)
1558 return;
1559
1560 i = strlen (bb_head->filename) - 3;
1561
1562 if (!strcmp (bb_head->filename+i, ".da"))
1563 {
1564 /* Must be -fprofile-arcs not -a.
1565 Dump data in a form that gcov expects. */
1566
1567 struct bb *ptr;
1568
1569 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
1570 {
e09d24ff
R
1571 int firstchar;
1572
1573 /* Make sure the output file exists -
1574 but don't clobber exiting data. */
1575 if ((da_file = fopen (ptr->filename, "a")) != 0)
1576 fclose (da_file);
1577
1578 /* Need to re-open in order to be able to write from the start. */
1579 da_file = fopen (ptr->filename, "r+b");
1580 /* Some old systems might not allow the 'b' mode modifier.
1581 Therefore, try to open without it. This can lead to a race
1582 condition so that when you delete and re-create the file, the
1583 file might be opened in text mode, but then, you shouldn't
1584 delete the file in the first place. */
1585 if (da_file == 0)
1586 da_file = fopen (ptr->filename, "r+");
1587 if (da_file == 0)
1588 {
1589 fprintf (stderr, "arc profiling: Can't open output file %s.\n",
1590 ptr->filename);
1591 continue;
1592 }
1593
1594 /* After a fork, another process might try to read and/or write
1595 the same file simultanously. So if we can, lock the file to
1596 avoid race conditions. */
1597#if defined (TARGET_HAS_F_SETLKW)
1598 {
1599 struct flock s_flock;
1600
1601 s_flock.l_type = F_WRLCK;
1602 s_flock.l_whence = SEEK_SET;
1603 s_flock.l_start = 0;
1604 s_flock.l_len = 1;
1605 s_flock.l_pid = getpid ();
1606
1607 while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
1608 && errno == EINTR);
1609 }
1610#endif
1611
1612 /* If the file is not empty, and the number of counts in it is the
1613 same, then merge them in. */
1614 firstchar = fgetc (da_file);
1615 if (firstchar == EOF)
1616 {
1617 if (ferror (da_file))
1618 {
1619 fprintf (stderr, "arc profiling: Can't read output file ");
1620 perror (ptr->filename);
1621 }
1622 }
1623 else
65f7a653
DE
1624 {
1625 long n_counts = 0;
65f7a653 1626
e09d24ff
R
1627 if (ungetc (firstchar, da_file) == EOF)
1628 rewind (da_file);
65f7a653
DE
1629 if (__read_long (&n_counts, da_file, 8) != 0)
1630 {
1631 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
1632 ptr->filename);
1633 continue;
1634 }
1635
1636 if (n_counts == ptr->ncounts)
1637 {
1638 int i;
1639
1640 for (i = 0; i < n_counts; i++)
1641 {
1642 long v = 0;
65f7a653
DE
1643
1644 if (__read_long (&v, da_file, 8) != 0)
1645 {
1646 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
1647 ptr->filename);
1648 break;
1649 }
1650 ptr->counts[i] += v;
1651 }
1652 }
1653
65f7a653
DE
1654 }
1655
e09d24ff
R
1656 rewind (da_file);
1657
956d6950 1658 /* ??? Should first write a header to the file. Preferably, a 4 byte
65f7a653
DE
1659 magic number, 4 bytes containing the time the program was
1660 compiled, 4 bytes containing the last modification time of the
1661 source file, and 4 bytes indicating the compiler options used.
1662
1663 That way we can easily verify that the proper source/executable/
1664 data file combination is being used from gcov. */
1665
1666 if (__write_long (ptr->ncounts, da_file, 8) != 0)
1667 {
1668
1669 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
1670 ptr->filename);
1671 }
1672 else
1673 {
1674 int j;
1675 long *count_ptr = ptr->counts;
1676 int ret = 0;
1677 for (j = ptr->ncounts; j > 0; j--)
1678 {
1679 if (__write_long (*count_ptr, da_file, 8) != 0)
1680 {
1681 ret=1;
1682 break;
1683 }
1684 count_ptr++;
1685 }
1686 if (ret)
1687 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
1688 ptr->filename);
1689 }
1690
1691 if (fclose (da_file) == EOF)
1692 fprintf (stderr, "arc profiling: Error closing output file %s.\n",
1693 ptr->filename);
1694 }
1695
1696 return;
1697 }
1698
1699 /* Must be basic block profiling. Emit a human readable output file. */
1700
1701 file = fopen ("bb.out", "a");
92832bb5
MM
1702
1703 if (!file)
1704 perror ("bb.out");
1705
1706 else
1707 {
1708 struct bb *ptr;
1709
1710 /* This is somewhat type incorrect, but it avoids worrying about
1711 exactly where time.h is included from. It should be ok unless
90b4a764 1712 a void * differs from other pointer formats, or if sizeof (long)
92832bb5
MM
1713 is < sizeof (time_t). It would be nice if we could assume the
1714 use of rationale standards here. */
1715
90b4a764 1716 time ((void *) &time_value);
92832bb5
MM
1717 fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
1718
1719 /* We check the length field explicitly in order to allow compatibility
1720 with older GCC's which did not provide it. */
1721
0f41302f 1722 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
92832bb5
MM
1723 {
1724 int i;
3e7d8ef1 1725 int func_p = (ptr->nwords >= (long) sizeof (struct bb)
65f7a653
DE
1726 && ptr->nwords <= 1000
1727 && ptr->functions);
92832bb5
MM
1728 int line_p = (func_p && ptr->line_nums);
1729 int file_p = (func_p && ptr->filenames);
65f7a653 1730 int addr_p = (ptr->addresses != 0);
92832bb5
MM
1731 long ncounts = ptr->ncounts;
1732 long cnt_max = 0;
1733 long line_max = 0;
1734 long addr_max = 0;
1735 int file_len = 0;
1736 int func_len = 0;
1737 int blk_len = num_digits (ncounts, 10);
1738 int cnt_len;
1739 int line_len;
1740 int addr_len;
1741
1742 fprintf (file, "File %s, %ld basic blocks \n\n",
1743 ptr->filename, ncounts);
1744
1745 /* Get max values for each field. */
1746 for (i = 0; i < ncounts; i++)
1747 {
1748 const char *p;
1749 int len;
1750
1751 if (cnt_max < ptr->counts[i])
1752 cnt_max = ptr->counts[i];
1753
3e7d8ef1 1754 if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
92832bb5
MM
1755 addr_max = ptr->addresses[i];
1756
1757 if (line_p && line_max < ptr->line_nums[i])
1758 line_max = ptr->line_nums[i];
1759
1760 if (func_p)
1761 {
1762 p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
1763 len = strlen (p);
1764 if (func_len < len)
1765 func_len = len;
1766 }
1767
1768 if (file_p)
1769 {
1770 p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
1771 len = strlen (p);
1772 if (file_len < len)
1773 file_len = len;
1774 }
1775 }
1776
1777 addr_len = num_digits (addr_max, 16);
1778 cnt_len = num_digits (cnt_max, 10);
1779 line_len = num_digits (line_max, 10);
1780
1781 /* Now print out the basic block information. */
1782 for (i = 0; i < ncounts; i++)
1783 {
1784 fprintf (file,
65f7a653 1785 " Block #%*d: executed %*ld time(s)",
92832bb5 1786 blk_len, i+1,
65f7a653
DE
1787 cnt_len, ptr->counts[i]);
1788
1789 if (addr_p)
1790 fprintf (file, " address= 0x%.*lx", addr_len,
1791 ptr->addresses[i]);
92832bb5
MM
1792
1793 if (func_p)
3cca99e8 1794 fprintf (file, " function= %-*s", func_len,
92832bb5
MM
1795 (ptr->functions[i]) ? ptr->functions[i] : "<none>");
1796
1797 if (line_p)
1d42e1b7 1798 fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
92832bb5
MM
1799
1800 if (file_p)
3cca99e8 1801 fprintf (file, " file= %s",
92832bb5
MM
1802 (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
1803
1804 fprintf (file, "\n");
1805 }
1806
1807 fprintf (file, "\n");
1808 fflush (file);
1809 }
1810
1811 fprintf (file, "\n\n");
1812 fclose (file);
1813 }
1814}
1815
1816void
1817__bb_init_func (struct bb *blocks)
1818{
1819 /* User is supposed to check whether the first word is non-0,
0f41302f 1820 but just in case.... */
92832bb5
MM
1821
1822 if (blocks->zero_word)
1823 return;
1824
92832bb5
MM
1825 /* Initialize destructor. */
1826 if (!bb_head)
c063dc98 1827 atexit (__bb_exit_func);
92832bb5
MM
1828
1829 /* Set up linked list. */
1830 blocks->zero_word = 1;
1831 blocks->next = bb_head;
1832 bb_head = blocks;
1833}
1834
e09d24ff
R
1835/* Called before fork or exec - write out profile information gathered so
1836 far and reset it to zero. This avoids duplication or loss of the
1837 profile information gathered so far. */
1838void
1839__bb_fork_func (void)
1840{
1841 struct bb *ptr;
1842
1843 __bb_exit_func ();
1844 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
1845 {
1846 long i;
1847 for (i = ptr->ncounts - 1; i >= 0; i--)
1848 ptr->counts[i] = 0;
1849 }
1850}
1851
90b4a764
RK
1852#ifndef MACHINE_STATE_SAVE
1853#define MACHINE_STATE_SAVE(ID)
1854#endif
1855#ifndef MACHINE_STATE_RESTORE
1856#define MACHINE_STATE_RESTORE(ID)
1857#endif
1858
0f41302f 1859/* Number of buckets in hashtable of basic block addresses. */
90b4a764
RK
1860
1861#define BB_BUCKETS 311
1862
0f41302f 1863/* Maximum length of string in file bb.in. */
90b4a764
RK
1864
1865#define BBINBUFSIZE 500
1866
90b4a764
RK
1867struct bb_edge
1868{
1869 struct bb_edge *next;
1870 unsigned long src_addr;
1871 unsigned long dst_addr;
1872 unsigned long count;
1873};
1874
1875enum bb_func_mode
1876{
1877 TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
1878};
1879
1880struct bb_func
1881{
1882 struct bb_func *next;
1883 char *funcname;
1884 char *filename;
1885 enum bb_func_mode mode;
1886};
1887
1888/* This is the connection to the outside world.
1889 The BLOCK_PROFILER macro must set __bb.blocks
0f41302f 1890 and __bb.blockno. */
90b4a764
RK
1891
1892struct {
1893 unsigned long blockno;
1894 struct bb *blocks;
1895} __bb;
1896
1897/* Vars to store addrs of source and destination basic blocks
0f41302f 1898 of a jump. */
90b4a764
RK
1899
1900static unsigned long bb_src = 0;
1901static unsigned long bb_dst = 0;
1902
0f41302f
MS
1903static FILE *bb_tracefile = (FILE *) 0;
1904static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
1905static struct bb_func *bb_func_head = (struct bb_func *) 0;
90b4a764
RK
1906static unsigned long bb_callcount = 0;
1907static int bb_mode = 0;
1908
0f41302f 1909static unsigned long *bb_stack = (unsigned long *) 0;
90b4a764
RK
1910static size_t bb_stacksize = 0;
1911
1912static int reported = 0;
1913
1914/* Trace modes:
1915Always : Print execution frequencies of basic blocks
1916 to file bb.out.
1917bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
1918bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
1919bb_mode & 4 != 0 : Cut call instructions from basic block flow.
1920bb_mode & 8 != 0 : Insert return instructions in basic block flow.
1921*/
1922
1923#ifdef HAVE_POPEN
1924
1925/*#include <sys/types.h>*/
1926#include <sys/stat.h>
1927/*#include <malloc.h>*/
1928
0f41302f 1929/* Commands executed by gopen. */
90b4a764
RK
1930
1931#define GOPENDECOMPRESS "gzip -cd "
1932#define GOPENCOMPRESS "gzip -c >"
1933
1934/* Like fopen but pipes through gzip. mode may only be "r" or "w".
1935 If it does not compile, simply replace gopen by fopen and delete
0f41302f 1936 '.gz' from any first parameter to gopen. */
90b4a764
RK
1937
1938static FILE *
37ef1054 1939gopen (char *fn, char *mode)
90b4a764
RK
1940{
1941 int use_gzip;
1942 char *p;
1943
1944 if (mode[1])
0f41302f 1945 return (FILE *) 0;
90b4a764
RK
1946
1947 if (mode[0] != 'r' && mode[0] != 'w')
0f41302f 1948 return (FILE *) 0;
90b4a764
RK
1949
1950 p = fn + strlen (fn)-1;
db3cf6fb
MS
1951 use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
1952 || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
90b4a764
RK
1953
1954 if (use_gzip)
1955 {
1956 if (mode[0]=='r')
1957 {
1958 FILE *f;
0f41302f
MS
1959 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1960 + sizeof (GOPENDECOMPRESS));
90b4a764
RK
1961 strcpy (s, GOPENDECOMPRESS);
1962 strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
1963 f = popen (s, mode);
1964 free (s);
1965 return f;
1966 }
1967
1968 else
1969 {
1970 FILE *f;
0f41302f
MS
1971 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1972 + sizeof (GOPENCOMPRESS));
90b4a764
RK
1973 strcpy (s, GOPENCOMPRESS);
1974 strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
1975 if (!(f = popen (s, mode)))
1976 f = fopen (s, mode);
1977 free (s);
1978 return f;
1979 }
1980 }
1981
1982 else
1983 return fopen (fn, mode);
1984}
1985
1986static int
37ef1054 1987gclose (FILE *f)
90b4a764
RK
1988{
1989 struct stat buf;
1990
920b13cc 1991 if (f != 0)
90b4a764
RK
1992 {
1993 if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
1994 return pclose (f);
1995
1996 return fclose (f);
1997 }
1998 return 0;
1999}
2000
2001#endif /* HAVE_POPEN */
2002
0f41302f 2003/* Called once per program. */
90b4a764
RK
2004
2005static void
3e7d8ef1 2006__bb_exit_trace_func (void)
90b4a764
RK
2007{
2008 FILE *file = fopen ("bb.out", "a");
2009 struct bb_func *f;
90b4a764
RK
2010 struct bb *b;
2011
2012 if (!file)
2013 perror ("bb.out");
2014
2015 if (bb_mode & 1)
2016 {
2017 if (!bb_tracefile)
2018 perror ("bbtrace");
2019 else
2020#ifdef HAVE_POPEN
2021 gclose (bb_tracefile);
2022#else
2023 fclose (bb_tracefile);
2024#endif /* HAVE_POPEN */
2025 }
2026
0f41302f 2027 /* Check functions in `bb.in'. */
90b4a764
RK
2028
2029 if (file)
2030 {
2031 long time_value;
2032 const struct bb_func *p;
2033 int printed_something = 0;
2034 struct bb *ptr;
2035 long blk;
2036
0f41302f 2037 /* This is somewhat type incorrect. */
90b4a764
RK
2038 time ((void *) &time_value);
2039
0f41302f 2040 for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
90b4a764 2041 {
0f41302f 2042 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
90b4a764 2043 {
51723711 2044 if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
90b4a764
RK
2045 continue;
2046 for (blk = 0; blk < ptr->ncounts; blk++)
2047 {
2048 if (!strcmp (p->funcname, ptr->functions[blk]))
2049 goto found;
2050 }
2051 }
2052
2053 if (!printed_something)
2054 {
2055 fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
2056 printed_something = 1;
2057 }
2058
2059 fprintf (file, "\tFunction %s", p->funcname);
2060 if (p->filename)
2061 fprintf (file, " of file %s", p->filename);
2062 fprintf (file, "\n" );
2063
2064found: ;
2065 }
2066
2067 if (printed_something)
2068 fprintf (file, "\n");
2069
2070 }
2071
2072 if (bb_mode & 2)
2073 {
2074 if (!bb_hashbuckets)
2075 {
2076 if (!reported)
2077 {
2078 fprintf (stderr, "Profiler: out of memory\n");
2079 reported = 1;
2080 }
2081 return;
2082 }
2083
2084 else if (file)
2085 {
2086 long time_value;
2087 int i;
2088 unsigned long addr_max = 0;
2089 unsigned long cnt_max = 0;
2090 int cnt_len;
2091 int addr_len;
2092
2093 /* This is somewhat type incorrect, but it avoids worrying about
2094 exactly where time.h is included from. It should be ok unless
2095 a void * differs from other pointer formats, or if sizeof (long)
2096 is < sizeof (time_t). It would be nice if we could assume the
2097 use of rationale standards here. */
2098
2099 time ((void *) &time_value);
2100 fprintf (file, "Basic block jump tracing");
2101
2102 switch (bb_mode & 12)
2103 {
2104 case 0:
2105 fprintf (file, " (with call)");
2106 break;
2107
2108 case 4:
0f41302f 2109 /* Print nothing. */
90b4a764
RK
2110 break;
2111
2112 case 8:
2113 fprintf (file, " (with call & ret)");
2114 break;
2115
2116 case 12:
2117 fprintf (file, " (with ret)");
2118 break;
2119 }
2120
2121 fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
2122
2123 for (i = 0; i < BB_BUCKETS; i++)
2124 {
2125 struct bb_edge *bucket = bb_hashbuckets[i];
2126 for ( ; bucket; bucket = bucket->next )
2127 {
2128 if (addr_max < bucket->src_addr)
2129 addr_max = bucket->src_addr;
2130 if (addr_max < bucket->dst_addr)
2131 addr_max = bucket->dst_addr;
2132 if (cnt_max < bucket->count)
2133 cnt_max = bucket->count;
2134 }
2135 }
2136 addr_len = num_digits (addr_max, 16);
2137 cnt_len = num_digits (cnt_max, 10);
2138
2139 for ( i = 0; i < BB_BUCKETS; i++)
2140 {
2141 struct bb_edge *bucket = bb_hashbuckets[i];
2142 for ( ; bucket; bucket = bucket->next )
2143 {
78a0d70c
ZW
2144 fprintf (file,
2145 "Jump from block 0x%.*lx to block 0x%.*lx executed %*lu time(s)\n",
90b4a764
RK
2146 addr_len, bucket->src_addr,
2147 addr_len, bucket->dst_addr,
2148 cnt_len, bucket->count);
2149 }
2150 }
2151
2152 fprintf (file, "\n");
2153
2154 }
2155 }
2156
2157 if (file)
2158 fclose (file);
2159
0f41302f 2160 /* Free allocated memory. */
90b4a764
RK
2161
2162 f = bb_func_head;
2163 while (f)
2164 {
2165 struct bb_func *old = f;
2166
2167 f = f->next;
2168 if (old->funcname) free (old->funcname);
2169 if (old->filename) free (old->filename);
2170 free (old);
2171 }
2172
2173 if (bb_stack)
2174 free (bb_stack);
2175
2176 if (bb_hashbuckets)
2177 {
2178 int i;
2179
2180 for (i = 0; i < BB_BUCKETS; i++)
2181 {
2182 struct bb_edge *old, *bucket = bb_hashbuckets[i];
2183
2184 while (bucket)
2185 {
2186 old = bucket;
2187 bucket = bucket->next;
2188 free (old);
2189 }
2190 }
2191 free (bb_hashbuckets);
2192 }
2193
2194 for (b = bb_head; b; b = b->next)
2195 if (b->flags) free (b->flags);
2196}
2197
0f41302f 2198/* Called once per program. */
90b4a764
RK
2199
2200static void
3e7d8ef1 2201__bb_init_prg (void)
90b4a764 2202{
90b4a764
RK
2203 FILE *file;
2204 char buf[BBINBUFSIZE];
2205 const char *p;
2206 const char *pos;
2207 enum bb_func_mode m;
c5c76735 2208 int i;
90b4a764 2209
90b4a764 2210 /* Initialize destructor. */
c063dc98 2211 atexit (__bb_exit_func);
90b4a764
RK
2212
2213 if (!(file = fopen ("bb.in", "r")))
2214 return;
2215
78a0d70c 2216 while(fgets (buf, BBINBUFSIZE, file) != 0)
90b4a764 2217 {
78a0d70c
ZW
2218 i = strlen (buf);
2219 if (buf[i] == '\n')
2220 buf[i--] = '\0';
2221
90b4a764
RK
2222 p = buf;
2223 if (*p == '-')
2224 {
2225 m = TRACE_OFF;
2226 p++;
2227 }
2228 else
2229 {
2230 m = TRACE_ON;
2231 }
2232 if (!strcmp (p, "__bb_trace__"))
2233 bb_mode |= 1;
2234 else if (!strcmp (p, "__bb_jumps__"))
2235 bb_mode |= 2;
2236 else if (!strcmp (p, "__bb_hidecall__"))
2237 bb_mode |= 4;
2238 else if (!strcmp (p, "__bb_showret__"))
2239 bb_mode |= 8;
2240 else
2241 {
0f41302f 2242 struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
90b4a764
RK
2243 if (f)
2244 {
2245 unsigned long l;
2246 f->next = bb_func_head;
51723711 2247 if ((pos = strchr (p, ':')))
90b4a764 2248 {
0f41302f 2249 if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
90b4a764
RK
2250 continue;
2251 strcpy (f->funcname, pos+1);
2252 l = pos-p;
0f41302f 2253 if ((f->filename = (char *) malloc (l+1)))
90b4a764
RK
2254 {
2255 strncpy (f->filename, p, l);
2256 f->filename[l] = '\0';
2257 }
2258 else
0f41302f 2259 f->filename = (char *) 0;
90b4a764
RK
2260 }
2261 else
2262 {
0f41302f 2263 if (!(f->funcname = (char *) malloc (strlen (p)+1)))
90b4a764
RK
2264 continue;
2265 strcpy (f->funcname, p);
0f41302f 2266 f->filename = (char *) 0;
90b4a764
RK
2267 }
2268 f->mode = m;
2269 bb_func_head = f;
2270 }
2271 }
2272 }
2273 fclose (file);
2274
2275#ifdef HAVE_POPEN
2276
2277 if (bb_mode & 1)
2278 bb_tracefile = gopen ("bbtrace.gz", "w");
2279
2280#else
2281
2282 if (bb_mode & 1)
2283 bb_tracefile = fopen ("bbtrace", "w");
2284
2285#endif /* HAVE_POPEN */
2286
2287 if (bb_mode & 2)
2288 {
2289 bb_hashbuckets = (struct bb_edge **)
2290 malloc (BB_BUCKETS * sizeof (struct bb_edge *));
2291 if (bb_hashbuckets)
c5c76735
JL
2292 /* Use a loop here rather than calling bzero to avoid having to
2293 conditionalize its existance. */
2294 for (i = 0; i < BB_BUCKETS; i++)
2295 bb_hashbuckets[i] = 0;
90b4a764
RK
2296 }
2297
2298 if (bb_mode & 12)
2299 {
2300 bb_stacksize = 10;
2301 bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
2302 }
2303
c063dc98
JM
2304 /* Initialize destructor. */
2305 atexit (__bb_exit_trace_func);
90b4a764
RK
2306}
2307
0f41302f 2308/* Called upon entering a basic block. */
90b4a764
RK
2309
2310void
3e7d8ef1 2311__bb_trace_func (void)
90b4a764
RK
2312{
2313 struct bb_edge *bucket;
2314
2315 MACHINE_STATE_SAVE("1")
2316
2317 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2318 goto skip;
2319
2320 bb_dst = __bb.blocks->addresses[__bb.blockno];
2321 __bb.blocks->counts[__bb.blockno]++;
2322
2323 if (bb_tracefile)
2324 {
2325 fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
2326 }
2327
2328 if (bb_hashbuckets)
2329 {
2330 struct bb_edge **startbucket, **oldnext;
2331
db3cf6fb
MS
2332 oldnext = startbucket
2333 = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
90b4a764
RK
2334 bucket = *startbucket;
2335
2336 for (bucket = *startbucket; bucket;
2337 oldnext = &(bucket->next), bucket = *oldnext)
2338 {
db3cf6fb
MS
2339 if (bucket->src_addr == bb_src
2340 && bucket->dst_addr == bb_dst)
90b4a764
RK
2341 {
2342 bucket->count++;
2343 *oldnext = bucket->next;
2344 bucket->next = *startbucket;
2345 *startbucket = bucket;
2346 goto ret;
2347 }
2348 }
2349
2350 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2351
2352 if (!bucket)
2353 {
2354 if (!reported)
2355 {
2356 fprintf (stderr, "Profiler: out of memory\n");
2357 reported = 1;
2358 }
2359 }
2360
2361 else
2362 {
2363 bucket->src_addr = bb_src;
2364 bucket->dst_addr = bb_dst;
2365 bucket->next = *startbucket;
2366 *startbucket = bucket;
2367 bucket->count = 1;
2368 }
2369 }
2370
2371ret:
2372 bb_src = bb_dst;
2373
2374skip:
2375 ;
2376
2377 MACHINE_STATE_RESTORE("1")
2378
2379}
2380
0f41302f 2381/* Called when returning from a function and `__bb_showret__' is set. */
90b4a764
RK
2382
2383static void
3e7d8ef1 2384__bb_trace_func_ret (void)
90b4a764
RK
2385{
2386 struct bb_edge *bucket;
2387
2388 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2389 goto skip;
2390
2391 if (bb_hashbuckets)
2392 {
2393 struct bb_edge **startbucket, **oldnext;
2394
db3cf6fb
MS
2395 oldnext = startbucket
2396 = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
90b4a764
RK
2397 bucket = *startbucket;
2398
2399 for (bucket = *startbucket; bucket;
2400 oldnext = &(bucket->next), bucket = *oldnext)
2401 {
db3cf6fb
MS
2402 if (bucket->src_addr == bb_dst
2403 && bucket->dst_addr == bb_src)
90b4a764
RK
2404 {
2405 bucket->count++;
2406 *oldnext = bucket->next;
2407 bucket->next = *startbucket;
2408 *startbucket = bucket;
2409 goto ret;
2410 }
2411 }
2412
2413 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2414
2415 if (!bucket)
2416 {
2417 if (!reported)
2418 {
2419 fprintf (stderr, "Profiler: out of memory\n");
2420 reported = 1;
2421 }
2422 }
2423
2424 else
2425 {
2426 bucket->src_addr = bb_dst;
2427 bucket->dst_addr = bb_src;
2428 bucket->next = *startbucket;
2429 *startbucket = bucket;
2430 bucket->count = 1;
2431 }
2432 }
2433
2434ret:
2435 bb_dst = bb_src;
2436
2437skip:
2438 ;
2439
2440}
2441
0f41302f 2442/* Called upon entering the first function of a file. */
90b4a764
RK
2443
2444static void
37ef1054 2445__bb_init_file (struct bb *blocks)
90b4a764
RK
2446{
2447
2448 const struct bb_func *p;
2449 long blk, ncounts = blocks->ncounts;
2450 const char **functions = blocks->functions;
2451
2452 /* Set up linked list. */
2453 blocks->zero_word = 1;
2454 blocks->next = bb_head;
2455 bb_head = blocks;
2456
2457 blocks->flags = 0;
db3cf6fb
MS
2458 if (!bb_func_head
2459 || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
90b4a764
RK
2460 return;
2461
2462 for (blk = 0; blk < ncounts; blk++)
2463 blocks->flags[blk] = 0;
2464
2465 for (blk = 0; blk < ncounts; blk++)
2466 {
2467 for (p = bb_func_head; p; p = p->next)
2468 {
db3cf6fb
MS
2469 if (!strcmp (p->funcname, functions[blk])
2470 && (!p->filename || !strcmp (p->filename, blocks->filename)))
90b4a764
RK
2471 {
2472 blocks->flags[blk] |= p->mode;
2473 }
2474 }
2475 }
2476
2477}
2478
0f41302f 2479/* Called when exiting from a function. */
90b4a764
RK
2480
2481void
3e7d8ef1 2482__bb_trace_ret (void)
90b4a764
RK
2483{
2484
2485 MACHINE_STATE_SAVE("2")
2486
2487 if (bb_callcount)
2488 {
2489 if ((bb_mode & 12) && bb_stacksize > bb_callcount)
2490 {
2491 bb_src = bb_stack[bb_callcount];
2492 if (bb_mode & 8)
2493 __bb_trace_func_ret ();
2494 }
2495
2496 bb_callcount -= 1;
2497 }
2498
2499 MACHINE_STATE_RESTORE("2")
2500
2501}
2502
0f41302f 2503/* Called when entering a function. */
90b4a764
RK
2504
2505void
37ef1054 2506__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
90b4a764
RK
2507{
2508 static int trace_init = 0;
2509
2510 MACHINE_STATE_SAVE("3")
2511
2512 if (!blocks->zero_word)
2513 {
2514 if (!trace_init)
2515 {
2516 trace_init = 1;
2517 __bb_init_prg ();
2518 }
2519 __bb_init_file (blocks);
2520 }
2521
2522 if (bb_callcount)
2523 {
2524
2525 bb_callcount += 1;
2526
2527 if (bb_mode & 12)
2528 {
2529 if (bb_callcount >= bb_stacksize)
2530 {
2531 size_t newsize = bb_callcount + 100;
2532
2533 bb_stack = (unsigned long *) realloc (bb_stack, newsize);
2534 if (! bb_stack)
2535 {
2536 if (!reported)
2537 {
2538 fprintf (stderr, "Profiler: out of memory\n");
2539 reported = 1;
2540 }
2541 bb_stacksize = 0;
2542 goto stack_overflow;
2543 }
2544 bb_stacksize = newsize;
2545 }
2546 bb_stack[bb_callcount] = bb_src;
2547
2548 if (bb_mode & 4)
2549 bb_src = 0;
2550
2551 }
2552
2553stack_overflow:;
2554
2555 }
2556
2557 else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
2558 {
2559 bb_callcount = 1;
2560 bb_src = 0;
2561
2562 if (bb_stack)
2563 bb_stack[bb_callcount] = bb_src;
2564 }
2565
2566 MACHINE_STATE_RESTORE("3")
2567}
2568
c7544ff7
RS
2569#endif /* not inhibit_libc */
2570#endif /* not BLOCK_PROFILER_CODE */
2571#endif /* L_bb */
203b91b9 2572\f
203b91b9
RS
2573#ifdef L_clear_cache
2574/* Clear part of an instruction cache. */
2575
2576#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
2577
2578void
139fa6f8
MM
2579__clear_cache (char *beg __attribute__((__unused__)),
2580 char *end __attribute__((__unused__)))
203b91b9 2581{
e1178973
KKT
2582#ifdef CLEAR_INSN_CACHE
2583 CLEAR_INSN_CACHE (beg, end);
2584#else
203b91b9
RS
2585#ifdef INSN_CACHE_SIZE
2586 static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
7e6f1890 2587 static int initialized;
203b91b9 2588 int offset;
b6422cca
RS
2589 void *start_addr
2590 void *end_addr;
3e7d8ef1 2591 typedef (*function_ptr) (void);
203b91b9
RS
2592
2593#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
2594 /* It's cheaper to clear the whole cache.
2595 Put in a series of jump instructions so that calling the beginning
2596 of the cache will clear the whole thing. */
2597
2598 if (! initialized)
2599 {
2600 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2601 & -INSN_CACHE_LINE_WIDTH);
2602 int end_ptr = ptr + INSN_CACHE_SIZE;
2603
2604 while (ptr < end_ptr)
2605 {
2606 *(INSTRUCTION_TYPE *)ptr
2607 = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
2608 ptr += INSN_CACHE_LINE_WIDTH;
2609 }
0f41302f 2610 *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
203b91b9
RS
2611
2612 initialized = 1;
2613 }
2614
2615 /* Call the beginning of the sequence. */
2616 (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2617 & -INSN_CACHE_LINE_WIDTH))
2618 ());
2619
2620#else /* Cache is large. */
2621
2622 if (! initialized)
2623 {
2624 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2625 & -INSN_CACHE_LINE_WIDTH);
2626
2627 while (ptr < (int) array + sizeof array)
2628 {
2629 *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
2630 ptr += INSN_CACHE_LINE_WIDTH;
2631 }
2632
2633 initialized = 1;
2634 }
2635
2636 /* Find the location in array that occupies the same cache line as BEG. */
2637
2638 offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
2639 start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
2640 & -INSN_CACHE_PLANE_SIZE)
2641 + offset);
2642
2643 /* Compute the cache alignment of the place to stop clearing. */
2644#if 0 /* This is not needed for gcc's purposes. */
2645 /* If the block to clear is bigger than a cache plane,
2646 we clear the entire cache, and OFFSET is already correct. */
2647 if (end < beg + INSN_CACHE_PLANE_SIZE)
2648#endif
2649 offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
2650 & -INSN_CACHE_LINE_WIDTH)
2651 & (INSN_CACHE_PLANE_SIZE - 1));
2652
2653#if INSN_CACHE_DEPTH > 1
2654 end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset;
2655 if (end_addr <= start_addr)
2656 end_addr += INSN_CACHE_PLANE_SIZE;
2657
2658 for (plane = 0; plane < INSN_CACHE_DEPTH; plane++)
2659 {
2660 int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE;
2661 int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE;
2662
2663 while (addr != stop)
2664 {
2665 /* Call the return instruction at ADDR. */
2666 ((function_ptr) addr) ();
2667
2668 addr += INSN_CACHE_LINE_WIDTH;
2669 }
2670 }
2671#else /* just one plane */
2672 do
2673 {
2674 /* Call the return instruction at START_ADDR. */
2675 ((function_ptr) start_addr) ();
2676
2677 start_addr += INSN_CACHE_LINE_WIDTH;
2678 }
2679 while ((start_addr % INSN_CACHE_SIZE) != offset);
2680#endif /* just one plane */
2681#endif /* Cache is large */
2682#endif /* Cache exists */
e1178973 2683#endif /* CLEAR_INSN_CACHE */
203b91b9
RS
2684}
2685
2686#endif /* L_clear_cache */
2687\f
2688#ifdef L_trampoline
2689
2690/* Jump to a trampoline, loading the static chain address. */
2691
b27d2bd5 2692#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN)
e3367a77 2693
3e7d8ef1
KG
2694long
2695getpagesize (void)
f5ea9817
RK
2696{
2697#ifdef _ALPHA_
2698 return 8192;
2699#else
2700 return 4096;
2701#endif
2702}
2703
d7ebf9ea 2704#ifdef __i386__
e4b15106
RK
2705extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
2706#endif
2707
272e2587
RK
2708int
2709mprotect (char *addr, int len, int prot)
f5ea9817
RK
2710{
2711 int np, op;
2712
272e2587
RK
2713 if (prot == 7)
2714 np = 0x40;
2715 else if (prot == 5)
2716 np = 0x20;
2717 else if (prot == 4)
2718 np = 0x10;
2719 else if (prot == 3)
2720 np = 0x04;
2721 else if (prot == 1)
2722 np = 0x02;
2723 else if (prot == 0)
2724 np = 0x01;
f5ea9817
RK
2725
2726 if (VirtualProtect (addr, len, np, &op))
2727 return 0;
2728 else
2729 return -1;
f5ea9817
RK
2730}
2731
b27d2bd5 2732#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
f5ea9817 2733
203b91b9
RS
2734#ifdef TRANSFER_FROM_TRAMPOLINE
2735TRANSFER_FROM_TRAMPOLINE
2736#endif
2737
c1381fd3
KKT
2738#if defined (NeXT) && defined (__MACH__)
2739
2740/* Make stack executable so we can call trampolines on stack.
2741 This is called from INITIALIZE_TRAMPOLINE in next.h. */
c5df463e
RK
2742#ifdef NeXTStep21
2743 #include <mach.h>
2744#else
2745 #include <mach/mach.h>
2746#endif
c1381fd3
KKT
2747
2748void
37ef1054 2749__enable_execute_stack (char *addr)
c1381fd3
KKT
2750{
2751 kern_return_t r;
2752 char *eaddr = addr + TRAMPOLINE_SIZE;
2753 vm_address_t a = (vm_address_t) addr;
2754
2755 /* turn on execute access on stack */
2756 r = vm_protect (task_self (), a, TRAMPOLINE_SIZE, FALSE, VM_PROT_ALL);
2757 if (r != KERN_SUCCESS)
2758 {
2759 mach_error("vm_protect VM_PROT_ALL", r);
2760 exit(1);
2761 }
2762
2763 /* We inline the i-cache invalidation for speed */
2764
2765#ifdef CLEAR_INSN_CACHE
2766 CLEAR_INSN_CACHE (addr, eaddr);
2767#else
2768 __clear_cache ((int) addr, (int) eaddr);
2769#endif
2770}
2771
2772#endif /* defined (NeXT) && defined (__MACH__) */
2773
203b91b9
RS
2774#ifdef __convex__
2775
2776/* Make stack executable so we can call trampolines on stack.
2777 This is called from INITIALIZE_TRAMPOLINE in convex.h. */
2778
2779#include <sys/mman.h>
2780#include <sys/vmparam.h>
2781#include <machine/machparam.h>
2782
2783void
3e7d8ef1 2784__enable_execute_stack (void)
203b91b9
RS
2785{
2786 int fp;
2787 static unsigned lowest = USRSTACK;
2788 unsigned current = (unsigned) &fp & -NBPG;
2789
2790 if (lowest > current)
2791 {
2792 unsigned len = lowest - current;
2793 mremap (current, &len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
2794 lowest = current;
2795 }
2796
0f41302f 2797 /* Clear instruction cache in case an old trampoline is in it. */
203b91b9
RS
2798 asm ("pich");
2799}
2800#endif /* __convex__ */
b335c2cc 2801
db87ec0b 2802#ifdef __sysV88__
0c8ae3d3 2803
0f41302f 2804/* Modified from the convex -code above. */
0c8ae3d3
RK
2805
2806#include <sys/param.h>
2807#include <errno.h>
2808#include <sys/m88kbcs.h>
2809
2810void
3e7d8ef1 2811__enable_execute_stack (void)
0c8ae3d3
RK
2812{
2813 int save_errno;
2814 static unsigned long lowest = USRSTACK;
2815 unsigned long current = (unsigned long) &save_errno & -NBPC;
2816
2817 /* Ignore errno being set. memctl sets errno to EINVAL whenever the
2818 address is seen as 'negative'. That is the case with the stack. */
2819
2820 save_errno=errno;
2821 if (lowest > current)
2822 {
2823 unsigned len=lowest-current;
2824 memctl(current,len,MCT_TEXT);
2825 lowest = current;
2826 }
2827 else
2828 memctl(current,NBPC,MCT_TEXT);
2829 errno=save_errno;
2830}
2831
db87ec0b 2832#endif /* __sysV88__ */
0c8ae3d3 2833
c85f7c16
JL
2834#ifdef __sysV68__
2835
2836#include <sys/signal.h>
2837#include <errno.h>
2838
2839/* Motorola forgot to put memctl.o in the libp version of libc881.a,
2840 so define it here, because we need it in __clear_insn_cache below */
3698f44e
MH
2841/* On older versions of this OS, no memctl or MCT_TEXT are defined;
2842 hence we enable this stuff only if MCT_TEXT is #define'd. */
c85f7c16 2843
3698f44e 2844#ifdef MCT_TEXT
c85f7c16
JL
2845asm("\n\
2846 global memctl\n\
2847memctl:\n\
2848 movq &75,%d0\n\
2849 trap &0\n\
2850 bcc.b noerror\n\
2851 jmp cerror%\n\
2852noerror:\n\
2853 movq &0,%d0\n\
2854 rts");
3698f44e 2855#endif
c85f7c16
JL
2856
2857/* Clear instruction cache so we can call trampolines on stack.
2858 This is called from FINALIZE_TRAMPOLINE in mot3300.h. */
2859
2860void
3e7d8ef1 2861__clear_insn_cache (void)
c85f7c16 2862{
3698f44e 2863#ifdef MCT_TEXT
c85f7c16
JL
2864 int save_errno;
2865
2866 /* Preserve errno, because users would be surprised to have
2867 errno changing without explicitly calling any system-call. */
2868 save_errno = errno;
2869
2870 /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache.
2871 No need to use an address derived from _start or %sp, as 0 works also. */
2872 memctl(0, 4096, MCT_TEXT);
2873 errno = save_errno;
3698f44e 2874#endif
c85f7c16
JL
2875}
2876
2877#endif /* __sysV68__ */
2878
b335c2cc
TW
2879#ifdef __pyr__
2880
98126ed6 2881#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
b335c2cc
TW
2882#include <stdio.h>
2883#include <sys/mman.h>
2884#include <sys/types.h>
2885#include <sys/param.h>
2886#include <sys/vmmac.h>
2887
2888/* Modified from the convex -code above.
0f41302f 2889 mremap promises to clear the i-cache. */
b335c2cc
TW
2890
2891void
3e7d8ef1 2892__enable_execute_stack (void)
b335c2cc
TW
2893{
2894 int fp;
2895 if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ,
2896 PROT_READ|PROT_WRITE|PROT_EXEC))
2897 {
2898 perror ("mprotect in __enable_execute_stack");
2899 fflush (stderr);
2900 abort ();
2901 }
2902}
2903#endif /* __pyr__ */
7d41c411
RK
2904
2905#if defined (sony_news) && defined (SYSTYPE_BSD)
2906
2907#include <stdio.h>
2908#include <sys/types.h>
2909#include <sys/param.h>
2910#include <syscall.h>
2911#include <machine/sysnews.h>
2912
2913/* cacheflush function for NEWS-OS 4.2.
2914 This function is called from trampoline-initialize code
2915 defined in config/mips/mips.h. */
2916
2917void
37ef1054 2918cacheflush (char *beg, int size, int flag)
7d41c411
RK
2919{
2920 if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
2921 {
2922 perror ("cache_flush");
2923 fflush (stderr);
2924 abort ();
2925 }
2926}
2927
2928#endif /* sony_news */
203b91b9
RS
2929#endif /* L_trampoline */
2930\f
cae21ae8 2931#ifndef __CYGWIN__
203b91b9
RS
2932#ifdef L__main
2933
2934#include "gbl-ctors.h"
c06cff95
RS
2935/* Some systems use __main in a way incompatible with its use in gcc, in these
2936 cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
2937 give the same symbol without quotes for an alternative entry point. You
0f41302f 2938 must define both, or neither. */
c06cff95
RS
2939#ifndef NAME__MAIN
2940#define NAME__MAIN "__main"
2941#define SYMBOL__MAIN __main
2942#endif
203b91b9 2943
fe1fd353
JM
2944#ifdef INIT_SECTION_ASM_OP
2945#undef HAS_INIT_SECTION
2946#define HAS_INIT_SECTION
2947#endif
2948
2949#if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
31cf0144
JM
2950
2951/* Some ELF crosses use crtstuff.c to provide __CTOR_LIST__, but use this
2952 code to run constructors. In that case, we need to handle EH here, too. */
2953
2954#ifdef EH_FRAME_SECTION
2955#include "frame.h"
2956extern unsigned char __EH_FRAME_BEGIN__[];
2957#endif
2958
203b91b9
RS
2959/* Run all the global destructors on exit from the program. */
2960
2961void
3e7d8ef1 2962__do_global_dtors (void)
203b91b9 2963{
89cf554b
RS
2964#ifdef DO_GLOBAL_DTORS_BODY
2965 DO_GLOBAL_DTORS_BODY;
2966#else
b40b9d93
MS
2967 static func_ptr *p = __DTOR_LIST__ + 1;
2968 while (*p)
2969 {
2970 p++;
2971 (*(p-1)) ();
2972 }
89cf554b 2973#endif
bf279c4e 2974#if defined (EH_FRAME_SECTION) && !defined (HAS_INIT_SECTION)
a4ebb0e6
GRK
2975 {
2976 static int completed = 0;
2977 if (! completed)
2978 {
2979 completed = 1;
2980 __deregister_frame_info (__EH_FRAME_BEGIN__);
2981 }
2982 }
31cf0144 2983#endif
203b91b9 2984}
68d69835 2985#endif
203b91b9 2986
fe1fd353 2987#ifndef HAS_INIT_SECTION
203b91b9
RS
2988/* Run all the global constructors on entry to the program. */
2989
203b91b9 2990void
3e7d8ef1 2991__do_global_ctors (void)
203b91b9 2992{
31cf0144
JM
2993#ifdef EH_FRAME_SECTION
2994 {
2995 static struct object object;
2996 __register_frame_info (__EH_FRAME_BEGIN__, &object);
2997 }
2998#endif
203b91b9 2999 DO_GLOBAL_CTORS_BODY;
a218d5ba 3000 atexit (__do_global_dtors);
203b91b9 3001}
fe1fd353 3002#endif /* no HAS_INIT_SECTION */
203b91b9 3003
fe1fd353 3004#if !defined (HAS_INIT_SECTION) || defined (INVOKE__main)
203b91b9
RS
3005/* Subroutine called automatically by `main'.
3006 Compiling a global function named `main'
3007 produces an automatic call to this function at the beginning.
3008
3009 For many systems, this routine calls __do_global_ctors.
3010 For systems which support a .init section we use the .init section
3011 to run __do_global_ctors, so we need not do anything here. */
3012
3013void
c06cff95 3014SYMBOL__MAIN ()
203b91b9
RS
3015{
3016 /* Support recursive calls to `main': run initializers just once. */
7e6f1890 3017 static int initialized;
203b91b9
RS
3018 if (! initialized)
3019 {
3020 initialized = 1;
3021 __do_global_ctors ();
3022 }
3023}
fe1fd353 3024#endif /* no HAS_INIT_SECTION or INVOKE__main */
203b91b9
RS
3025
3026#endif /* L__main */
cae21ae8 3027#endif /* __CYGWIN__ */
203b91b9 3028\f
ad38743d 3029#ifdef L_ctors
203b91b9
RS
3030
3031#include "gbl-ctors.h"
3032
3033/* Provide default definitions for the lists of constructors and
657be7af
JL
3034 destructors, so that we don't get linker errors. These symbols are
3035 intentionally bss symbols, so that gld and/or collect will provide
3036 the right values. */
203b91b9
RS
3037
3038/* We declare the lists here with two elements each,
657be7af
JL
3039 so that they are valid empty lists if no other definition is loaded.
3040
3041 If we are using the old "set" extensions to have the gnu linker
3042 collect ctors and dtors, then we __CTOR_LIST__ and __DTOR_LIST__
3043 must be in the bss/common section.
3044
3045 Long term no port should use those extensions. But many still do. */
b335c2cc 3046#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
657be7af 3047#if defined (ASM_OUTPUT_CONSTRUCTOR) || defined (USE_COLLECT2)
d15d0264
RS
3048func_ptr __CTOR_LIST__[2] = {0, 0};
3049func_ptr __DTOR_LIST__[2] = {0, 0};
657be7af
JL
3050#else
3051func_ptr __CTOR_LIST__[2];
3052func_ptr __DTOR_LIST__[2];
3053#endif
b335c2cc 3054#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
ad38743d
RS
3055#endif /* L_ctors */
3056\f
3057#ifdef L_exit
3058
3059#include "gbl-ctors.h"
203b91b9 3060
8b7677be 3061#ifdef NEED_ATEXIT
8b7677be 3062
f75e8946 3063#ifndef ON_EXIT
203b91b9 3064
8b7677be
RK
3065# include <errno.h>
3066
920b13cc 3067static func_ptr *atexit_chain = 0;
8b7677be
RK
3068static long atexit_chain_length = 0;
3069static volatile long last_atexit_chain_slot = -1;
3070
c063dc98
JM
3071int
3072atexit (func_ptr func)
8b7677be
RK
3073{
3074 if (++last_atexit_chain_slot == atexit_chain_length)
3075 {
3076 atexit_chain_length += 32;
3077 if (atexit_chain)
a25cea96
RK
3078 atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
3079 * sizeof (func_ptr));
8b7677be 3080 else
a25cea96
RK
3081 atexit_chain = (func_ptr *) malloc (atexit_chain_length
3082 * sizeof (func_ptr));
8b7677be
RK
3083 if (! atexit_chain)
3084 {
3085 atexit_chain_length = 0;
3086 last_atexit_chain_slot = -1;
3087 errno = ENOMEM;
3088 return (-1);
3089 }
3090 }
3091 atexit_chain[last_atexit_chain_slot] = func;
3092 return (0);
3093}
8b7677be 3094
3e7d8ef1
KG
3095extern void _cleanup (void);
3096extern void _exit (int) __attribute__ ((__noreturn__));
203b91b9
RS
3097
3098void
37ef1054 3099exit (int status)
203b91b9 3100{
8b7677be
RK
3101 if (atexit_chain)
3102 {
3103 for ( ; last_atexit_chain_slot-- >= 0; )
3104 {
3105 (*atexit_chain[last_atexit_chain_slot + 1]) ();
920b13cc 3106 atexit_chain[last_atexit_chain_slot + 1] = 0;
8b7677be
RK
3107 }
3108 free (atexit_chain);
920b13cc 3109 atexit_chain = 0;
8b7677be 3110 }
203b91b9
RS
3111#ifdef EXIT_BODY
3112 EXIT_BODY;
3113#else
3114 _cleanup ();
3115#endif
3116 _exit (status);
3117}
3118
f75e8946 3119#else /* ON_EXIT */
bceb30e7 3120
c063dc98
JM
3121/* Simple; we just need a wrapper for ON_EXIT. */
3122int
3123atexit (func_ptr func)
bceb30e7 3124{
c063dc98 3125 return ON_EXIT (func);
bceb30e7 3126}
c063dc98 3127
f75e8946 3128#endif /* ON_EXIT */
c063dc98 3129#endif /* NEED_ATEXIT */
203b91b9
RS
3130
3131#endif /* L_exit */
3132\f
ad912eec 3133#ifdef L_eh
6adb4e3a 3134
f24af81b 3135#include "gthr.h"
6adb4e3a 3136
154bba13 3137/* Shared exception handling support routines. */
6adb4e3a 3138
e976b8b2 3139void
3e7d8ef1 3140__default_terminate (void)
e976b8b2
MS
3141{
3142 abort ();
3143}
3144
8a1894ac 3145static __terminate_func_ptr __terminate_func =
3e7d8ef1 3146 __default_terminate;
e976b8b2 3147
1854631b 3148void __attribute__((__noreturn__))
3e7d8ef1 3149__terminate (void)
e976b8b2
MS
3150{
3151 (*__terminate_func)();
3152}
3153
8a1894ac
CD
3154__terminate_func_ptr
3155__terminate_set_func (__terminate_func_ptr newfunc)
3156{
3157 __terminate_func_ptr oldfunc = __terminate_func;
3158
3159 __terminate_func = newfunc;
3160 return (oldfunc);
3161}
3162
ca55abae
JM
3163void *
3164__throw_type_match (void *catch_type, void *throw_type, void *obj)
3165{
3166#if 0
3167 printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n",
3168 catch_type, throw_type);
3169#endif
3170 if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
3171 return obj;
3172 return 0;
3173}
3174
3175void
3e7d8ef1 3176__empty (void)
ca55abae
JM
3177{
3178}
3179\f
154bba13 3180
9a0d1e1b
AM
3181/* Include definitions of EH context and table layout */
3182
3183#include "eh-common.h"
43566944 3184#ifndef inhibit_libc
7ac2148b 3185#include <stdio.h>
43566944 3186#endif
154bba13 3187
154bba13
TT
3188/* Allocate and return a new EH context structure. */
3189
3e7d8ef1 3190#if __GTHREADS
154bba13 3191static void *
3e7d8ef1 3192new_eh_context (void)
154bba13 3193{
d0b9a143
MS
3194 struct eh_full_context {
3195 struct eh_context c;
3196 void *top_elt[2];
3197 } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
3198
3199 if (! ehfc)
154bba13
TT
3200 __terminate ();
3201
d0b9a143 3202 memset (ehfc, 0, sizeof *ehfc);
154bba13 3203
d0b9a143 3204 ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt;
154bba13 3205
d0b9a143
MS
3206 /* This should optimize out entirely. This should always be true,
3207 but just in case it ever isn't, don't allow bogus code to be
3208 generated. */
3209
3210 if ((void*)(&ehfc->c) != (void*)ehfc)
3211 __terminate ();
3212
3213 return &ehfc->c;
154bba13
TT
3214}
3215
154bba13
TT
3216static __gthread_key_t eh_context_key;
3217
3218/* Destructor for struct eh_context. */
3219static void
3220eh_context_free (void *ptr)
3221{
f24af81b 3222 __gthread_key_dtor (eh_context_key, ptr);
154bba13
TT
3223 if (ptr)
3224 free (ptr);
3225}
3226#endif
3227
3228/* Pointer to function to return EH context. */
3229
3e7d8ef1
KG
3230static struct eh_context *eh_context_initialize (void);
3231static struct eh_context *eh_context_static (void);
154bba13 3232#if __GTHREADS
3e7d8ef1 3233static struct eh_context *eh_context_specific (void);
154bba13
TT
3234#endif
3235
3e7d8ef1 3236static struct eh_context *(*get_eh_context) (void) = &eh_context_initialize;
154bba13
TT
3237
3238/* Routine to get EH context.
3239 This one will simply call the function pointer. */
3240
3241void *
3e7d8ef1 3242__get_eh_context (void)
154bba13
TT
3243{
3244 return (void *) (*get_eh_context) ();
3245}
3246
3247/* Get and set the language specific info pointer. */
3248
3249void **
3e7d8ef1 3250__get_eh_info (void)
154bba13
TT
3251{
3252 struct eh_context *eh = (*get_eh_context) ();
0776059e 3253 return &eh->info;
154bba13
TT
3254}
3255\f
d9d5c9de
BS
3256#ifdef DWARF2_UNWIND_INFO
3257static int dwarf_reg_size_table_initialized = 0;
7e259f25 3258static char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
d9d5c9de
BS
3259
3260static void
3e7d8ef1 3261init_reg_size_table (void)
d9d5c9de
BS
3262{
3263 __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
3264 dwarf_reg_size_table_initialized = 1;
3265}
3266#endif
3267
154bba13
TT
3268#if __GTHREADS
3269static void
3e7d8ef1 3270eh_threads_initialize (void)
154bba13
TT
3271{
3272 /* Try to create the key. If it fails, revert to static method,
3273 otherwise start using thread specific EH contexts. */
3274 if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0)
3275 get_eh_context = &eh_context_specific;
3276 else
3277 get_eh_context = &eh_context_static;
3278}
3279#endif /* no __GTHREADS */
3280
3281/* Initialize EH context.
3282 This will be called only once, since we change GET_EH_CONTEXT
3283 pointer to another routine. */
3284
3285static struct eh_context *
3e7d8ef1 3286eh_context_initialize (void)
154bba13
TT
3287{
3288#if __GTHREADS
3289
3290 static __gthread_once_t once = __GTHREAD_ONCE_INIT;
754d1a92
TT
3291 /* Make sure that get_eh_context does not point to us anymore.
3292 Some systems have dummy thread routines in their libc that
3293 return a success (Solaris 2.6 for example). */
3294 if (__gthread_once (&once, eh_threads_initialize) != 0
3295 || get_eh_context == &eh_context_initialize)
f24af81b
TT
3296 {
3297 /* Use static version of EH context. */
3298 get_eh_context = &eh_context_static;
3299 }
d9d5c9de
BS
3300#ifdef DWARF2_UNWIND_INFO
3301 {
3302 static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
3303 if (__gthread_once (&once_regsizes, init_reg_size_table) != 0
3304 || ! dwarf_reg_size_table_initialized)
3305 init_reg_size_table ();
3306 }
3307#endif
154bba13
TT
3308
3309#else /* no __GTHREADS */
3310
3311 /* Use static version of EH context. */
3312 get_eh_context = &eh_context_static;
3313
d9d5c9de
BS
3314#ifdef DWARF2_UNWIND_INFO
3315 init_reg_size_table ();
3316#endif
3317
154bba13
TT
3318#endif /* no __GTHREADS */
3319
3320 return (*get_eh_context) ();
3321}
3322
3323/* Return a static EH context. */
3324
3325static struct eh_context *
3e7d8ef1 3326eh_context_static (void)
154bba13 3327{
c3cad221
JL
3328 static struct eh_context eh;
3329 static int initialized;
d0b9a143
MS
3330 static void *top_elt[2];
3331
c3cad221
JL
3332 if (! initialized)
3333 {
3334 initialized = 1;
3335 memset (&eh, 0, sizeof eh);
3336 eh.dynamic_handler_chain = top_elt;
3337 }
3338 return &eh;
154bba13
TT
3339}
3340
3341#if __GTHREADS
3342/* Return a thread specific EH context. */
3343
3344static struct eh_context *
3e7d8ef1 3345eh_context_specific (void)
154bba13
TT
3346{
3347 struct eh_context *eh;
3348 eh = (struct eh_context *) __gthread_getspecific (eh_context_key);
3349 if (! eh)
3350 {
3351 eh = new_eh_context ();
3352 if (__gthread_setspecific (eh_context_key, (void *) eh) != 0)
3353 __terminate ();
3354 }
3355
3356 return eh;
3357}
7efe41a9 3358#endif /* __GTHREADS */
154bba13 3359\f
103c63ae
NS
3360/* Support routines for alloc/free during exception handling */
3361
3362/* __eh_alloc and __eh_free attempt allocation using malloc, but fall back to
3363 the small arena in the eh_context. This is needed because throwing an
3364 out-of-memory exception would fail otherwise. The emergency space is
3365 allocated in blocks of size EH_ALLOC_ALIGN, the
3366 minimum allocation being two blocks. A bitmask indicates which blocks
3367 have been allocated. To indicate the size of an allocation, the bit for
3368 the final block is not set. Hence each allocation is a run of 1s followed
3369 by a zero. */
3370void *
3371__eh_alloc (size_t size)
3372{
3373 void *p;
3374
3375 if (!size)
3376 abort();
3377 p = malloc (size);
3378 if (p == 0)
3379 {
3380 struct eh_context *eh = __get_eh_context ();
3381 unsigned blocks = (size + EH_ALLOC_ALIGN - 1) / EH_ALLOC_ALIGN;
3382 unsigned real_mask = eh->alloc_mask | (eh->alloc_mask << 1);
3383 unsigned our_mask;
3384 unsigned ix;
3385
3386 if (blocks > EH_ALLOC_SIZE / EH_ALLOC_ALIGN)
3387 __terminate ();
3388 blocks += blocks == 1;
3389 our_mask = (1 << blocks) - 1;
3390
3391 for (ix = EH_ALLOC_SIZE / EH_ALLOC_ALIGN - blocks; ix; ix--)
3392 if (! ((real_mask >> ix) & our_mask))
3393 {
3394 /* found some space */
3395 p = &eh->alloc_buffer[ix * EH_ALLOC_ALIGN];
3396 eh->alloc_mask |= (our_mask >> 1) << ix;
3397 return p;
3398 }
3399 __terminate ();
3400 }
3401 return p;
3402}
3403
3404/* Free the memory for an cp_eh_info and associated exception, given
3405 a pointer to the cp_eh_info. */
3406void
3407__eh_free (void *p)
3408{
3409 struct eh_context *eh = __get_eh_context ();
3410
3411 ptrdiff_t diff = (char *)p - &eh->alloc_buffer[0];
3412 if (diff >= 0 && diff < EH_ALLOC_SIZE)
3413 {
3414 unsigned mask = eh->alloc_mask;
3415 unsigned bit = 1 << (diff / EH_ALLOC_ALIGN);
3416
3417 do
3418 {
3419 mask ^= bit;
3420 bit <<= 1;
3421 }
3422 while (mask & bit);
3423 eh->alloc_mask = mask;
3424 }
3425 else
3426 free (p);
3427}
3428\f
ca55abae
JM
3429/* Support routines for setjmp/longjmp exception handling. */
3430
e976b8b2
MS
3431/* Calls to __sjthrow are generated by the compiler when an exception
3432 is raised when using the setjmp/longjmp exception handling codegen
3433 method. */
3434
154bba13 3435#ifdef DONT_USE_BUILTIN_SETJMP
6e6a07d2 3436extern void longjmp (void *, int);
154bba13 3437#endif
e976b8b2
MS
3438
3439/* Routine to get the head of the current thread's dynamic handler chain
154bba13 3440 use for exception handling. */
e976b8b2
MS
3441
3442void ***
3e7d8ef1 3443__get_dynamic_handler_chain (void)
e976b8b2 3444{
154bba13 3445 struct eh_context *eh = (*get_eh_context) ();
0776059e 3446 return &eh->dynamic_handler_chain;
e976b8b2
MS
3447}
3448
3449/* This is used to throw an exception when the setjmp/longjmp codegen
3450 method is used for exception handling.
3451
154bba13
TT
3452 We call __terminate if there are no handlers left. Otherwise we run the
3453 cleanup actions off the dynamic cleanup stack, and pop the top of the
3454 dynamic handler chain, and use longjmp to transfer back to the associated
3455 handler. */
e976b8b2
MS
3456
3457void
3e7d8ef1 3458__sjthrow (void)
e976b8b2 3459{
154bba13
TT
3460 struct eh_context *eh = (*get_eh_context) ();
3461 void ***dhc = &eh->dynamic_handler_chain;
e976b8b2
MS
3462 void *jmpbuf;
3463 void (*func)(void *, int);
3464 void *arg;
3e7d8ef1
KG
3465 /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
3466 void ***cleanup = (void***)&(*dhc)[1];
e976b8b2
MS
3467
3468 /* If there are any cleanups in the chain, run them now. */
3469 if (cleanup[0])
3470 {
3471 double store[200];
3472 void **buf = (void**)store;
3473 buf[1] = 0;
3474 buf[0] = (*dhc);
3475
3476 /* try { */
6e6a07d2 3477#ifdef DONT_USE_BUILTIN_SETJMP
e976b8b2 3478 if (! setjmp (&buf[2]))
6e6a07d2
MS
3479#else
3480 if (! __builtin_setjmp (&buf[2]))
3481#endif
e976b8b2
MS
3482 {
3483 *dhc = buf;
3484 while (cleanup[0])
3485 {
3486 func = (void(*)(void*, int))cleanup[0][1];
3487 arg = (void*)cleanup[0][2];
3488
3489 /* Update this before running the cleanup. */
3490 cleanup[0] = (void **)cleanup[0][0];
3491
3492 (*func)(arg, 2);
3493 }
3494 *dhc = buf[0];
3495 }
3496 /* catch (...) */
3497 else
3498 {
3499 __terminate ();
3500 }
3501 }
3502
3503 /* We must call terminate if we try and rethrow an exception, when
3504 there is no exception currently active and when there are no
3505 handlers left. */
d0b9a143 3506 if (! eh->info || (*dhc)[0] == 0)
e976b8b2
MS
3507 __terminate ();
3508
3509 /* Find the jmpbuf associated with the top element of the dynamic
3510 handler chain. The jumpbuf starts two words into the buffer. */
3511 jmpbuf = &(*dhc)[2];
3512
3513 /* Then we pop the top element off the dynamic handler chain. */
3514 *dhc = (void**)(*dhc)[0];
3515
3516 /* And then we jump to the handler. */
3517
6e6a07d2 3518#ifdef DONT_USE_BUILTIN_SETJMP
e976b8b2 3519 longjmp (jmpbuf, 1);
6e6a07d2
MS
3520#else
3521 __builtin_longjmp (jmpbuf, 1);
e976b8b2
MS
3522#endif
3523}
3524
3525/* Run cleanups on the dynamic cleanup stack for the current dynamic
3526 handler, then pop the handler off the dynamic handler stack, and
3527 then throw. This is used to skip the first handler, and transfer
3528 control to the next handler in the dynamic handler stack. */
3529
3530void
3e7d8ef1 3531__sjpopnthrow (void)
e976b8b2 3532{
154bba13
TT
3533 struct eh_context *eh = (*get_eh_context) ();
3534 void ***dhc = &eh->dynamic_handler_chain;
e976b8b2
MS
3535 void (*func)(void *, int);
3536 void *arg;
3e7d8ef1
KG
3537 /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
3538 void ***cleanup = (void***)&(*dhc)[1];
e976b8b2
MS
3539
3540 /* If there are any cleanups in the chain, run them now. */
3541 if (cleanup[0])
3542 {
3543 double store[200];
3544 void **buf = (void**)store;
3545 buf[1] = 0;
3546 buf[0] = (*dhc);
3547
3548 /* try { */
6e6a07d2 3549#ifdef DONT_USE_BUILTIN_SETJMP
e976b8b2 3550 if (! setjmp (&buf[2]))
6e6a07d2
MS
3551#else
3552 if (! __builtin_setjmp (&buf[2]))
3553#endif
e976b8b2
MS
3554 {
3555 *dhc = buf;
3556 while (cleanup[0])
3557 {
3558 func = (void(*)(void*, int))cleanup[0][1];
3559 arg = (void*)cleanup[0][2];
3560
3561 /* Update this before running the cleanup. */
3562 cleanup[0] = (void **)cleanup[0][0];
3563
3564 (*func)(arg, 2);
3565 }
3566 *dhc = buf[0];
3567 }
3568 /* catch (...) */
3569 else
3570 {
3571 __terminate ();
3572 }
3573 }
3574
3575 /* Then we pop the top element off the dynamic handler chain. */
3576 *dhc = (void**)(*dhc)[0];
3577
3578 __sjthrow ();
3579}
ca55abae
JM
3580\f
3581/* Support code for all exception region-based exception handling. */
3582
bf71cd2e
AM
3583int
3584__eh_rtime_match (void *rtime)
3585{
3586 void *info;
3587 __eh_matcher matcher;
3588 void *ret;
3589
3590 info = *(__get_eh_info ());
3591 matcher = ((__eh_info *)info)->match_function;
7ac2148b
AM
3592 if (! matcher)
3593 {
43566944 3594#ifndef inhibit_libc
7ac2148b 3595 fprintf (stderr, "Internal Compiler Bug: No runtime type matcher.");
43566944 3596#endif
7ac2148b
AM
3597 return 0;
3598 }
bf71cd2e 3599 ret = (*matcher) (info, rtime, (void *)0);
7ac2148b 3600 return (ret != NULL);
bf71cd2e
AM
3601}
3602
ca55abae
JM
3603/* This value identifies the place from which an exception is being
3604 thrown. */
3605
ca55abae
JM
3606#ifdef EH_TABLE_LOOKUP
3607
3608EH_TABLE_LOOKUP
e976b8b2 3609
ca55abae
JM
3610#else
3611
d6f4ec51 3612#ifdef DWARF2_UNWIND_INFO
ad912eec 3613
48b24bcd
AM
3614/* Return the table version of an exception descriptor */
3615
3616short
3617__get_eh_table_version (exception_descriptor *table)
3618{
3619 return table->lang.version;
3620}
3621
3622/* Return the originating table language of an exception descriptor */
3623
3624short
3625__get_eh_table_language (exception_descriptor *table)
3626{
3627 return table->lang.language;
3628}
3629
ca55abae
JM
3630/* This routine takes a PC and a pointer to the exception region TABLE for
3631 its translation unit, and returns the address of the exception handler
3632 associated with the closest exception table handler entry associated
3633 with that PC, or 0 if there are no table entries the PC fits in.
3634
3635 In the advent of a tie, we have to give the last entry, as it represents
3636 an inner block. */
3637
a1622f83
AM
3638static void *
3639old_find_exception_handler (void *pc, old_exception_table *table)
3640{
3641 if (table)
3642 {
3643 int pos;
3644 int best = -1;
3645
3646 /* We can't do a binary search because the table isn't guaranteed
3647 to be sorted from function to function. */
3648 for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
3649 {
3650 if (table[pos].start_region <= pc && table[pos].end_region > pc)
3651 {
3652 /* This can apply. Make sure it is at least as small as
3653 the previous best. */
3654 if (best == -1 || (table[pos].end_region <= table[best].end_region
3655 && table[pos].start_region >= table[best].start_region))
3656 best = pos;
3657 }
3658 /* But it is sorted by starting PC within a function. */
3659 else if (best >= 0 && table[pos].start_region > pc)
3660 break;
3661 }
3662 if (best != -1)
3663 return table[best].exception_handler;
3664 }
3665
3666 return (void *) 0;
3667}
3668
e6cfb550
AM
3669/* find_exception_handler finds the correct handler, if there is one, to
3670 handle an exception.
3671 returns a pointer to the handler which controlled should be transferred
3672 to, or NULL if there is nothing left.
3673 Parameters:
3674 PC - pc where the exception originates. If this is a rethrow,
3675 then this starts out as a pointer to the exception table
3676 entry we wish to rethrow out of.
3677 TABLE - exception table for the current module.
3678 EH_INFO - eh info pointer for this exception.
3679 RETHROW - 1 if this is a rethrow. (see incoming value of PC).
3680 CLEANUP - returned flag indicating whether this is a cleanup handler.
3681*/
ca55abae 3682static void *
e6cfb550
AM
3683find_exception_handler (void *pc, exception_descriptor *table,
3684 __eh_info *eh_info, int rethrow, int *cleanup)
ca55abae 3685{
e6cfb550
AM
3686
3687 void *retval = NULL;
3688 *cleanup = 1;
ca55abae
JM
3689 if (table)
3690 {
e6cfb550 3691 int pos = 0;
9a0d1e1b
AM
3692 /* The new model assumed the table is sorted inner-most out so the
3693 first region we find which matches is the correct one */
3694
9a0d1e1b
AM
3695 exception_table *tab = &(table->table[0]);
3696
3697 /* Subtract 1 from the PC to avoid hitting the next region */
e6cfb550
AM
3698 if (rethrow)
3699 {
3700 /* pc is actually the region table entry to rethrow out of */
3701 pos = ((exception_table *) pc) - tab;
3702 pc = ((exception_table *) pc)->end_region - 1;
3703
3704 /* The label is always on the LAST handler entry for a region,
3705 so we know the next entry is a different region, even if the
3706 addresses are the same. Make sure its not end of table tho. */
3707 if (tab[pos].start_region != (void *) -1)
3708 pos++;
3709 }
3710 else
3711 pc--;
9a0d1e1b
AM
3712
3713 /* We can't do a binary search because the table is in inner-most
3714 to outermost address ranges within functions */
e6cfb550 3715 for ( ; tab[pos].start_region != (void *) -1; pos++)
9a0d1e1b
AM
3716 {
3717 if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
3718 {
3719 if (tab[pos].match_info)
3720 {
e6cfb550 3721 __eh_matcher matcher = eh_info->match_function;
9a0d1e1b
AM
3722 /* match info but no matcher is NOT a match */
3723 if (matcher)
3724 {
e6cfb550
AM
3725 void *ret = (*matcher)((void *) eh_info,
3726 tab[pos].match_info, table);
3727 if (ret)
3728 {
3729 if (retval == NULL)
3730 retval = tab[pos].exception_handler;
3731 *cleanup = 0;
3732 break;
3733 }
9a0d1e1b
AM
3734 }
3735 }
3736 else
e6cfb550
AM
3737 {
3738 if (retval == NULL)
3739 retval = tab[pos].exception_handler;
3740 }
9a0d1e1b
AM
3741 }
3742 }
ca55abae 3743 }
e6cfb550 3744 return retval;
ca55abae 3745}
d6f4ec51 3746#endif /* DWARF2_UNWIND_INFO */
ca55abae
JM
3747#endif /* EH_TABLE_LOOKUP */
3748\f
0776059e 3749#ifdef DWARF2_UNWIND_INFO
ca55abae
JM
3750/* Support code for exception handling using static unwind information. */
3751
3752#include "frame.h"
3753
3754/* This type is used in get_reg and put_reg to deal with ABIs where a void*
3755 is smaller than a word, such as the Irix 6 n32 ABI. We cast twice to
3756 avoid a warning about casting between int and pointer of different
3757 sizes. */
3758
3759typedef int ptr_type __attribute__ ((mode (pointer)));
3760
44f715c8
AH
3761typedef struct
3762{
3763 word_type *reg[DWARF_FRAME_REGISTERS];
3764} saved_regs_t;
3765
71038426
RH
3766#ifdef INCOMING_REGNO
3767/* Is the saved value for register REG in frame UDATA stored in a register
3768 window in the previous frame? */
3769
3770/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT. This allows us
3771 to use the macro here. One wonders, though, that perhaps TARGET_FLAT
3772 compiled functions won't work with the frame-unwind stuff here.
3773 Perhaps the entireity of in_reg_window should be conditional on having
3774 seen a DW_CFA_GNU_window_save? */
3775#define target_flags 0
3776
3777static int
3778in_reg_window (int reg, frame_state *udata)
3779{
3780 if (udata->saved[reg] == REG_SAVED_REG)
3781 return INCOMING_REGNO (reg) == reg;
3782 if (udata->saved[reg] != REG_SAVED_OFFSET)
3783 return 0;
3784
3785#ifdef STACK_GROWS_DOWNWARD
3786 return udata->reg_or_offset[reg] > 0;
3787#else
3788 return udata->reg_or_offset[reg] < 0;
3789#endif
3790}
3791#else
3e7d8ef1
KG
3792static inline int
3793in_reg_window (int reg __attribute__ ((__unused__)),
3794 frame_state *udata __attribute__ ((__unused__)))
3795{
3796 return 0;
3797}
71038426
RH
3798#endif /* INCOMING_REGNO */
3799
3800/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
ca55abae
JM
3801 frame called by UDATA or 0. */
3802
71038426
RH
3803static word_type *
3804get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
ca55abae 3805{
71038426
RH
3806 while (udata->saved[reg] == REG_SAVED_REG)
3807 {
3808 reg = udata->reg_or_offset[reg];
3809 if (in_reg_window (reg, udata))
3810 {
3811 udata = sub_udata;
3812 sub_udata = NULL;
3813 }
3814 }
ca55abae 3815 if (udata->saved[reg] == REG_SAVED_OFFSET)
71038426 3816 return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
ca55abae 3817 else
44f715c8
AH
3818 /* We don't have a saved copy of this register. */
3819 return NULL;
ca55abae
JM
3820}
3821
71038426
RH
3822/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
3823 frame called by UDATA or 0. */
3824
3825static inline void *
3826get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
3827{
3828 return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata);
3829}
3830
ca55abae
JM
3831/* Overwrite the saved value for register REG in frame UDATA with VAL. */
3832
71038426 3833static inline void
ca55abae
JM
3834put_reg (unsigned reg, void *val, frame_state *udata)
3835{
71038426 3836 *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
ca55abae
JM
3837}
3838
44f715c8 3839/* Copy the saved value for register REG from PTREG to frame
2f3ca9e7
JM
3840 TARGET_UDATA. Unlike the previous two functions, this can handle
3841 registers that are not one word large. */
3842
3843static void
44f715c8 3844copy_reg (unsigned reg, word_type *preg, frame_state *target_udata)
2f3ca9e7 3845{
71038426 3846 word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
d9d5c9de 3847 memcpy (ptreg, preg, dwarf_reg_size_table [reg]);
2f3ca9e7
JM
3848}
3849
71038426 3850/* Retrieve the return address for frame UDATA. */
ca55abae
JM
3851
3852static inline void *
3853get_return_addr (frame_state *udata, frame_state *sub_udata)
3854{
3855 return __builtin_extract_return_addr
3856 (get_reg (udata->retaddr_column, udata, sub_udata));
3857}
3858
3859/* Overwrite the return address for frame UDATA with VAL. */
3860
3861static inline void
3862put_return_addr (void *val, frame_state *udata)
3863{
3864 val = __builtin_frob_return_addr (val);
3865 put_reg (udata->retaddr_column, val, udata);
3866}
3867
3868/* Given the current frame UDATA and its return address PC, return the
44f715c8
AH
3869 information about the calling frame in CALLER_UDATA and update the
3870 register array in SAVED_REGS. */
ca55abae
JM
3871
3872static void *
44f715c8
AH
3873next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata,
3874 saved_regs_t *saved_regs)
ca55abae 3875{
44f715c8
AH
3876 int i;
3877 word_type *p;
3878
3879 /* Collect all of the registers for the current frame. */
3880 for (i = 0; i < DWARF_FRAME_REGISTERS; i++)
3881 if (udata->saved[i])
3882 saved_regs->reg[i] = get_reg_addr (i, udata, caller_udata);
3883
ca55abae
JM
3884 caller_udata = __frame_state_for (pc, caller_udata);
3885 if (! caller_udata)
3886 return 0;
3887
44f715c8
AH
3888 /* Now go back to our caller's stack frame. If our caller's CFA was
3889 saved in a register in this stack frame or a previous one,
3890 restore it; otherwise, assume CFA register was saved in SP and
3891 restore it to our CFA value. */
3892
3893 p = saved_regs->reg[caller_udata->cfa_reg];
3894 if (p)
3895 caller_udata->cfa = (void *)(ptr_type)*p;
ca55abae
JM
3896 else
3897 caller_udata->cfa = udata->cfa;
44f715c8 3898
7d9d8943 3899 if (caller_udata->indirect)
14e7eabd
NC
3900 caller_udata->cfa = * (void **) ((unsigned char *)caller_udata->cfa
3901 + caller_udata->base_offset);
ca55abae
JM
3902 caller_udata->cfa += caller_udata->cfa_offset;
3903
3904 return caller_udata;
3905}
3906
e6cfb550
AM
3907/* Hook to call before __terminate if only cleanup handlers remain. */
3908void
3e7d8ef1 3909__unwinding_cleanup (void)
ca55abae 3910{
e6cfb550 3911}
ca55abae 3912
e6cfb550
AM
3913/* throw_helper performs some of the common grunt work for a throw. This
3914 routine is called by throw and rethrows. This is pretty much split
3915 out from the old __throw routine. An addition has been added which allows
3916 for a dummy call to a routine __unwinding_cleanup() when there are nothing
3917 but cleanups remaining. This allows a debugger to examine the state
3918 at which the throw was executed, before any cleanups, rather than
51980de6
JM
3919 at the terminate point after the stack has been unwound.
3920
3921 EH is the current eh_context structure.
3922 PC is the address of the call to __throw.
3923 MY_UDATA is the unwind information for __throw.
3924 OFFSET_P is where we return the SP adjustment offset. */
ca55abae 3925
e6cfb550 3926static void *
3e7d8ef1
KG
3927throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata,
3928 long *offset_p)
e6cfb550 3929{
51980de6 3930 frame_state ustruct2, *udata = &ustruct2;
e6cfb550
AM
3931 frame_state ustruct;
3932 frame_state *sub_udata = &ustruct;
3933 void *saved_pc = pc;
3934 void *handler;
3e7d8ef1
KG
3935 void *handler_p = 0;
3936 void *pc_p = 0;
44f715c8 3937 void *callee_cfa = 0;
e6cfb550
AM
3938 frame_state saved_ustruct;
3939 int new_eh_model;
3940 int cleanup = 0;
3941 int only_cleanup = 0;
3942 int rethrow = 0;
3943 int saved_state = 0;
51980de6 3944 long args_size;
44f715c8 3945 saved_regs_t saved_regs, cleanup_regs;
e6cfb550 3946 __eh_info *eh_info = (__eh_info *)eh->info;
44f715c8
AH
3947 int i;
3948
3949 memset (saved_regs.reg, 0, sizeof saved_regs.reg);
3950 memset (sub_udata->saved, REG_UNSAVED, sizeof sub_udata->saved);
e6cfb550
AM
3951
3952 /* Do we find a handler based on a re-throw PC? */
3953 if (eh->table_index != (void *) 0)
3954 rethrow = 1;
3955
51980de6
JM
3956 memcpy (udata, my_udata, sizeof (*udata));
3957
e6cfb550 3958 handler = (void *) 0;
ca55abae
JM
3959 for (;;)
3960 {
3961 frame_state *p = udata;
44f715c8
AH
3962
3963 udata = next_stack_level (pc, udata, sub_udata, &saved_regs);
ca55abae
JM
3964 sub_udata = p;
3965
3966 /* If we couldn't find the next frame, we lose. */
3967 if (! udata)
3968 break;
3969
a1622f83 3970 if (udata->eh_ptr == NULL)
e6cfb550 3971 new_eh_model = 0;
a1622f83 3972 else
e6cfb550 3973 new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
44f715c8 3974 runtime_id_field == NEW_EH_RUNTIME);
a1622f83 3975
e6cfb550
AM
3976 if (rethrow)
3977 {
3978 rethrow = 0;
3979 handler = find_exception_handler (eh->table_index, udata->eh_ptr,
44f715c8 3980 eh_info, 1, &cleanup);
e6cfb550
AM
3981 eh->table_index = (void *)0;
3982 }
a1622f83 3983 else
e6cfb550
AM
3984 if (new_eh_model)
3985 handler = find_exception_handler (pc, udata->eh_ptr, eh_info,
3986 0, &cleanup);
3987 else
3988 handler = old_find_exception_handler (pc, udata->eh_ptr);
3989
3990 /* If we found one, we can stop searching, if its not a cleanup.
3991 for cleanups, we save the state, and keep looking. This allows
3992 us to call a debug hook if there are nothing but cleanups left. */
ca55abae 3993 if (handler)
1b528097 3994 {
44f715c8
AH
3995 /* sub_udata now refers to the frame called by the handler frame. */
3996
1b528097
JM
3997 if (cleanup)
3998 {
3999 if (!saved_state)
4000 {
4001 saved_ustruct = *udata;
44f715c8 4002 cleanup_regs = saved_regs;
1b528097
JM
4003 handler_p = handler;
4004 pc_p = pc;
4005 saved_state = 1;
4006 only_cleanup = 1;
44f715c8
AH
4007 /* Save the CFA of the frame called by the handler
4008 frame. */
4009 callee_cfa = sub_udata->cfa;
1b528097
JM
4010 }
4011 }
4012 else
4013 {
4014 only_cleanup = 0;
44f715c8
AH
4015 if (!saved_state)
4016 callee_cfa = sub_udata->cfa;
1b528097
JM
4017 break;
4018 }
4019 }
ca55abae 4020
6020d360
JM
4021 /* Otherwise, we continue searching. We subtract 1 from PC to avoid
4022 hitting the beginning of the next region. */
4023 pc = get_return_addr (udata, sub_udata) - 1;
ca55abae
JM
4024 }
4025
e6cfb550
AM
4026 if (saved_state)
4027 {
4028 udata = &saved_ustruct;
44f715c8 4029 saved_regs = cleanup_regs;
e6cfb550
AM
4030 handler = handler_p;
4031 pc = pc_p;
4032 if (only_cleanup)
4033 __unwinding_cleanup ();
4034 }
4035
ca55abae
JM
4036 /* If we haven't found a handler by now, this is an unhandled
4037 exception. */
e6cfb550
AM
4038 if (! handler)
4039 __terminate();
ca55abae 4040
9a0d1e1b 4041 eh->handler_label = handler;
9a0d1e1b 4042
51980de6
JM
4043 args_size = udata->args_size;
4044
51980de6
JM
4045 /* We adjust SP by the difference between __throw's CFA and the CFA for
4046 the frame called by the handler frame, because those CFAs correspond
4047 to the SP values at the two call sites. We need to further adjust by
4048 the args_size of the handler frame itself to get the handler frame's
4049 SP from before the args were pushed for that call. */
4050#ifdef STACK_GROWS_DOWNWARD
44f715c8 4051 *offset_p = callee_cfa - my_udata->cfa + args_size;
51980de6 4052#else
44f715c8 4053 *offset_p = my_udata->cfa - callee_cfa - args_size;
51980de6
JM
4054#endif
4055
44f715c8
AH
4056 /* If we found a handler in the throw context there's no need to
4057 unwind. */
4058 if (pc != saved_pc)
4059 {
4060 /* Copy saved register values into our register save slots. */
4061 for (i = 0; i < DWARF_FRAME_REGISTERS; i++)
4062 if (i != udata->retaddr_column && saved_regs.reg[i])
4063 copy_reg (i, saved_regs.reg[i], my_udata);
4064 }
4065
e6cfb550
AM
4066 return handler;
4067}
4068
4069
4070/* We first search for an exception handler, and if we don't find
4071 it, we call __terminate on the current stack frame so that we may
4072 use the debugger to walk the stack and understand why no handler
4073 was found.
4074
4075 If we find one, then we unwind the frames down to the one that
4076 has the handler and transfer control into the handler. */
4077
4078/*extern void __throw(void) __attribute__ ((__noreturn__));*/
4079
4080void
3e7d8ef1 4081__throw (void)
e6cfb550
AM
4082{
4083 struct eh_context *eh = (*get_eh_context) ();
4084 void *pc, *handler;
51980de6
JM
4085 long offset;
4086
4087 /* XXX maybe make my_ustruct static so we don't have to look it up for
4088 each throw. */
e6cfb550
AM
4089 frame_state my_ustruct, *my_udata = &my_ustruct;
4090
4091 /* This is required for C++ semantics. We must call terminate if we
4092 try and rethrow an exception, when there is no exception currently
4093 active. */
4094 if (! eh->info)
4095 __terminate ();
4096
4097 /* Start at our stack frame. */
4098label:
51980de6
JM
4099 my_udata = __frame_state_for (&&label, my_udata);
4100 if (! my_udata)
e6cfb550
AM
4101 __terminate ();
4102
4103 /* We need to get the value from the CFA register. */
51980de6 4104 my_udata->cfa = __builtin_dwarf_cfa ();
e6cfb550
AM
4105
4106 /* Do any necessary initialization to access arbitrary stack frames.
4107 On the SPARC, this means flushing the register windows. */
4108 __builtin_unwind_init ();
4109
4110 /* Now reset pc to the right throw point. */
4111 pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
4112
51980de6 4113 handler = throw_helper (eh, pc, my_udata, &offset);
e6cfb550
AM
4114
4115 /* Now go! */
4116
51980de6 4117 __builtin_eh_return ((void *)eh, offset, handler);
e6cfb550
AM
4118
4119 /* Epilogue: restore the handler frame's register values and return
4120 to the stub. */
4121}
4122
4123/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
4124
4125void
3e7d8ef1 4126__rethrow (void *index)
e6cfb550
AM
4127{
4128 struct eh_context *eh = (*get_eh_context) ();
4129 void *pc, *handler;
51980de6
JM
4130 long offset;
4131
4132 /* XXX maybe make my_ustruct static so we don't have to look it up for
4133 each throw. */
e6cfb550
AM
4134 frame_state my_ustruct, *my_udata = &my_ustruct;
4135
4136 /* This is required for C++ semantics. We must call terminate if we
4137 try and rethrow an exception, when there is no exception currently
4138 active. */
4139 if (! eh->info)
4140 __terminate ();
4141
4142 /* This is the table index we want to rethrow from. The value of
4143 the END_REGION label is used for the PC of the throw, and the
4144 search begins with the next table entry. */
4145 eh->table_index = index;
4146
4147 /* Start at our stack frame. */
4148label:
51980de6
JM
4149 my_udata = __frame_state_for (&&label, my_udata);
4150 if (! my_udata)
e6cfb550
AM
4151 __terminate ();
4152
4153 /* We need to get the value from the CFA register. */
51980de6 4154 my_udata->cfa = __builtin_dwarf_cfa ();
e6cfb550
AM
4155
4156 /* Do any necessary initialization to access arbitrary stack frames.
4157 On the SPARC, this means flushing the register windows. */
4158 __builtin_unwind_init ();
4159
4160 /* Now reset pc to the right throw point. */
4161 pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
4162
51980de6 4163 handler = throw_helper (eh, pc, my_udata, &offset);
ca55abae 4164
71038426 4165 /* Now go! */
9a0d1e1b 4166
51980de6 4167 __builtin_eh_return ((void *)eh, offset, handler);
ca55abae
JM
4168
4169 /* Epilogue: restore the handler frame's register values and return
4170 to the stub. */
4171}
0776059e 4172#endif /* DWARF2_UNWIND_INFO */
ca55abae 4173
ce152ef8
AM
4174#ifdef IA64_UNWIND_INFO
4175#include "frame.h"
4176
4177/* Return handler to which we want to transfer control, NULL if we don't
4178 intend to handle this exception here. */
4179void *
4180__ia64_personality_v1 (void *pc, old_exception_table *table)
4181{
4182 if (table)
4183 {
4184 int pos;
4185 int best = -1;
4186
4187 for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
4188 {
4189 if (table[pos].start_region <= pc && table[pos].end_region > pc)
4190 {
4191 /* This can apply. Make sure it is at least as small as
4192 the previous best. */
4193 if (best == -1 || (table[pos].end_region <= table[best].end_region
4194 && table[pos].start_region >= table[best].start_region))
4195 best = pos;
4196 }
4197 /* It is sorted by starting PC within a function. */
4198 else if (best >= 0 && table[pos].start_region > pc)
4199 break;
4200 }
4201 if (best != -1)
4202 return table[best].exception_handler;
4203 }
4204 return (void *) 0;
4205}
4206
4207static void
db2e2f48
RH
4208ia64_throw_helper (ia64_frame_state *throw_frame, ia64_frame_state *caller,
4209 void *throw_bsp, void *throw_sp)
ce152ef8 4210{
46327bc5 4211 void *throw_pc = __builtin_return_address (0);
ce152ef8
AM
4212 unwind_info_ptr *info;
4213 void *pc, *handler = NULL;
4214 void *pc_base;
4215 int frame_count;
4216 void *bsp;
4217
4218 __builtin_ia64_flushrs (); /* Make the local register stacks available. */
4219
4220 /* Start at our stack frame, get our state. */
db2e2f48
RH
4221 __build_ia64_frame_state (throw_pc, throw_frame, throw_bsp, throw_sp,
4222 &pc_base);
ce152ef8
AM
4223
4224 /* Now we have to find the proper frame for pc, and see if there
4225 is a handler for it. if not, we keep going back frames until
4226 we do find one. Otherwise we call uncaught (). */
4227
4228 frame_count = 0;
4229 memcpy (caller, throw_frame, sizeof (*caller));
4230 while (!handler)
4231 {
0024a804 4232 void *(*personality) (void *, old_exception_table *);
ce152ef8
AM
4233 void *eh_table;
4234
4235 frame_count++;
4236 /* We only care about the RP right now, so we dont need to keep
4237 any other information about a call frame right now. */
4238 pc = __get_real_reg_value (&caller->rp) - 1;
db2e2f48
RH
4239 bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs),
4240 caller->my_bsp);
4241 info = __build_ia64_frame_state (pc, caller, bsp, caller->my_psp,
4242 &pc_base);
ce152ef8
AM
4243
4244 /* If we couldn't find the next frame, we lose. */
4245 if (! info)
4246 break;
4247
4248 personality = __get_personality (info);
4249 /* TODO Haven't figured out how to actually load the personality address
4250 yet, so just always default to the one we expect for now. */
4251 if (personality != 0)
4252 personality = __ia64_personality_v1;
4253 eh_table = __get_except_table (info);
4254 /* If there is no personality routine, we'll keep unwinding. */
4255 if (personality)
4256 /* Pass a segment relative PC address to the personality routine,
4257 because the unwind_info section uses segrel relocs. */
0024a804 4258 handler = personality ((void *)(pc - pc_base), eh_table);
ce152ef8
AM
4259 }
4260
4261 if (!handler)
db2e2f48 4262 __terminate ();
ce152ef8
AM
4263
4264 /* Handler is a segment relative address, so we must adjust it here. */
4265 handler += (long) pc_base;
4266
4267 /* If we found a handler, we need to unwind the stack to that point.
4268 We do this by copying saved values from previous frames into the
4269 save slot for the throw_frame saved slots. when __throw returns,
4270 it'll pickup the correct values. */
4271
4272 /* Start with where __throw saved things, and copy each saved register
4273 of each previous frame until we get to the one before we're
4274 throwing back to. */
4275 memcpy (caller, throw_frame, sizeof (*caller));
4276 for ( ; frame_count > 0; frame_count--)
4277 {
4278 pc = __get_real_reg_value (&caller->rp) - 1;
db2e2f48
RH
4279 bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs),
4280 caller->my_bsp);
4281 __build_ia64_frame_state (pc, caller, bsp, caller->my_psp, &pc_base);
ce152ef8
AM
4282 /* Any regs that were saved can be put in the throw frame now. */
4283 /* We don't want to copy any saved register from the
4284 target destination, but we do want to load up it's frame. */
4285 if (frame_count > 1)
4286 __copy_saved_reg_state (throw_frame, caller);
4287 }
4288
4289 /* Set return address of the throw frame to the handler. */
4290 __set_real_reg_value (&throw_frame->rp, handler);
4291
4292 /* TODO, do we need to do anything to make the values we wrote 'stick'? */
4293 /* DO we need to go through the whole loadrs seqeunce? */
ce152ef8
AM
4294}
4295
db2e2f48 4296
ce152ef8
AM
4297void
4298__throw ()
4299{
db2e2f48 4300 register void *stack_pointer __asm__("r12");
ce152ef8
AM
4301 struct eh_context *eh = (*get_eh_context) ();
4302 ia64_frame_state my_frame;
4303 ia64_frame_state originator; /* For the context handler is in. */
4304 void *bsp, *tmp_bsp;
4305 long offset;
4306
4307 /* This is required for C++ semantics. We must call terminate if we
4308 try and rethrow an exception, when there is no exception currently
4309 active. */
4310 if (! eh->info)
4311 __terminate ();
4312
4313 __builtin_unwind_init ();
db2e2f48 4314
ce152ef8
AM
4315 /* We have to call another routine to actually process the frame
4316 information, which will force all of __throw's local registers into
4317 backing store. */
4318
4319 /* Get the value of ar.bsp while we're here. */
4320
4321 bsp = __builtin_ia64_bsp ();
db2e2f48 4322 ia64_throw_helper (&my_frame, &originator, bsp, stack_pointer);
ce152ef8
AM
4323
4324 /* Now we have to fudge the bsp by the amount in our (__throw)
4325 frame marker, since the return is going to adjust it by that much. */
4326
4327 tmp_bsp = __calc_caller_bsp ((long)__get_real_reg_value (&my_frame.pfs),
4328 my_frame.my_bsp);
4329 offset = (char *)my_frame.my_bsp - (char *)tmp_bsp;
4330 tmp_bsp = (char *)originator.my_bsp + offset;
4331
ce152ef8
AM
4332 __builtin_eh_return (tmp_bsp, offset, originator.my_sp);
4333
4334 /* The return address was already set by throw_helper. */
4335}
4336
4337#endif /* IA64_UNWIND_INFO */
4338
ad912eec 4339#endif /* L_eh */
This page took 1.786988 seconds and 5 git commands to generate.