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