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