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