]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/libgcc2.c
* i386.h (CONST_OK_FOR_LETTER): Re-add 'N'; document.
[thirdparty/gcc.git] / gcc / libgcc2.c
CommitLineData
62c63f32 1/* More subroutines needed by GCC output code on some machines. */
2/* Compile this one with gcc. */
255b8f3f 3/* Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 1999, 2000
4 Free Software Foundation, Inc.
62c63f32 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
4c9b6e71 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
62c63f32 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
0355838f 29the Free Software Foundation, 59 Temple Place - Suite 330,
30Boston, MA 02111-1307, USA. */
62c63f32 31
62c63f32 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
c538053c 36#include "tconfig.h"
069631e1 37#include "tsystem.h"
8c304688 38
33927595 39#include "machmode.h"
9a0ce7db 40#include "defaults.h"
62c63f32 41
42/* Don't use `fancy_abort' here even if config.h says to use it. */
43#ifdef abort
44#undef abort
45#endif
46
b1e341a2 47#include "libgcc2.h"
62c63f32 48\f
49#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
50#if defined (L_divdi3) || defined (L_moddi3)
51static inline
52#endif
bec2d490 53
54#ifdef L_addvsi3
55SItype
56__addvsi3 (SItype a, SItype b)
57{
58 SItype w, w1;
59
60 w = a + b;
61
62 if (b >= 0 ? w < a : w > a)
63 abort ();
64
65 return w;
66}
67\f
68#ifdef L_addvdi3
69DItype
70__addvdi3 (DItype a, DItype b)
71{
72 DItype w;
73
74 w = a + b;
75
76 if (b >= 0 ? w < a : w > a)
77 abort ();
78
79 return w;
80}
81#endif
82\f
83#ifdef L_subvsi3
84SItype
85__subvsi3 (SItype a, SItype b)
86{
87#ifdef L_addvsi3
88 return __addvsi3 (a, (-b));
89#else
90 DItype w;
91
92 w = a - b;
93
94 if (b >= 0 ? w > a : w < a)
95 abort ();
96
97 return w;
98#endif
99}
100#endif
101\f
102#ifdef L_subvdi3
103DItype
104__subvdi3 (DItype a, DItype b)
105{
106#ifdef L_addvdi3
107 return (a, (-b));
108#else
109 DItype w;
110
111 w = a - b;
112
113 if (b >= 0 ? w > a : w < a)
114 abort ();
115
116 return w;
117#endif
118}
119#endif
120\f
121#ifdef L_mulvsi3
122SItype
123__mulvsi3 (SItype a, SItype b)
124{
125 DItype w;
126
127 w = a * b;
128
129 if ((a >= 0 && b >= 0) ? w < 0
130 : (a >= 0 || b >= 0) ? w > 0 : w < 0)
131 abort ();
132
133 return w;
134}
135#endif
136\f
137#ifdef L_negvsi2
138SItype
139__negvsi2 (SItype a)
140{
141 SItype w;
142
143 w = -a;
144
145 if (a >= 0 ? w > 0 : w < 0)
146 abort ();
147
148 return w;
149}
150#endif
151\f
152#ifdef L_negvdi2
153DItype
154__negvdi2 (DItype a)
155{
156 DItype w;
157
158 w = -a;
159
160 if (a >= 0 ? w > 0 : w < 0)
161 abort ();
162
163 return w;
164}
165#endif
166\f
167#ifdef L_absvsi2
168SItype
169__absvsi2 (SItype a)
170{
171 SItype w = a;
172
173 if (a < 0)
174#ifdef L_negvsi2
175 w = __negvsi2 (a);
176#else
177 w = -a;
178
179 if (w < 0)
180 abort ();
181#endif
182
183 return w;
184}
185#endif
186\f
187#ifdef L_absvdi2
188DItype
189__absvdi2 (DItype a)
190{
191 DItype w = a;
192
193 if (a < 0)
194#ifdef L_negvsi2
195 w = __negvsi2 (a);
196#else
197 w = -a;
198
199 if (w < 0)
200 abort ();
201#endif
202
203 return w;
204}
205#endif
206\f
207#ifdef L_mulvdi3
208DItype
209__mulvdi3 (DItype u, DItype v)
210{
211 DItype w;
212
213 w = u * v;
214
215 if ((u >= 0 && v >= 0) ? w < 0
216 : (u >= 0 || v >= 0) ? w > 0 : w < 0)
217 abort ();
218
219 return w;
220}
221#endif
222\f
cf378360 223DWtype
224__negdi2 (DWtype u)
62c63f32 225{
cf378360 226 DWunion w;
227 DWunion uu;
62c63f32 228
229 uu.ll = u;
230
231 w.s.low = -uu.s.low;
cf378360 232 w.s.high = -uu.s.high - ((UWtype) w.s.low > 0);
62c63f32 233
234 return w.ll;
235}
236#endif
237\f
4f195a89 238/* Unless shift functions are defined whith full ANSI prototypes,
239 parameter b will be promoted to int if word_type is smaller than an int. */
62c63f32 240#ifdef L_lshrdi3
cf378360 241DWtype
242__lshrdi3 (DWtype u, word_type b)
62c63f32 243{
cf378360 244 DWunion w;
60a744a6 245 word_type bm;
cf378360 246 DWunion uu;
62c63f32 247
248 if (b == 0)
249 return u;
250
251 uu.ll = u;
252
cf378360 253 bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
62c63f32 254 if (bm <= 0)
255 {
256 w.s.high = 0;
d1138980 257 w.s.low = (UWtype) uu.s.high >> -bm;
62c63f32 258 }
259 else
260 {
d1138980 261 UWtype carries = (UWtype) uu.s.high << bm;
262
263 w.s.high = (UWtype) uu.s.high >> b;
264 w.s.low = ((UWtype) uu.s.low >> b) | carries;
62c63f32 265 }
266
267 return w.ll;
268}
269#endif
270
271#ifdef L_ashldi3
cf378360 272DWtype
273__ashldi3 (DWtype u, word_type b)
62c63f32 274{
cf378360 275 DWunion w;
60a744a6 276 word_type bm;
cf378360 277 DWunion uu;
62c63f32 278
279 if (b == 0)
280 return u;
281
282 uu.ll = u;
283
cf378360 284 bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
62c63f32 285 if (bm <= 0)
286 {
287 w.s.low = 0;
d1138980 288 w.s.high = (UWtype) uu.s.low << -bm;
62c63f32 289 }
290 else
291 {
d1138980 292 UWtype carries = (UWtype) uu.s.low >> bm;
293
294 w.s.low = (UWtype) uu.s.low << b;
295 w.s.high = ((UWtype) uu.s.high << b) | carries;
62c63f32 296 }
297
298 return w.ll;
299}
300#endif
301
302#ifdef L_ashrdi3
cf378360 303DWtype
304__ashrdi3 (DWtype u, word_type b)
62c63f32 305{
cf378360 306 DWunion w;
60a744a6 307 word_type bm;
cf378360 308 DWunion uu;
62c63f32 309
310 if (b == 0)
311 return u;
312
313 uu.ll = u;
314
cf378360 315 bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
62c63f32 316 if (bm <= 0)
317 {
318 /* w.s.high = 1..1 or 0..0 */
cf378360 319 w.s.high = uu.s.high >> (sizeof (Wtype) * BITS_PER_UNIT - 1);
62c63f32 320 w.s.low = uu.s.high >> -bm;
321 }
322 else
323 {
d1138980 324 UWtype carries = (UWtype) uu.s.high << bm;
325
62c63f32 326 w.s.high = uu.s.high >> b;
d1138980 327 w.s.low = ((UWtype) uu.s.low >> b) | carries;
62c63f32 328 }
329
330 return w.ll;
331}
332#endif
333\f
5e4e1583 334#ifdef L_ffsdi2
cf378360 335DWtype
336__ffsdi2 (DWtype u)
5e4e1583 337{
9ce1b52b 338 DWunion uu;
339 UWtype word, count, add;
340
5e4e1583 341 uu.ll = u;
9ce1b52b 342 if (uu.s.low != 0)
343 word = uu.s.low, add = 0;
344 else if (uu.s.high != 0)
345 word = uu.s.high, add = BITS_PER_UNIT * sizeof (Wtype);
346 else
347 return 0;
348
349 count_trailing_zeros (count, word);
350 return count + add + 1;
5e4e1583 351}
352#endif
353\f
62c63f32 354#ifdef L_muldi3
cf378360 355DWtype
356__muldi3 (DWtype u, DWtype v)
62c63f32 357{
cf378360 358 DWunion w;
359 DWunion uu, vv;
62c63f32 360
361 uu.ll = u,
362 vv.ll = v;
363
364 w.ll = __umulsidi3 (uu.s.low, vv.s.low);
cf378360 365 w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high
366 + (UWtype) uu.s.high * (UWtype) vv.s.low);
62c63f32 367
368 return w.ll;
369}
370#endif
371\f
a46ef09f 372#ifdef L_udiv_w_sdiv
b10877f3 373#if defined (sdiv_qrnnd)
cf378360 374UWtype
375__udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d)
ba628a68 376{
cf378360 377 UWtype q, r;
378 UWtype c0, c1, b1;
ba628a68 379
cf378360 380 if ((Wtype) d >= 0)
ba628a68 381 {
cf378360 382 if (a1 < d - a1 - (a0 >> (W_TYPE_SIZE - 1)))
ba628a68 383 {
384 /* dividend, divisor, and quotient are nonnegative */
385 sdiv_qrnnd (q, r, a1, a0, d);
386 }
387 else
388 {
389 /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
cf378360 390 sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (W_TYPE_SIZE - 1));
ba628a68 391 /* Divide (c1*2^32 + c0) by d */
392 sdiv_qrnnd (q, r, c1, c0, d);
393 /* Add 2^31 to quotient */
cf378360 394 q += (UWtype) 1 << (W_TYPE_SIZE - 1);
ba628a68 395 }
396 }
397 else
398 {
399 b1 = d >> 1; /* d/2, between 2^30 and 2^31 - 1 */
400 c1 = a1 >> 1; /* A/2 */
cf378360 401 c0 = (a1 << (W_TYPE_SIZE - 1)) + (a0 >> 1);
ba628a68 402
403 if (a1 < b1) /* A < 2^32*b1, so A/2 < 2^31*b1 */
404 {
405 sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
406
407 r = 2*r + (a0 & 1); /* Remainder from A/(2*b1) */
408 if ((d & 1) != 0)
409 {
410 if (r >= q)
411 r = r - q;
412 else if (q - r <= d)
413 {
414 r = r - q + d;
415 q--;
416 }
417 else
418 {
419 r = r - q + 2*d;
420 q -= 2;
421 }
422 }
423 }
424 else if (c1 < b1) /* So 2^31 <= (A/2)/b1 < 2^32 */
425 {
426 c1 = (b1 - 1) - c1;
427 c0 = ~c0; /* logical NOT */
428
429 sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
430
431 q = ~q; /* (A/2)/b1 */
432 r = (b1 - 1) - r;
433
434 r = 2*r + (a0 & 1); /* A/(2*b1) */
435
436 if ((d & 1) != 0)
437 {
438 if (r >= q)
439 r = r - q;
440 else if (q - r <= d)
441 {
442 r = r - q + d;
443 q--;
444 }
445 else
446 {
447 r = r - q + 2*d;
448 q -= 2;
449 }
450 }
451 }
452 else /* Implies c1 = b1 */
453 { /* Hence a1 = d - 1 = 2*b1 - 1 */
454 if (a0 >= -d)
455 {
456 q = -1;
457 r = a0 + d;
458 }
459 else
460 {
461 q = -2;
462 r = a0 + 2*d;
463 }
464 }
465 }
466
467 *rp = r;
468 return q;
469}
b10877f3 470#else
471/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv. */
cf378360 472UWtype
473__udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)),
474 UWtype a1 __attribute__ ((__unused__)),
475 UWtype a0 __attribute__ ((__unused__)),
476 UWtype d __attribute__ ((__unused__)))
73439ee0 477{
478 return 0;
479}
b10877f3 480#endif
ba628a68 481#endif
482\f
a47053cf 483#if (defined (L_udivdi3) || defined (L_divdi3) || \
484 defined (L_umoddi3) || defined (L_moddi3))
485#define L_udivmoddi4
486#endif
487
9ce1b52b 488#ifdef L_clz
489const UQItype __clz_tab[] =
62c63f32 490{
491 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,
492 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,
493 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,
494 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,
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 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,
498 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,
499};
9ce1b52b 500#endif
501
502#ifdef L_udivmoddi4
62c63f32 503
a47053cf 504#if (defined (L_udivdi3) || defined (L_divdi3) || \
505 defined (L_umoddi3) || defined (L_moddi3))
506static inline
507#endif
cf378360 508UDWtype
509__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
62c63f32 510{
cf378360 511 DWunion ww;
512 DWunion nn, dd;
513 DWunion rr;
514 UWtype d0, d1, n0, n1, n2;
515 UWtype q0, q1;
516 UWtype b, bm;
62c63f32 517
518 nn.ll = n;
519 dd.ll = d;
520
521 d0 = dd.s.low;
522 d1 = dd.s.high;
523 n0 = nn.s.low;
524 n1 = nn.s.high;
525
526#if !UDIV_NEEDS_NORMALIZATION
527 if (d1 == 0)
528 {
529 if (d0 > n1)
530 {
531 /* 0q = nn / 0D */
532
533 udiv_qrnnd (q0, n0, n1, n0, d0);
534 q1 = 0;
535
536 /* Remainder in n0. */
537 }
538 else
539 {
540 /* qq = NN / 0d */
541
542 if (d0 == 0)
543 d0 = 1 / d0; /* Divide intentionally by zero. */
544
545 udiv_qrnnd (q1, n1, 0, n1, d0);
546 udiv_qrnnd (q0, n0, n1, n0, d0);
547
548 /* Remainder in n0. */
549 }
550
551 if (rp != 0)
552 {
553 rr.s.low = n0;
554 rr.s.high = 0;
555 *rp = rr.ll;
556 }
557 }
558
559#else /* UDIV_NEEDS_NORMALIZATION */
560
561 if (d1 == 0)
562 {
563 if (d0 > n1)
564 {
565 /* 0q = nn / 0D */
566
567 count_leading_zeros (bm, d0);
568
569 if (bm != 0)
570 {
571 /* Normalize, i.e. make the most significant bit of the
572 denominator set. */
573
574 d0 = d0 << bm;
cf378360 575 n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
62c63f32 576 n0 = n0 << bm;
577 }
578
579 udiv_qrnnd (q0, n0, n1, n0, d0);
580 q1 = 0;
581
582 /* Remainder in n0 >> bm. */
583 }
584 else
585 {
586 /* qq = NN / 0d */
587
588 if (d0 == 0)
589 d0 = 1 / d0; /* Divide intentionally by zero. */
590
591 count_leading_zeros (bm, d0);
592
593 if (bm == 0)
594 {
595 /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
596 conclude (the most significant bit of n1 is set) /\ (the
597 leading quotient digit q1 = 1).
598
599 This special case is necessary, not an optimization.
cf378360 600 (Shifts counts of W_TYPE_SIZE are undefined.) */
62c63f32 601
602 n1 -= d0;
603 q1 = 1;
604 }
605 else
606 {
607 /* Normalize. */
608
cf378360 609 b = W_TYPE_SIZE - bm;
62c63f32 610
611 d0 = d0 << bm;
612 n2 = n1 >> b;
613 n1 = (n1 << bm) | (n0 >> b);
614 n0 = n0 << bm;
615
616 udiv_qrnnd (q1, n1, n2, n1, d0);
617 }
618
a92771b8 619 /* n1 != d0... */
62c63f32 620
621 udiv_qrnnd (q0, n0, n1, n0, d0);
622
623 /* Remainder in n0 >> bm. */
624 }
625
626 if (rp != 0)
627 {
628 rr.s.low = n0 >> bm;
629 rr.s.high = 0;
630 *rp = rr.ll;
631 }
632 }
633#endif /* UDIV_NEEDS_NORMALIZATION */
634
635 else
636 {
637 if (d1 > n1)
638 {
639 /* 00 = nn / DD */
640
641 q0 = 0;
642 q1 = 0;
643
644 /* Remainder in n1n0. */
645 if (rp != 0)
646 {
647 rr.s.low = n0;
648 rr.s.high = n1;
649 *rp = rr.ll;
650 }
651 }
652 else
653 {
654 /* 0q = NN / dd */
655
656 count_leading_zeros (bm, d1);
657 if (bm == 0)
658 {
659 /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
660 conclude (the most significant bit of n1 is set) /\ (the
661 quotient digit q0 = 0 or 1).
662
663 This special case is necessary, not an optimization. */
664
665 /* The condition on the next line takes advantage of that
666 n1 >= d1 (true due to program flow). */
667 if (n1 > d1 || n0 >= d0)
668 {
669 q0 = 1;
670 sub_ddmmss (n1, n0, n1, n0, d1, d0);
671 }
672 else
673 q0 = 0;
674
675 q1 = 0;
676
677 if (rp != 0)
678 {
679 rr.s.low = n0;
680 rr.s.high = n1;
681 *rp = rr.ll;
682 }
683 }
684 else
685 {
cf378360 686 UWtype m1, m0;
62c63f32 687 /* Normalize. */
688
cf378360 689 b = W_TYPE_SIZE - bm;
62c63f32 690
691 d1 = (d1 << bm) | (d0 >> b);
692 d0 = d0 << bm;
693 n2 = n1 >> b;
694 n1 = (n1 << bm) | (n0 >> b);
695 n0 = n0 << bm;
696
697 udiv_qrnnd (q0, n1, n2, n1, d1);
698 umul_ppmm (m1, m0, q0, d0);
699
700 if (m1 > n1 || (m1 == n1 && m0 > n0))
701 {
702 q0--;
703 sub_ddmmss (m1, m0, m1, m0, d1, d0);
704 }
705
706 q1 = 0;
707
708 /* Remainder in (n1n0 - m1m0) >> bm. */
709 if (rp != 0)
710 {
711 sub_ddmmss (n1, n0, n1, n0, m1, m0);
712 rr.s.low = (n1 << b) | (n0 >> bm);
713 rr.s.high = n1 >> bm;
714 *rp = rr.ll;
715 }
716 }
717 }
718 }
719
720 ww.s.low = q0;
721 ww.s.high = q1;
722 return ww.ll;
723}
724#endif
725
726#ifdef L_divdi3
cf378360 727DWtype
728__divdi3 (DWtype u, DWtype v)
62c63f32 729{
60a744a6 730 word_type c = 0;
cf378360 731 DWunion uu, vv;
732 DWtype w;
62c63f32 733
734 uu.ll = u;
735 vv.ll = v;
736
737 if (uu.s.high < 0)
738 c = ~c,
739 uu.ll = __negdi2 (uu.ll);
740 if (vv.s.high < 0)
741 c = ~c,
742 vv.ll = __negdi2 (vv.ll);
743
cf378360 744 w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
62c63f32 745 if (c)
746 w = __negdi2 (w);
747
748 return w;
749}
750#endif
751
752#ifdef L_moddi3
cf378360 753DWtype
754__moddi3 (DWtype u, DWtype v)
62c63f32 755{
60a744a6 756 word_type c = 0;
cf378360 757 DWunion uu, vv;
758 DWtype w;
62c63f32 759
760 uu.ll = u;
761 vv.ll = v;
762
763 if (uu.s.high < 0)
764 c = ~c,
765 uu.ll = __negdi2 (uu.ll);
766 if (vv.s.high < 0)
767 vv.ll = __negdi2 (vv.ll);
768
769 (void) __udivmoddi4 (uu.ll, vv.ll, &w);
770 if (c)
771 w = __negdi2 (w);
772
773 return w;
774}
775#endif
776
777#ifdef L_umoddi3
cf378360 778UDWtype
779__umoddi3 (UDWtype u, UDWtype v)
62c63f32 780{
cf378360 781 UDWtype w;
62c63f32 782
783 (void) __udivmoddi4 (u, v, &w);
784
785 return w;
786}
787#endif
788
789#ifdef L_udivdi3
cf378360 790UDWtype
791__udivdi3 (UDWtype n, UDWtype d)
62c63f32 792{
cf378360 793 return __udivmoddi4 (n, d, (UDWtype *) 0);
62c63f32 794}
795#endif
796\f
797#ifdef L_cmpdi2
61d95568 798word_type
cf378360 799__cmpdi2 (DWtype a, DWtype b)
62c63f32 800{
cf378360 801 DWunion au, bu;
62c63f32 802
803 au.ll = a, bu.ll = b;
804
805 if (au.s.high < bu.s.high)
806 return 0;
807 else if (au.s.high > bu.s.high)
808 return 2;
cf378360 809 if ((UWtype) au.s.low < (UWtype) bu.s.low)
62c63f32 810 return 0;
cf378360 811 else if ((UWtype) au.s.low > (UWtype) bu.s.low)
62c63f32 812 return 2;
813 return 1;
814}
815#endif
816
817#ifdef L_ucmpdi2
61d95568 818word_type
cf378360 819__ucmpdi2 (DWtype a, DWtype b)
62c63f32 820{
cf378360 821 DWunion au, bu;
62c63f32 822
823 au.ll = a, bu.ll = b;
824
cf378360 825 if ((UWtype) au.s.high < (UWtype) bu.s.high)
62c63f32 826 return 0;
cf378360 827 else if ((UWtype) au.s.high > (UWtype) bu.s.high)
62c63f32 828 return 2;
cf378360 829 if ((UWtype) au.s.low < (UWtype) bu.s.low)
62c63f32 830 return 0;
cf378360 831 else if ((UWtype) au.s.low > (UWtype) bu.s.low)
62c63f32 832 return 2;
833 return 1;
834}
835#endif
836\f
dd84cabc 837#if defined(L_fixunstfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
cf378360 838#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
839#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
ade0e71b 840
cf378360 841DWtype
d1138980 842__fixunstfDI (TFtype a)
ade0e71b 843{
844 TFtype b;
cf378360 845 UDWtype v;
ade0e71b 846
847 if (a < 0)
848 return 0;
849
850 /* Compute high word of result, as a flonum. */
851 b = (a / HIGH_WORD_COEFF);
cf378360 852 /* Convert that to fixed (but not to DWtype!),
ade0e71b 853 and shift it into the high word. */
cf378360 854 v = (UWtype) b;
ade0e71b 855 v <<= WORD_SIZE;
856 /* Remove high part from the TFtype, leaving the low part as flonum. */
857 a -= (TFtype)v;
cf378360 858 /* Convert that to fixed (but not to DWtype!) and add it in.
ade0e71b 859 Sometimes A comes out negative. This is significant, since
860 A has more bits than a long int does. */
861 if (a < 0)
cf378360 862 v -= (UWtype) (- a);
ade0e71b 863 else
cf378360 864 v += (UWtype) a;
ade0e71b 865 return v;
866}
867#endif
868
dd84cabc 869#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
cf378360 870DWtype
4f195a89 871__fixtfdi (TFtype a)
ade0e71b 872{
873 if (a < 0)
d1138980 874 return - __fixunstfDI (-a);
875 return __fixunstfDI (a);
ade0e71b 876}
877#endif
878
dd84cabc 879#if defined(L_fixunsxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
cf378360 880#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
881#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
0e1cc047 882
cf378360 883DWtype
d1138980 884__fixunsxfDI (XFtype a)
0e1cc047 885{
886 XFtype b;
cf378360 887 UDWtype v;
0e1cc047 888
889 if (a < 0)
890 return 0;
891
892 /* Compute high word of result, as a flonum. */
893 b = (a / HIGH_WORD_COEFF);
cf378360 894 /* Convert that to fixed (but not to DWtype!),
0e1cc047 895 and shift it into the high word. */
cf378360 896 v = (UWtype) b;
0e1cc047 897 v <<= WORD_SIZE;
898 /* Remove high part from the XFtype, leaving the low part as flonum. */
899 a -= (XFtype)v;
cf378360 900 /* Convert that to fixed (but not to DWtype!) and add it in.
0e1cc047 901 Sometimes A comes out negative. This is significant, since
902 A has more bits than a long int does. */
903 if (a < 0)
cf378360 904 v -= (UWtype) (- a);
0e1cc047 905 else
cf378360 906 v += (UWtype) a;
0e1cc047 907 return v;
908}
909#endif
910
dd84cabc 911#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
cf378360 912DWtype
4f195a89 913__fixxfdi (XFtype a)
0e1cc047 914{
915 if (a < 0)
d1138980 916 return - __fixunsxfDI (-a);
917 return __fixunsxfDI (a);
0e1cc047 918}
919#endif
920
62c63f32 921#ifdef L_fixunsdfdi
cf378360 922#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
923#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
62c63f32 924
cf378360 925DWtype
d1138980 926__fixunsdfDI (DFtype a)
62c63f32 927{
ade0e71b 928 DFtype b;
cf378360 929 UDWtype v;
62c63f32 930
931 if (a < 0)
932 return 0;
933
934 /* Compute high word of result, as a flonum. */
935 b = (a / HIGH_WORD_COEFF);
cf378360 936 /* Convert that to fixed (but not to DWtype!),
62c63f32 937 and shift it into the high word. */
cf378360 938 v = (UWtype) b;
62c63f32 939 v <<= WORD_SIZE;
ade0e71b 940 /* Remove high part from the DFtype, leaving the low part as flonum. */
941 a -= (DFtype)v;
cf378360 942 /* Convert that to fixed (but not to DWtype!) and add it in.
62c63f32 943 Sometimes A comes out negative. This is significant, since
944 A has more bits than a long int does. */
945 if (a < 0)
cf378360 946 v -= (UWtype) (- a);
62c63f32 947 else
cf378360 948 v += (UWtype) a;
62c63f32 949 return v;
950}
951#endif
952
953#ifdef L_fixdfdi
cf378360 954DWtype
4f195a89 955__fixdfdi (DFtype a)
62c63f32 956{
957 if (a < 0)
d1138980 958 return - __fixunsdfDI (-a);
959 return __fixunsdfDI (a);
62c63f32 960}
961#endif
962
963#ifdef L_fixunssfdi
cf378360 964#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
965#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
62c63f32 966
cf378360 967DWtype
d1138980 968__fixunssfDI (SFtype original_a)
62c63f32 969{
ade0e71b 970 /* Convert the SFtype to a DFtype, because that is surely not going
62c63f32 971 to lose any bits. Some day someone else can write a faster version
ade0e71b 972 that avoids converting to DFtype, and verify it really works right. */
973 DFtype a = original_a;
974 DFtype b;
cf378360 975 UDWtype v;
62c63f32 976
977 if (a < 0)
978 return 0;
979
980 /* Compute high word of result, as a flonum. */
981 b = (a / HIGH_WORD_COEFF);
cf378360 982 /* Convert that to fixed (but not to DWtype!),
62c63f32 983 and shift it into the high word. */
cf378360 984 v = (UWtype) b;
62c63f32 985 v <<= WORD_SIZE;
ade0e71b 986 /* Remove high part from the DFtype, leaving the low part as flonum. */
d1138980 987 a -= (DFtype) v;
cf378360 988 /* Convert that to fixed (but not to DWtype!) and add it in.
62c63f32 989 Sometimes A comes out negative. This is significant, since
990 A has more bits than a long int does. */
991 if (a < 0)
cf378360 992 v -= (UWtype) (- a);
62c63f32 993 else
cf378360 994 v += (UWtype) a;
62c63f32 995 return v;
996}
997#endif
998
999#ifdef L_fixsfdi
cf378360 1000DWtype
ade0e71b 1001__fixsfdi (SFtype a)
62c63f32 1002{
1003 if (a < 0)
d1138980 1004 return - __fixunssfDI (-a);
1005 return __fixunssfDI (a);
62c63f32 1006}
1007#endif
1008
dd84cabc 1009#if defined(L_floatdixf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
cf378360 1010#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
1011#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
1012#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
0e1cc047 1013
1014XFtype
cf378360 1015__floatdixf (DWtype u)
0e1cc047 1016{
1017 XFtype d;
0e1cc047 1018
cf378360 1019 d = (Wtype) (u >> WORD_SIZE);
0e1cc047 1020 d *= HIGH_HALFWORD_COEFF;
1021 d *= HIGH_HALFWORD_COEFF;
cf378360 1022 d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
0e1cc047 1023
997d68fe 1024 return d;
0e1cc047 1025}
1026#endif
1027
dd84cabc 1028#if defined(L_floatditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
cf378360 1029#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
1030#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
1031#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
ade0e71b 1032
1033TFtype
cf378360 1034__floatditf (DWtype u)
ade0e71b 1035{
1036 TFtype d;
ade0e71b 1037
cf378360 1038 d = (Wtype) (u >> WORD_SIZE);
ade0e71b 1039 d *= HIGH_HALFWORD_COEFF;
1040 d *= HIGH_HALFWORD_COEFF;
cf378360 1041 d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
ade0e71b 1042
997d68fe 1043 return d;
ade0e71b 1044}
1045#endif
1046
62c63f32 1047#ifdef L_floatdidf
cf378360 1048#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
1049#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
1050#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
62c63f32 1051
ade0e71b 1052DFtype
cf378360 1053__floatdidf (DWtype u)
62c63f32 1054{
ade0e71b 1055 DFtype d;
62c63f32 1056
cf378360 1057 d = (Wtype) (u >> WORD_SIZE);
62c63f32 1058 d *= HIGH_HALFWORD_COEFF;
1059 d *= HIGH_HALFWORD_COEFF;
cf378360 1060 d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
62c63f32 1061
997d68fe 1062 return d;
62c63f32 1063}
1064#endif
1065
1066#ifdef L_floatdisf
cf378360 1067#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
1068#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
1069#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
1070#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
d16023de 1071
1072/* Define codes for all the float formats that we know of. Note
1073 that this is copied from real.h. */
1074
1075#define UNKNOWN_FLOAT_FORMAT 0
1076#define IEEE_FLOAT_FORMAT 1
1077#define VAX_FLOAT_FORMAT 2
1078#define IBM_FLOAT_FORMAT 3
1079
1080/* Default to IEEE float if not specified. Nearly all machines use it. */
1081#ifndef HOST_FLOAT_FORMAT
1082#define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT
1083#endif
1084
1085#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
b37ebc51 1086#define DF_SIZE 53
1087#define SF_SIZE 24
d16023de 1088#endif
1089
1090#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
b37ebc51 1091#define DF_SIZE 56
1092#define SF_SIZE 24
d16023de 1093#endif
1094
1095#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
b37ebc51 1096#define DF_SIZE 56
1097#define SF_SIZE 24
b37ebc51 1098#endif
62c63f32 1099
ade0e71b 1100SFtype
cf378360 1101__floatdisf (DWtype u)
62c63f32 1102{
a06dece2 1103 /* Do the calculation in DFmode
1104 so that we don't lose any of the precision of the high word
1105 while multiplying it. */
1106 DFtype f;
62c63f32 1107
b37ebc51 1108 /* Protect against double-rounding error.
1109 Represent any low-order bits, that might be truncated in DFmode,
1110 by a bit that won't be lost. The bit can go in anywhere below the
1111 rounding position of the SFmode. A fixed mask and bit position
1112 handles all usual configurations. It doesn't handle the case
1113 of 128-bit DImode, however. */
1114 if (DF_SIZE < DI_SIZE
1115 && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
1116 {
d1138980 1117#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE))
cf378360 1118 if (! (- ((DWtype) 1 << DF_SIZE) < u
1119 && u < ((DWtype) 1 << DF_SIZE)))
b37ebc51 1120 {
d1138980 1121 if ((UDWtype) u & (REP_BIT - 1))
b37ebc51 1122 u |= REP_BIT;
1123 }
1124 }
cf378360 1125 f = (Wtype) (u >> WORD_SIZE);
62c63f32 1126 f *= HIGH_HALFWORD_COEFF;
1127 f *= HIGH_HALFWORD_COEFF;
cf378360 1128 f += (UWtype) (u & (HIGH_WORD_COEFF - 1));
62c63f32 1129
997d68fe 1130 return (SFtype) f;
62c63f32 1131}
1132#endif
1133
dd84cabc 1134#if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
3873e172 1135/* Reenable the normal types, in case limits.h needs them. */
1136#undef char
1137#undef short
1138#undef int
1139#undef long
1140#undef unsigned
1141#undef float
1142#undef double
35e6d592 1143#undef MIN
1144#undef MAX
ab195728 1145#include <limits.h>
0e1cc047 1146
cf378360 1147UWtype
d1138980 1148__fixunsxfSI (XFtype a)
0e1cc047 1149{
1150 if (a >= - (DFtype) LONG_MIN)
cf378360 1151 return (Wtype) (a + LONG_MIN) - LONG_MIN;
1152 return (Wtype) a;
0e1cc047 1153}
1154#endif
1155
62c63f32 1156#ifdef L_fixunsdfsi
3873e172 1157/* Reenable the normal types, in case limits.h needs them. */
1158#undef char
1159#undef short
1160#undef int
1161#undef long
1162#undef unsigned
1163#undef float
1164#undef double
35e6d592 1165#undef MIN
1166#undef MAX
ab195728 1167#include <limits.h>
62c63f32 1168
cf378360 1169UWtype
d1138980 1170__fixunsdfSI (DFtype a)
62c63f32 1171{
ade0e71b 1172 if (a >= - (DFtype) LONG_MIN)
cf378360 1173 return (Wtype) (a + LONG_MIN) - LONG_MIN;
1174 return (Wtype) a;
62c63f32 1175}
1176#endif
1177
1178#ifdef L_fixunssfsi
3873e172 1179/* Reenable the normal types, in case limits.h needs them. */
1180#undef char
1181#undef short
1182#undef int
1183#undef long
1184#undef unsigned
1185#undef float
1186#undef double
35e6d592 1187#undef MIN
1188#undef MAX
ab195728 1189#include <limits.h>
62c63f32 1190
cf378360 1191UWtype
d1138980 1192__fixunssfSI (SFtype a)
62c63f32 1193{
ade0e71b 1194 if (a >= - (SFtype) LONG_MIN)
cf378360 1195 return (Wtype) (a + LONG_MIN) - LONG_MIN;
1196 return (Wtype) a;
62c63f32 1197}
1198#endif
1199\f
ade0e71b 1200/* From here on down, the routines use normal data types. */
1201
1202#define SItype bogus_type
1203#define USItype bogus_type
1204#define DItype bogus_type
1205#define UDItype bogus_type
1206#define SFtype bogus_type
1207#define DFtype bogus_type
cf378360 1208#undef Wtype
1209#undef UWtype
1210#undef HWtype
1211#undef UHWtype
1212#undef DWtype
1213#undef UDWtype
ade0e71b 1214
1215#undef char
1216#undef short
1217#undef int
1218#undef long
1219#undef unsigned
1220#undef float
1221#undef double
e674bcb7 1222\f
1223#ifdef L__gcc_bcmp
1224
1225/* Like bcmp except the sign is meaningful.
c3418f42 1226 Result is negative if S1 is less than S2,
e674bcb7 1227 positive if S1 is greater, 0 if S1 and S2 are equal. */
1228
1229int
b1e341a2 1230__gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size)
e674bcb7 1231{
1232 while (size > 0)
1233 {
e4ee4217 1234 unsigned char c1 = *s1++, c2 = *s2++;
e674bcb7 1235 if (c1 != c2)
1236 return c1 - c2;
1237 size--;
1238 }
1239 return 0;
1240}
ade0e71b 1241
e674bcb7 1242#endif
1243\f\f
aa743289 1244#ifdef L__dummy
1245void
71218a21 1246__dummy (void) {}
aa743289 1247#endif
1248
62c63f32 1249#ifdef L_varargs
1250#ifdef __i860__
2afc9c04 1251#if defined(__svr4__) || defined(__alliant__)
62c63f32 1252 asm (" .text");
1253 asm (" .align 4");
1254
ffcdee45 1255/* The Alliant needs the added underscore. */
62c63f32 1256 asm (".globl __builtin_saveregs");
1257asm ("__builtin_saveregs:");
ffcdee45 1258 asm (".globl ___builtin_saveregs");
1259asm ("___builtin_saveregs:");
1260
1261 asm (" andnot 0x0f,%sp,%sp"); /* round down to 16-byte boundary */
62c63f32 1262 asm (" adds -96,%sp,%sp"); /* allocate stack space for reg save
1263 area and also for a new va_list
1264 structure */
1265 /* Save all argument registers in the arg reg save area. The
1266 arg reg save area must have the following layout (according
1267 to the svr4 ABI):
1268
1269 struct {
1270 union {
1271 float freg[8];
1272 double dreg[4];
1273 } float_regs;
1274 long ireg[12];
1275 };
1276 */
1277
1278 asm (" fst.q %f8, 0(%sp)"); /* save floating regs (f8-f15) */
1279 asm (" fst.q %f12,16(%sp)");
1280
1281 asm (" st.l %r16,32(%sp)"); /* save integer regs (r16-r27) */
1282 asm (" st.l %r17,36(%sp)");
1283 asm (" st.l %r18,40(%sp)");
1284 asm (" st.l %r19,44(%sp)");
1285 asm (" st.l %r20,48(%sp)");
1286 asm (" st.l %r21,52(%sp)");
1287 asm (" st.l %r22,56(%sp)");
1288 asm (" st.l %r23,60(%sp)");
1289 asm (" st.l %r24,64(%sp)");
1290 asm (" st.l %r25,68(%sp)");
1291 asm (" st.l %r26,72(%sp)");
1292 asm (" st.l %r27,76(%sp)");
1293
1294 asm (" adds 80,%sp,%r16"); /* compute the address of the new
1295 va_list structure. Put in into
1296 r16 so that it will be returned
1297 to the caller. */
1298
1299 /* Initialize all fields of the new va_list structure. This
1300 structure looks like:
1301
1302 typedef struct {
1303 unsigned long ireg_used;
1304 unsigned long freg_used;
1305 long *reg_base;
1306 long *mem_ptr;
1307 } va_list;
1308 */
1309
1310 asm (" st.l %r0, 0(%r16)"); /* nfixed */
1311 asm (" st.l %r0, 4(%r16)"); /* nfloating */
1312 asm (" st.l %sp, 8(%r16)"); /* __va_ctl points to __va_struct. */
1313 asm (" bri %r1"); /* delayed return */
1314 asm (" st.l %r28,12(%r16)"); /* pointer to overflow args */
1315
99bf8eeb 1316#else /* not __svr4__ */
a588d976 1317#if defined(__PARAGON__)
1318 /*
1319 * we'll use SVR4-ish varargs but need SVR3.2 assembler syntax,
1320 * and we stand a better chance of hooking into libraries
1321 * compiled by PGI. [andyp@ssd.intel.com]
1322 */
1323 asm (" .text");
1324 asm (" .align 4");
1325 asm (".globl __builtin_saveregs");
1326asm ("__builtin_saveregs:");
1327 asm (".globl ___builtin_saveregs");
1328asm ("___builtin_saveregs:");
1329
1330 asm (" andnot 0x0f,sp,sp"); /* round down to 16-byte boundary */
1331 asm (" adds -96,sp,sp"); /* allocate stack space for reg save
1332 area and also for a new va_list
1333 structure */
1334 /* Save all argument registers in the arg reg save area. The
1335 arg reg save area must have the following layout (according
1336 to the svr4 ABI):
1337
1338 struct {
1339 union {
1340 float freg[8];
1341 double dreg[4];
1342 } float_regs;
1343 long ireg[12];
1344 };
1345 */
1346
1347 asm (" fst.q f8, 0(sp)");
1348 asm (" fst.q f12,16(sp)");
1349 asm (" st.l r16,32(sp)");
1350 asm (" st.l r17,36(sp)");
1351 asm (" st.l r18,40(sp)");
1352 asm (" st.l r19,44(sp)");
1353 asm (" st.l r20,48(sp)");
1354 asm (" st.l r21,52(sp)");
1355 asm (" st.l r22,56(sp)");
1356 asm (" st.l r23,60(sp)");
1357 asm (" st.l r24,64(sp)");
1358 asm (" st.l r25,68(sp)");
1359 asm (" st.l r26,72(sp)");
1360 asm (" st.l r27,76(sp)");
1361
1362 asm (" adds 80,sp,r16"); /* compute the address of the new
1363 va_list structure. Put in into
1364 r16 so that it will be returned
1365 to the caller. */
1366
1367 /* Initialize all fields of the new va_list structure. This
1368 structure looks like:
1369
1370 typedef struct {
1371 unsigned long ireg_used;
1372 unsigned long freg_used;
1373 long *reg_base;
1374 long *mem_ptr;
1375 } va_list;
1376 */
1377
1378 asm (" st.l r0, 0(r16)"); /* nfixed */
1379 asm (" st.l r0, 4(r16)"); /* nfloating */
1380 asm (" st.l sp, 8(r16)"); /* __va_ctl points to __va_struct. */
1381 asm (" bri r1"); /* delayed return */
1382 asm (" st.l r28,12(r16)"); /* pointer to overflow args */
1383#else /* not __PARAGON__ */
62c63f32 1384 asm (" .text");
1385 asm (" .align 4");
1386
1387 asm (".globl ___builtin_saveregs");
1388 asm ("___builtin_saveregs:");
1389 asm (" mov sp,r30");
1390 asm (" andnot 0x0f,sp,sp");
1391 asm (" adds -96,sp,sp"); /* allocate sufficient space on the stack */
1392
1393/* Fill in the __va_struct. */
1394 asm (" st.l r16, 0(sp)"); /* save integer regs (r16-r27) */
1395 asm (" st.l r17, 4(sp)"); /* int fixed[12] */
1396 asm (" st.l r18, 8(sp)");
1397 asm (" st.l r19,12(sp)");
1398 asm (" st.l r20,16(sp)");
1399 asm (" st.l r21,20(sp)");
1400 asm (" st.l r22,24(sp)");
1401 asm (" st.l r23,28(sp)");
1402 asm (" st.l r24,32(sp)");
1403 asm (" st.l r25,36(sp)");
1404 asm (" st.l r26,40(sp)");
1405 asm (" st.l r27,44(sp)");
1406
1407 asm (" fst.q f8, 48(sp)"); /* save floating regs (f8-f15) */
1408 asm (" fst.q f12,64(sp)"); /* int floating[8] */
1409
1410/* Fill in the __va_ctl. */
1411 asm (" st.l sp, 80(sp)"); /* __va_ctl points to __va_struct. */
1412 asm (" st.l r28,84(sp)"); /* pointer to more args */
1413 asm (" st.l r0, 88(sp)"); /* nfixed */
1414 asm (" st.l r0, 92(sp)"); /* nfloating */
1415
1416 asm (" adds 80,sp,r16"); /* return address of the __va_ctl. */
1417 asm (" bri r1");
1418 asm (" mov r30,sp");
1419 /* recover stack and pass address to start
1420 of data. */
a588d976 1421#endif /* not __PARAGON__ */
99bf8eeb 1422#endif /* not __svr4__ */
62c63f32 1423#else /* not __i860__ */
1424#ifdef __sparc__
b13ae905 1425 asm (".global __builtin_saveregs");
1426 asm ("__builtin_saveregs:");
62c63f32 1427 asm (".global ___builtin_saveregs");
1428 asm ("___builtin_saveregs:");
0cb31e48 1429#ifdef NEED_PROC_COMMAND
1430 asm (".proc 020");
b13ae905 1431#endif
62c63f32 1432 asm ("st %i0,[%fp+68]");
1433 asm ("st %i1,[%fp+72]");
1434 asm ("st %i2,[%fp+76]");
1435 asm ("st %i3,[%fp+80]");
1436 asm ("st %i4,[%fp+84]");
1437 asm ("retl");
1438 asm ("st %i5,[%fp+88]");
0cb31e48 1439#ifdef NEED_TYPE_COMMAND
1440 asm (".type __builtin_saveregs,#function");
1441 asm (".size __builtin_saveregs,.-__builtin_saveregs");
1442#endif
62c63f32 1443#else /* not __sparc__ */
1444#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
1445
1446 asm (" .text");
7682c809 1447#ifdef __mips16
1448 asm (" .set nomips16");
1449#endif
62c63f32 1450 asm (" .ent __builtin_saveregs");
1451 asm (" .globl __builtin_saveregs");
1452 asm ("__builtin_saveregs:");
1453 asm (" sw $4,0($30)");
1454 asm (" sw $5,4($30)");
1455 asm (" sw $6,8($30)");
1456 asm (" sw $7,12($30)");
1457 asm (" j $31");
1458 asm (" .end __builtin_saveregs");
a92771b8 1459#else /* not __mips__, etc. */
49fa6225 1460
b1e341a2 1461void * __attribute__ ((__noreturn__))
71218a21 1462__builtin_saveregs (void)
62c63f32 1463{
1464 abort ();
1465}
49fa6225 1466
62c63f32 1467#endif /* not __mips__ */
1468#endif /* not __sparc__ */
1469#endif /* not __i860__ */
1470#endif
1471\f
1472#ifdef L_eprintf
bae05c53 1473#ifndef inhibit_libc
b8bb46a6 1474
62c63f32 1475#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
1476#include <stdio.h>
1477/* This is used by the `assert' macro. */
1478void
4f195a89 1479__eprintf (const char *string, const char *expression,
94631519 1480 unsigned int line, const char *filename)
62c63f32 1481{
1482 fprintf (stderr, string, expression, line, filename);
1483 fflush (stderr);
1484 abort ();
1485}
b8bb46a6 1486
1487#endif
62c63f32 1488#endif
1489
1490#ifdef L_bb
62c63f32 1491
543e7f6c 1492/* Structure emitted by -a */
62c63f32 1493struct bb
1494{
543e7f6c 1495 long zero_word;
1496 const char *filename;
1497 long *counts;
1498 long ncounts;
1499 struct bb *next;
1500 const unsigned long *addresses;
1501
1502 /* Older GCC's did not emit these fields. */
1503 long nwords;
1504 const char **functions;
1505 const long *line_nums;
1506 const char **filenames;
eb6cf4cb 1507 char *flags;
62c63f32 1508};
1509
543e7f6c 1510#ifdef BLOCK_PROFILER_CODE
1511BLOCK_PROFILER_CODE
1512#else
6e94b6ac 1513#ifndef inhibit_libc
543e7f6c 1514
1515/* Simple minded basic block profiling output dumper for
c3418f42 1516 systems that don't provide tcov support. At present,
543e7f6c 1517 it requires atexit and stdio. */
1518
92bc8f0b 1519#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
543e7f6c 1520#include <stdio.h>
e7cd69a0 1521char *ctime ();
62c63f32 1522
2fea28a7 1523#include "gbl-ctors.h"
6e5fdcc0 1524#include "gcov-io.h"
bc33205e 1525#include <string.h>
255b8f3f 1526#ifdef TARGET_HAS_F_SETLKW
1527#include <fcntl.h>
1528#include <errno.h>
1529#endif
543e7f6c 1530
5233d224 1531static struct bb *bb_head;
543e7f6c 1532
06484bf1 1533static int num_digits (long value, int base) __attribute__ ((const));
1534
543e7f6c 1535/* Return the number of digits needed to print a value */
1536/* __inline__ */ static int num_digits (long value, int base)
62c63f32 1537{
543e7f6c 1538 int minus = (value < 0 && base != 16);
1539 unsigned long v = (minus) ? -value : value;
1540 int ret = minus;
62c63f32 1541
543e7f6c 1542 do
1543 {
1544 v /= base;
1545 ret++;
1546 }
1547 while (v);
1548
1549 return ret;
62c63f32 1550}
1551
543e7f6c 1552void
1553__bb_exit_func (void)
1554{
6e5fdcc0 1555 FILE *da_file, *file;
543e7f6c 1556 long time_value;
6e5fdcc0 1557 int i;
1558
1559 if (bb_head == 0)
1560 return;
1561
1562 i = strlen (bb_head->filename) - 3;
1563
1564 if (!strcmp (bb_head->filename+i, ".da"))
1565 {
1566 /* Must be -fprofile-arcs not -a.
1567 Dump data in a form that gcov expects. */
1568
1569 struct bb *ptr;
1570
1571 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
1572 {
255b8f3f 1573 int firstchar;
1574
1575 /* Make sure the output file exists -
1576 but don't clobber exiting data. */
1577 if ((da_file = fopen (ptr->filename, "a")) != 0)
1578 fclose (da_file);
1579
1580 /* Need to re-open in order to be able to write from the start. */
1581 da_file = fopen (ptr->filename, "r+b");
1582 /* Some old systems might not allow the 'b' mode modifier.
1583 Therefore, try to open without it. This can lead to a race
1584 condition so that when you delete and re-create the file, the
1585 file might be opened in text mode, but then, you shouldn't
1586 delete the file in the first place. */
1587 if (da_file == 0)
1588 da_file = fopen (ptr->filename, "r+");
1589 if (da_file == 0)
1590 {
1591 fprintf (stderr, "arc profiling: Can't open output file %s.\n",
1592 ptr->filename);
1593 continue;
1594 }
1595
1596 /* After a fork, another process might try to read and/or write
1597 the same file simultanously. So if we can, lock the file to
1598 avoid race conditions. */
1599#if defined (TARGET_HAS_F_SETLKW)
1600 {
1601 struct flock s_flock;
1602
1603 s_flock.l_type = F_WRLCK;
1604 s_flock.l_whence = SEEK_SET;
1605 s_flock.l_start = 0;
1606 s_flock.l_len = 1;
1607 s_flock.l_pid = getpid ();
1608
1609 while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
1610 && errno == EINTR);
1611 }
1612#endif
1613
1614 /* If the file is not empty, and the number of counts in it is the
1615 same, then merge them in. */
1616 firstchar = fgetc (da_file);
1617 if (firstchar == EOF)
1618 {
1619 if (ferror (da_file))
1620 {
1621 fprintf (stderr, "arc profiling: Can't read output file ");
1622 perror (ptr->filename);
1623 }
1624 }
1625 else
6e5fdcc0 1626 {
1627 long n_counts = 0;
6e5fdcc0 1628
255b8f3f 1629 if (ungetc (firstchar, da_file) == EOF)
1630 rewind (da_file);
6e5fdcc0 1631 if (__read_long (&n_counts, da_file, 8) != 0)
1632 {
1633 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
1634 ptr->filename);
1635 continue;
1636 }
1637
1638 if (n_counts == ptr->ncounts)
1639 {
1640 int i;
1641
1642 for (i = 0; i < n_counts; i++)
1643 {
1644 long v = 0;
6e5fdcc0 1645
1646 if (__read_long (&v, da_file, 8) != 0)
1647 {
1648 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
1649 ptr->filename);
1650 break;
1651 }
1652 ptr->counts[i] += v;
1653 }
1654 }
1655
6e5fdcc0 1656 }
1657
255b8f3f 1658 rewind (da_file);
1659
ad87de1e 1660 /* ??? Should first write a header to the file. Preferably, a 4 byte
6e5fdcc0 1661 magic number, 4 bytes containing the time the program was
1662 compiled, 4 bytes containing the last modification time of the
1663 source file, and 4 bytes indicating the compiler options used.
1664
1665 That way we can easily verify that the proper source/executable/
1666 data file combination is being used from gcov. */
1667
1668 if (__write_long (ptr->ncounts, da_file, 8) != 0)
1669 {
1670
1671 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
1672 ptr->filename);
1673 }
1674 else
1675 {
1676 int j;
1677 long *count_ptr = ptr->counts;
1678 int ret = 0;
1679 for (j = ptr->ncounts; j > 0; j--)
1680 {
1681 if (__write_long (*count_ptr, da_file, 8) != 0)
1682 {
1683 ret=1;
1684 break;
1685 }
1686 count_ptr++;
1687 }
1688 if (ret)
1689 fprintf (stderr, "arc profiling: Error writing output file %s.\n",
1690 ptr->filename);
1691 }
1692
1693 if (fclose (da_file) == EOF)
1694 fprintf (stderr, "arc profiling: Error closing output file %s.\n",
1695 ptr->filename);
1696 }
1697
1698 return;
1699 }
1700
1701 /* Must be basic block profiling. Emit a human readable output file. */
1702
1703 file = fopen ("bb.out", "a");
543e7f6c 1704
1705 if (!file)
1706 perror ("bb.out");
1707
1708 else
1709 {
1710 struct bb *ptr;
1711
1712 /* This is somewhat type incorrect, but it avoids worrying about
1713 exactly where time.h is included from. It should be ok unless
eb6cf4cb 1714 a void * differs from other pointer formats, or if sizeof (long)
543e7f6c 1715 is < sizeof (time_t). It would be nice if we could assume the
1716 use of rationale standards here. */
1717
eb6cf4cb 1718 time ((void *) &time_value);
543e7f6c 1719 fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
1720
1721 /* We check the length field explicitly in order to allow compatibility
1722 with older GCC's which did not provide it. */
1723
a92771b8 1724 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
543e7f6c 1725 {
1726 int i;
71218a21 1727 int func_p = (ptr->nwords >= (long) sizeof (struct bb)
6e5fdcc0 1728 && ptr->nwords <= 1000
1729 && ptr->functions);
543e7f6c 1730 int line_p = (func_p && ptr->line_nums);
1731 int file_p = (func_p && ptr->filenames);
6e5fdcc0 1732 int addr_p = (ptr->addresses != 0);
543e7f6c 1733 long ncounts = ptr->ncounts;
1734 long cnt_max = 0;
1735 long line_max = 0;
1736 long addr_max = 0;
1737 int file_len = 0;
1738 int func_len = 0;
1739 int blk_len = num_digits (ncounts, 10);
1740 int cnt_len;
1741 int line_len;
1742 int addr_len;
1743
1744 fprintf (file, "File %s, %ld basic blocks \n\n",
1745 ptr->filename, ncounts);
1746
1747 /* Get max values for each field. */
1748 for (i = 0; i < ncounts; i++)
1749 {
1750 const char *p;
1751 int len;
1752
1753 if (cnt_max < ptr->counts[i])
1754 cnt_max = ptr->counts[i];
1755
71218a21 1756 if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
543e7f6c 1757 addr_max = ptr->addresses[i];
1758
1759 if (line_p && line_max < ptr->line_nums[i])
1760 line_max = ptr->line_nums[i];
1761
1762 if (func_p)
1763 {
1764 p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
1765 len = strlen (p);
1766 if (func_len < len)
1767 func_len = len;
1768 }
1769
1770 if (file_p)
1771 {
1772 p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
1773 len = strlen (p);
1774 if (file_len < len)
1775 file_len = len;
1776 }
1777 }
1778
1779 addr_len = num_digits (addr_max, 16);
1780 cnt_len = num_digits (cnt_max, 10);
1781 line_len = num_digits (line_max, 10);
1782
1783 /* Now print out the basic block information. */
1784 for (i = 0; i < ncounts; i++)
1785 {
1786 fprintf (file,
6e5fdcc0 1787 " Block #%*d: executed %*ld time(s)",
543e7f6c 1788 blk_len, i+1,
6e5fdcc0 1789 cnt_len, ptr->counts[i]);
1790
1791 if (addr_p)
1792 fprintf (file, " address= 0x%.*lx", addr_len,
1793 ptr->addresses[i]);
543e7f6c 1794
1795 if (func_p)
dcaf9054 1796 fprintf (file, " function= %-*s", func_len,
543e7f6c 1797 (ptr->functions[i]) ? ptr->functions[i] : "<none>");
1798
1799 if (line_p)
36b7c7ce 1800 fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
543e7f6c 1801
1802 if (file_p)
dcaf9054 1803 fprintf (file, " file= %s",
543e7f6c 1804 (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
1805
1806 fprintf (file, "\n");
1807 }
1808
1809 fprintf (file, "\n");
1810 fflush (file);
1811 }
1812
1813 fprintf (file, "\n\n");
1814 fclose (file);
1815 }
1816}
1817
1818void
1819__bb_init_func (struct bb *blocks)
1820{
1821 /* User is supposed to check whether the first word is non-0,
a92771b8 1822 but just in case.... */
543e7f6c 1823
1824 if (blocks->zero_word)
1825 return;
1826
543e7f6c 1827 /* Initialize destructor. */
1828 if (!bb_head)
3da2e097 1829 atexit (__bb_exit_func);
543e7f6c 1830
1831 /* Set up linked list. */
1832 blocks->zero_word = 1;
1833 blocks->next = bb_head;
1834 bb_head = blocks;
1835}
1836
255b8f3f 1837/* Called before fork or exec - write out profile information gathered so
1838 far and reset it to zero. This avoids duplication or loss of the
1839 profile information gathered so far. */
1840void
1841__bb_fork_func (void)
1842{
1843 struct bb *ptr;
1844
1845 __bb_exit_func ();
1846 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
1847 {
1848 long i;
1849 for (i = ptr->ncounts - 1; i >= 0; i--)
1850 ptr->counts[i] = 0;
1851 }
1852}
1853
eb6cf4cb 1854#ifndef MACHINE_STATE_SAVE
1855#define MACHINE_STATE_SAVE(ID)
1856#endif
1857#ifndef MACHINE_STATE_RESTORE
1858#define MACHINE_STATE_RESTORE(ID)
1859#endif
1860
a92771b8 1861/* Number of buckets in hashtable of basic block addresses. */
eb6cf4cb 1862
1863#define BB_BUCKETS 311
1864
a92771b8 1865/* Maximum length of string in file bb.in. */
eb6cf4cb 1866
1867#define BBINBUFSIZE 500
1868
eb6cf4cb 1869struct bb_edge
1870{
1871 struct bb_edge *next;
1872 unsigned long src_addr;
1873 unsigned long dst_addr;
1874 unsigned long count;
1875};
1876
1877enum bb_func_mode
1878{
1879 TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
1880};
1881
1882struct bb_func
1883{
1884 struct bb_func *next;
1885 char *funcname;
1886 char *filename;
1887 enum bb_func_mode mode;
1888};
1889
1890/* This is the connection to the outside world.
1891 The BLOCK_PROFILER macro must set __bb.blocks
a92771b8 1892 and __bb.blockno. */
eb6cf4cb 1893
1894struct {
1895 unsigned long blockno;
1896 struct bb *blocks;
1897} __bb;
1898
1899/* Vars to store addrs of source and destination basic blocks
a92771b8 1900 of a jump. */
eb6cf4cb 1901
1902static unsigned long bb_src = 0;
1903static unsigned long bb_dst = 0;
1904
a92771b8 1905static FILE *bb_tracefile = (FILE *) 0;
1906static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
1907static struct bb_func *bb_func_head = (struct bb_func *) 0;
eb6cf4cb 1908static unsigned long bb_callcount = 0;
1909static int bb_mode = 0;
1910
a92771b8 1911static unsigned long *bb_stack = (unsigned long *) 0;
eb6cf4cb 1912static size_t bb_stacksize = 0;
1913
1914static int reported = 0;
1915
1916/* Trace modes:
1917Always : Print execution frequencies of basic blocks
1918 to file bb.out.
1919bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
1920bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
1921bb_mode & 4 != 0 : Cut call instructions from basic block flow.
1922bb_mode & 8 != 0 : Insert return instructions in basic block flow.
1923*/
1924
1925#ifdef HAVE_POPEN
1926
1927/*#include <sys/types.h>*/
1928#include <sys/stat.h>
1929/*#include <malloc.h>*/
1930
a92771b8 1931/* Commands executed by gopen. */
eb6cf4cb 1932
1933#define GOPENDECOMPRESS "gzip -cd "
1934#define GOPENCOMPRESS "gzip -c >"
1935
1936/* Like fopen but pipes through gzip. mode may only be "r" or "w".
1937 If it does not compile, simply replace gopen by fopen and delete
a92771b8 1938 '.gz' from any first parameter to gopen. */
eb6cf4cb 1939
1940static FILE *
4f195a89 1941gopen (char *fn, char *mode)
eb6cf4cb 1942{
1943 int use_gzip;
1944 char *p;
1945
1946 if (mode[1])
a92771b8 1947 return (FILE *) 0;
eb6cf4cb 1948
1949 if (mode[0] != 'r' && mode[0] != 'w')
a92771b8 1950 return (FILE *) 0;
eb6cf4cb 1951
1952 p = fn + strlen (fn)-1;
0bc644e0 1953 use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
1954 || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
eb6cf4cb 1955
1956 if (use_gzip)
1957 {
1958 if (mode[0]=='r')
1959 {
1960 FILE *f;
a92771b8 1961 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1962 + sizeof (GOPENDECOMPRESS));
eb6cf4cb 1963 strcpy (s, GOPENDECOMPRESS);
1964 strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
1965 f = popen (s, mode);
1966 free (s);
1967 return f;
1968 }
1969
1970 else
1971 {
1972 FILE *f;
a92771b8 1973 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1974 + sizeof (GOPENCOMPRESS));
eb6cf4cb 1975 strcpy (s, GOPENCOMPRESS);
1976 strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
1977 if (!(f = popen (s, mode)))
1978 f = fopen (s, mode);
1979 free (s);
1980 return f;
1981 }
1982 }
1983
1984 else
1985 return fopen (fn, mode);
1986}
1987
1988static int
4f195a89 1989gclose (FILE *f)
eb6cf4cb 1990{
1991 struct stat buf;
1992
2998886d 1993 if (f != 0)
eb6cf4cb 1994 {
1995 if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
1996 return pclose (f);
1997
1998 return fclose (f);
1999 }
2000 return 0;
2001}
2002
2003#endif /* HAVE_POPEN */
2004
a92771b8 2005/* Called once per program. */
eb6cf4cb 2006
2007static void
71218a21 2008__bb_exit_trace_func (void)
eb6cf4cb 2009{
2010 FILE *file = fopen ("bb.out", "a");
2011 struct bb_func *f;
eb6cf4cb 2012 struct bb *b;
2013
2014 if (!file)
2015 perror ("bb.out");
2016
2017 if (bb_mode & 1)
2018 {
2019 if (!bb_tracefile)
2020 perror ("bbtrace");
2021 else
2022#ifdef HAVE_POPEN
2023 gclose (bb_tracefile);
2024#else
2025 fclose (bb_tracefile);
2026#endif /* HAVE_POPEN */
2027 }
2028
a92771b8 2029 /* Check functions in `bb.in'. */
eb6cf4cb 2030
2031 if (file)
2032 {
2033 long time_value;
2034 const struct bb_func *p;
2035 int printed_something = 0;
2036 struct bb *ptr;
2037 long blk;
2038
a92771b8 2039 /* This is somewhat type incorrect. */
eb6cf4cb 2040 time ((void *) &time_value);
2041
a92771b8 2042 for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
eb6cf4cb 2043 {
a92771b8 2044 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
eb6cf4cb 2045 {
7d27e4c9 2046 if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
eb6cf4cb 2047 continue;
2048 for (blk = 0; blk < ptr->ncounts; blk++)
2049 {
2050 if (!strcmp (p->funcname, ptr->functions[blk]))
2051 goto found;
2052 }
2053 }
2054
2055 if (!printed_something)
2056 {
2057 fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
2058 printed_something = 1;
2059 }
2060
2061 fprintf (file, "\tFunction %s", p->funcname);
2062 if (p->filename)
2063 fprintf (file, " of file %s", p->filename);
2064 fprintf (file, "\n" );
2065
2066found: ;
2067 }
2068
2069 if (printed_something)
2070 fprintf (file, "\n");
2071
2072 }
2073
2074 if (bb_mode & 2)
2075 {
2076 if (!bb_hashbuckets)
2077 {
2078 if (!reported)
2079 {
2080 fprintf (stderr, "Profiler: out of memory\n");
2081 reported = 1;
2082 }
2083 return;
2084 }
2085
2086 else if (file)
2087 {
2088 long time_value;
2089 int i;
2090 unsigned long addr_max = 0;
2091 unsigned long cnt_max = 0;
2092 int cnt_len;
2093 int addr_len;
2094
2095 /* This is somewhat type incorrect, but it avoids worrying about
2096 exactly where time.h is included from. It should be ok unless
2097 a void * differs from other pointer formats, or if sizeof (long)
2098 is < sizeof (time_t). It would be nice if we could assume the
2099 use of rationale standards here. */
2100
2101 time ((void *) &time_value);
2102 fprintf (file, "Basic block jump tracing");
2103
2104 switch (bb_mode & 12)
2105 {
2106 case 0:
2107 fprintf (file, " (with call)");
2108 break;
2109
2110 case 4:
a92771b8 2111 /* Print nothing. */
eb6cf4cb 2112 break;
2113
2114 case 8:
2115 fprintf (file, " (with call & ret)");
2116 break;
2117
2118 case 12:
2119 fprintf (file, " (with ret)");
2120 break;
2121 }
2122
2123 fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
2124
2125 for (i = 0; i < BB_BUCKETS; i++)
2126 {
2127 struct bb_edge *bucket = bb_hashbuckets[i];
2128 for ( ; bucket; bucket = bucket->next )
2129 {
2130 if (addr_max < bucket->src_addr)
2131 addr_max = bucket->src_addr;
2132 if (addr_max < bucket->dst_addr)
2133 addr_max = bucket->dst_addr;
2134 if (cnt_max < bucket->count)
2135 cnt_max = bucket->count;
2136 }
2137 }
2138 addr_len = num_digits (addr_max, 16);
2139 cnt_len = num_digits (cnt_max, 10);
2140
2141 for ( i = 0; i < BB_BUCKETS; i++)
2142 {
2143 struct bb_edge *bucket = bb_hashbuckets[i];
2144 for ( ; bucket; bucket = bucket->next )
2145 {
641b112b 2146 fprintf (file,
2147 "Jump from block 0x%.*lx to block 0x%.*lx executed %*lu time(s)\n",
eb6cf4cb 2148 addr_len, bucket->src_addr,
2149 addr_len, bucket->dst_addr,
2150 cnt_len, bucket->count);
2151 }
2152 }
2153
2154 fprintf (file, "\n");
2155
2156 }
2157 }
2158
2159 if (file)
2160 fclose (file);
2161
a92771b8 2162 /* Free allocated memory. */
eb6cf4cb 2163
2164 f = bb_func_head;
2165 while (f)
2166 {
2167 struct bb_func *old = f;
2168
2169 f = f->next;
2170 if (old->funcname) free (old->funcname);
2171 if (old->filename) free (old->filename);
2172 free (old);
2173 }
2174
2175 if (bb_stack)
2176 free (bb_stack);
2177
2178 if (bb_hashbuckets)
2179 {
2180 int i;
2181
2182 for (i = 0; i < BB_BUCKETS; i++)
2183 {
2184 struct bb_edge *old, *bucket = bb_hashbuckets[i];
2185
2186 while (bucket)
2187 {
2188 old = bucket;
2189 bucket = bucket->next;
2190 free (old);
2191 }
2192 }
2193 free (bb_hashbuckets);
2194 }
2195
2196 for (b = bb_head; b; b = b->next)
2197 if (b->flags) free (b->flags);
2198}
2199
a92771b8 2200/* Called once per program. */
eb6cf4cb 2201
2202static void
71218a21 2203__bb_init_prg (void)
eb6cf4cb 2204{
eb6cf4cb 2205 FILE *file;
2206 char buf[BBINBUFSIZE];
2207 const char *p;
2208 const char *pos;
2209 enum bb_func_mode m;
7014838c 2210 int i;
eb6cf4cb 2211
eb6cf4cb 2212 /* Initialize destructor. */
3da2e097 2213 atexit (__bb_exit_func);
eb6cf4cb 2214
2215 if (!(file = fopen ("bb.in", "r")))
2216 return;
2217
641b112b 2218 while(fgets (buf, BBINBUFSIZE, file) != 0)
eb6cf4cb 2219 {
641b112b 2220 i = strlen (buf);
2221 if (buf[i] == '\n')
2222 buf[i--] = '\0';
2223
eb6cf4cb 2224 p = buf;
2225 if (*p == '-')
2226 {
2227 m = TRACE_OFF;
2228 p++;
2229 }
2230 else
2231 {
2232 m = TRACE_ON;
2233 }
2234 if (!strcmp (p, "__bb_trace__"))
2235 bb_mode |= 1;
2236 else if (!strcmp (p, "__bb_jumps__"))
2237 bb_mode |= 2;
2238 else if (!strcmp (p, "__bb_hidecall__"))
2239 bb_mode |= 4;
2240 else if (!strcmp (p, "__bb_showret__"))
2241 bb_mode |= 8;
2242 else
2243 {
a92771b8 2244 struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
eb6cf4cb 2245 if (f)
2246 {
2247 unsigned long l;
2248 f->next = bb_func_head;
7d27e4c9 2249 if ((pos = strchr (p, ':')))
eb6cf4cb 2250 {
a92771b8 2251 if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
eb6cf4cb 2252 continue;
2253 strcpy (f->funcname, pos+1);
2254 l = pos-p;
a92771b8 2255 if ((f->filename = (char *) malloc (l+1)))
eb6cf4cb 2256 {
2257 strncpy (f->filename, p, l);
2258 f->filename[l] = '\0';
2259 }
2260 else
a92771b8 2261 f->filename = (char *) 0;
eb6cf4cb 2262 }
2263 else
2264 {
a92771b8 2265 if (!(f->funcname = (char *) malloc (strlen (p)+1)))
eb6cf4cb 2266 continue;
2267 strcpy (f->funcname, p);
a92771b8 2268 f->filename = (char *) 0;
eb6cf4cb 2269 }
2270 f->mode = m;
2271 bb_func_head = f;
2272 }
2273 }
2274 }
2275 fclose (file);
2276
2277#ifdef HAVE_POPEN
2278
2279 if (bb_mode & 1)
2280 bb_tracefile = gopen ("bbtrace.gz", "w");
2281
2282#else
2283
2284 if (bb_mode & 1)
2285 bb_tracefile = fopen ("bbtrace", "w");
2286
2287#endif /* HAVE_POPEN */
2288
2289 if (bb_mode & 2)
2290 {
2291 bb_hashbuckets = (struct bb_edge **)
2292 malloc (BB_BUCKETS * sizeof (struct bb_edge *));
2293 if (bb_hashbuckets)
7014838c 2294 /* Use a loop here rather than calling bzero to avoid having to
2295 conditionalize its existance. */
2296 for (i = 0; i < BB_BUCKETS; i++)
2297 bb_hashbuckets[i] = 0;
eb6cf4cb 2298 }
2299
2300 if (bb_mode & 12)
2301 {
2302 bb_stacksize = 10;
2303 bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
2304 }
2305
3da2e097 2306 /* Initialize destructor. */
2307 atexit (__bb_exit_trace_func);
eb6cf4cb 2308}
2309
a92771b8 2310/* Called upon entering a basic block. */
eb6cf4cb 2311
2312void
71218a21 2313__bb_trace_func (void)
eb6cf4cb 2314{
2315 struct bb_edge *bucket;
2316
2317 MACHINE_STATE_SAVE("1")
2318
2319 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2320 goto skip;
2321
2322 bb_dst = __bb.blocks->addresses[__bb.blockno];
2323 __bb.blocks->counts[__bb.blockno]++;
2324
2325 if (bb_tracefile)
2326 {
2327 fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
2328 }
2329
2330 if (bb_hashbuckets)
2331 {
2332 struct bb_edge **startbucket, **oldnext;
2333
0bc644e0 2334 oldnext = startbucket
2335 = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
eb6cf4cb 2336 bucket = *startbucket;
2337
2338 for (bucket = *startbucket; bucket;
2339 oldnext = &(bucket->next), bucket = *oldnext)
2340 {
0bc644e0 2341 if (bucket->src_addr == bb_src
2342 && bucket->dst_addr == bb_dst)
eb6cf4cb 2343 {
2344 bucket->count++;
2345 *oldnext = bucket->next;
2346 bucket->next = *startbucket;
2347 *startbucket = bucket;
2348 goto ret;
2349 }
2350 }
2351
2352 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2353
2354 if (!bucket)
2355 {
2356 if (!reported)
2357 {
2358 fprintf (stderr, "Profiler: out of memory\n");
2359 reported = 1;
2360 }
2361 }
2362
2363 else
2364 {
2365 bucket->src_addr = bb_src;
2366 bucket->dst_addr = bb_dst;
2367 bucket->next = *startbucket;
2368 *startbucket = bucket;
2369 bucket->count = 1;
2370 }
2371 }
2372
2373ret:
2374 bb_src = bb_dst;
2375
2376skip:
2377 ;
2378
2379 MACHINE_STATE_RESTORE("1")
2380
2381}
2382
a92771b8 2383/* Called when returning from a function and `__bb_showret__' is set. */
eb6cf4cb 2384
2385static void
71218a21 2386__bb_trace_func_ret (void)
eb6cf4cb 2387{
2388 struct bb_edge *bucket;
2389
2390 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2391 goto skip;
2392
2393 if (bb_hashbuckets)
2394 {
2395 struct bb_edge **startbucket, **oldnext;
2396
0bc644e0 2397 oldnext = startbucket
2398 = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
eb6cf4cb 2399 bucket = *startbucket;
2400
2401 for (bucket = *startbucket; bucket;
2402 oldnext = &(bucket->next), bucket = *oldnext)
2403 {
0bc644e0 2404 if (bucket->src_addr == bb_dst
2405 && bucket->dst_addr == bb_src)
eb6cf4cb 2406 {
2407 bucket->count++;
2408 *oldnext = bucket->next;
2409 bucket->next = *startbucket;
2410 *startbucket = bucket;
2411 goto ret;
2412 }
2413 }
2414
2415 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2416
2417 if (!bucket)
2418 {
2419 if (!reported)
2420 {
2421 fprintf (stderr, "Profiler: out of memory\n");
2422 reported = 1;
2423 }
2424 }
2425
2426 else
2427 {
2428 bucket->src_addr = bb_dst;
2429 bucket->dst_addr = bb_src;
2430 bucket->next = *startbucket;
2431 *startbucket = bucket;
2432 bucket->count = 1;
2433 }
2434 }
2435
2436ret:
2437 bb_dst = bb_src;
2438
2439skip:
2440 ;
2441
2442}
2443
a92771b8 2444/* Called upon entering the first function of a file. */
eb6cf4cb 2445
2446static void
4f195a89 2447__bb_init_file (struct bb *blocks)
eb6cf4cb 2448{
2449
2450 const struct bb_func *p;
2451 long blk, ncounts = blocks->ncounts;
2452 const char **functions = blocks->functions;
2453
2454 /* Set up linked list. */
2455 blocks->zero_word = 1;
2456 blocks->next = bb_head;
2457 bb_head = blocks;
2458
2459 blocks->flags = 0;
0bc644e0 2460 if (!bb_func_head
2461 || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
eb6cf4cb 2462 return;
2463
2464 for (blk = 0; blk < ncounts; blk++)
2465 blocks->flags[blk] = 0;
2466
2467 for (blk = 0; blk < ncounts; blk++)
2468 {
2469 for (p = bb_func_head; p; p = p->next)
2470 {
0bc644e0 2471 if (!strcmp (p->funcname, functions[blk])
2472 && (!p->filename || !strcmp (p->filename, blocks->filename)))
eb6cf4cb 2473 {
2474 blocks->flags[blk] |= p->mode;
2475 }
2476 }
2477 }
2478
2479}
2480
a92771b8 2481/* Called when exiting from a function. */
eb6cf4cb 2482
2483void
71218a21 2484__bb_trace_ret (void)
eb6cf4cb 2485{
2486
2487 MACHINE_STATE_SAVE("2")
2488
2489 if (bb_callcount)
2490 {
2491 if ((bb_mode & 12) && bb_stacksize > bb_callcount)
2492 {
2493 bb_src = bb_stack[bb_callcount];
2494 if (bb_mode & 8)
2495 __bb_trace_func_ret ();
2496 }
2497
2498 bb_callcount -= 1;
2499 }
2500
2501 MACHINE_STATE_RESTORE("2")
2502
2503}
2504
a92771b8 2505/* Called when entering a function. */
eb6cf4cb 2506
2507void
4f195a89 2508__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
eb6cf4cb 2509{
2510 static int trace_init = 0;
2511
2512 MACHINE_STATE_SAVE("3")
2513
2514 if (!blocks->zero_word)
2515 {
2516 if (!trace_init)
2517 {
2518 trace_init = 1;
2519 __bb_init_prg ();
2520 }
2521 __bb_init_file (blocks);
2522 }
2523
2524 if (bb_callcount)
2525 {
2526
2527 bb_callcount += 1;
2528
2529 if (bb_mode & 12)
2530 {
2531 if (bb_callcount >= bb_stacksize)
2532 {
2533 size_t newsize = bb_callcount + 100;
2534
2535 bb_stack = (unsigned long *) realloc (bb_stack, newsize);
2536 if (! bb_stack)
2537 {
2538 if (!reported)
2539 {
2540 fprintf (stderr, "Profiler: out of memory\n");
2541 reported = 1;
2542 }
2543 bb_stacksize = 0;
2544 goto stack_overflow;
2545 }
2546 bb_stacksize = newsize;
2547 }
2548 bb_stack[bb_callcount] = bb_src;
2549
2550 if (bb_mode & 4)
2551 bb_src = 0;
2552
2553 }
2554
2555stack_overflow:;
2556
2557 }
2558
2559 else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
2560 {
2561 bb_callcount = 1;
2562 bb_src = 0;
2563
2564 if (bb_stack)
2565 bb_stack[bb_callcount] = bb_src;
2566 }
2567
2568 MACHINE_STATE_RESTORE("3")
2569}
2570
6e94b6ac 2571#endif /* not inhibit_libc */
2572#endif /* not BLOCK_PROFILER_CODE */
2573#endif /* L_bb */
62c63f32 2574\f
62c63f32 2575#ifdef L_shtab
2576unsigned int __shtab[] = {
2577 0x00000001, 0x00000002, 0x00000004, 0x00000008,
2578 0x00000010, 0x00000020, 0x00000040, 0x00000080,
2579 0x00000100, 0x00000200, 0x00000400, 0x00000800,
2580 0x00001000, 0x00002000, 0x00004000, 0x00008000,
2581 0x00010000, 0x00020000, 0x00040000, 0x00080000,
2582 0x00100000, 0x00200000, 0x00400000, 0x00800000,
2583 0x01000000, 0x02000000, 0x04000000, 0x08000000,
2584 0x10000000, 0x20000000, 0x40000000, 0x80000000
2585 };
2586#endif
2587\f
2588#ifdef L_clear_cache
2589/* Clear part of an instruction cache. */
2590
2591#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
2592
2593void
abbe5a3d 2594__clear_cache (char *beg __attribute__((__unused__)),
2595 char *end __attribute__((__unused__)))
62c63f32 2596{
efa58f1a 2597#ifdef CLEAR_INSN_CACHE
2598 CLEAR_INSN_CACHE (beg, end);
2599#else
62c63f32 2600#ifdef INSN_CACHE_SIZE
2601 static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
5233d224 2602 static int initialized;
62c63f32 2603 int offset;
10307b3e 2604 void *start_addr
2605 void *end_addr;
71218a21 2606 typedef (*function_ptr) (void);
62c63f32 2607
2608#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
2609 /* It's cheaper to clear the whole cache.
2610 Put in a series of jump instructions so that calling the beginning
2611 of the cache will clear the whole thing. */
2612
2613 if (! initialized)
2614 {
2615 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2616 & -INSN_CACHE_LINE_WIDTH);
2617 int end_ptr = ptr + INSN_CACHE_SIZE;
2618
2619 while (ptr < end_ptr)
2620 {
2621 *(INSTRUCTION_TYPE *)ptr
2622 = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
2623 ptr += INSN_CACHE_LINE_WIDTH;
2624 }
a92771b8 2625 *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
62c63f32 2626
2627 initialized = 1;
2628 }
2629
2630 /* Call the beginning of the sequence. */
2631 (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2632 & -INSN_CACHE_LINE_WIDTH))
2633 ());
2634
2635#else /* Cache is large. */
2636
2637 if (! initialized)
2638 {
2639 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2640 & -INSN_CACHE_LINE_WIDTH);
2641
2642 while (ptr < (int) array + sizeof array)
2643 {
2644 *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
2645 ptr += INSN_CACHE_LINE_WIDTH;
2646 }
2647
2648 initialized = 1;
2649 }
2650
2651 /* Find the location in array that occupies the same cache line as BEG. */
2652
2653 offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
2654 start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
2655 & -INSN_CACHE_PLANE_SIZE)
2656 + offset);
2657
2658 /* Compute the cache alignment of the place to stop clearing. */
2659#if 0 /* This is not needed for gcc's purposes. */
2660 /* If the block to clear is bigger than a cache plane,
2661 we clear the entire cache, and OFFSET is already correct. */
2662 if (end < beg + INSN_CACHE_PLANE_SIZE)
2663#endif
2664 offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
2665 & -INSN_CACHE_LINE_WIDTH)
2666 & (INSN_CACHE_PLANE_SIZE - 1));
2667
2668#if INSN_CACHE_DEPTH > 1
2669 end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset;
2670 if (end_addr <= start_addr)
2671 end_addr += INSN_CACHE_PLANE_SIZE;
2672
2673 for (plane = 0; plane < INSN_CACHE_DEPTH; plane++)
2674 {
2675 int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE;
2676 int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE;
2677
2678 while (addr != stop)
2679 {
2680 /* Call the return instruction at ADDR. */
2681 ((function_ptr) addr) ();
2682
2683 addr += INSN_CACHE_LINE_WIDTH;
2684 }
2685 }
2686#else /* just one plane */
2687 do
2688 {
2689 /* Call the return instruction at START_ADDR. */
2690 ((function_ptr) start_addr) ();
2691
2692 start_addr += INSN_CACHE_LINE_WIDTH;
2693 }
2694 while ((start_addr % INSN_CACHE_SIZE) != offset);
2695#endif /* just one plane */
2696#endif /* Cache is large */
2697#endif /* Cache exists */
efa58f1a 2698#endif /* CLEAR_INSN_CACHE */
62c63f32 2699}
2700
2701#endif /* L_clear_cache */
2702\f
2703#ifdef L_trampoline
2704
2705/* Jump to a trampoline, loading the static chain address. */
2706
f1959ea2 2707#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN)
8e782fcd 2708
71218a21 2709long
2710getpagesize (void)
e30b7e49 2711{
2712#ifdef _ALPHA_
2713 return 8192;
2714#else
2715 return 4096;
2716#endif
2717}
2718
1ec6144c 2719#ifdef __i386__
bdf89453 2720extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
2721#endif
2722
38e911c3 2723int
2724mprotect (char *addr, int len, int prot)
e30b7e49 2725{
2726 int np, op;
2727
38e911c3 2728 if (prot == 7)
2729 np = 0x40;
2730 else if (prot == 5)
2731 np = 0x20;
2732 else if (prot == 4)
2733 np = 0x10;
2734 else if (prot == 3)
2735 np = 0x04;
2736 else if (prot == 1)
2737 np = 0x02;
2738 else if (prot == 0)
2739 np = 0x01;
e30b7e49 2740
2741 if (VirtualProtect (addr, len, np, &op))
2742 return 0;
2743 else
2744 return -1;
e30b7e49 2745}
2746
f1959ea2 2747#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
e30b7e49 2748
62c63f32 2749#ifdef TRANSFER_FROM_TRAMPOLINE
2750TRANSFER_FROM_TRAMPOLINE
2751#endif
2752
e4f25d58 2753#if defined (NeXT) && defined (__MACH__)
2754
2755/* Make stack executable so we can call trampolines on stack.
2756 This is called from INITIALIZE_TRAMPOLINE in next.h. */
4a197d83 2757#ifdef NeXTStep21
2758 #include <mach.h>
2759#else
2760 #include <mach/mach.h>
2761#endif
e4f25d58 2762
2763void
4f195a89 2764__enable_execute_stack (char *addr)
e4f25d58 2765{
2766 kern_return_t r;
2767 char *eaddr = addr + TRAMPOLINE_SIZE;
2768 vm_address_t a = (vm_address_t) addr;
2769
2770 /* turn on execute access on stack */
2771 r = vm_protect (task_self (), a, TRAMPOLINE_SIZE, FALSE, VM_PROT_ALL);
2772 if (r != KERN_SUCCESS)
2773 {
2774 mach_error("vm_protect VM_PROT_ALL", r);
2775 exit(1);
2776 }
2777
2778 /* We inline the i-cache invalidation for speed */
2779
2780#ifdef CLEAR_INSN_CACHE
2781 CLEAR_INSN_CACHE (addr, eaddr);
2782#else
2783 __clear_cache ((int) addr, (int) eaddr);
2784#endif
2785}
2786
2787#endif /* defined (NeXT) && defined (__MACH__) */
2788
62c63f32 2789#ifdef __convex__
2790
2791/* Make stack executable so we can call trampolines on stack.
2792 This is called from INITIALIZE_TRAMPOLINE in convex.h. */
2793
2794#include <sys/mman.h>
2795#include <sys/vmparam.h>
2796#include <machine/machparam.h>
2797
2798void
71218a21 2799__enable_execute_stack (void)
62c63f32 2800{
2801 int fp;
2802 static unsigned lowest = USRSTACK;
2803 unsigned current = (unsigned) &fp & -NBPG;
2804
2805 if (lowest > current)
2806 {
2807 unsigned len = lowest - current;
2808 mremap (current, &len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
2809 lowest = current;
2810 }
2811
a92771b8 2812 /* Clear instruction cache in case an old trampoline is in it. */
62c63f32 2813 asm ("pich");
2814}
2815#endif /* __convex__ */
b13ae905 2816
183c280a 2817#ifdef __sysV88__
767a6cf5 2818
a92771b8 2819/* Modified from the convex -code above. */
767a6cf5 2820
2821#include <sys/param.h>
2822#include <errno.h>
2823#include <sys/m88kbcs.h>
2824
2825void
71218a21 2826__enable_execute_stack (void)
767a6cf5 2827{
2828 int save_errno;
2829 static unsigned long lowest = USRSTACK;
2830 unsigned long current = (unsigned long) &save_errno & -NBPC;
2831
2832 /* Ignore errno being set. memctl sets errno to EINVAL whenever the
2833 address is seen as 'negative'. That is the case with the stack. */
2834
2835 save_errno=errno;
2836 if (lowest > current)
2837 {
2838 unsigned len=lowest-current;
2839 memctl(current,len,MCT_TEXT);
2840 lowest = current;
2841 }
2842 else
2843 memctl(current,NBPC,MCT_TEXT);
2844 errno=save_errno;
2845}
2846
183c280a 2847#endif /* __sysV88__ */
767a6cf5 2848
220345e0 2849#ifdef __sysV68__
2850
2851#include <sys/signal.h>
2852#include <errno.h>
2853
2854/* Motorola forgot to put memctl.o in the libp version of libc881.a,
2855 so define it here, because we need it in __clear_insn_cache below */
aaa36d7c 2856/* On older versions of this OS, no memctl or MCT_TEXT are defined;
2857 hence we enable this stuff only if MCT_TEXT is #define'd. */
220345e0 2858
aaa36d7c 2859#ifdef MCT_TEXT
220345e0 2860asm("\n\
2861 global memctl\n\
2862memctl:\n\
2863 movq &75,%d0\n\
2864 trap &0\n\
2865 bcc.b noerror\n\
2866 jmp cerror%\n\
2867noerror:\n\
2868 movq &0,%d0\n\
2869 rts");
aaa36d7c 2870#endif
220345e0 2871
2872/* Clear instruction cache so we can call trampolines on stack.
2873 This is called from FINALIZE_TRAMPOLINE in mot3300.h. */
2874
2875void
71218a21 2876__clear_insn_cache (void)
220345e0 2877{
aaa36d7c 2878#ifdef MCT_TEXT
220345e0 2879 int save_errno;
2880
2881 /* Preserve errno, because users would be surprised to have
2882 errno changing without explicitly calling any system-call. */
2883 save_errno = errno;
2884
2885 /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache.
2886 No need to use an address derived from _start or %sp, as 0 works also. */
2887 memctl(0, 4096, MCT_TEXT);
2888 errno = save_errno;
aaa36d7c 2889#endif
220345e0 2890}
2891
2892#endif /* __sysV68__ */
2893
b13ae905 2894#ifdef __pyr__
2895
eb213bff 2896#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
b13ae905 2897#include <stdio.h>
2898#include <sys/mman.h>
2899#include <sys/types.h>
2900#include <sys/param.h>
2901#include <sys/vmmac.h>
2902
2903/* Modified from the convex -code above.
a92771b8 2904 mremap promises to clear the i-cache. */
b13ae905 2905
2906void
71218a21 2907__enable_execute_stack (void)
b13ae905 2908{
2909 int fp;
2910 if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ,
2911 PROT_READ|PROT_WRITE|PROT_EXEC))
2912 {
2913 perror ("mprotect in __enable_execute_stack");
2914 fflush (stderr);
2915 abort ();
2916 }
2917}
2918#endif /* __pyr__ */
568326b2 2919
2920#if defined (sony_news) && defined (SYSTYPE_BSD)
2921
2922#include <stdio.h>
2923#include <sys/types.h>
2924#include <sys/param.h>
2925#include <syscall.h>
2926#include <machine/sysnews.h>
2927
2928/* cacheflush function for NEWS-OS 4.2.
2929 This function is called from trampoline-initialize code
2930 defined in config/mips/mips.h. */
2931
2932void
4f195a89 2933cacheflush (char *beg, int size, int flag)
568326b2 2934{
2935 if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
2936 {
2937 perror ("cache_flush");
2938 fflush (stderr);
2939 abort ();
2940 }
2941}
2942
2943#endif /* sony_news */
62c63f32 2944#endif /* L_trampoline */
2945\f
e678484c 2946#ifndef __CYGWIN__
62c63f32 2947#ifdef L__main
2948
2949#include "gbl-ctors.h"
0c945479 2950/* Some systems use __main in a way incompatible with its use in gcc, in these
2951 cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
2952 give the same symbol without quotes for an alternative entry point. You
a92771b8 2953 must define both, or neither. */
0c945479 2954#ifndef NAME__MAIN
2955#define NAME__MAIN "__main"
2956#define SYMBOL__MAIN __main
2957#endif
62c63f32 2958
8313a782 2959#ifdef INIT_SECTION_ASM_OP
2960#undef HAS_INIT_SECTION
2961#define HAS_INIT_SECTION
2962#endif
2963
2964#if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
a6881cf3 2965
2966/* Some ELF crosses use crtstuff.c to provide __CTOR_LIST__, but use this
2967 code to run constructors. In that case, we need to handle EH here, too. */
2968
2969#ifdef EH_FRAME_SECTION
2970#include "frame.h"
2971extern unsigned char __EH_FRAME_BEGIN__[];
2972#endif
2973
62c63f32 2974/* Run all the global destructors on exit from the program. */
2975
2976void
71218a21 2977__do_global_dtors (void)
62c63f32 2978{
3a158972 2979#ifdef DO_GLOBAL_DTORS_BODY
2980 DO_GLOBAL_DTORS_BODY;
2981#else
113f9ca7 2982 static func_ptr *p = __DTOR_LIST__ + 1;
2983 while (*p)
2984 {
2985 p++;
2986 (*(p-1)) ();
2987 }
3a158972 2988#endif
09f02799 2989#if defined (EH_FRAME_SECTION) && !defined (HAS_INIT_SECTION)
3b1bfdbe 2990 {
2991 static int completed = 0;
2992 if (! completed)
2993 {
2994 completed = 1;
2995 __deregister_frame_info (__EH_FRAME_BEGIN__);
2996 }
2997 }
a6881cf3 2998#endif
62c63f32 2999}
b7c87ff2 3000#endif
62c63f32 3001
8313a782 3002#ifndef HAS_INIT_SECTION
62c63f32 3003/* Run all the global constructors on entry to the program. */
3004
62c63f32 3005void
71218a21 3006__do_global_ctors (void)
62c63f32 3007{
a6881cf3 3008#ifdef EH_FRAME_SECTION
3009 {
3010 static struct object object;
3011 __register_frame_info (__EH_FRAME_BEGIN__, &object);
3012 }
3013#endif
62c63f32 3014 DO_GLOBAL_CTORS_BODY;
bd84a596 3015 atexit (__do_global_dtors);
62c63f32 3016}
8313a782 3017#endif /* no HAS_INIT_SECTION */
62c63f32 3018
8313a782 3019#if !defined (HAS_INIT_SECTION) || defined (INVOKE__main)
62c63f32 3020/* Subroutine called automatically by `main'.
3021 Compiling a global function named `main'
3022 produces an automatic call to this function at the beginning.
3023
3024 For many systems, this routine calls __do_global_ctors.
3025 For systems which support a .init section we use the .init section
3026 to run __do_global_ctors, so we need not do anything here. */
3027
3028void
0c945479 3029SYMBOL__MAIN ()
62c63f32 3030{
3031 /* Support recursive calls to `main': run initializers just once. */
5233d224 3032 static int initialized;
62c63f32 3033 if (! initialized)
3034 {
3035 initialized = 1;
3036 __do_global_ctors ();
3037 }
3038}
8313a782 3039#endif /* no HAS_INIT_SECTION or INVOKE__main */
62c63f32 3040
3041#endif /* L__main */
e678484c 3042#endif /* __CYGWIN__ */
62c63f32 3043\f
a0f2694a 3044#ifdef L_ctors
62c63f32 3045
3046#include "gbl-ctors.h"
3047
3048/* Provide default definitions for the lists of constructors and
98ae6ed6 3049 destructors, so that we don't get linker errors. These symbols are
3050 intentionally bss symbols, so that gld and/or collect will provide
3051 the right values. */
62c63f32 3052
3053/* We declare the lists here with two elements each,
98ae6ed6 3054 so that they are valid empty lists if no other definition is loaded.
3055
3056 If we are using the old "set" extensions to have the gnu linker
3057 collect ctors and dtors, then we __CTOR_LIST__ and __DTOR_LIST__
3058 must be in the bss/common section.
3059
3060 Long term no port should use those extensions. But many still do. */
b13ae905 3061#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
98ae6ed6 3062#if defined (ASM_OUTPUT_CONSTRUCTOR) || defined (USE_COLLECT2)
d069195c 3063func_ptr __CTOR_LIST__[2] = {0, 0};
3064func_ptr __DTOR_LIST__[2] = {0, 0};
98ae6ed6 3065#else
3066func_ptr __CTOR_LIST__[2];
3067func_ptr __DTOR_LIST__[2];
3068#endif
b13ae905 3069#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
a0f2694a 3070#endif /* L_ctors */
3071\f
3072#ifdef L_exit
3073
3074#include "gbl-ctors.h"
62c63f32 3075
2fea28a7 3076#ifdef NEED_ATEXIT
2fea28a7 3077
9f030acd 3078#ifndef ON_EXIT
62c63f32 3079
2fea28a7 3080# include <errno.h>
3081
2998886d 3082static func_ptr *atexit_chain = 0;
2fea28a7 3083static long atexit_chain_length = 0;
3084static volatile long last_atexit_chain_slot = -1;
3085
3da2e097 3086int
3087atexit (func_ptr func)
2fea28a7 3088{
3089 if (++last_atexit_chain_slot == atexit_chain_length)
3090 {
3091 atexit_chain_length += 32;
3092 if (atexit_chain)
3223d5a7 3093 atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
3094 * sizeof (func_ptr));
2fea28a7 3095 else
3223d5a7 3096 atexit_chain = (func_ptr *) malloc (atexit_chain_length
3097 * sizeof (func_ptr));
2fea28a7 3098 if (! atexit_chain)
3099 {
3100 atexit_chain_length = 0;
3101 last_atexit_chain_slot = -1;
3102 errno = ENOMEM;
3103 return (-1);
3104 }
3105 }
3106 atexit_chain[last_atexit_chain_slot] = func;
3107 return (0);
3108}
2fea28a7 3109
71218a21 3110extern void _cleanup (void);
3111extern void _exit (int) __attribute__ ((__noreturn__));
62c63f32 3112
3113void
4f195a89 3114exit (int status)
62c63f32 3115{
2fea28a7 3116 if (atexit_chain)
3117 {
3118 for ( ; last_atexit_chain_slot-- >= 0; )
3119 {
3120 (*atexit_chain[last_atexit_chain_slot + 1]) ();
2998886d 3121 atexit_chain[last_atexit_chain_slot + 1] = 0;
2fea28a7 3122 }
3123 free (atexit_chain);
2998886d 3124 atexit_chain = 0;
2fea28a7 3125 }
62c63f32 3126#ifdef EXIT_BODY
3127 EXIT_BODY;
3128#else
3129 _cleanup ();
3130#endif
3131 _exit (status);
3132}
3133
9f030acd 3134#else /* ON_EXIT */
729610a1 3135
3da2e097 3136/* Simple; we just need a wrapper for ON_EXIT. */
3137int
3138atexit (func_ptr func)
729610a1 3139{
3da2e097 3140 return ON_EXIT (func);
729610a1 3141}
3da2e097 3142
9f030acd 3143#endif /* ON_EXIT */
3da2e097 3144#endif /* NEED_ATEXIT */
62c63f32 3145
3146#endif /* L_exit */
3147\f
99962ae2 3148#ifdef L_eh
485aaaaf 3149
58febf9e 3150#include "gthr.h"
485aaaaf 3151
732992fa 3152/* Shared exception handling support routines. */
485aaaaf 3153
694ec519 3154void
71218a21 3155__default_terminate (void)
694ec519 3156{
3157 abort ();
3158}
3159
71218a21 3160void (*__terminate_func)(void) __attribute__ ((__noreturn__)) =
3161 __default_terminate;
694ec519 3162
89bf85ce 3163void __attribute__((__noreturn__))
71218a21 3164__terminate (void)
694ec519 3165{
3166 (*__terminate_func)();
3167}
3168
447a9eb9 3169void *
3170__throw_type_match (void *catch_type, void *throw_type, void *obj)
3171{
3172#if 0
3173 printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n",
3174 catch_type, throw_type);
3175#endif
3176 if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
3177 return obj;
3178 return 0;
3179}
3180
3181void
71218a21 3182__empty (void)
447a9eb9 3183{
3184}
3185\f
732992fa 3186
011a7f23 3187/* Include definitions of EH context and table layout */
3188
3189#include "eh-common.h"
485d67d3 3190#ifndef inhibit_libc
6a4a2724 3191#include <stdio.h>
485d67d3 3192#endif
732992fa 3193
732992fa 3194/* Allocate and return a new EH context structure. */
3195
71218a21 3196#if __GTHREADS
732992fa 3197static void *
71218a21 3198new_eh_context (void)
732992fa 3199{
a79fbe95 3200 struct eh_full_context {
3201 struct eh_context c;
3202 void *top_elt[2];
3203 } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
3204
3205 if (! ehfc)
732992fa 3206 __terminate ();
3207
a79fbe95 3208 memset (ehfc, 0, sizeof *ehfc);
732992fa 3209
a79fbe95 3210 ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt;
732992fa 3211
a79fbe95 3212 /* This should optimize out entirely. This should always be true,
3213 but just in case it ever isn't, don't allow bogus code to be
3214 generated. */
3215
3216 if ((void*)(&ehfc->c) != (void*)ehfc)
3217 __terminate ();
3218
3219 return &ehfc->c;
732992fa 3220}
3221
732992fa 3222static __gthread_key_t eh_context_key;
3223
3224/* Destructor for struct eh_context. */
3225static void
3226eh_context_free (void *ptr)
3227{
58febf9e 3228 __gthread_key_dtor (eh_context_key, ptr);
732992fa 3229 if (ptr)
3230 free (ptr);
3231}
3232#endif
3233
3234/* Pointer to function to return EH context. */
3235
71218a21 3236static struct eh_context *eh_context_initialize (void);
3237static struct eh_context *eh_context_static (void);
732992fa 3238#if __GTHREADS
71218a21 3239static struct eh_context *eh_context_specific (void);
732992fa 3240#endif
3241
71218a21 3242static struct eh_context *(*get_eh_context) (void) = &eh_context_initialize;
732992fa 3243
3244/* Routine to get EH context.
3245 This one will simply call the function pointer. */
3246
3247void *
71218a21 3248__get_eh_context (void)
732992fa 3249{
3250 return (void *) (*get_eh_context) ();
3251}
3252
3253/* Get and set the language specific info pointer. */
3254
3255void **
71218a21 3256__get_eh_info (void)
732992fa 3257{
3258 struct eh_context *eh = (*get_eh_context) ();
725cde8f 3259 return &eh->info;
732992fa 3260}
3261\f
695e919b 3262#ifdef DWARF2_UNWIND_INFO
3263static int dwarf_reg_size_table_initialized = 0;
1e98be2e 3264static char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
695e919b 3265
3266static void
71218a21 3267init_reg_size_table (void)
695e919b 3268{
3269 __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
3270 dwarf_reg_size_table_initialized = 1;
3271}
3272#endif
3273
732992fa 3274#if __GTHREADS
3275static void
71218a21 3276eh_threads_initialize (void)
732992fa 3277{
3278 /* Try to create the key. If it fails, revert to static method,
3279 otherwise start using thread specific EH contexts. */
3280 if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0)
3281 get_eh_context = &eh_context_specific;
3282 else
3283 get_eh_context = &eh_context_static;
3284}
3285#endif /* no __GTHREADS */
3286
3287/* Initialize EH context.
3288 This will be called only once, since we change GET_EH_CONTEXT
3289 pointer to another routine. */
3290
3291static struct eh_context *
71218a21 3292eh_context_initialize (void)
732992fa 3293{
3294#if __GTHREADS
3295
3296 static __gthread_once_t once = __GTHREAD_ONCE_INIT;
f8809366 3297 /* Make sure that get_eh_context does not point to us anymore.
3298 Some systems have dummy thread routines in their libc that
3299 return a success (Solaris 2.6 for example). */
3300 if (__gthread_once (&once, eh_threads_initialize) != 0
3301 || get_eh_context == &eh_context_initialize)
58febf9e 3302 {
3303 /* Use static version of EH context. */
3304 get_eh_context = &eh_context_static;
3305 }
695e919b 3306#ifdef DWARF2_UNWIND_INFO
3307 {
3308 static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
3309 if (__gthread_once (&once_regsizes, init_reg_size_table) != 0
3310 || ! dwarf_reg_size_table_initialized)
3311 init_reg_size_table ();
3312 }
3313#endif
732992fa 3314
3315#else /* no __GTHREADS */
3316
3317 /* Use static version of EH context. */
3318 get_eh_context = &eh_context_static;
3319
695e919b 3320#ifdef DWARF2_UNWIND_INFO
3321 init_reg_size_table ();
3322#endif
3323
732992fa 3324#endif /* no __GTHREADS */
3325
3326 return (*get_eh_context) ();
3327}
3328
3329/* Return a static EH context. */
3330
3331static struct eh_context *
71218a21 3332eh_context_static (void)
732992fa 3333{
c058cad4 3334 static struct eh_context eh;
3335 static int initialized;
a79fbe95 3336 static void *top_elt[2];
3337
c058cad4 3338 if (! initialized)
3339 {
3340 initialized = 1;
3341 memset (&eh, 0, sizeof eh);
3342 eh.dynamic_handler_chain = top_elt;
3343 }
3344 return &eh;
732992fa 3345}
3346
3347#if __GTHREADS
3348/* Return a thread specific EH context. */
3349
3350static struct eh_context *
71218a21 3351eh_context_specific (void)
732992fa 3352{
3353 struct eh_context *eh;
3354 eh = (struct eh_context *) __gthread_getspecific (eh_context_key);
3355 if (! eh)
3356 {
3357 eh = new_eh_context ();
3358 if (__gthread_setspecific (eh_context_key, (void *) eh) != 0)
3359 __terminate ();
3360 }
3361
3362 return eh;
3363}
a54788b7 3364#endif /* __GTHREADS */
732992fa 3365\f
d3e1375a 3366/* Support routines for alloc/free during exception handling */
3367
3368/* __eh_alloc and __eh_free attempt allocation using malloc, but fall back to
3369 the small arena in the eh_context. This is needed because throwing an
3370 out-of-memory exception would fail otherwise. The emergency space is
3371 allocated in blocks of size EH_ALLOC_ALIGN, the
3372 minimum allocation being two blocks. A bitmask indicates which blocks
3373 have been allocated. To indicate the size of an allocation, the bit for
3374 the final block is not set. Hence each allocation is a run of 1s followed
3375 by a zero. */
3376void *
3377__eh_alloc (size_t size)
3378{
3379 void *p;
3380
3381 if (!size)
3382 abort();
3383 p = malloc (size);
3384 if (p == 0)
3385 {
3386 struct eh_context *eh = __get_eh_context ();
3387 unsigned blocks = (size + EH_ALLOC_ALIGN - 1) / EH_ALLOC_ALIGN;
3388 unsigned real_mask = eh->alloc_mask | (eh->alloc_mask << 1);
3389 unsigned our_mask;
3390 unsigned ix;
3391
3392 if (blocks > EH_ALLOC_SIZE / EH_ALLOC_ALIGN)
3393 __terminate ();
3394 blocks += blocks == 1;
3395 our_mask = (1 << blocks) - 1;
3396
3397 for (ix = EH_ALLOC_SIZE / EH_ALLOC_ALIGN - blocks; ix; ix--)
3398 if (! ((real_mask >> ix) & our_mask))
3399 {
3400 /* found some space */
3401 p = &eh->alloc_buffer[ix * EH_ALLOC_ALIGN];
3402 eh->alloc_mask |= (our_mask >> 1) << ix;
3403 return p;
3404 }
3405 __terminate ();
3406 }
3407 return p;
3408}
3409
3410/* Free the memory for an cp_eh_info and associated exception, given
3411 a pointer to the cp_eh_info. */
3412void
3413__eh_free (void *p)
3414{
3415 struct eh_context *eh = __get_eh_context ();
3416
3417 ptrdiff_t diff = (char *)p - &eh->alloc_buffer[0];
3418 if (diff >= 0 && diff < EH_ALLOC_SIZE)
3419 {
3420 unsigned mask = eh->alloc_mask;
3421 unsigned bit = 1 << (diff / EH_ALLOC_ALIGN);
3422
3423 do
3424 {
3425 mask ^= bit;
3426 bit <<= 1;
3427 }
3428 while (mask & bit);
3429 eh->alloc_mask = mask;
3430 }
3431 else
3432 free (p);
3433}
3434\f
447a9eb9 3435/* Support routines for setjmp/longjmp exception handling. */
3436
694ec519 3437/* Calls to __sjthrow are generated by the compiler when an exception
3438 is raised when using the setjmp/longjmp exception handling codegen
3439 method. */
3440
732992fa 3441#ifdef DONT_USE_BUILTIN_SETJMP
17785858 3442extern void longjmp (void *, int);
732992fa 3443#endif
694ec519 3444
3445/* Routine to get the head of the current thread's dynamic handler chain
732992fa 3446 use for exception handling. */
694ec519 3447
3448void ***
71218a21 3449__get_dynamic_handler_chain (void)
694ec519 3450{
732992fa 3451 struct eh_context *eh = (*get_eh_context) ();
725cde8f 3452 return &eh->dynamic_handler_chain;
694ec519 3453}
3454
3455/* This is used to throw an exception when the setjmp/longjmp codegen
3456 method is used for exception handling.
3457
732992fa 3458 We call __terminate if there are no handlers left. Otherwise we run the
3459 cleanup actions off the dynamic cleanup stack, and pop the top of the
3460 dynamic handler chain, and use longjmp to transfer back to the associated
3461 handler. */
694ec519 3462
3463void
71218a21 3464__sjthrow (void)
694ec519 3465{
732992fa 3466 struct eh_context *eh = (*get_eh_context) ();
3467 void ***dhc = &eh->dynamic_handler_chain;
694ec519 3468 void *jmpbuf;
3469 void (*func)(void *, int);
3470 void *arg;
71218a21 3471 /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
3472 void ***cleanup = (void***)&(*dhc)[1];
694ec519 3473
3474 /* If there are any cleanups in the chain, run them now. */
3475 if (cleanup[0])
3476 {
3477 double store[200];
3478 void **buf = (void**)store;
3479 buf[1] = 0;
3480 buf[0] = (*dhc);
3481
3482 /* try { */
17785858 3483#ifdef DONT_USE_BUILTIN_SETJMP
694ec519 3484 if (! setjmp (&buf[2]))
17785858 3485#else
3486 if (! __builtin_setjmp (&buf[2]))
3487#endif
694ec519 3488 {
3489 *dhc = buf;
3490 while (cleanup[0])
3491 {
3492 func = (void(*)(void*, int))cleanup[0][1];
3493 arg = (void*)cleanup[0][2];
3494
3495 /* Update this before running the cleanup. */
3496 cleanup[0] = (void **)cleanup[0][0];
3497
3498 (*func)(arg, 2);
3499 }
3500 *dhc = buf[0];
3501 }
3502 /* catch (...) */
3503 else
3504 {
3505 __terminate ();
3506 }
3507 }
3508
3509 /* We must call terminate if we try and rethrow an exception, when
3510 there is no exception currently active and when there are no
3511 handlers left. */
a79fbe95 3512 if (! eh->info || (*dhc)[0] == 0)
694ec519 3513 __terminate ();
3514
3515 /* Find the jmpbuf associated with the top element of the dynamic
3516 handler chain. The jumpbuf starts two words into the buffer. */
3517 jmpbuf = &(*dhc)[2];
3518
3519 /* Then we pop the top element off the dynamic handler chain. */
3520 *dhc = (void**)(*dhc)[0];
3521
3522 /* And then we jump to the handler. */
3523
17785858 3524#ifdef DONT_USE_BUILTIN_SETJMP
694ec519 3525 longjmp (jmpbuf, 1);
17785858 3526#else
3527 __builtin_longjmp (jmpbuf, 1);
694ec519 3528#endif
3529}
3530
3531/* Run cleanups on the dynamic cleanup stack for the current dynamic
3532 handler, then pop the handler off the dynamic handler stack, and
3533 then throw. This is used to skip the first handler, and transfer
3534 control to the next handler in the dynamic handler stack. */
3535
3536void
71218a21 3537__sjpopnthrow (void)
694ec519 3538{
732992fa 3539 struct eh_context *eh = (*get_eh_context) ();
3540 void ***dhc = &eh->dynamic_handler_chain;
694ec519 3541 void (*func)(void *, int);
3542 void *arg;
71218a21 3543 /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
3544 void ***cleanup = (void***)&(*dhc)[1];
694ec519 3545
3546 /* If there are any cleanups in the chain, run them now. */
3547 if (cleanup[0])
3548 {
3549 double store[200];
3550 void **buf = (void**)store;
3551 buf[1] = 0;
3552 buf[0] = (*dhc);
3553
3554 /* try { */
17785858 3555#ifdef DONT_USE_BUILTIN_SETJMP
694ec519 3556 if (! setjmp (&buf[2]))
17785858 3557#else
3558 if (! __builtin_setjmp (&buf[2]))
3559#endif
694ec519 3560 {
3561 *dhc = buf;
3562 while (cleanup[0])
3563 {
3564 func = (void(*)(void*, int))cleanup[0][1];
3565 arg = (void*)cleanup[0][2];
3566
3567 /* Update this before running the cleanup. */
3568 cleanup[0] = (void **)cleanup[0][0];
3569
3570 (*func)(arg, 2);
3571 }
3572 *dhc = buf[0];
3573 }
3574 /* catch (...) */
3575 else
3576 {
3577 __terminate ();
3578 }
3579 }
3580
3581 /* Then we pop the top element off the dynamic handler chain. */
3582 *dhc = (void**)(*dhc)[0];
3583
3584 __sjthrow ();
3585}
447a9eb9 3586\f
3587/* Support code for all exception region-based exception handling. */
3588
15f6e7d9 3589int
3590__eh_rtime_match (void *rtime)
3591{
3592 void *info;
3593 __eh_matcher matcher;
3594 void *ret;
3595
3596 info = *(__get_eh_info ());
3597 matcher = ((__eh_info *)info)->match_function;
6a4a2724 3598 if (! matcher)
3599 {
485d67d3 3600#ifndef inhibit_libc
6a4a2724 3601 fprintf (stderr, "Internal Compiler Bug: No runtime type matcher.");
485d67d3 3602#endif
6a4a2724 3603 return 0;
3604 }
15f6e7d9 3605 ret = (*matcher) (info, rtime, (void *)0);
6a4a2724 3606 return (ret != NULL);
15f6e7d9 3607}
3608
447a9eb9 3609/* This value identifies the place from which an exception is being
3610 thrown. */
3611
447a9eb9 3612#ifdef EH_TABLE_LOOKUP
3613
3614EH_TABLE_LOOKUP
694ec519 3615
447a9eb9 3616#else
3617
cd03a192 3618#ifdef DWARF2_UNWIND_INFO
99962ae2 3619
9e2ffae5 3620/* Return the table version of an exception descriptor */
3621
3622short
3623__get_eh_table_version (exception_descriptor *table)
3624{
3625 return table->lang.version;
3626}
3627
3628/* Return the originating table language of an exception descriptor */
3629
3630short
3631__get_eh_table_language (exception_descriptor *table)
3632{
3633 return table->lang.language;
3634}
3635
447a9eb9 3636/* This routine takes a PC and a pointer to the exception region TABLE for
3637 its translation unit, and returns the address of the exception handler
3638 associated with the closest exception table handler entry associated
3639 with that PC, or 0 if there are no table entries the PC fits in.
3640
3641 In the advent of a tie, we have to give the last entry, as it represents
3642 an inner block. */
3643
173f0bec 3644static void *
3645old_find_exception_handler (void *pc, old_exception_table *table)
3646{
3647 if (table)
3648 {
3649 int pos;
3650 int best = -1;
3651
3652 /* We can't do a binary search because the table isn't guaranteed
3653 to be sorted from function to function. */
3654 for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
3655 {
3656 if (table[pos].start_region <= pc && table[pos].end_region > pc)
3657 {
3658 /* This can apply. Make sure it is at least as small as
3659 the previous best. */
3660 if (best == -1 || (table[pos].end_region <= table[best].end_region
3661 && table[pos].start_region >= table[best].start_region))
3662 best = pos;
3663 }
3664 /* But it is sorted by starting PC within a function. */
3665 else if (best >= 0 && table[pos].start_region > pc)
3666 break;
3667 }
3668 if (best != -1)
3669 return table[best].exception_handler;
3670 }
3671
3672 return (void *) 0;
3673}
3674
d63ea2f2 3675/* find_exception_handler finds the correct handler, if there is one, to
3676 handle an exception.
3677 returns a pointer to the handler which controlled should be transferred
3678 to, or NULL if there is nothing left.
3679 Parameters:
3680 PC - pc where the exception originates. If this is a rethrow,
3681 then this starts out as a pointer to the exception table
3682 entry we wish to rethrow out of.
3683 TABLE - exception table for the current module.
3684 EH_INFO - eh info pointer for this exception.
3685 RETHROW - 1 if this is a rethrow. (see incoming value of PC).
3686 CLEANUP - returned flag indicating whether this is a cleanup handler.
3687*/
447a9eb9 3688static void *
d63ea2f2 3689find_exception_handler (void *pc, exception_descriptor *table,
3690 __eh_info *eh_info, int rethrow, int *cleanup)
447a9eb9 3691{
d63ea2f2 3692
3693 void *retval = NULL;
3694 *cleanup = 1;
447a9eb9 3695 if (table)
3696 {
d63ea2f2 3697 int pos = 0;
011a7f23 3698 /* The new model assumed the table is sorted inner-most out so the
3699 first region we find which matches is the correct one */
3700
011a7f23 3701 exception_table *tab = &(table->table[0]);
3702
3703 /* Subtract 1 from the PC to avoid hitting the next region */
d63ea2f2 3704 if (rethrow)
3705 {
3706 /* pc is actually the region table entry to rethrow out of */
3707 pos = ((exception_table *) pc) - tab;
3708 pc = ((exception_table *) pc)->end_region - 1;
3709
3710 /* The label is always on the LAST handler entry for a region,
3711 so we know the next entry is a different region, even if the
3712 addresses are the same. Make sure its not end of table tho. */
3713 if (tab[pos].start_region != (void *) -1)
3714 pos++;
3715 }
3716 else
3717 pc--;
011a7f23 3718
3719 /* We can't do a binary search because the table is in inner-most
3720 to outermost address ranges within functions */
d63ea2f2 3721 for ( ; tab[pos].start_region != (void *) -1; pos++)
011a7f23 3722 {
3723 if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
3724 {
3725 if (tab[pos].match_info)
3726 {
d63ea2f2 3727 __eh_matcher matcher = eh_info->match_function;
011a7f23 3728 /* match info but no matcher is NOT a match */
3729 if (matcher)
3730 {
d63ea2f2 3731 void *ret = (*matcher)((void *) eh_info,
3732 tab[pos].match_info, table);
3733 if (ret)
3734 {
3735 if (retval == NULL)
3736 retval = tab[pos].exception_handler;
3737 *cleanup = 0;
3738 break;
3739 }
011a7f23 3740 }
3741 }
3742 else
d63ea2f2 3743 {
3744 if (retval == NULL)
3745 retval = tab[pos].exception_handler;
3746 }
011a7f23 3747 }
3748 }
447a9eb9 3749 }
d63ea2f2 3750 return retval;
447a9eb9 3751}
cd03a192 3752#endif /* DWARF2_UNWIND_INFO */
447a9eb9 3753#endif /* EH_TABLE_LOOKUP */
3754\f
725cde8f 3755#ifdef DWARF2_UNWIND_INFO
447a9eb9 3756/* Support code for exception handling using static unwind information. */
3757
3758#include "frame.h"
3759
3760/* This type is used in get_reg and put_reg to deal with ABIs where a void*
3761 is smaller than a word, such as the Irix 6 n32 ABI. We cast twice to
3762 avoid a warning about casting between int and pointer of different
3763 sizes. */
3764
3765typedef int ptr_type __attribute__ ((mode (pointer)));
3766
ec37ccb4 3767#ifdef INCOMING_REGNO
3768/* Is the saved value for register REG in frame UDATA stored in a register
3769 window in the previous frame? */
3770
3771/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT. This allows us
3772 to use the macro here. One wonders, though, that perhaps TARGET_FLAT
3773 compiled functions won't work with the frame-unwind stuff here.
3774 Perhaps the entireity of in_reg_window should be conditional on having
3775 seen a DW_CFA_GNU_window_save? */
3776#define target_flags 0
3777
3778static int
3779in_reg_window (int reg, frame_state *udata)
3780{
3781 if (udata->saved[reg] == REG_SAVED_REG)
3782 return INCOMING_REGNO (reg) == reg;
3783 if (udata->saved[reg] != REG_SAVED_OFFSET)
3784 return 0;
3785
3786#ifdef STACK_GROWS_DOWNWARD
3787 return udata->reg_or_offset[reg] > 0;
3788#else
3789 return udata->reg_or_offset[reg] < 0;
3790#endif
3791}
3792#else
71218a21 3793static inline int
3794in_reg_window (int reg __attribute__ ((__unused__)),
3795 frame_state *udata __attribute__ ((__unused__)))
3796{
3797 return 0;
3798}
ec37ccb4 3799#endif /* INCOMING_REGNO */
3800
3801/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
447a9eb9 3802 frame called by UDATA or 0. */
3803
ec37ccb4 3804static word_type *
3805get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
447a9eb9 3806{
ec37ccb4 3807 while (udata->saved[reg] == REG_SAVED_REG)
3808 {
3809 reg = udata->reg_or_offset[reg];
3810 if (in_reg_window (reg, udata))
3811 {
3812 udata = sub_udata;
3813 sub_udata = NULL;
3814 }
3815 }
447a9eb9 3816 if (udata->saved[reg] == REG_SAVED_OFFSET)
ec37ccb4 3817 return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
447a9eb9 3818 else
3819 abort ();
3820}
3821
ec37ccb4 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
447a9eb9 3831/* Overwrite the saved value for register REG in frame UDATA with VAL. */
3832
ec37ccb4 3833static inline void
447a9eb9 3834put_reg (unsigned reg, void *val, frame_state *udata)
3835{
ec37ccb4 3836 *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
447a9eb9 3837}
3838
5ff00a1d 3839/* Copy the saved value for register REG from frame UDATA to frame
3840 TARGET_UDATA. Unlike the previous two functions, this can handle
3841 registers that are not one word large. */
3842
3843static void
3844copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
3845{
ec37ccb4 3846 word_type *preg = get_reg_addr (reg, udata, NULL);
3847 word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
3848
695e919b 3849 memcpy (ptreg, preg, dwarf_reg_size_table [reg]);
5ff00a1d 3850}
3851
ec37ccb4 3852/* Retrieve the return address for frame UDATA. */
447a9eb9 3853
3854static inline void *
3855get_return_addr (frame_state *udata, frame_state *sub_udata)
3856{
3857 return __builtin_extract_return_addr
3858 (get_reg (udata->retaddr_column, udata, sub_udata));
3859}
3860
3861/* Overwrite the return address for frame UDATA with VAL. */
3862
3863static inline void
3864put_return_addr (void *val, frame_state *udata)
3865{
3866 val = __builtin_frob_return_addr (val);
3867 put_reg (udata->retaddr_column, val, udata);
3868}
3869
3870/* Given the current frame UDATA and its return address PC, return the
3871 information about the calling frame in CALLER_UDATA. */
3872
3873static void *
3874next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
3875{
3876 caller_udata = __frame_state_for (pc, caller_udata);
3877 if (! caller_udata)
3878 return 0;
3879
3880 /* Now go back to our caller's stack frame. If our caller's CFA register
3881 was saved in our stack frame, restore it; otherwise, assume the CFA
3882 register is SP and restore it to our CFA value. */
3883 if (udata->saved[caller_udata->cfa_reg])
3884 caller_udata->cfa = get_reg (caller_udata->cfa_reg, udata, 0);
3885 else
3886 caller_udata->cfa = udata->cfa;
4b72e226 3887 if (caller_udata->indirect)
f07e9100 3888 caller_udata->cfa = * (void **) ((unsigned char *)caller_udata->cfa
3889 + caller_udata->base_offset);
447a9eb9 3890 caller_udata->cfa += caller_udata->cfa_offset;
3891
3892 return caller_udata;
3893}
3894
d63ea2f2 3895/* Hook to call before __terminate if only cleanup handlers remain. */
3896void
71218a21 3897__unwinding_cleanup (void)
447a9eb9 3898{
d63ea2f2 3899}
447a9eb9 3900
d63ea2f2 3901/* throw_helper performs some of the common grunt work for a throw. This
3902 routine is called by throw and rethrows. This is pretty much split
3903 out from the old __throw routine. An addition has been added which allows
3904 for a dummy call to a routine __unwinding_cleanup() when there are nothing
3905 but cleanups remaining. This allows a debugger to examine the state
3906 at which the throw was executed, before any cleanups, rather than
fb3ed2fa 3907 at the terminate point after the stack has been unwound.
3908
3909 EH is the current eh_context structure.
3910 PC is the address of the call to __throw.
3911 MY_UDATA is the unwind information for __throw.
3912 OFFSET_P is where we return the SP adjustment offset. */
447a9eb9 3913
d63ea2f2 3914static void *
71218a21 3915throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata,
3916 long *offset_p)
d63ea2f2 3917{
fb3ed2fa 3918 frame_state ustruct2, *udata = &ustruct2;
d63ea2f2 3919 frame_state ustruct;
3920 frame_state *sub_udata = &ustruct;
3921 void *saved_pc = pc;
3922 void *handler;
71218a21 3923 void *handler_p = 0;
3924 void *pc_p = 0;
d63ea2f2 3925 frame_state saved_ustruct;
3926 int new_eh_model;
3927 int cleanup = 0;
3928 int only_cleanup = 0;
3929 int rethrow = 0;
3930 int saved_state = 0;
fb3ed2fa 3931 long args_size;
d63ea2f2 3932 __eh_info *eh_info = (__eh_info *)eh->info;
3933
3934 /* Do we find a handler based on a re-throw PC? */
3935 if (eh->table_index != (void *) 0)
3936 rethrow = 1;
3937
fb3ed2fa 3938 memcpy (udata, my_udata, sizeof (*udata));
3939
d63ea2f2 3940 handler = (void *) 0;
447a9eb9 3941 for (;;)
3942 {
3943 frame_state *p = udata;
3944 udata = next_stack_level (pc, udata, sub_udata);
3945 sub_udata = p;
3946
3947 /* If we couldn't find the next frame, we lose. */
3948 if (! udata)
3949 break;
3950
173f0bec 3951 if (udata->eh_ptr == NULL)
d63ea2f2 3952 new_eh_model = 0;
173f0bec 3953 else
d63ea2f2 3954 new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
173f0bec 3955 runtime_id_field == NEW_EH_RUNTIME);
3956
d63ea2f2 3957 if (rethrow)
3958 {
3959 rethrow = 0;
3960 handler = find_exception_handler (eh->table_index, udata->eh_ptr,
3961 eh_info, 1, &cleanup);
3962 eh->table_index = (void *)0;
3963 }
173f0bec 3964 else
d63ea2f2 3965 if (new_eh_model)
3966 handler = find_exception_handler (pc, udata->eh_ptr, eh_info,
3967 0, &cleanup);
3968 else
3969 handler = old_find_exception_handler (pc, udata->eh_ptr);
3970
3971 /* If we found one, we can stop searching, if its not a cleanup.
3972 for cleanups, we save the state, and keep looking. This allows
3973 us to call a debug hook if there are nothing but cleanups left. */
447a9eb9 3974 if (handler)
2ba28c7a 3975 {
3976 if (cleanup)
3977 {
3978 if (!saved_state)
3979 {
3980 saved_ustruct = *udata;
3981 handler_p = handler;
3982 pc_p = pc;
3983 saved_state = 1;
3984 only_cleanup = 1;
3985 }
3986 }
3987 else
3988 {
3989 only_cleanup = 0;
3990 break;
3991 }
3992 }
447a9eb9 3993
24db2725 3994 /* Otherwise, we continue searching. We subtract 1 from PC to avoid
3995 hitting the beginning of the next region. */
3996 pc = get_return_addr (udata, sub_udata) - 1;
447a9eb9 3997 }
3998
d63ea2f2 3999 if (saved_state)
4000 {
4001 udata = &saved_ustruct;
4002 handler = handler_p;
4003 pc = pc_p;
4004 if (only_cleanup)
4005 __unwinding_cleanup ();
4006 }
4007
447a9eb9 4008 /* If we haven't found a handler by now, this is an unhandled
4009 exception. */
d63ea2f2 4010 if (! handler)
4011 __terminate();
447a9eb9 4012
011a7f23 4013 eh->handler_label = handler;
011a7f23 4014
fb3ed2fa 4015 args_size = udata->args_size;
4016
732992fa 4017 if (pc == saved_pc)
447a9eb9 4018 /* We found a handler in the throw context, no need to unwind. */
4019 udata = my_udata;
4020 else
4021 {
4022 int i;
447a9eb9 4023
4024 /* Unwind all the frames between this one and the handler by copying
4025 their saved register values into our register save slots. */
4026
4027 /* Remember the PC where we found the handler. */
4028 void *handler_pc = pc;
4029
4030 /* Start from the throw context again. */
732992fa 4031 pc = saved_pc;
447a9eb9 4032 memcpy (udata, my_udata, sizeof (*udata));
4033
4034 while (pc != handler_pc)
4035 {
4036 frame_state *p = udata;
4037 udata = next_stack_level (pc, udata, sub_udata);
4038 sub_udata = p;
4039
1e98be2e 4040 for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
73eac312 4041 if (i != udata->retaddr_column && udata->saved[i])
447a9eb9 4042 {
447a9eb9 4043 /* If you modify the saved value of the return address
4044 register on the SPARC, you modify the return address for
4045 your caller's frame. Don't do that here, as it will
4046 confuse get_return_addr. */
4047 if (in_reg_window (i, udata)
4048 && udata->saved[udata->retaddr_column] == REG_SAVED_REG
4049 && udata->reg_or_offset[udata->retaddr_column] == i)
4050 continue;
5ff00a1d 4051 copy_reg (i, udata, my_udata);
447a9eb9 4052 }
4053
24db2725 4054 pc = get_return_addr (udata, sub_udata) - 1;
447a9eb9 4055 }
4056
447a9eb9 4057 /* But we do need to update the saved return address register from
4058 the last frame we unwind, or the handler frame will have the wrong
4059 return address. */
4060 if (udata->saved[udata->retaddr_column] == REG_SAVED_REG)
4061 {
4062 i = udata->reg_or_offset[udata->retaddr_column];
4063 if (in_reg_window (i, udata))
61a2823b 4064 copy_reg (i, udata, my_udata);
447a9eb9 4065 }
447a9eb9 4066 }
d63ea2f2 4067 /* udata now refers to the frame called by the handler frame. */
4068
fb3ed2fa 4069 /* We adjust SP by the difference between __throw's CFA and the CFA for
4070 the frame called by the handler frame, because those CFAs correspond
4071 to the SP values at the two call sites. We need to further adjust by
4072 the args_size of the handler frame itself to get the handler frame's
4073 SP from before the args were pushed for that call. */
4074#ifdef STACK_GROWS_DOWNWARD
4075 *offset_p = udata->cfa - my_udata->cfa + args_size;
4076#else
4077 *offset_p = my_udata->cfa - udata->cfa - args_size;
4078#endif
4079
d63ea2f2 4080 return handler;
4081}
4082
4083
4084/* We first search for an exception handler, and if we don't find
4085 it, we call __terminate on the current stack frame so that we may
4086 use the debugger to walk the stack and understand why no handler
4087 was found.
4088
4089 If we find one, then we unwind the frames down to the one that
4090 has the handler and transfer control into the handler. */
4091
4092/*extern void __throw(void) __attribute__ ((__noreturn__));*/
4093
4094void
71218a21 4095__throw (void)
d63ea2f2 4096{
4097 struct eh_context *eh = (*get_eh_context) ();
4098 void *pc, *handler;
fb3ed2fa 4099 long offset;
4100
4101 /* XXX maybe make my_ustruct static so we don't have to look it up for
4102 each throw. */
d63ea2f2 4103 frame_state my_ustruct, *my_udata = &my_ustruct;
4104
4105 /* This is required for C++ semantics. We must call terminate if we
4106 try and rethrow an exception, when there is no exception currently
4107 active. */
4108 if (! eh->info)
4109 __terminate ();
4110
4111 /* Start at our stack frame. */
4112label:
fb3ed2fa 4113 my_udata = __frame_state_for (&&label, my_udata);
4114 if (! my_udata)
d63ea2f2 4115 __terminate ();
4116
4117 /* We need to get the value from the CFA register. */
fb3ed2fa 4118 my_udata->cfa = __builtin_dwarf_cfa ();
d63ea2f2 4119
4120 /* Do any necessary initialization to access arbitrary stack frames.
4121 On the SPARC, this means flushing the register windows. */
4122 __builtin_unwind_init ();
4123
4124 /* Now reset pc to the right throw point. */
4125 pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
4126
fb3ed2fa 4127 handler = throw_helper (eh, pc, my_udata, &offset);
d63ea2f2 4128
4129 /* Now go! */
4130
fb3ed2fa 4131 __builtin_eh_return ((void *)eh, offset, handler);
d63ea2f2 4132
4133 /* Epilogue: restore the handler frame's register values and return
4134 to the stub. */
4135}
4136
4137/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
4138
4139void
71218a21 4140__rethrow (void *index)
d63ea2f2 4141{
4142 struct eh_context *eh = (*get_eh_context) ();
4143 void *pc, *handler;
fb3ed2fa 4144 long offset;
4145
4146 /* XXX maybe make my_ustruct static so we don't have to look it up for
4147 each throw. */
d63ea2f2 4148 frame_state my_ustruct, *my_udata = &my_ustruct;
4149
4150 /* This is required for C++ semantics. We must call terminate if we
4151 try and rethrow an exception, when there is no exception currently
4152 active. */
4153 if (! eh->info)
4154 __terminate ();
4155
4156 /* This is the table index we want to rethrow from. The value of
4157 the END_REGION label is used for the PC of the throw, and the
4158 search begins with the next table entry. */
4159 eh->table_index = index;
4160
4161 /* Start at our stack frame. */
4162label:
fb3ed2fa 4163 my_udata = __frame_state_for (&&label, my_udata);
4164 if (! my_udata)
d63ea2f2 4165 __terminate ();
4166
4167 /* We need to get the value from the CFA register. */
fb3ed2fa 4168 my_udata->cfa = __builtin_dwarf_cfa ();
d63ea2f2 4169
4170 /* Do any necessary initialization to access arbitrary stack frames.
4171 On the SPARC, this means flushing the register windows. */
4172 __builtin_unwind_init ();
4173
4174 /* Now reset pc to the right throw point. */
4175 pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
4176
fb3ed2fa 4177 handler = throw_helper (eh, pc, my_udata, &offset);
447a9eb9 4178
ec37ccb4 4179 /* Now go! */
011a7f23 4180
fb3ed2fa 4181 __builtin_eh_return ((void *)eh, offset, handler);
447a9eb9 4182
4183 /* Epilogue: restore the handler frame's register values and return
4184 to the stub. */
4185}
725cde8f 4186#endif /* DWARF2_UNWIND_INFO */
447a9eb9 4187
fbba5463 4188#ifdef IA64_UNWIND_INFO
4189#include "frame.h"
4190
4191/* Return handler to which we want to transfer control, NULL if we don't
4192 intend to handle this exception here. */
4193void *
4194__ia64_personality_v1 (void *pc, old_exception_table *table)
4195{
4196 if (table)
4197 {
4198 int pos;
4199 int best = -1;
4200
4201 for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
4202 {
4203 if (table[pos].start_region <= pc && table[pos].end_region > pc)
4204 {
4205 /* This can apply. Make sure it is at least as small as
4206 the previous best. */
4207 if (best == -1 || (table[pos].end_region <= table[best].end_region
4208 && table[pos].start_region >= table[best].start_region))
4209 best = pos;
4210 }
4211 /* It is sorted by starting PC within a function. */
4212 else if (best >= 0 && table[pos].start_region > pc)
4213 break;
4214 }
4215 if (best != -1)
4216 return table[best].exception_handler;
4217 }
4218 return (void *) 0;
4219}
4220
4221static void
70009d12 4222ia64_throw_helper (ia64_frame_state *throw_frame, ia64_frame_state *caller,
4223 void *throw_bsp, void *throw_sp)
fbba5463 4224{
1a2eb8ab 4225 void *throw_pc = __builtin_return_address (0);
fbba5463 4226 unwind_info_ptr *info;
4227 void *pc, *handler = NULL;
4228 void *pc_base;
4229 int frame_count;
4230 void *bsp;
4231
4232 __builtin_ia64_flushrs (); /* Make the local register stacks available. */
4233
4234 /* Start at our stack frame, get our state. */
70009d12 4235 __build_ia64_frame_state (throw_pc, throw_frame, throw_bsp, throw_sp,
4236 &pc_base);
fbba5463 4237
4238 /* Now we have to find the proper frame for pc, and see if there
4239 is a handler for it. if not, we keep going back frames until
4240 we do find one. Otherwise we call uncaught (). */
4241
4242 frame_count = 0;
4243 memcpy (caller, throw_frame, sizeof (*caller));
4244 while (!handler)
4245 {
4246 void *(*personality) ();
4247 void *eh_table;
4248
4249 frame_count++;
4250 /* We only care about the RP right now, so we dont need to keep
4251 any other information about a call frame right now. */
4252 pc = __get_real_reg_value (&caller->rp) - 1;
70009d12 4253 bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs),
4254 caller->my_bsp);
4255 info = __build_ia64_frame_state (pc, caller, bsp, caller->my_psp,
4256 &pc_base);
fbba5463 4257
4258 /* If we couldn't find the next frame, we lose. */
4259 if (! info)
4260 break;
4261
4262 personality = __get_personality (info);
4263 /* TODO Haven't figured out how to actually load the personality address
4264 yet, so just always default to the one we expect for now. */
4265 if (personality != 0)
4266 personality = __ia64_personality_v1;
4267 eh_table = __get_except_table (info);
4268 /* If there is no personality routine, we'll keep unwinding. */
4269 if (personality)
4270 /* Pass a segment relative PC address to the personality routine,
4271 because the unwind_info section uses segrel relocs. */
4272 handler = personality (pc - pc_base, eh_table);
4273 }
4274
4275 if (!handler)
70009d12 4276 __terminate ();
fbba5463 4277
4278 /* Handler is a segment relative address, so we must adjust it here. */
4279 handler += (long) pc_base;
4280
4281 /* If we found a handler, we need to unwind the stack to that point.
4282 We do this by copying saved values from previous frames into the
4283 save slot for the throw_frame saved slots. when __throw returns,
4284 it'll pickup the correct values. */
4285
4286 /* Start with where __throw saved things, and copy each saved register
4287 of each previous frame until we get to the one before we're
4288 throwing back to. */
4289 memcpy (caller, throw_frame, sizeof (*caller));
4290 for ( ; frame_count > 0; frame_count--)
4291 {
4292 pc = __get_real_reg_value (&caller->rp) - 1;
70009d12 4293 bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs),
4294 caller->my_bsp);
4295 __build_ia64_frame_state (pc, caller, bsp, caller->my_psp, &pc_base);
fbba5463 4296 /* Any regs that were saved can be put in the throw frame now. */
4297 /* We don't want to copy any saved register from the
4298 target destination, but we do want to load up it's frame. */
4299 if (frame_count > 1)
4300 __copy_saved_reg_state (throw_frame, caller);
4301 }
4302
4303 /* Set return address of the throw frame to the handler. */
4304 __set_real_reg_value (&throw_frame->rp, handler);
4305
4306 /* TODO, do we need to do anything to make the values we wrote 'stick'? */
4307 /* DO we need to go through the whole loadrs seqeunce? */
fbba5463 4308}
4309
70009d12 4310
fbba5463 4311void
4312__throw ()
4313{
70009d12 4314 register void *stack_pointer __asm__("r12");
fbba5463 4315 struct eh_context *eh = (*get_eh_context) ();
4316 ia64_frame_state my_frame;
4317 ia64_frame_state originator; /* For the context handler is in. */
4318 void *bsp, *tmp_bsp;
4319 long offset;
4320
4321 /* This is required for C++ semantics. We must call terminate if we
4322 try and rethrow an exception, when there is no exception currently
4323 active. */
4324 if (! eh->info)
4325 __terminate ();
4326
4327 __builtin_unwind_init ();
70009d12 4328
fbba5463 4329 /* We have to call another routine to actually process the frame
4330 information, which will force all of __throw's local registers into
4331 backing store. */
4332
4333 /* Get the value of ar.bsp while we're here. */
4334
4335 bsp = __builtin_ia64_bsp ();
70009d12 4336 ia64_throw_helper (&my_frame, &originator, bsp, stack_pointer);
fbba5463 4337
4338 /* Now we have to fudge the bsp by the amount in our (__throw)
4339 frame marker, since the return is going to adjust it by that much. */
4340
4341 tmp_bsp = __calc_caller_bsp ((long)__get_real_reg_value (&my_frame.pfs),
4342 my_frame.my_bsp);
4343 offset = (char *)my_frame.my_bsp - (char *)tmp_bsp;
4344 tmp_bsp = (char *)originator.my_bsp + offset;
4345
fbba5463 4346 __builtin_eh_return (tmp_bsp, offset, originator.my_sp);
4347
4348 /* The return address was already set by throw_helper. */
4349}
4350
4351#endif /* IA64_UNWIND_INFO */
4352
99962ae2 4353#endif /* L_eh */