]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/libgcc2.c
(print_operand): New operand output modifiers d,t,b,B,w.
[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. */
8b7677be 3/* Copyright (C) 1989, 92, 93, 94, 95, 1996 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"
bfe655f9 34#include "machmode.h"
daefd78b 35#include "defaults.h"
b335c2cc 36#ifndef L_trampoline
8717efce 37#include <stddef.h>
b335c2cc 38#endif
203b91b9
RS
39
40/* Don't use `fancy_abort' here even if config.h says to use it. */
41#ifdef abort
42#undef abort
43#endif
44
71c672c0 45#if (SUPPORTS_WEAK == 1) && (defined (ASM_OUTPUT_DEF) || defined (ASM_OUTPUT_WEAK_ALIAS))
daefd78b
JM
46#define WEAK_ALIAS
47#endif
48
f76b9db2
ILT
49/* Permit the tm.h file to select the endianness to use just for this
50 file. This is used when the endianness is determined when the
51 compiler is run. */
52
53#ifndef LIBGCC2_WORDS_BIG_ENDIAN
54#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
55#endif
56
ab495388
RS
57/* In the first part of this file, we are interfacing to calls generated
58 by the compiler itself. These calls pass values into these routines
59 which have very specific modes (rather than very specific types), and
60 these compiler-generated calls also expect any return values to have
61 very specific modes (rather than very specific types). Thus, we need
62 to avoid using regular C language type names in this part of the file
63 because the sizes for those types can be configured to be anything.
64 Instead we use the following special type names. */
65
b2bf5aef
RK
66typedef unsigned int UQItype __attribute__ ((mode (QI)));
67typedef int SItype __attribute__ ((mode (SI)));
68typedef unsigned int USItype __attribute__ ((mode (SI)));
69typedef int DItype __attribute__ ((mode (DI)));
70typedef unsigned int UDItype __attribute__ ((mode (DI)));
a07805c0 71
b2bf5aef
RK
72typedef float SFtype __attribute__ ((mode (SF)));
73typedef float DFtype __attribute__ ((mode (DF)));
a07805c0 74
e0799b34 75#if LONG_DOUBLE_TYPE_SIZE == 96
b2bf5aef 76typedef float XFtype __attribute__ ((mode (XF)));
258d1356
CH
77#endif
78#if LONG_DOUBLE_TYPE_SIZE == 128
b2bf5aef 79typedef float TFtype __attribute__ ((mode (TF)));
258d1356 80#endif
ab495388 81
a07805c0 82typedef int word_type __attribute__ ((mode (__word__)));
4be7c28f 83
a1c37766 84/* Make sure that we don't accidentally use any normal C language built-in
ab495388
RS
85 type names in the first part of this file. Instead we want to use *only*
86 the type names defined above. The following macro definitions insure
19197caa 87 that if we *do* accidentally use some normal C language built-in type name,
ab495388
RS
88 we will get a syntax error. */
89
90#define char bogus_type
91#define short bogus_type
92#define int bogus_type
93#define long bogus_type
94#define unsigned bogus_type
95#define float bogus_type
96#define double bogus_type
97
98#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
99
100/* DIstructs are pairs of SItype values in the order determined by
f76b9db2 101 LIBGCC2_WORDS_BIG_ENDIAN. */
203b91b9 102
f76b9db2 103#if LIBGCC2_WORDS_BIG_ENDIAN
ab495388 104 struct DIstruct {SItype high, low;};
203b91b9 105#else
ab495388 106 struct DIstruct {SItype low, high;};
203b91b9
RS
107#endif
108
ab495388
RS
109/* We need this union to unpack/pack DImode values, since we don't have
110 any arithmetic yet. Incoming DImode parameters are stored into the
111 `ll' field, and the unpacked result is read from the struct `s'. */
203b91b9
RS
112
113typedef union
114{
ab495388
RS
115 struct DIstruct s;
116 DItype ll;
117} DIunion;
203b91b9 118
536bfcd0
RK
119#if (defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)\
120 || defined (L_divdi3) || defined (L_udivdi3) \
121 || defined (L_moddi3) || defined (L_umoddi3))
203b91b9
RS
122
123#include "longlong.h"
124
125#endif /* udiv or mul */
126
ab495388
RS
127extern DItype __fixunssfdi (SFtype a);
128extern DItype __fixunsdfdi (DFtype a);
96fc2623 129#if LONG_DOUBLE_TYPE_SIZE == 96
f70ad14c 130extern DItype __fixunsxfdi (XFtype a);
96fc2623
RS
131#endif
132#if LONG_DOUBLE_TYPE_SIZE == 128
cc3cdac3 133extern DItype __fixunstfdi (TFtype a);
96fc2623 134#endif
203b91b9
RS
135\f
136#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
137#if defined (L_divdi3) || defined (L_moddi3)
138static inline
139#endif
ab495388 140DItype
203b91b9 141__negdi2 (u)
ab495388 142 DItype u;
203b91b9 143{
ab495388
RS
144 DIunion w;
145 DIunion uu;
203b91b9
RS
146
147 uu.ll = u;
148
149 w.s.low = -uu.s.low;
ab495388 150 w.s.high = -uu.s.high - ((USItype) w.s.low > 0);
203b91b9
RS
151
152 return w.ll;
153}
154#endif
155\f
203b91b9 156#ifdef L_lshrdi3
ab495388 157DItype
203b91b9 158__lshrdi3 (u, b)
ab495388 159 DItype u;
b799cfc3 160 word_type b;
203b91b9 161{
ab495388 162 DIunion w;
b799cfc3 163 word_type bm;
ab495388 164 DIunion uu;
203b91b9
RS
165
166 if (b == 0)
167 return u;
168
169 uu.ll = u;
170
ab495388 171 bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
203b91b9
RS
172 if (bm <= 0)
173 {
174 w.s.high = 0;
ab495388 175 w.s.low = (USItype)uu.s.high >> -bm;
203b91b9
RS
176 }
177 else
178 {
ab495388
RS
179 USItype carries = (USItype)uu.s.high << bm;
180 w.s.high = (USItype)uu.s.high >> b;
181 w.s.low = ((USItype)uu.s.low >> b) | carries;
203b91b9
RS
182 }
183
184 return w.ll;
185}
186#endif
187
188#ifdef L_ashldi3
ab495388 189DItype
203b91b9 190__ashldi3 (u, b)
ab495388 191 DItype u;
b799cfc3 192 word_type b;
203b91b9 193{
ab495388 194 DIunion w;
b799cfc3 195 word_type bm;
ab495388 196 DIunion uu;
203b91b9
RS
197
198 if (b == 0)
199 return u;
200
201 uu.ll = u;
202
ab495388 203 bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
203b91b9
RS
204 if (bm <= 0)
205 {
206 w.s.low = 0;
ab495388 207 w.s.high = (USItype)uu.s.low << -bm;
203b91b9
RS
208 }
209 else
210 {
ab495388
RS
211 USItype carries = (USItype)uu.s.low >> bm;
212 w.s.low = (USItype)uu.s.low << b;
213 w.s.high = ((USItype)uu.s.high << b) | carries;
203b91b9
RS
214 }
215
216 return w.ll;
217}
218#endif
219
220#ifdef L_ashrdi3
ab495388 221DItype
203b91b9 222__ashrdi3 (u, b)
ab495388 223 DItype u;
b799cfc3 224 word_type b;
203b91b9 225{
ab495388 226 DIunion w;
b799cfc3 227 word_type bm;
ab495388 228 DIunion uu;
203b91b9
RS
229
230 if (b == 0)
231 return u;
232
233 uu.ll = u;
234
ab495388 235 bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
203b91b9
RS
236 if (bm <= 0)
237 {
238 /* w.s.high = 1..1 or 0..0 */
ab495388 239 w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
203b91b9
RS
240 w.s.low = uu.s.high >> -bm;
241 }
242 else
243 {
ab495388 244 USItype carries = (USItype)uu.s.high << bm;
203b91b9 245 w.s.high = uu.s.high >> b;
ab495388 246 w.s.low = ((USItype)uu.s.low >> b) | carries;
203b91b9
RS
247 }
248
249 return w.ll;
250}
251#endif
252\f
aa66bd06
RS
253#ifdef L_ffsdi2
254DItype
255__ffsdi2 (u)
256 DItype u;
257{
258 DIunion uu, w;
259 uu.ll = u;
260 w.s.high = 0;
261 w.s.low = ffs (uu.s.low);
262 if (w.s.low != 0)
de6cbba6 263 return w.ll;
aa66bd06
RS
264 w.s.low = ffs (uu.s.high);
265 if (w.s.low != 0)
266 {
267 w.s.low += BITS_PER_UNIT * sizeof (SItype);
de6cbba6 268 return w.ll;
aa66bd06 269 }
de6cbba6 270 return w.ll;
aa66bd06
RS
271}
272#endif
273\f
203b91b9 274#ifdef L_muldi3
ab495388 275DItype
203b91b9 276__muldi3 (u, v)
ab495388 277 DItype u, v;
203b91b9 278{
ab495388
RS
279 DIunion w;
280 DIunion uu, vv;
203b91b9
RS
281
282 uu.ll = u,
283 vv.ll = v;
284
285 w.ll = __umulsidi3 (uu.s.low, vv.s.low);
ab495388
RS
286 w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
287 + (USItype) uu.s.high * (USItype) vv.s.low);
203b91b9
RS
288
289 return w.ll;
290}
291#endif
292\f
3904131a 293#ifdef L_udiv_w_sdiv
ce13d15f 294#if defined (sdiv_qrnnd)
431b1ee0 295USItype
3904131a 296__udiv_w_sdiv (rp, a1, a0, d)
431b1ee0
TG
297 USItype *rp, a1, a0, d;
298{
299 USItype q, r;
300 USItype c0, c1, b1;
301
302 if ((SItype) d >= 0)
303 {
7bc7d45a 304 if (a1 < d - a1 - (a0 >> (SI_TYPE_SIZE - 1)))
431b1ee0
TG
305 {
306 /* dividend, divisor, and quotient are nonnegative */
307 sdiv_qrnnd (q, r, a1, a0, d);
308 }
309 else
310 {
311 /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
7bc7d45a 312 sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (SI_TYPE_SIZE - 1));
431b1ee0
TG
313 /* Divide (c1*2^32 + c0) by d */
314 sdiv_qrnnd (q, r, c1, c0, d);
315 /* Add 2^31 to quotient */
7bc7d45a 316 q += (USItype) 1 << (SI_TYPE_SIZE - 1);
431b1ee0
TG
317 }
318 }
319 else
320 {
321 b1 = d >> 1; /* d/2, between 2^30 and 2^31 - 1 */
322 c1 = a1 >> 1; /* A/2 */
7bc7d45a 323 c0 = (a1 << (SI_TYPE_SIZE - 1)) + (a0 >> 1);
431b1ee0
TG
324
325 if (a1 < b1) /* A < 2^32*b1, so A/2 < 2^31*b1 */
326 {
327 sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
328
329 r = 2*r + (a0 & 1); /* Remainder from A/(2*b1) */
330 if ((d & 1) != 0)
331 {
332 if (r >= q)
333 r = r - q;
334 else if (q - r <= d)
335 {
336 r = r - q + d;
337 q--;
338 }
339 else
340 {
341 r = r - q + 2*d;
342 q -= 2;
343 }
344 }
345 }
346 else if (c1 < b1) /* So 2^31 <= (A/2)/b1 < 2^32 */
347 {
348 c1 = (b1 - 1) - c1;
349 c0 = ~c0; /* logical NOT */
350
351 sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
352
353 q = ~q; /* (A/2)/b1 */
354 r = (b1 - 1) - r;
355
356 r = 2*r + (a0 & 1); /* A/(2*b1) */
357
358 if ((d & 1) != 0)
359 {
360 if (r >= q)
361 r = r - q;
362 else if (q - r <= d)
363 {
364 r = r - q + d;
365 q--;
366 }
367 else
368 {
369 r = r - q + 2*d;
370 q -= 2;
371 }
372 }
373 }
374 else /* Implies c1 = b1 */
375 { /* Hence a1 = d - 1 = 2*b1 - 1 */
376 if (a0 >= -d)
377 {
378 q = -1;
379 r = a0 + d;
380 }
381 else
382 {
383 q = -2;
384 r = a0 + 2*d;
385 }
386 }
387 }
388
389 *rp = r;
390 return q;
391}
ce13d15f
RK
392#else
393/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv. */
394USItype
395__udiv_w_sdiv (rp, a1, a0, d)
396 USItype *rp, a1, a0, d;
397{}
398#endif
431b1ee0
TG
399#endif
400\f
536bfcd0
RK
401#if (defined (L_udivdi3) || defined (L_divdi3) || \
402 defined (L_umoddi3) || defined (L_moddi3))
403#define L_udivmoddi4
404#endif
405
203b91b9 406#ifdef L_udivmoddi4
ab495388 407static const UQItype __clz_tab[] =
203b91b9
RS
408{
409 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,
410 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,
411 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,
412 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,
413 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,
414 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,
415 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,
416 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,
417};
418
536bfcd0
RK
419#if (defined (L_udivdi3) || defined (L_divdi3) || \
420 defined (L_umoddi3) || defined (L_moddi3))
421static inline
422#endif
ab495388 423UDItype
203b91b9 424__udivmoddi4 (n, d, rp)
ab495388
RS
425 UDItype n, d;
426 UDItype *rp;
203b91b9 427{
ab495388
RS
428 DIunion ww;
429 DIunion nn, dd;
430 DIunion rr;
431 USItype d0, d1, n0, n1, n2;
432 USItype q0, q1;
433 USItype b, bm;
203b91b9
RS
434
435 nn.ll = n;
436 dd.ll = d;
437
438 d0 = dd.s.low;
439 d1 = dd.s.high;
440 n0 = nn.s.low;
441 n1 = nn.s.high;
442
443#if !UDIV_NEEDS_NORMALIZATION
444 if (d1 == 0)
445 {
446 if (d0 > n1)
447 {
448 /* 0q = nn / 0D */
449
450 udiv_qrnnd (q0, n0, n1, n0, d0);
451 q1 = 0;
452
453 /* Remainder in n0. */
454 }
455 else
456 {
457 /* qq = NN / 0d */
458
459 if (d0 == 0)
460 d0 = 1 / d0; /* Divide intentionally by zero. */
461
462 udiv_qrnnd (q1, n1, 0, n1, d0);
463 udiv_qrnnd (q0, n0, n1, n0, d0);
464
465 /* Remainder in n0. */
466 }
467
468 if (rp != 0)
469 {
470 rr.s.low = n0;
471 rr.s.high = 0;
472 *rp = rr.ll;
473 }
474 }
475
476#else /* UDIV_NEEDS_NORMALIZATION */
477
478 if (d1 == 0)
479 {
480 if (d0 > n1)
481 {
482 /* 0q = nn / 0D */
483
484 count_leading_zeros (bm, d0);
485
486 if (bm != 0)
487 {
488 /* Normalize, i.e. make the most significant bit of the
489 denominator set. */
490
491 d0 = d0 << bm;
ab495388 492 n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
203b91b9
RS
493 n0 = n0 << bm;
494 }
495
496 udiv_qrnnd (q0, n0, n1, n0, d0);
497 q1 = 0;
498
499 /* Remainder in n0 >> bm. */
500 }
501 else
502 {
503 /* qq = NN / 0d */
504
505 if (d0 == 0)
506 d0 = 1 / d0; /* Divide intentionally by zero. */
507
508 count_leading_zeros (bm, d0);
509
510 if (bm == 0)
511 {
512 /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
513 conclude (the most significant bit of n1 is set) /\ (the
514 leading quotient digit q1 = 1).
515
516 This special case is necessary, not an optimization.
ab495388 517 (Shifts counts of SI_TYPE_SIZE are undefined.) */
203b91b9
RS
518
519 n1 -= d0;
520 q1 = 1;
521 }
522 else
523 {
524 /* Normalize. */
525
ab495388 526 b = SI_TYPE_SIZE - bm;
203b91b9
RS
527
528 d0 = d0 << bm;
529 n2 = n1 >> b;
530 n1 = (n1 << bm) | (n0 >> b);
531 n0 = n0 << bm;
532
533 udiv_qrnnd (q1, n1, n2, n1, d0);
534 }
535
0f41302f 536 /* n1 != d0... */
203b91b9
RS
537
538 udiv_qrnnd (q0, n0, n1, n0, d0);
539
540 /* Remainder in n0 >> bm. */
541 }
542
543 if (rp != 0)
544 {
545 rr.s.low = n0 >> bm;
546 rr.s.high = 0;
547 *rp = rr.ll;
548 }
549 }
550#endif /* UDIV_NEEDS_NORMALIZATION */
551
552 else
553 {
554 if (d1 > n1)
555 {
556 /* 00 = nn / DD */
557
558 q0 = 0;
559 q1 = 0;
560
561 /* Remainder in n1n0. */
562 if (rp != 0)
563 {
564 rr.s.low = n0;
565 rr.s.high = n1;
566 *rp = rr.ll;
567 }
568 }
569 else
570 {
571 /* 0q = NN / dd */
572
573 count_leading_zeros (bm, d1);
574 if (bm == 0)
575 {
576 /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
577 conclude (the most significant bit of n1 is set) /\ (the
578 quotient digit q0 = 0 or 1).
579
580 This special case is necessary, not an optimization. */
581
582 /* The condition on the next line takes advantage of that
583 n1 >= d1 (true due to program flow). */
584 if (n1 > d1 || n0 >= d0)
585 {
586 q0 = 1;
587 sub_ddmmss (n1, n0, n1, n0, d1, d0);
588 }
589 else
590 q0 = 0;
591
592 q1 = 0;
593
594 if (rp != 0)
595 {
596 rr.s.low = n0;
597 rr.s.high = n1;
598 *rp = rr.ll;
599 }
600 }
601 else
602 {
ab495388 603 USItype m1, m0;
203b91b9
RS
604 /* Normalize. */
605
ab495388 606 b = SI_TYPE_SIZE - bm;
203b91b9
RS
607
608 d1 = (d1 << bm) | (d0 >> b);
609 d0 = d0 << bm;
610 n2 = n1 >> b;
611 n1 = (n1 << bm) | (n0 >> b);
612 n0 = n0 << bm;
613
614 udiv_qrnnd (q0, n1, n2, n1, d1);
615 umul_ppmm (m1, m0, q0, d0);
616
617 if (m1 > n1 || (m1 == n1 && m0 > n0))
618 {
619 q0--;
620 sub_ddmmss (m1, m0, m1, m0, d1, d0);
621 }
622
623 q1 = 0;
624
625 /* Remainder in (n1n0 - m1m0) >> bm. */
626 if (rp != 0)
627 {
628 sub_ddmmss (n1, n0, n1, n0, m1, m0);
629 rr.s.low = (n1 << b) | (n0 >> bm);
630 rr.s.high = n1 >> bm;
631 *rp = rr.ll;
632 }
633 }
634 }
635 }
636
637 ww.s.low = q0;
638 ww.s.high = q1;
639 return ww.ll;
640}
641#endif
642
643#ifdef L_divdi3
ab495388 644UDItype __udivmoddi4 ();
f70ad14c 645
ab495388 646DItype
203b91b9 647__divdi3 (u, v)
ab495388 648 DItype u, v;
203b91b9 649{
b799cfc3 650 word_type c = 0;
ab495388
RS
651 DIunion uu, vv;
652 DItype w;
203b91b9
RS
653
654 uu.ll = u;
655 vv.ll = v;
656
657 if (uu.s.high < 0)
658 c = ~c,
659 uu.ll = __negdi2 (uu.ll);
660 if (vv.s.high < 0)
661 c = ~c,
662 vv.ll = __negdi2 (vv.ll);
663
ab495388 664 w = __udivmoddi4 (uu.ll, vv.ll, (UDItype *) 0);
203b91b9
RS
665 if (c)
666 w = __negdi2 (w);
667
668 return w;
669}
670#endif
671
672#ifdef L_moddi3
ab495388
RS
673UDItype __udivmoddi4 ();
674DItype
203b91b9 675__moddi3 (u, v)
ab495388 676 DItype u, v;
203b91b9 677{
b799cfc3 678 word_type c = 0;
ab495388
RS
679 DIunion uu, vv;
680 DItype w;
203b91b9
RS
681
682 uu.ll = u;
683 vv.ll = v;
684
685 if (uu.s.high < 0)
686 c = ~c,
687 uu.ll = __negdi2 (uu.ll);
688 if (vv.s.high < 0)
689 vv.ll = __negdi2 (vv.ll);
690
691 (void) __udivmoddi4 (uu.ll, vv.ll, &w);
692 if (c)
693 w = __negdi2 (w);
694
695 return w;
696}
697#endif
698
699#ifdef L_umoddi3
ab495388
RS
700UDItype __udivmoddi4 ();
701UDItype
203b91b9 702__umoddi3 (u, v)
ab495388 703 UDItype u, v;
203b91b9 704{
b89a6f69 705 UDItype w;
203b91b9
RS
706
707 (void) __udivmoddi4 (u, v, &w);
708
709 return w;
710}
711#endif
712
713#ifdef L_udivdi3
ab495388
RS
714UDItype __udivmoddi4 ();
715UDItype
203b91b9 716__udivdi3 (n, d)
ab495388 717 UDItype n, d;
203b91b9 718{
ab495388 719 return __udivmoddi4 (n, d, (UDItype *) 0);
203b91b9
RS
720}
721#endif
722\f
723#ifdef L_cmpdi2
4be7c28f 724word_type
203b91b9 725__cmpdi2 (a, b)
ab495388 726 DItype a, b;
203b91b9 727{
ab495388 728 DIunion au, bu;
203b91b9
RS
729
730 au.ll = a, bu.ll = b;
731
732 if (au.s.high < bu.s.high)
733 return 0;
734 else if (au.s.high > bu.s.high)
735 return 2;
ab495388 736 if ((USItype) au.s.low < (USItype) bu.s.low)
203b91b9 737 return 0;
ab495388 738 else if ((USItype) au.s.low > (USItype) bu.s.low)
203b91b9
RS
739 return 2;
740 return 1;
741}
742#endif
743
744#ifdef L_ucmpdi2
4be7c28f 745word_type
203b91b9 746__ucmpdi2 (a, b)
ab495388 747 DItype a, b;
203b91b9 748{
ab495388 749 DIunion au, bu;
203b91b9
RS
750
751 au.ll = a, bu.ll = b;
752
ab495388 753 if ((USItype) au.s.high < (USItype) bu.s.high)
203b91b9 754 return 0;
ab495388 755 else if ((USItype) au.s.high > (USItype) bu.s.high)
203b91b9 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\f
ab495388
RS
765#if defined(L_fixunstfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
766#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
767#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
768
769DItype
770__fixunstfdi (a)
771 TFtype a;
772{
773 TFtype b;
774 UDItype v;
775
776 if (a < 0)
777 return 0;
778
779 /* Compute high word of result, as a flonum. */
780 b = (a / HIGH_WORD_COEFF);
781 /* Convert that to fixed (but not to DItype!),
782 and shift it into the high word. */
783 v = (USItype) b;
784 v <<= WORD_SIZE;
785 /* Remove high part from the TFtype, leaving the low part as flonum. */
786 a -= (TFtype)v;
787 /* Convert that to fixed (but not to DItype!) and add it in.
788 Sometimes A comes out negative. This is significant, since
789 A has more bits than a long int does. */
790 if (a < 0)
791 v -= (USItype) (- a);
792 else
793 v += (USItype) a;
794 return v;
795}
796#endif
797
798#if defined(L_fixtfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
799DItype
800__fixtfdi (a)
801 TFtype a;
802{
803 if (a < 0)
804 return - __fixunstfdi (-a);
805 return __fixunstfdi (a);
806}
807#endif
808
e0799b34
RS
809#if defined(L_fixunsxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
810#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
811#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
812
813DItype
814__fixunsxfdi (a)
815 XFtype a;
816{
817 XFtype b;
818 UDItype v;
819
820 if (a < 0)
821 return 0;
822
823 /* Compute high word of result, as a flonum. */
824 b = (a / HIGH_WORD_COEFF);
825 /* Convert that to fixed (but not to DItype!),
826 and shift it into the high word. */
827 v = (USItype) b;
828 v <<= WORD_SIZE;
829 /* Remove high part from the XFtype, leaving the low part as flonum. */
830 a -= (XFtype)v;
831 /* Convert that to fixed (but not to DItype!) and add it in.
832 Sometimes A comes out negative. This is significant, since
833 A has more bits than a long int does. */
834 if (a < 0)
835 v -= (USItype) (- a);
836 else
837 v += (USItype) a;
838 return v;
839}
840#endif
841
842#if defined(L_fixxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
843DItype
844__fixxfdi (a)
845 XFtype a;
846{
847 if (a < 0)
848 return - __fixunsxfdi (-a);
849 return __fixunsxfdi (a);
850}
851#endif
852
203b91b9 853#ifdef L_fixunsdfdi
ab495388
RS
854#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
855#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
203b91b9 856
ab495388 857DItype
203b91b9 858__fixunsdfdi (a)
ab495388 859 DFtype a;
203b91b9 860{
ab495388
RS
861 DFtype b;
862 UDItype v;
203b91b9
RS
863
864 if (a < 0)
865 return 0;
866
867 /* Compute high word of result, as a flonum. */
868 b = (a / HIGH_WORD_COEFF);
ab495388 869 /* Convert that to fixed (but not to DItype!),
203b91b9 870 and shift it into the high word. */
ab495388 871 v = (USItype) b;
203b91b9 872 v <<= WORD_SIZE;
ab495388
RS
873 /* Remove high part from the DFtype, leaving the low part as flonum. */
874 a -= (DFtype)v;
875 /* Convert that to fixed (but not to DItype!) and add it in.
203b91b9
RS
876 Sometimes A comes out negative. This is significant, since
877 A has more bits than a long int does. */
878 if (a < 0)
ab495388 879 v -= (USItype) (- a);
203b91b9 880 else
ab495388 881 v += (USItype) a;
203b91b9
RS
882 return v;
883}
884#endif
885
886#ifdef L_fixdfdi
ab495388 887DItype
203b91b9 888__fixdfdi (a)
ab495388 889 DFtype a;
203b91b9
RS
890{
891 if (a < 0)
892 return - __fixunsdfdi (-a);
893 return __fixunsdfdi (a);
894}
895#endif
896
897#ifdef L_fixunssfdi
ab495388
RS
898#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
899#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
203b91b9 900
ab495388
RS
901DItype
902__fixunssfdi (SFtype original_a)
203b91b9 903{
ab495388 904 /* Convert the SFtype to a DFtype, because that is surely not going
203b91b9 905 to lose any bits. Some day someone else can write a faster version
ab495388
RS
906 that avoids converting to DFtype, and verify it really works right. */
907 DFtype a = original_a;
908 DFtype b;
909 UDItype v;
203b91b9
RS
910
911 if (a < 0)
912 return 0;
913
914 /* Compute high word of result, as a flonum. */
915 b = (a / HIGH_WORD_COEFF);
ab495388 916 /* Convert that to fixed (but not to DItype!),
203b91b9 917 and shift it into the high word. */
ab495388 918 v = (USItype) b;
203b91b9 919 v <<= WORD_SIZE;
ab495388
RS
920 /* Remove high part from the DFtype, leaving the low part as flonum. */
921 a -= (DFtype)v;
922 /* Convert that to fixed (but not to DItype!) and add it in.
203b91b9
RS
923 Sometimes A comes out negative. This is significant, since
924 A has more bits than a long int does. */
925 if (a < 0)
ab495388 926 v -= (USItype) (- a);
203b91b9 927 else
ab495388 928 v += (USItype) a;
203b91b9
RS
929 return v;
930}
931#endif
932
933#ifdef L_fixsfdi
ab495388
RS
934DItype
935__fixsfdi (SFtype a)
203b91b9
RS
936{
937 if (a < 0)
938 return - __fixunssfdi (-a);
939 return __fixunssfdi (a);
940}
941#endif
942
e0799b34
RS
943#if defined(L_floatdixf) && (LONG_DOUBLE_TYPE_SIZE == 96)
944#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
945#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
946#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
947
948XFtype
949__floatdixf (u)
950 DItype u;
951{
952 XFtype d;
953 SItype negate = 0;
954
955 if (u < 0)
956 u = -u, negate = 1;
957
958 d = (USItype) (u >> WORD_SIZE);
959 d *= HIGH_HALFWORD_COEFF;
960 d *= HIGH_HALFWORD_COEFF;
961 d += (USItype) (u & (HIGH_WORD_COEFF - 1));
962
963 return (negate ? -d : d);
964}
965#endif
966
ab495388
RS
967#if defined(L_floatditf) && (LONG_DOUBLE_TYPE_SIZE == 128)
968#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
969#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
970#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
971
972TFtype
973__floatditf (u)
974 DItype u;
975{
976 TFtype d;
977 SItype negate = 0;
978
979 if (u < 0)
980 u = -u, negate = 1;
981
982 d = (USItype) (u >> WORD_SIZE);
983 d *= HIGH_HALFWORD_COEFF;
984 d *= HIGH_HALFWORD_COEFF;
985 d += (USItype) (u & (HIGH_WORD_COEFF - 1));
986
987 return (negate ? -d : d);
988}
989#endif
990
203b91b9 991#ifdef L_floatdidf
ab495388
RS
992#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
993#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
994#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
203b91b9 995
ab495388 996DFtype
203b91b9 997__floatdidf (u)
ab495388 998 DItype u;
203b91b9 999{
ab495388
RS
1000 DFtype d;
1001 SItype negate = 0;
203b91b9
RS
1002
1003 if (u < 0)
1004 u = -u, negate = 1;
1005
ab495388 1006 d = (USItype) (u >> WORD_SIZE);
203b91b9
RS
1007 d *= HIGH_HALFWORD_COEFF;
1008 d *= HIGH_HALFWORD_COEFF;
ab495388 1009 d += (USItype) (u & (HIGH_WORD_COEFF - 1));
203b91b9
RS
1010
1011 return (negate ? -d : d);
1012}
1013#endif
1014
1015#ifdef L_floatdisf
ab495388
RS
1016#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
1017#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
1018#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
d9e1ab8d 1019#define DI_SIZE (sizeof (DItype) * BITS_PER_UNIT)
cac896d8
RK
1020
1021/* Define codes for all the float formats that we know of. Note
1022 that this is copied from real.h. */
1023
1024#define UNKNOWN_FLOAT_FORMAT 0
1025#define IEEE_FLOAT_FORMAT 1
1026#define VAX_FLOAT_FORMAT 2
1027#define IBM_FLOAT_FORMAT 3
1028
1029/* Default to IEEE float if not specified. Nearly all machines use it. */
1030#ifndef HOST_FLOAT_FORMAT
1031#define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT
1032#endif
1033
1034#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
d9e1ab8d
RK
1035#define DF_SIZE 53
1036#define SF_SIZE 24
cac896d8
RK
1037#endif
1038
1039#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
d9e1ab8d
RK
1040#define DF_SIZE 56
1041#define SF_SIZE 24
cac896d8
RK
1042#endif
1043
1044#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
d9e1ab8d
RK
1045#define DF_SIZE 56
1046#define SF_SIZE 24
d9e1ab8d 1047#endif
203b91b9 1048
ab495388 1049SFtype
203b91b9 1050__floatdisf (u)
ab495388 1051 DItype u;
203b91b9 1052{
56b03d5f
RS
1053 /* Do the calculation in DFmode
1054 so that we don't lose any of the precision of the high word
1055 while multiplying it. */
1056 DFtype f;
ab495388 1057 SItype negate = 0;
203b91b9
RS
1058
1059 if (u < 0)
1060 u = -u, negate = 1;
1061
d9e1ab8d
RK
1062 /* Protect against double-rounding error.
1063 Represent any low-order bits, that might be truncated in DFmode,
1064 by a bit that won't be lost. The bit can go in anywhere below the
1065 rounding position of the SFmode. A fixed mask and bit position
1066 handles all usual configurations. It doesn't handle the case
1067 of 128-bit DImode, however. */
1068 if (DF_SIZE < DI_SIZE
1069 && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
1070 {
1071#define REP_BIT ((USItype) 1 << (DI_SIZE - DF_SIZE))
1072 if (u >= ((UDItype) 1 << DF_SIZE))
1073 {
1074 if ((USItype) u & (REP_BIT - 1))
1075 u |= REP_BIT;
1076 }
1077 }
ab495388 1078 f = (USItype) (u >> WORD_SIZE);
203b91b9
RS
1079 f *= HIGH_HALFWORD_COEFF;
1080 f *= HIGH_HALFWORD_COEFF;
ab495388 1081 f += (USItype) (u & (HIGH_WORD_COEFF - 1));
203b91b9 1082
56b03d5f 1083 return (SFtype) (negate ? -f : f);
203b91b9
RS
1084}
1085#endif
1086
e0799b34 1087#if defined(L_fixunsxfsi) && LONG_DOUBLE_TYPE_SIZE == 96
3f3d2ec8
JW
1088/* Reenable the normal types, in case limits.h needs them. */
1089#undef char
1090#undef short
1091#undef int
1092#undef long
1093#undef unsigned
1094#undef float
1095#undef double
c07e26bd
RK
1096#undef MIN
1097#undef MAX
a99598c9 1098#include <limits.h>
e0799b34
RS
1099
1100USItype
1101__fixunsxfsi (a)
1102 XFtype a;
1103{
1104 if (a >= - (DFtype) LONG_MIN)
1105 return (SItype) (a + LONG_MIN) - LONG_MIN;
1106 return (SItype) a;
1107}
1108#endif
1109
203b91b9 1110#ifdef L_fixunsdfsi
3f3d2ec8
JW
1111/* Reenable the normal types, in case limits.h needs them. */
1112#undef char
1113#undef short
1114#undef int
1115#undef long
1116#undef unsigned
1117#undef float
1118#undef double
c07e26bd
RK
1119#undef MIN
1120#undef MAX
a99598c9 1121#include <limits.h>
203b91b9 1122
ab495388 1123USItype
203b91b9 1124__fixunsdfsi (a)
ab495388 1125 DFtype a;
203b91b9 1126{
ab495388 1127 if (a >= - (DFtype) LONG_MIN)
203b91b9
RS
1128 return (SItype) (a + LONG_MIN) - LONG_MIN;
1129 return (SItype) a;
1130}
1131#endif
1132
1133#ifdef L_fixunssfsi
3f3d2ec8
JW
1134/* Reenable the normal types, in case limits.h needs them. */
1135#undef char
1136#undef short
1137#undef int
1138#undef long
1139#undef unsigned
1140#undef float
1141#undef double
c07e26bd
RK
1142#undef MIN
1143#undef MAX
a99598c9 1144#include <limits.h>
203b91b9 1145
ab495388
RS
1146USItype
1147__fixunssfsi (SFtype a)
203b91b9 1148{
ab495388 1149 if (a >= - (SFtype) LONG_MIN)
203b91b9
RS
1150 return (SItype) (a + LONG_MIN) - LONG_MIN;
1151 return (SItype) a;
1152}
1153#endif
1154\f
ab495388
RS
1155/* From here on down, the routines use normal data types. */
1156
1157#define SItype bogus_type
1158#define USItype bogus_type
1159#define DItype bogus_type
1160#define UDItype bogus_type
1161#define SFtype bogus_type
1162#define DFtype bogus_type
1163
1164#undef char
1165#undef short
1166#undef int
1167#undef long
1168#undef unsigned
1169#undef float
1170#undef double
9bd23d2c
RS
1171\f
1172#ifdef L__gcc_bcmp
1173
1174/* Like bcmp except the sign is meaningful.
9faa82d8 1175 Result is negative if S1 is less than S2,
9bd23d2c
RS
1176 positive if S1 is greater, 0 if S1 and S2 are equal. */
1177
1178int
1179__gcc_bcmp (s1, s2, size)
78e33213 1180 unsigned char *s1, *s2;
9bd23d2c
RS
1181 size_t size;
1182{
1183 while (size > 0)
1184 {
78e33213 1185 unsigned char c1 = *s1++, c2 = *s2++;
9bd23d2c
RS
1186 if (c1 != c2)
1187 return c1 - c2;
1188 size--;
1189 }
1190 return 0;
1191}
ab495388 1192
9bd23d2c
RS
1193#endif
1194\f\f
2e06e616
RK
1195#ifdef L__dummy
1196void
1197__dummy () {}
1198#endif
1199
203b91b9
RS
1200#ifdef L_varargs
1201#ifdef __i860__
600032fc 1202#if defined(__svr4__) || defined(__alliant__)
203b91b9
RS
1203 asm (" .text");
1204 asm (" .align 4");
1205
27d21d32 1206/* The Alliant needs the added underscore. */
203b91b9
RS
1207 asm (".globl __builtin_saveregs");
1208asm ("__builtin_saveregs:");
27d21d32
RS
1209 asm (".globl ___builtin_saveregs");
1210asm ("___builtin_saveregs:");
1211
1212 asm (" andnot 0x0f,%sp,%sp"); /* round down to 16-byte boundary */
203b91b9
RS
1213 asm (" adds -96,%sp,%sp"); /* allocate stack space for reg save
1214 area and also for a new va_list
1215 structure */
1216 /* Save all argument registers in the arg reg save area. The
1217 arg reg save area must have the following layout (according
1218 to the svr4 ABI):
1219
1220 struct {
1221 union {
1222 float freg[8];
1223 double dreg[4];
1224 } float_regs;
1225 long ireg[12];
1226 };
1227 */
1228
1229 asm (" fst.q %f8, 0(%sp)"); /* save floating regs (f8-f15) */
1230 asm (" fst.q %f12,16(%sp)");
1231
1232 asm (" st.l %r16,32(%sp)"); /* save integer regs (r16-r27) */
1233 asm (" st.l %r17,36(%sp)");
1234 asm (" st.l %r18,40(%sp)");
1235 asm (" st.l %r19,44(%sp)");
1236 asm (" st.l %r20,48(%sp)");
1237 asm (" st.l %r21,52(%sp)");
1238 asm (" st.l %r22,56(%sp)");
1239 asm (" st.l %r23,60(%sp)");
1240 asm (" st.l %r24,64(%sp)");
1241 asm (" st.l %r25,68(%sp)");
1242 asm (" st.l %r26,72(%sp)");
1243 asm (" st.l %r27,76(%sp)");
1244
1245 asm (" adds 80,%sp,%r16"); /* compute the address of the new
1246 va_list structure. Put in into
1247 r16 so that it will be returned
1248 to the caller. */
1249
1250 /* Initialize all fields of the new va_list structure. This
1251 structure looks like:
1252
1253 typedef struct {
1254 unsigned long ireg_used;
1255 unsigned long freg_used;
1256 long *reg_base;
1257 long *mem_ptr;
1258 } va_list;
1259 */
1260
1261 asm (" st.l %r0, 0(%r16)"); /* nfixed */
1262 asm (" st.l %r0, 4(%r16)"); /* nfloating */
1263 asm (" st.l %sp, 8(%r16)"); /* __va_ctl points to __va_struct. */
1264 asm (" bri %r1"); /* delayed return */
1265 asm (" st.l %r28,12(%r16)"); /* pointer to overflow args */
1266
24e4939e 1267#else /* not __svr4__ */
6aadf9c2
RS
1268#if defined(__PARAGON__)
1269 /*
1270 * we'll use SVR4-ish varargs but need SVR3.2 assembler syntax,
1271 * and we stand a better chance of hooking into libraries
1272 * compiled by PGI. [andyp@ssd.intel.com]
1273 */
1274 asm (" .text");
1275 asm (" .align 4");
1276 asm (".globl __builtin_saveregs");
1277asm ("__builtin_saveregs:");
1278 asm (".globl ___builtin_saveregs");
1279asm ("___builtin_saveregs:");
1280
1281 asm (" andnot 0x0f,sp,sp"); /* round down to 16-byte boundary */
1282 asm (" adds -96,sp,sp"); /* allocate stack space for reg save
1283 area and also for a new va_list
1284 structure */
1285 /* Save all argument registers in the arg reg save area. The
1286 arg reg save area must have the following layout (according
1287 to the svr4 ABI):
1288
1289 struct {
1290 union {
1291 float freg[8];
1292 double dreg[4];
1293 } float_regs;
1294 long ireg[12];
1295 };
1296 */
1297
1298 asm (" fst.q f8, 0(sp)");
1299 asm (" fst.q f12,16(sp)");
1300 asm (" st.l r16,32(sp)");
1301 asm (" st.l r17,36(sp)");
1302 asm (" st.l r18,40(sp)");
1303 asm (" st.l r19,44(sp)");
1304 asm (" st.l r20,48(sp)");
1305 asm (" st.l r21,52(sp)");
1306 asm (" st.l r22,56(sp)");
1307 asm (" st.l r23,60(sp)");
1308 asm (" st.l r24,64(sp)");
1309 asm (" st.l r25,68(sp)");
1310 asm (" st.l r26,72(sp)");
1311 asm (" st.l r27,76(sp)");
1312
1313 asm (" adds 80,sp,r16"); /* compute the address of the new
1314 va_list structure. Put in into
1315 r16 so that it will be returned
1316 to the caller. */
1317
1318 /* Initialize all fields of the new va_list structure. This
1319 structure looks like:
1320
1321 typedef struct {
1322 unsigned long ireg_used;
1323 unsigned long freg_used;
1324 long *reg_base;
1325 long *mem_ptr;
1326 } va_list;
1327 */
1328
1329 asm (" st.l r0, 0(r16)"); /* nfixed */
1330 asm (" st.l r0, 4(r16)"); /* nfloating */
1331 asm (" st.l sp, 8(r16)"); /* __va_ctl points to __va_struct. */
1332 asm (" bri r1"); /* delayed return */
1333 asm (" st.l r28,12(r16)"); /* pointer to overflow args */
1334#else /* not __PARAGON__ */
203b91b9
RS
1335 asm (" .text");
1336 asm (" .align 4");
1337
1338 asm (".globl ___builtin_saveregs");
1339 asm ("___builtin_saveregs:");
1340 asm (" mov sp,r30");
1341 asm (" andnot 0x0f,sp,sp");
1342 asm (" adds -96,sp,sp"); /* allocate sufficient space on the stack */
1343
1344/* Fill in the __va_struct. */
1345 asm (" st.l r16, 0(sp)"); /* save integer regs (r16-r27) */
1346 asm (" st.l r17, 4(sp)"); /* int fixed[12] */
1347 asm (" st.l r18, 8(sp)");
1348 asm (" st.l r19,12(sp)");
1349 asm (" st.l r20,16(sp)");
1350 asm (" st.l r21,20(sp)");
1351 asm (" st.l r22,24(sp)");
1352 asm (" st.l r23,28(sp)");
1353 asm (" st.l r24,32(sp)");
1354 asm (" st.l r25,36(sp)");
1355 asm (" st.l r26,40(sp)");
1356 asm (" st.l r27,44(sp)");
1357
1358 asm (" fst.q f8, 48(sp)"); /* save floating regs (f8-f15) */
1359 asm (" fst.q f12,64(sp)"); /* int floating[8] */
1360
1361/* Fill in the __va_ctl. */
1362 asm (" st.l sp, 80(sp)"); /* __va_ctl points to __va_struct. */
1363 asm (" st.l r28,84(sp)"); /* pointer to more args */
1364 asm (" st.l r0, 88(sp)"); /* nfixed */
1365 asm (" st.l r0, 92(sp)"); /* nfloating */
1366
1367 asm (" adds 80,sp,r16"); /* return address of the __va_ctl. */
1368 asm (" bri r1");
1369 asm (" mov r30,sp");
1370 /* recover stack and pass address to start
1371 of data. */
6aadf9c2 1372#endif /* not __PARAGON__ */
24e4939e 1373#endif /* not __svr4__ */
203b91b9
RS
1374#else /* not __i860__ */
1375#ifdef __sparc__
b335c2cc
TW
1376 asm (".global __builtin_saveregs");
1377 asm ("__builtin_saveregs:");
203b91b9
RS
1378 asm (".global ___builtin_saveregs");
1379 asm ("___builtin_saveregs:");
b1166fae
RS
1380#ifdef NEED_PROC_COMMAND
1381 asm (".proc 020");
b335c2cc 1382#endif
203b91b9
RS
1383 asm ("st %i0,[%fp+68]");
1384 asm ("st %i1,[%fp+72]");
1385 asm ("st %i2,[%fp+76]");
1386 asm ("st %i3,[%fp+80]");
1387 asm ("st %i4,[%fp+84]");
1388 asm ("retl");
1389 asm ("st %i5,[%fp+88]");
b1166fae
RS
1390#ifdef NEED_TYPE_COMMAND
1391 asm (".type __builtin_saveregs,#function");
1392 asm (".size __builtin_saveregs,.-__builtin_saveregs");
1393#endif
203b91b9
RS
1394#else /* not __sparc__ */
1395#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
1396
1397 asm (" .text");
1398 asm (" .ent __builtin_saveregs");
1399 asm (" .globl __builtin_saveregs");
1400 asm ("__builtin_saveregs:");
1401 asm (" sw $4,0($30)");
1402 asm (" sw $5,4($30)");
1403 asm (" sw $6,8($30)");
1404 asm (" sw $7,12($30)");
1405 asm (" j $31");
1406 asm (" .end __builtin_saveregs");
0f41302f 1407#else /* not __mips__, etc. */
3bd4f3b8
DE
1408
1409void *
203b91b9
RS
1410__builtin_saveregs ()
1411{
1412 abort ();
1413}
3bd4f3b8 1414
203b91b9
RS
1415#endif /* not __mips__ */
1416#endif /* not __sparc__ */
1417#endif /* not __i860__ */
1418#endif
1419\f
1420#ifdef L_eprintf
c74d5583 1421#ifndef inhibit_libc
bba2431c 1422
203b91b9
RS
1423#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
1424#include <stdio.h>
1425/* This is used by the `assert' macro. */
1426void
1427__eprintf (string, expression, line, filename)
b1166fae
RS
1428 const char *string;
1429 const char *expression;
203b91b9 1430 int line;
b1166fae 1431 const char *filename;
203b91b9
RS
1432{
1433 fprintf (stderr, string, expression, line, filename);
1434 fflush (stderr);
1435 abort ();
1436}
bba2431c
RS
1437
1438#endif
203b91b9
RS
1439#endif
1440
1441#ifdef L_bb
203b91b9 1442
92832bb5 1443/* Structure emitted by -a */
203b91b9
RS
1444struct bb
1445{
92832bb5
MM
1446 long zero_word;
1447 const char *filename;
1448 long *counts;
1449 long ncounts;
1450 struct bb *next;
1451 const unsigned long *addresses;
1452
1453 /* Older GCC's did not emit these fields. */
1454 long nwords;
1455 const char **functions;
1456 const long *line_nums;
1457 const char **filenames;
90b4a764 1458 char *flags;
203b91b9
RS
1459};
1460
92832bb5
MM
1461#ifdef BLOCK_PROFILER_CODE
1462BLOCK_PROFILER_CODE
1463#else
c7544ff7 1464#ifndef inhibit_libc
92832bb5
MM
1465
1466/* Simple minded basic block profiling output dumper for
9faa82d8 1467 systems that don't provide tcov support. At present,
92832bb5
MM
1468 it requires atexit and stdio. */
1469
ebd41309 1470#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
92832bb5 1471#include <stdio.h>
b077f3ac 1472char *ctime ();
203b91b9 1473
8b7677be 1474#include "gbl-ctors.h"
92832bb5 1475
7e6f1890 1476static struct bb *bb_head;
92832bb5
MM
1477
1478/* Return the number of digits needed to print a value */
1479/* __inline__ */ static int num_digits (long value, int base)
203b91b9 1480{
92832bb5
MM
1481 int minus = (value < 0 && base != 16);
1482 unsigned long v = (minus) ? -value : value;
1483 int ret = minus;
203b91b9 1484
92832bb5
MM
1485 do
1486 {
1487 v /= base;
1488 ret++;
1489 }
1490 while (v);
1491
1492 return ret;
203b91b9
RS
1493}
1494
92832bb5
MM
1495void
1496__bb_exit_func (void)
1497{
1498 FILE *file = fopen ("bb.out", "a");
1499 long time_value;
1500
1501 if (!file)
1502 perror ("bb.out");
1503
1504 else
1505 {
1506 struct bb *ptr;
1507
1508 /* This is somewhat type incorrect, but it avoids worrying about
1509 exactly where time.h is included from. It should be ok unless
90b4a764 1510 a void * differs from other pointer formats, or if sizeof (long)
92832bb5
MM
1511 is < sizeof (time_t). It would be nice if we could assume the
1512 use of rationale standards here. */
1513
90b4a764 1514 time ((void *) &time_value);
92832bb5
MM
1515 fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
1516
1517 /* We check the length field explicitly in order to allow compatibility
1518 with older GCC's which did not provide it. */
1519
0f41302f 1520 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
92832bb5
MM
1521 {
1522 int i;
1523 int func_p = (ptr->nwords >= sizeof (struct bb) && ptr->nwords <= 1000);
1524 int line_p = (func_p && ptr->line_nums);
1525 int file_p = (func_p && ptr->filenames);
1526 long ncounts = ptr->ncounts;
1527 long cnt_max = 0;
1528 long line_max = 0;
1529 long addr_max = 0;
1530 int file_len = 0;
1531 int func_len = 0;
1532 int blk_len = num_digits (ncounts, 10);
1533 int cnt_len;
1534 int line_len;
1535 int addr_len;
1536
1537 fprintf (file, "File %s, %ld basic blocks \n\n",
1538 ptr->filename, ncounts);
1539
1540 /* Get max values for each field. */
1541 for (i = 0; i < ncounts; i++)
1542 {
1543 const char *p;
1544 int len;
1545
1546 if (cnt_max < ptr->counts[i])
1547 cnt_max = ptr->counts[i];
1548
1549 if (addr_max < ptr->addresses[i])
1550 addr_max = ptr->addresses[i];
1551
1552 if (line_p && line_max < ptr->line_nums[i])
1553 line_max = ptr->line_nums[i];
1554
1555 if (func_p)
1556 {
1557 p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
1558 len = strlen (p);
1559 if (func_len < len)
1560 func_len = len;
1561 }
1562
1563 if (file_p)
1564 {
1565 p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
1566 len = strlen (p);
1567 if (file_len < len)
1568 file_len = len;
1569 }
1570 }
1571
1572 addr_len = num_digits (addr_max, 16);
1573 cnt_len = num_digits (cnt_max, 10);
1574 line_len = num_digits (line_max, 10);
1575
1576 /* Now print out the basic block information. */
1577 for (i = 0; i < ncounts; i++)
1578 {
1579 fprintf (file,
3cca99e8 1580 " Block #%*d: executed %*ld time(s) address= 0x%.*lx",
92832bb5
MM
1581 blk_len, i+1,
1582 cnt_len, ptr->counts[i],
1583 addr_len, ptr->addresses[i]);
1584
1585 if (func_p)
3cca99e8 1586 fprintf (file, " function= %-*s", func_len,
92832bb5
MM
1587 (ptr->functions[i]) ? ptr->functions[i] : "<none>");
1588
1589 if (line_p)
1d42e1b7 1590 fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
92832bb5
MM
1591
1592 if (file_p)
3cca99e8 1593 fprintf (file, " file= %s",
92832bb5
MM
1594 (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
1595
1596 fprintf (file, "\n");
1597 }
1598
1599 fprintf (file, "\n");
1600 fflush (file);
1601 }
1602
1603 fprintf (file, "\n\n");
1604 fclose (file);
1605 }
1606}
1607
1608void
1609__bb_init_func (struct bb *blocks)
1610{
1611 /* User is supposed to check whether the first word is non-0,
0f41302f 1612 but just in case.... */
92832bb5
MM
1613
1614 if (blocks->zero_word)
1615 return;
1616
1617#ifdef ON_EXIT
1618 /* Initialize destructor. */
1619 if (!bb_head)
1620 ON_EXIT (__bb_exit_func, 0);
203b91b9 1621#endif
92832bb5
MM
1622
1623 /* Set up linked list. */
1624 blocks->zero_word = 1;
1625 blocks->next = bb_head;
1626 bb_head = blocks;
1627}
1628
90b4a764
RK
1629#ifndef MACHINE_STATE_SAVE
1630#define MACHINE_STATE_SAVE(ID)
1631#endif
1632#ifndef MACHINE_STATE_RESTORE
1633#define MACHINE_STATE_RESTORE(ID)
1634#endif
1635
1636#include <string.h>
1637
0f41302f 1638/* Number of buckets in hashtable of basic block addresses. */
90b4a764
RK
1639
1640#define BB_BUCKETS 311
1641
0f41302f 1642/* Maximum length of string in file bb.in. */
90b4a764
RK
1643
1644#define BBINBUFSIZE 500
1645
1646/* BBINBUFSIZE-1 with double quotes. We could use #BBINBUFSIZE or
0f41302f 1647 "BBINBUFSIZE" but want to avoid trouble with preprocessors. */
90b4a764
RK
1648
1649#define BBINBUFSIZESTR "499"
1650
1651struct bb_edge
1652{
1653 struct bb_edge *next;
1654 unsigned long src_addr;
1655 unsigned long dst_addr;
1656 unsigned long count;
1657};
1658
1659enum bb_func_mode
1660{
1661 TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
1662};
1663
1664struct bb_func
1665{
1666 struct bb_func *next;
1667 char *funcname;
1668 char *filename;
1669 enum bb_func_mode mode;
1670};
1671
1672/* This is the connection to the outside world.
1673 The BLOCK_PROFILER macro must set __bb.blocks
0f41302f 1674 and __bb.blockno. */
90b4a764
RK
1675
1676struct {
1677 unsigned long blockno;
1678 struct bb *blocks;
1679} __bb;
1680
1681/* Vars to store addrs of source and destination basic blocks
0f41302f 1682 of a jump. */
90b4a764
RK
1683
1684static unsigned long bb_src = 0;
1685static unsigned long bb_dst = 0;
1686
0f41302f
MS
1687static FILE *bb_tracefile = (FILE *) 0;
1688static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
1689static struct bb_func *bb_func_head = (struct bb_func *) 0;
90b4a764
RK
1690static unsigned long bb_callcount = 0;
1691static int bb_mode = 0;
1692
0f41302f 1693static unsigned long *bb_stack = (unsigned long *) 0;
90b4a764
RK
1694static size_t bb_stacksize = 0;
1695
1696static int reported = 0;
1697
1698/* Trace modes:
1699Always : Print execution frequencies of basic blocks
1700 to file bb.out.
1701bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
1702bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
1703bb_mode & 4 != 0 : Cut call instructions from basic block flow.
1704bb_mode & 8 != 0 : Insert return instructions in basic block flow.
1705*/
1706
1707#ifdef HAVE_POPEN
1708
1709/*#include <sys/types.h>*/
1710#include <sys/stat.h>
1711/*#include <malloc.h>*/
1712
0f41302f 1713/* Commands executed by gopen. */
90b4a764
RK
1714
1715#define GOPENDECOMPRESS "gzip -cd "
1716#define GOPENCOMPRESS "gzip -c >"
1717
1718/* Like fopen but pipes through gzip. mode may only be "r" or "w".
1719 If it does not compile, simply replace gopen by fopen and delete
0f41302f 1720 '.gz' from any first parameter to gopen. */
90b4a764
RK
1721
1722static FILE *
1723gopen (fn, mode)
1724 char *fn;
1725 char *mode;
1726{
1727 int use_gzip;
1728 char *p;
1729
1730 if (mode[1])
0f41302f 1731 return (FILE *) 0;
90b4a764
RK
1732
1733 if (mode[0] != 'r' && mode[0] != 'w')
0f41302f 1734 return (FILE *) 0;
90b4a764
RK
1735
1736 p = fn + strlen (fn)-1;
1737 use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z')) ||
1738 (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
1739
1740 if (use_gzip)
1741 {
1742 if (mode[0]=='r')
1743 {
1744 FILE *f;
0f41302f
MS
1745 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1746 + sizeof (GOPENDECOMPRESS));
90b4a764
RK
1747 strcpy (s, GOPENDECOMPRESS);
1748 strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
1749 f = popen (s, mode);
1750 free (s);
1751 return f;
1752 }
1753
1754 else
1755 {
1756 FILE *f;
0f41302f
MS
1757 char *s = (char *) malloc (sizeof (char) * strlen (fn)
1758 + sizeof (GOPENCOMPRESS));
90b4a764
RK
1759 strcpy (s, GOPENCOMPRESS);
1760 strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
1761 if (!(f = popen (s, mode)))
1762 f = fopen (s, mode);
1763 free (s);
1764 return f;
1765 }
1766 }
1767
1768 else
1769 return fopen (fn, mode);
1770}
1771
1772static int
1773gclose (f)
1774 FILE *f;
1775{
1776 struct stat buf;
1777
1778 if (f != NULL)
1779 {
1780 if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
1781 return pclose (f);
1782
1783 return fclose (f);
1784 }
1785 return 0;
1786}
1787
1788#endif /* HAVE_POPEN */
1789
0f41302f 1790/* Called once per program. */
90b4a764
RK
1791
1792static void
1793__bb_exit_trace_func ()
1794{
1795 FILE *file = fopen ("bb.out", "a");
1796 struct bb_func *f;
1797 struct bb_edge *e;
1798 struct bb *b;
1799
1800 if (!file)
1801 perror ("bb.out");
1802
1803 if (bb_mode & 1)
1804 {
1805 if (!bb_tracefile)
1806 perror ("bbtrace");
1807 else
1808#ifdef HAVE_POPEN
1809 gclose (bb_tracefile);
1810#else
1811 fclose (bb_tracefile);
1812#endif /* HAVE_POPEN */
1813 }
1814
0f41302f 1815 /* Check functions in `bb.in'. */
90b4a764
RK
1816
1817 if (file)
1818 {
1819 long time_value;
1820 const struct bb_func *p;
1821 int printed_something = 0;
1822 struct bb *ptr;
1823 long blk;
1824
0f41302f 1825 /* This is somewhat type incorrect. */
90b4a764
RK
1826 time ((void *) &time_value);
1827
0f41302f 1828 for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
90b4a764 1829 {
0f41302f 1830 for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
90b4a764 1831 {
0f41302f 1832 if (!ptr->filename || p->filename != (char *) 0 && strcmp (p->filename, ptr->filename))
90b4a764
RK
1833 continue;
1834 for (blk = 0; blk < ptr->ncounts; blk++)
1835 {
1836 if (!strcmp (p->funcname, ptr->functions[blk]))
1837 goto found;
1838 }
1839 }
1840
1841 if (!printed_something)
1842 {
1843 fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
1844 printed_something = 1;
1845 }
1846
1847 fprintf (file, "\tFunction %s", p->funcname);
1848 if (p->filename)
1849 fprintf (file, " of file %s", p->filename);
1850 fprintf (file, "\n" );
1851
1852found: ;
1853 }
1854
1855 if (printed_something)
1856 fprintf (file, "\n");
1857
1858 }
1859
1860 if (bb_mode & 2)
1861 {
1862 if (!bb_hashbuckets)
1863 {
1864 if (!reported)
1865 {
1866 fprintf (stderr, "Profiler: out of memory\n");
1867 reported = 1;
1868 }
1869 return;
1870 }
1871
1872 else if (file)
1873 {
1874 long time_value;
1875 int i;
1876 unsigned long addr_max = 0;
1877 unsigned long cnt_max = 0;
1878 int cnt_len;
1879 int addr_len;
1880
1881 /* This is somewhat type incorrect, but it avoids worrying about
1882 exactly where time.h is included from. It should be ok unless
1883 a void * differs from other pointer formats, or if sizeof (long)
1884 is < sizeof (time_t). It would be nice if we could assume the
1885 use of rationale standards here. */
1886
1887 time ((void *) &time_value);
1888 fprintf (file, "Basic block jump tracing");
1889
1890 switch (bb_mode & 12)
1891 {
1892 case 0:
1893 fprintf (file, " (with call)");
1894 break;
1895
1896 case 4:
0f41302f 1897 /* Print nothing. */
90b4a764
RK
1898 break;
1899
1900 case 8:
1901 fprintf (file, " (with call & ret)");
1902 break;
1903
1904 case 12:
1905 fprintf (file, " (with ret)");
1906 break;
1907 }
1908
1909 fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
1910
1911 for (i = 0; i < BB_BUCKETS; i++)
1912 {
1913 struct bb_edge *bucket = bb_hashbuckets[i];
1914 for ( ; bucket; bucket = bucket->next )
1915 {
1916 if (addr_max < bucket->src_addr)
1917 addr_max = bucket->src_addr;
1918 if (addr_max < bucket->dst_addr)
1919 addr_max = bucket->dst_addr;
1920 if (cnt_max < bucket->count)
1921 cnt_max = bucket->count;
1922 }
1923 }
1924 addr_len = num_digits (addr_max, 16);
1925 cnt_len = num_digits (cnt_max, 10);
1926
1927 for ( i = 0; i < BB_BUCKETS; i++)
1928 {
1929 struct bb_edge *bucket = bb_hashbuckets[i];
1930 for ( ; bucket; bucket = bucket->next )
1931 {
1932 fprintf (file, "Jump from block 0x%.*lx to "
1933 "block 0x%.*lx executed %*d time(s)\n",
1934 addr_len, bucket->src_addr,
1935 addr_len, bucket->dst_addr,
1936 cnt_len, bucket->count);
1937 }
1938 }
1939
1940 fprintf (file, "\n");
1941
1942 }
1943 }
1944
1945 if (file)
1946 fclose (file);
1947
0f41302f 1948 /* Free allocated memory. */
90b4a764
RK
1949
1950 f = bb_func_head;
1951 while (f)
1952 {
1953 struct bb_func *old = f;
1954
1955 f = f->next;
1956 if (old->funcname) free (old->funcname);
1957 if (old->filename) free (old->filename);
1958 free (old);
1959 }
1960
1961 if (bb_stack)
1962 free (bb_stack);
1963
1964 if (bb_hashbuckets)
1965 {
1966 int i;
1967
1968 for (i = 0; i < BB_BUCKETS; i++)
1969 {
1970 struct bb_edge *old, *bucket = bb_hashbuckets[i];
1971
1972 while (bucket)
1973 {
1974 old = bucket;
1975 bucket = bucket->next;
1976 free (old);
1977 }
1978 }
1979 free (bb_hashbuckets);
1980 }
1981
1982 for (b = bb_head; b; b = b->next)
1983 if (b->flags) free (b->flags);
1984}
1985
0f41302f 1986/* Called once per program. */
90b4a764
RK
1987
1988static void
1989__bb_init_prg ()
1990{
1991
1992 FILE *file;
1993 char buf[BBINBUFSIZE];
1994 const char *p;
1995 const char *pos;
1996 enum bb_func_mode m;
1997
1998#ifdef ON_EXIT
1999 /* Initialize destructor. */
2000 ON_EXIT (__bb_exit_func, 0);
2001#endif
2002
2003 if (!(file = fopen ("bb.in", "r")))
2004 return;
2005
2006 while(fscanf (file, " %" BBINBUFSIZESTR "s ", buf) != EOF)
2007 {
2008 p = buf;
2009 if (*p == '-')
2010 {
2011 m = TRACE_OFF;
2012 p++;
2013 }
2014 else
2015 {
2016 m = TRACE_ON;
2017 }
2018 if (!strcmp (p, "__bb_trace__"))
2019 bb_mode |= 1;
2020 else if (!strcmp (p, "__bb_jumps__"))
2021 bb_mode |= 2;
2022 else if (!strcmp (p, "__bb_hidecall__"))
2023 bb_mode |= 4;
2024 else if (!strcmp (p, "__bb_showret__"))
2025 bb_mode |= 8;
2026 else
2027 {
0f41302f 2028 struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
90b4a764
RK
2029 if (f)
2030 {
2031 unsigned long l;
2032 f->next = bb_func_head;
2033 if (pos = strchr (p, ':'))
2034 {
0f41302f 2035 if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
90b4a764
RK
2036 continue;
2037 strcpy (f->funcname, pos+1);
2038 l = pos-p;
0f41302f 2039 if ((f->filename = (char *) malloc (l+1)))
90b4a764
RK
2040 {
2041 strncpy (f->filename, p, l);
2042 f->filename[l] = '\0';
2043 }
2044 else
0f41302f 2045 f->filename = (char *) 0;
90b4a764
RK
2046 }
2047 else
2048 {
0f41302f 2049 if (!(f->funcname = (char *) malloc (strlen (p)+1)))
90b4a764
RK
2050 continue;
2051 strcpy (f->funcname, p);
0f41302f 2052 f->filename = (char *) 0;
90b4a764
RK
2053 }
2054 f->mode = m;
2055 bb_func_head = f;
2056 }
2057 }
2058 }
2059 fclose (file);
2060
2061#ifdef HAVE_POPEN
2062
2063 if (bb_mode & 1)
2064 bb_tracefile = gopen ("bbtrace.gz", "w");
2065
2066#else
2067
2068 if (bb_mode & 1)
2069 bb_tracefile = fopen ("bbtrace", "w");
2070
2071#endif /* HAVE_POPEN */
2072
2073 if (bb_mode & 2)
2074 {
2075 bb_hashbuckets = (struct bb_edge **)
2076 malloc (BB_BUCKETS * sizeof (struct bb_edge *));
2077 if (bb_hashbuckets)
9bb89050 2078 bzero ((char *) bb_hashbuckets, BB_BUCKETS);
90b4a764
RK
2079 }
2080
2081 if (bb_mode & 12)
2082 {
2083 bb_stacksize = 10;
2084 bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
2085 }
2086
2087#ifdef ON_EXIT
2088 /* Initialize destructor. */
2089 ON_EXIT (__bb_exit_trace_func, 0);
2090#endif
2091
2092}
2093
0f41302f 2094/* Called upon entering a basic block. */
90b4a764
RK
2095
2096void
2097__bb_trace_func ()
2098{
2099 struct bb_edge *bucket;
2100
2101 MACHINE_STATE_SAVE("1")
2102
2103 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2104 goto skip;
2105
2106 bb_dst = __bb.blocks->addresses[__bb.blockno];
2107 __bb.blocks->counts[__bb.blockno]++;
2108
2109 if (bb_tracefile)
2110 {
2111 fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
2112 }
2113
2114 if (bb_hashbuckets)
2115 {
2116 struct bb_edge **startbucket, **oldnext;
2117
2118 oldnext = startbucket =
0f41302f 2119 & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
90b4a764
RK
2120 bucket = *startbucket;
2121
2122 for (bucket = *startbucket; bucket;
2123 oldnext = &(bucket->next), bucket = *oldnext)
2124 {
2125 if ( bucket->src_addr == bb_src &&
2126 bucket->dst_addr == bb_dst )
2127 {
2128 bucket->count++;
2129 *oldnext = bucket->next;
2130 bucket->next = *startbucket;
2131 *startbucket = bucket;
2132 goto ret;
2133 }
2134 }
2135
2136 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2137
2138 if (!bucket)
2139 {
2140 if (!reported)
2141 {
2142 fprintf (stderr, "Profiler: out of memory\n");
2143 reported = 1;
2144 }
2145 }
2146
2147 else
2148 {
2149 bucket->src_addr = bb_src;
2150 bucket->dst_addr = bb_dst;
2151 bucket->next = *startbucket;
2152 *startbucket = bucket;
2153 bucket->count = 1;
2154 }
2155 }
2156
2157ret:
2158 bb_src = bb_dst;
2159
2160skip:
2161 ;
2162
2163 MACHINE_STATE_RESTORE("1")
2164
2165}
2166
0f41302f 2167/* Called when returning from a function and `__bb_showret__' is set. */
90b4a764
RK
2168
2169static void
2170__bb_trace_func_ret ()
2171{
2172 struct bb_edge *bucket;
2173
2174 if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
2175 goto skip;
2176
2177 if (bb_hashbuckets)
2178 {
2179 struct bb_edge **startbucket, **oldnext;
2180
2181 oldnext = startbucket =
0f41302f 2182 & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
90b4a764
RK
2183 bucket = *startbucket;
2184
2185 for (bucket = *startbucket; bucket;
2186 oldnext = &(bucket->next), bucket = *oldnext)
2187 {
2188 if ( bucket->src_addr == bb_dst &&
2189 bucket->dst_addr == bb_src )
2190 {
2191 bucket->count++;
2192 *oldnext = bucket->next;
2193 bucket->next = *startbucket;
2194 *startbucket = bucket;
2195 goto ret;
2196 }
2197 }
2198
2199 bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
2200
2201 if (!bucket)
2202 {
2203 if (!reported)
2204 {
2205 fprintf (stderr, "Profiler: out of memory\n");
2206 reported = 1;
2207 }
2208 }
2209
2210 else
2211 {
2212 bucket->src_addr = bb_dst;
2213 bucket->dst_addr = bb_src;
2214 bucket->next = *startbucket;
2215 *startbucket = bucket;
2216 bucket->count = 1;
2217 }
2218 }
2219
2220ret:
2221 bb_dst = bb_src;
2222
2223skip:
2224 ;
2225
2226}
2227
0f41302f 2228/* Called upon entering the first function of a file. */
90b4a764
RK
2229
2230static void
2231__bb_init_file (blocks)
2232 struct bb *blocks;
2233{
2234
2235 const struct bb_func *p;
2236 long blk, ncounts = blocks->ncounts;
2237 const char **functions = blocks->functions;
2238
2239 /* Set up linked list. */
2240 blocks->zero_word = 1;
2241 blocks->next = bb_head;
2242 bb_head = blocks;
2243
2244 blocks->flags = 0;
2245 if (!bb_func_head ||
0f41302f 2246 !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
90b4a764
RK
2247 return;
2248
2249 for (blk = 0; blk < ncounts; blk++)
2250 blocks->flags[blk] = 0;
2251
2252 for (blk = 0; blk < ncounts; blk++)
2253 {
2254 for (p = bb_func_head; p; p = p->next)
2255 {
2256 if (!strcmp (p->funcname, functions[blk]) &&
2257 (!p->filename || !strcmp (p->filename, blocks->filename)))
2258 {
2259 blocks->flags[blk] |= p->mode;
2260 }
2261 }
2262 }
2263
2264}
2265
0f41302f 2266/* Called when exiting from a function. */
90b4a764
RK
2267
2268void
2269__bb_trace_ret ()
2270{
2271
2272 MACHINE_STATE_SAVE("2")
2273
2274 if (bb_callcount)
2275 {
2276 if ((bb_mode & 12) && bb_stacksize > bb_callcount)
2277 {
2278 bb_src = bb_stack[bb_callcount];
2279 if (bb_mode & 8)
2280 __bb_trace_func_ret ();
2281 }
2282
2283 bb_callcount -= 1;
2284 }
2285
2286 MACHINE_STATE_RESTORE("2")
2287
2288}
2289
0f41302f 2290/* Called when entering a function. */
90b4a764
RK
2291
2292void
2293__bb_init_trace_func (blocks, blockno)
2294 struct bb *blocks;
2295 unsigned long blockno;
2296{
2297 static int trace_init = 0;
2298
2299 MACHINE_STATE_SAVE("3")
2300
2301 if (!blocks->zero_word)
2302 {
2303 if (!trace_init)
2304 {
2305 trace_init = 1;
2306 __bb_init_prg ();
2307 }
2308 __bb_init_file (blocks);
2309 }
2310
2311 if (bb_callcount)
2312 {
2313
2314 bb_callcount += 1;
2315
2316 if (bb_mode & 12)
2317 {
2318 if (bb_callcount >= bb_stacksize)
2319 {
2320 size_t newsize = bb_callcount + 100;
2321
2322 bb_stack = (unsigned long *) realloc (bb_stack, newsize);
2323 if (! bb_stack)
2324 {
2325 if (!reported)
2326 {
2327 fprintf (stderr, "Profiler: out of memory\n");
2328 reported = 1;
2329 }
2330 bb_stacksize = 0;
2331 goto stack_overflow;
2332 }
2333 bb_stacksize = newsize;
2334 }
2335 bb_stack[bb_callcount] = bb_src;
2336
2337 if (bb_mode & 4)
2338 bb_src = 0;
2339
2340 }
2341
2342stack_overflow:;
2343
2344 }
2345
2346 else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
2347 {
2348 bb_callcount = 1;
2349 bb_src = 0;
2350
2351 if (bb_stack)
2352 bb_stack[bb_callcount] = bb_src;
2353 }
2354
2355 MACHINE_STATE_RESTORE("3")
2356}
2357
c7544ff7
RS
2358#endif /* not inhibit_libc */
2359#endif /* not BLOCK_PROFILER_CODE */
2360#endif /* L_bb */
203b91b9 2361\f
6ffe3a32 2362/* Default free-store management functions for C++, per sections 12.5 and
0f41302f 2363 17.3.3 of the Working Paper. */
203b91b9 2364
ec06f00a 2365#ifdef L_op_new
6ffe3a32 2366/* operator new (size_t), described in 17.3.3.5. This function is used by
0f41302f 2367 C++ programs to allocate a block of memory to hold a single object. */
203b91b9 2368
6ffe3a32 2369typedef void (*vfp)(void);
203b91b9 2370extern vfp __new_handler;
8a552066 2371extern void __default_new_handler (void);
203b91b9 2372
daefd78b
JM
2373#ifdef WEAK_ALIAS
2374void * __builtin_new (size_t sz)
2375 __attribute__ ((weak, alias ("___builtin_new")));
2376void *
2377___builtin_new (size_t sz)
2378#else
203b91b9 2379void *
ec06f00a 2380__builtin_new (size_t sz)
daefd78b 2381#endif
203b91b9
RS
2382{
2383 void *p;
8a552066 2384 vfp handler = (__new_handler) ? __new_handler : __default_new_handler;
203b91b9 2385
bcea2185
RS
2386 /* malloc (0) is unpredictable; avoid it. */
2387 if (sz == 0)
2388 sz = 1;
ecbe06a1 2389 p = (void *) malloc (sz);
442e881d
RK
2390 while (p == 0)
2391 {
8a552066 2392 (*handler) ();
442e881d
RK
2393 p = (void *) malloc (sz);
2394 }
2395
203b91b9
RS
2396 return p;
2397}
ec06f00a 2398#endif /* L_op_new */
203b91b9 2399
4c548483 2400#ifdef L_op_vnew
6ffe3a32
JM
2401/* void * operator new [] (size_t), described in 17.3.3.6. This function
2402 is used by C++ programs to allocate a block of memory for an array. */
2403
2404extern void * __builtin_new (size_t);
2405
daefd78b
JM
2406#ifdef WEAK_ALIAS
2407void * __builtin_vec_new (size_t sz)
2408 __attribute__ ((weak, alias ("___builtin_vec_new")));
2409void *
2410___builtin_vec_new (size_t sz)
2411#else
6ffe3a32
JM
2412void *
2413__builtin_vec_new (size_t sz)
daefd78b 2414#endif
6ffe3a32
JM
2415{
2416 return __builtin_new (sz);
2417}
4c548483 2418#endif /* L_op_vnew */
6ffe3a32 2419
ec06f00a 2420#ifdef L_new_handler
6ffe3a32
JM
2421/* set_new_handler (fvoid_t *) and the default new handler, described in
2422 17.3.3.2 and 17.3.3.5. These functions define the result of a failure
0f41302f 2423 to allocate the amount of memory requested from operator new or new []. */
fffa6914 2424
c74d5583 2425#ifndef inhibit_libc
fffa6914 2426/* This gets us __GNU_LIBRARY__. */
98126ed6 2427#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
fffa6914
RS
2428#include <stdio.h>
2429
2430#ifdef __GNU_LIBRARY__
2431 /* Avoid forcing the library's meaning of `write' on the user program
e45d9b98 2432 by using the "internal" name (for use within the library) */
fffa6914
RS
2433#define write(fd, buf, n) __write((fd), (buf), (n))
2434#endif
c74d5583 2435#endif /* inhibit_libc */
fffa6914 2436
203b91b9 2437typedef void (*vfp)(void);
6ffe3a32 2438void __default_new_handler (void);
203b91b9 2439
0f41302f 2440vfp __new_handler = (vfp) 0;
203b91b9 2441
203b91b9 2442vfp
6ffe3a32 2443set_new_handler (vfp handler)
203b91b9
RS
2444{
2445 vfp prev_handler;
2446
2447 prev_handler = __new_handler;
442e881d 2448 if (handler == 0) handler = __default_new_handler;
203b91b9
RS
2449 __new_handler = handler;
2450 return prev_handler;
2451}
2452
b1166fae
RS
2453#define MESSAGE "Virtual memory exceeded in `new'\n"
2454
6ffe3a32 2455void
442e881d 2456__default_new_handler ()
203b91b9 2457{
2c62c124 2458#ifndef inhibit_libc
203b91b9
RS
2459 /* don't use fprintf (stderr, ...) because it may need to call malloc. */
2460 /* This should really print the name of the program, but that is hard to
2461 do. We need a standard, clean way to get at the name. */
b1166fae 2462 write (2, MESSAGE, sizeof (MESSAGE));
2c62c124 2463#endif
203b91b9
RS
2464 /* don't call exit () because that may call global destructors which
2465 may cause a loop. */
2466 _exit (-1);
2467}
2468#endif
203b91b9 2469
ec06f00a 2470#ifdef L_op_delete
6ffe3a32
JM
2471/* operator delete (void *), described in 17.3.3.3. This function is used
2472 by C++ programs to return to the free store a block of memory allocated
0f41302f 2473 as a single object. */
6ffe3a32 2474
daefd78b
JM
2475#ifdef WEAK_ALIAS
2476void __builtin_delete (void *ptr)
2477 __attribute__ ((weak, alias ("___builtin_delete")));
2478void
2479___builtin_delete (void *ptr)
2480#else
203b91b9 2481void
ec06f00a 2482__builtin_delete (void *ptr)
daefd78b 2483#endif
203b91b9
RS
2484{
2485 if (ptr)
2486 free (ptr);
2487}
203b91b9 2488#endif
6ffe3a32 2489
4c548483 2490#ifdef L_op_vdel
6ffe3a32
JM
2491/* operator delete [] (void *), described in 17.3.3.4. This function is
2492 used by C++ programs to return to the free store a block of memory
0f41302f 2493 allocated as an array. */
6ffe3a32
JM
2494
2495extern void __builtin_delete (void *);
2496
daefd78b
JM
2497#ifdef WEAK_ALIAS
2498void __builtin_vec_delete (void *ptr)
2499 __attribute__ ((weak, alias ("___builtin_vec_delete")));
2500void
2501___builtin_vec_delete (void *ptr)
2502#else
6ffe3a32
JM
2503void
2504__builtin_vec_delete (void *ptr)
daefd78b 2505#endif
6ffe3a32
JM
2506{
2507 __builtin_delete (ptr);
2508}
2509#endif
2510
2511/* End of C++ free-store management functions */
ec06f00a 2512\f
203b91b9
RS
2513#ifdef L_shtab
2514unsigned int __shtab[] = {
2515 0x00000001, 0x00000002, 0x00000004, 0x00000008,
2516 0x00000010, 0x00000020, 0x00000040, 0x00000080,
2517 0x00000100, 0x00000200, 0x00000400, 0x00000800,
2518 0x00001000, 0x00002000, 0x00004000, 0x00008000,
2519 0x00010000, 0x00020000, 0x00040000, 0x00080000,
2520 0x00100000, 0x00200000, 0x00400000, 0x00800000,
2521 0x01000000, 0x02000000, 0x04000000, 0x08000000,
2522 0x10000000, 0x20000000, 0x40000000, 0x80000000
2523 };
2524#endif
2525\f
2526#ifdef L_clear_cache
2527/* Clear part of an instruction cache. */
2528
2529#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
2530
2531void
2532__clear_cache (beg, end)
2533 char *beg, *end;
2534{
e1178973
KKT
2535#ifdef CLEAR_INSN_CACHE
2536 CLEAR_INSN_CACHE (beg, end);
2537#else
203b91b9
RS
2538#ifdef INSN_CACHE_SIZE
2539 static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
7e6f1890 2540 static int initialized;
203b91b9 2541 int offset;
b6422cca
RS
2542 void *start_addr
2543 void *end_addr;
203b91b9
RS
2544 typedef (*function_ptr) ();
2545
2546#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
2547 /* It's cheaper to clear the whole cache.
2548 Put in a series of jump instructions so that calling the beginning
2549 of the cache will clear the whole thing. */
2550
2551 if (! initialized)
2552 {
2553 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2554 & -INSN_CACHE_LINE_WIDTH);
2555 int end_ptr = ptr + INSN_CACHE_SIZE;
2556
2557 while (ptr < end_ptr)
2558 {
2559 *(INSTRUCTION_TYPE *)ptr
2560 = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
2561 ptr += INSN_CACHE_LINE_WIDTH;
2562 }
0f41302f 2563 *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
203b91b9
RS
2564
2565 initialized = 1;
2566 }
2567
2568 /* Call the beginning of the sequence. */
2569 (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2570 & -INSN_CACHE_LINE_WIDTH))
2571 ());
2572
2573#else /* Cache is large. */
2574
2575 if (! initialized)
2576 {
2577 int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
2578 & -INSN_CACHE_LINE_WIDTH);
2579
2580 while (ptr < (int) array + sizeof array)
2581 {
2582 *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
2583 ptr += INSN_CACHE_LINE_WIDTH;
2584 }
2585
2586 initialized = 1;
2587 }
2588
2589 /* Find the location in array that occupies the same cache line as BEG. */
2590
2591 offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
2592 start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
2593 & -INSN_CACHE_PLANE_SIZE)
2594 + offset);
2595
2596 /* Compute the cache alignment of the place to stop clearing. */
2597#if 0 /* This is not needed for gcc's purposes. */
2598 /* If the block to clear is bigger than a cache plane,
2599 we clear the entire cache, and OFFSET is already correct. */
2600 if (end < beg + INSN_CACHE_PLANE_SIZE)
2601#endif
2602 offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
2603 & -INSN_CACHE_LINE_WIDTH)
2604 & (INSN_CACHE_PLANE_SIZE - 1));
2605
2606#if INSN_CACHE_DEPTH > 1
2607 end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset;
2608 if (end_addr <= start_addr)
2609 end_addr += INSN_CACHE_PLANE_SIZE;
2610
2611 for (plane = 0; plane < INSN_CACHE_DEPTH; plane++)
2612 {
2613 int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE;
2614 int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE;
2615
2616 while (addr != stop)
2617 {
2618 /* Call the return instruction at ADDR. */
2619 ((function_ptr) addr) ();
2620
2621 addr += INSN_CACHE_LINE_WIDTH;
2622 }
2623 }
2624#else /* just one plane */
2625 do
2626 {
2627 /* Call the return instruction at START_ADDR. */
2628 ((function_ptr) start_addr) ();
2629
2630 start_addr += INSN_CACHE_LINE_WIDTH;
2631 }
2632 while ((start_addr % INSN_CACHE_SIZE) != offset);
2633#endif /* just one plane */
2634#endif /* Cache is large */
2635#endif /* Cache exists */
e1178973 2636#endif /* CLEAR_INSN_CACHE */
203b91b9
RS
2637}
2638
2639#endif /* L_clear_cache */
2640\f
2641#ifdef L_trampoline
2642
2643/* Jump to a trampoline, loading the static chain address. */
2644
f5ea9817
RK
2645#ifdef WINNT
2646
2647long getpagesize()
2648{
2649#ifdef _ALPHA_
2650 return 8192;
2651#else
2652 return 4096;
2653#endif
2654}
2655
2656int mprotect(addr, len, prot)
2657 char *addr;
2658 int len, prot;
2659{
2660 int np, op;
2661
2662 if (prot == 7) np = 0x40;
2663 else if (prot == 5) np = 0x20;
2664 else if (prot == 4) np = 0x10;
2665 else if (prot == 3) np = 0x04;
2666 else if (prot == 1) np = 0x02;
2667 else if (prot == 0) np = 0x01;
2668
2669 if (VirtualProtect (addr, len, np, &op))
2670 return 0;
2671 else
2672 return -1;
2673
2674}
2675
2676#endif
2677
203b91b9
RS
2678#ifdef TRANSFER_FROM_TRAMPOLINE
2679TRANSFER_FROM_TRAMPOLINE
2680#endif
2681
c1381fd3
KKT
2682#if defined (NeXT) && defined (__MACH__)
2683
2684/* Make stack executable so we can call trampolines on stack.
2685 This is called from INITIALIZE_TRAMPOLINE in next.h. */
c5df463e
RK
2686#ifdef NeXTStep21
2687 #include <mach.h>
2688#else
2689 #include <mach/mach.h>
2690#endif
c1381fd3
KKT
2691
2692void
2693__enable_execute_stack (addr)
2694 char *addr;
2695{
2696 kern_return_t r;
2697 char *eaddr = addr + TRAMPOLINE_SIZE;
2698 vm_address_t a = (vm_address_t) addr;
2699
2700 /* turn on execute access on stack */
2701 r = vm_protect (task_self (), a, TRAMPOLINE_SIZE, FALSE, VM_PROT_ALL);
2702 if (r != KERN_SUCCESS)
2703 {
2704 mach_error("vm_protect VM_PROT_ALL", r);
2705 exit(1);
2706 }
2707
2708 /* We inline the i-cache invalidation for speed */
2709
2710#ifdef CLEAR_INSN_CACHE
2711 CLEAR_INSN_CACHE (addr, eaddr);
2712#else
2713 __clear_cache ((int) addr, (int) eaddr);
2714#endif
2715}
2716
2717#endif /* defined (NeXT) && defined (__MACH__) */
2718
203b91b9
RS
2719#ifdef __convex__
2720
2721/* Make stack executable so we can call trampolines on stack.
2722 This is called from INITIALIZE_TRAMPOLINE in convex.h. */
2723
2724#include <sys/mman.h>
2725#include <sys/vmparam.h>
2726#include <machine/machparam.h>
2727
2728void
2729__enable_execute_stack ()
2730{
2731 int fp;
2732 static unsigned lowest = USRSTACK;
2733 unsigned current = (unsigned) &fp & -NBPG;
2734
2735 if (lowest > current)
2736 {
2737 unsigned len = lowest - current;
2738 mremap (current, &len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
2739 lowest = current;
2740 }
2741
0f41302f 2742 /* Clear instruction cache in case an old trampoline is in it. */
203b91b9
RS
2743 asm ("pich");
2744}
2745#endif /* __convex__ */
b335c2cc 2746
0c8ae3d3
RK
2747#ifdef __DOLPHIN__
2748
0f41302f 2749/* Modified from the convex -code above. */
0c8ae3d3
RK
2750
2751#include <sys/param.h>
2752#include <errno.h>
2753#include <sys/m88kbcs.h>
2754
2755void
2756__enable_execute_stack ()
2757{
2758 int save_errno;
2759 static unsigned long lowest = USRSTACK;
2760 unsigned long current = (unsigned long) &save_errno & -NBPC;
2761
2762 /* Ignore errno being set. memctl sets errno to EINVAL whenever the
2763 address is seen as 'negative'. That is the case with the stack. */
2764
2765 save_errno=errno;
2766 if (lowest > current)
2767 {
2768 unsigned len=lowest-current;
2769 memctl(current,len,MCT_TEXT);
2770 lowest = current;
2771 }
2772 else
2773 memctl(current,NBPC,MCT_TEXT);
2774 errno=save_errno;
2775}
2776
2777#endif /* __DOLPHIN__ */
2778
b335c2cc
TW
2779#ifdef __pyr__
2780
98126ed6 2781#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
b335c2cc
TW
2782#include <stdio.h>
2783#include <sys/mman.h>
2784#include <sys/types.h>
2785#include <sys/param.h>
2786#include <sys/vmmac.h>
2787
2788/* Modified from the convex -code above.
0f41302f 2789 mremap promises to clear the i-cache. */
b335c2cc
TW
2790
2791void
2792__enable_execute_stack ()
2793{
2794 int fp;
2795 if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ,
2796 PROT_READ|PROT_WRITE|PROT_EXEC))
2797 {
2798 perror ("mprotect in __enable_execute_stack");
2799 fflush (stderr);
2800 abort ();
2801 }
2802}
2803#endif /* __pyr__ */
7d41c411
RK
2804
2805#if defined (sony_news) && defined (SYSTYPE_BSD)
2806
2807#include <stdio.h>
2808#include <sys/types.h>
2809#include <sys/param.h>
2810#include <syscall.h>
2811#include <machine/sysnews.h>
2812
2813/* cacheflush function for NEWS-OS 4.2.
2814 This function is called from trampoline-initialize code
2815 defined in config/mips/mips.h. */
2816
2817void
2818cacheflush (beg,size,flag)
2819 char *beg;
2820 int size;
2821 int flag;
2822{
2823 if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
2824 {
2825 perror ("cache_flush");
2826 fflush (stderr);
2827 abort ();
2828 }
2829}
2830
2831#endif /* sony_news */
203b91b9
RS
2832#endif /* L_trampoline */
2833\f
2834#ifdef L__main
2835
2836#include "gbl-ctors.h"
c06cff95
RS
2837/* Some systems use __main in a way incompatible with its use in gcc, in these
2838 cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
2839 give the same symbol without quotes for an alternative entry point. You
0f41302f 2840 must define both, or neither. */
c06cff95
RS
2841#ifndef NAME__MAIN
2842#define NAME__MAIN "__main"
2843#define SYMBOL__MAIN __main
2844#endif
203b91b9 2845
fe1fd353
JM
2846#ifdef INIT_SECTION_ASM_OP
2847#undef HAS_INIT_SECTION
2848#define HAS_INIT_SECTION
2849#endif
2850
2851#if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
203b91b9
RS
2852/* Run all the global destructors on exit from the program. */
2853
2854void
2855__do_global_dtors ()
2856{
89cf554b
RS
2857#ifdef DO_GLOBAL_DTORS_BODY
2858 DO_GLOBAL_DTORS_BODY;
2859#else
b40b9d93
MS
2860 static func_ptr *p = __DTOR_LIST__ + 1;
2861 while (*p)
2862 {
2863 p++;
2864 (*(p-1)) ();
2865 }
89cf554b 2866#endif
203b91b9 2867}
68d69835 2868#endif
203b91b9 2869
fe1fd353 2870#ifndef HAS_INIT_SECTION
203b91b9
RS
2871/* Run all the global constructors on entry to the program. */
2872
135461d9 2873#ifndef ON_EXIT
203b91b9
RS
2874#define ON_EXIT(a, b)
2875#else
2876/* Make sure the exit routine is pulled in to define the globals as
2877 bss symbols, just in case the linker does not automatically pull
2878 bss definitions from the library. */
2879
2880extern int _exit_dummy_decl;
2881int *_exit_dummy_ref = &_exit_dummy_decl;
2882#endif /* ON_EXIT */
2883
2884void
2885__do_global_ctors ()
2886{
2887 DO_GLOBAL_CTORS_BODY;
135461d9 2888 ON_EXIT (__do_global_dtors, 0);
203b91b9 2889}
fe1fd353 2890#endif /* no HAS_INIT_SECTION */
203b91b9 2891
fe1fd353 2892#if !defined (HAS_INIT_SECTION) || defined (INVOKE__main)
203b91b9
RS
2893/* Subroutine called automatically by `main'.
2894 Compiling a global function named `main'
2895 produces an automatic call to this function at the beginning.
2896
2897 For many systems, this routine calls __do_global_ctors.
2898 For systems which support a .init section we use the .init section
2899 to run __do_global_ctors, so we need not do anything here. */
2900
2901void
c06cff95 2902SYMBOL__MAIN ()
203b91b9
RS
2903{
2904 /* Support recursive calls to `main': run initializers just once. */
7e6f1890 2905 static int initialized;
203b91b9
RS
2906 if (! initialized)
2907 {
2908 initialized = 1;
2909 __do_global_ctors ();
2910 }
2911}
fe1fd353 2912#endif /* no HAS_INIT_SECTION or INVOKE__main */
203b91b9
RS
2913
2914#endif /* L__main */
2915\f
ad38743d 2916#ifdef L_ctors
203b91b9
RS
2917
2918#include "gbl-ctors.h"
2919
2920/* Provide default definitions for the lists of constructors and
2921 destructors, so that we don't get linker errors. These symbols are
2922 intentionally bss symbols, so that gld and/or collect will provide
2923 the right values. */
2924
2925/* We declare the lists here with two elements each,
2926 so that they are valid empty lists if no other definition is loaded. */
b335c2cc 2927#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
b667f58f 2928#if defined(__NeXT__) || defined(_AIX)
d15d0264
RS
2929/* After 2.3, try this definition on all systems. */
2930func_ptr __CTOR_LIST__[2] = {0, 0};
2931func_ptr __DTOR_LIST__[2] = {0, 0};
2932#else
203b91b9
RS
2933func_ptr __CTOR_LIST__[2];
2934func_ptr __DTOR_LIST__[2];
d15d0264 2935#endif
b335c2cc 2936#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
ad38743d
RS
2937#endif /* L_ctors */
2938\f
2939#ifdef L_exit
2940
2941#include "gbl-ctors.h"
203b91b9 2942
8b7677be
RK
2943#ifdef NEED_ATEXIT
2944# ifdef ON_EXIT
2945# undef ON_EXIT
2946# endif
2947int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
2948#endif
2949
203b91b9
RS
2950#ifndef ON_EXIT
2951
8b7677be
RK
2952#ifdef NEED_ATEXIT
2953# include <errno.h>
2954
8b7677be
RK
2955static func_ptr *atexit_chain = NULL;
2956static long atexit_chain_length = 0;
2957static volatile long last_atexit_chain_slot = -1;
2958
2959int atexit (func_ptr func)
2960{
2961 if (++last_atexit_chain_slot == atexit_chain_length)
2962 {
2963 atexit_chain_length += 32;
2964 if (atexit_chain)
2965 atexit_chain = realloc (atexit_chain,
2966 atexit_chain_length * sizeof (func_ptr));
2967 else
2968 atexit_chain = malloc (atexit_chain_length * sizeof (func_ptr));
2969 if (! atexit_chain)
2970 {
2971 atexit_chain_length = 0;
2972 last_atexit_chain_slot = -1;
2973 errno = ENOMEM;
2974 return (-1);
2975 }
2976 }
2977 atexit_chain[last_atexit_chain_slot] = func;
2978 return (0);
2979}
2980#endif /* NEED_ATEXIT */
2981
203b91b9
RS
2982/* If we have no known way of registering our own __do_global_dtors
2983 routine so that it will be invoked at program exit time, then we
2984 have to define our own exit routine which will get this to happen. */
2985
2986extern void __do_global_dtors ();
2987extern void _cleanup ();
003be455 2988extern void _exit () __attribute__ ((noreturn));
203b91b9
RS
2989
2990void
2991exit (status)
2992 int status;
2993{
3a5ece65 2994#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
8b7677be
RK
2995#ifdef NEED_ATEXIT
2996 if (atexit_chain)
2997 {
2998 for ( ; last_atexit_chain_slot-- >= 0; )
2999 {
3000 (*atexit_chain[last_atexit_chain_slot + 1]) ();
3001 atexit_chain[last_atexit_chain_slot + 1] = NULL;
3002 }
3003 free (atexit_chain);
3004 atexit_chain = NULL;
3005 }
3006#else /* No NEED_ATEXIT */
203b91b9 3007 __do_global_dtors ();
8b7677be 3008#endif /* No NEED_ATEXIT */
5fd507a9 3009#endif
203b91b9
RS
3010#ifdef EXIT_BODY
3011 EXIT_BODY;
3012#else
3013 _cleanup ();
3014#endif
3015 _exit (status);
3016}
3017
3018#else
3019int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
3020#endif
3021
3022#endif /* L_exit */
3023\f
ad912eec 3024#ifdef L_eh
6adb4e3a
MS
3025
3026#ifdef EH_TABLE_LOOKUP
3027
3028EH_TABLE_LOOKUP
3029
3030#else
3031
ad912eec
MS
3032typedef struct {
3033 void *start;
3034 void *end;
3035 void *exception_handler;
3036} exception_table;
3037
3038struct exception_table_node {
3039 exception_table *table;
3040 void *start;
3041 void *end;
3042 struct exception_table_node *next;
3043};
3044
7e6f1890 3045static struct exception_table_node *exception_table_list;
ad912eec
MS
3046
3047static exception_table *
3048find_exception_table (pc)
0f41302f 3049 void *pc;
ad912eec
MS
3050{
3051 register struct exception_table_node *table = exception_table_list;
3052 for ( ; table != 0; table = table->next)
3053 {
3054 if (table->start <= pc && table->end > pc)
3055 return table->table;
3056 }
3057 return 0;
3058}
3059
3060/* this routine takes a pc, and the address of the exception handler associated
3061 with the closest exception table handler entry associated with that PC,
3062 or 0 if there are no table entries the PC fits in. The algorithm works
3063 something like this:
3064
3065 while(current_entry exists) {
3066 if(current_entry.start < pc )
3067 current_entry = next_entry;
3068 else {
3069 if(prev_entry.start <= pc && prev_entry.end > pc) {
3070 save pointer to prev_entry;
3071 return prev_entry.exception_handler;
3072 }
3073 else return 0;
3074 }
3075 }
3076 return 0;
3077
3078 Assuming a correctly sorted table (ascending order) this routine should
abc95ed3 3079 return the tightest match...
ad912eec
MS
3080
3081 In the advent of a tie, we have to give the last entry, as it represents
0f41302f 3082 an inner block. */
ad912eec
MS
3083
3084void *
8e702085
MS
3085__find_first_exception_table_match (pc)
3086 void *pc;
ad912eec
MS
3087{
3088 exception_table *table = find_exception_table (pc);
3089 int pos = 0;
3090 int best = 0;
3091 if (table == 0)
0f41302f 3092 return (void *) 0;
ad912eec 3093#if 0
8e702085 3094 printf ("find_first_exception_table_match (): pc = %x!\n", pc);
ad912eec
MS
3095#endif
3096
ad912eec
MS
3097#if 0
3098 /* We can't do this yet, as we don't know that the table is sorted. */
3099 do {
3100 ++pos;
8e702085
MS
3101 if (table[pos].start > pc)
3102 /* found the first table[pos].start > pc, so the previous
ad912eec
MS
3103 entry better be the one we want! */
3104 break;
0f41302f 3105 } while (table[pos].exception_handler != (void *) -1);
ad912eec
MS
3106
3107 --pos;
8e702085 3108 if (table[pos].start <= pc && table[pos].end > pc)
ad912eec 3109 {
ad912eec 3110#if 0
8e702085 3111 printf ("find_first_eh_table_match (): found match: %x\n", table[pos].exception_handler);
ad912eec
MS
3112#endif
3113 return table[pos].exception_handler;
3114 }
3115#else
0f41302f 3116 while (table[++pos].exception_handler != (void *) -1) {
8e702085 3117 if (table[pos].start <= pc && table[pos].end > pc)
ad912eec
MS
3118 {
3119 /* This can apply. Make sure it is better or as good as the previous
3120 best. */
0f41302f 3121 /* The best one ends first. */
ad912eec
MS
3122 if (best == 0 || (table[pos].end <= table[best].end
3123 /* The best one starts last. */
3124 && table[pos].start >= table[best].start))
3125 best = pos;
3126 }
3127 }
3128 if (best != 0)
3129 return table[best].exception_handler;
3130#endif
3131
3132#if 0
8e702085 3133 printf ("find_first_eh_table_match (): else: returning NULL!\n");
ad912eec 3134#endif
6adb4e3a 3135 return (void *) 0;
ad912eec
MS
3136}
3137
3138void
3139__register_exceptions (exception_table *table)
3140{
47c0d9de 3141 struct exception_table_node *node;
ad912eec 3142 exception_table *range = table + 1;
47c0d9de 3143
0f41302f 3144 if (range->start == (void *) -1)
47c0d9de
MS
3145 return;
3146
0f41302f 3147 node = (struct exception_table_node *)
47c0d9de 3148 malloc (sizeof (struct exception_table_node));
ad912eec
MS
3149 node->table = table;
3150
3151 /* This look can be optimized away either if the table
0f41302f 3152 is sorted, or if we pass in extra parameters. */
ad912eec
MS
3153 node->start = range->start;
3154 node->end = range->end;
0f41302f 3155 for (range++ ; range->start != (void *) (-1); range++)
ad912eec
MS
3156 {
3157 if (range->start < node->start)
3158 node->start = range->start;
56031823 3159 if (range->end > node->end)
ad912eec
MS
3160 node->end = range->end;
3161 }
3162
3163 node->next = exception_table_list;
3164 exception_table_list = node;
3165}
6adb4e3a
MS
3166#endif
3167
3168void *
3169__throw_type_match (void *catch_type, void *throw_type, void *obj)
3170{
3171#if 0
3172 printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n",
3173 catch_type, throw_type);
3174#endif
3175 if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
3176 return obj;
3177 return 0;
3178}
56031823 3179
843e8335
MS
3180/* Throw stub routine.
3181
3182 This is work in progress, but not completed yet. */
3183
3184void
3185__throw ()
3186{
3187 abort ();
3188}
3189
3190/* This value identifies the place from which an exception is being
3191 thrown. */
3192
3193void *__eh_pc;
3194
8fa6b6c9
MS
3195void
3196__empty ()
3197{
3198}
3199
1e58f107 3200#if #machine(i386)
56031823
MS
3201void
3202__unwind_function(void *ptr)
3203{
3204 asm("movl 8(%esp),%ecx");
3205 /* Undo current frame */
3206 asm("movl %ebp,%esp");
3207 asm("popl %ebp");
fd4cb6b0 3208 /* like ret, but stay here */
56031823
MS
3209 asm("addl $4,%esp");
3210
0f41302f 3211 /* Now, undo previous frame. */
56031823 3212 /* This is a test routine, as we have to dynamically probe to find out
0f41302f 3213 what to pop for certain, this is just a guess. */
56031823 3214 asm("leal -16(%ebp),%esp");
c6e84dc4
RK
3215 asm("pop %ebx");
3216 asm("pop %esi");
3217 asm("pop %edi");
56031823
MS
3218 asm("movl %ebp,%esp");
3219 asm("popl %ebp");
3220
3221 asm("movl %ecx,0(%esp)");
3222 asm("ret");
3223}
6b8149a1 3224#elif #machine(rs6000) && !defined _ARCH_PPC
71a81095
MS
3225__unwind_function(void *ptr)
3226{
3227 asm("mr 31,1");
3228 asm("l 1,0(1)");
3229 asm("l 31,-4(1)");
3230 asm("# br");
3231
3232 asm("mr 31,1");
3233 asm("l 1,0(1)");
0f41302f 3234 /* use 31 as a scratch register to restore the link register. */
71a81095
MS
3235 asm("l 31, 8(1);mtlr 31 # l lr,8(1)");
3236 asm("l 31,-4(1)");
3237 asm("# br");
3238 asm("mtctr 3;bctr # b 3");
3239}
6b8149a1 3240#elif (#machine(rs6000) || #machine(powerpc)) && defined _ARCH_PPC
bf18d031
MM
3241__unwind_function(void *ptr)
3242{
3243 asm("mr 31,1");
3244 asm("lwz 1,0(1)");
3245 asm("lwz 31,-4(1)");
3246 asm("# br");
3247
3248 asm("mr 31,1");
3249 asm("lwz 1,0(1)");
0f41302f 3250 /* use 31 as a scratch register to restore the link register. */
bf18d031
MM
3251 asm("lwz 31, 8(1);mtlr 31 # l lr,8(1)");
3252 asm("lwz 31,-4(1)");
3253 asm("# br");
3254 asm("mtctr 3;bctr # b 3");
3255}
139eda62
RK
3256#elif #machine(vax)
3257__unwind_function(void *ptr)
3258{
3259 __label__ return_again;
3260
3261 /* Replace our frame's return address with the label below.
3262 During execution, we will first return here instead of to
3263 caller, then second return takes caller's frame off the stack.
3264 Two returns matches two actual calls, so is less likely to
3265 confuse debuggers. `16' corresponds to RETURN_ADDRESS_OFFSET. */
3266 __asm ("movl %0,16(fp)" : : "p" (&& return_again));
3267 return;
3268
3269 return_again:
3270 return;
3271}
c6e84dc4
RK
3272#else
3273__unwind_function(void *ptr)
3274{
3275 abort ();
3276}
bf18d031 3277#endif /* powerpc */
ad912eec 3278#endif /* L_eh */
efc955c7
JM
3279\f
3280#ifdef L_pure
2c62c124
JM
3281#ifndef inhibit_libc
3282/* This gets us __GNU_LIBRARY__. */
3283#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
3284#include <stdio.h>
3285
3286#ifdef __GNU_LIBRARY__
3287 /* Avoid forcing the library's meaning of `write' on the user program
3288 by using the "internal" name (for use within the library) */
3289#define write(fd, buf, n) __write((fd), (buf), (n))
3290#endif
3291#endif /* inhibit_libc */
3292
efc955c7 3293#define MESSAGE "pure virtual method called\n"
2c62c124 3294
efc955c7
JM
3295void
3296__pure_virtual ()
3297{
2c62c124 3298#ifndef inhibit_libc
efc955c7 3299 write (2, MESSAGE, sizeof (MESSAGE) - 1);
2c62c124 3300#endif
efc955c7
JM
3301 _exit (-1);
3302}
3303#endif