00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #define __STDC_LIMIT_MACROS
00041 #include <stdint.h>
00042 #include <alloca.h>
00043
00044 #include "linker.h"
00045 #include "pass1.h"
00046 #include "main.h"
00047 #include "ipc_weak.h"
00048
00049 #include "symtab.h"
00050 #include "ipa_option.h"
00051 #include "ipc_symtab_merge.h"
00052 #include "ipc_pic.h"
00053 #include "ld_ipa_interface.h"
00054
00055
00056
00057 static void Get_IPA_Object_Name(){
00058 char *bname = basename(outfilename);
00059
00060 while (*bname == '/')
00061 bname++;
00062
00063 IPA_Object_Name = (char *) malloc (strlen(bname) + 1);
00064
00065 int i;
00066 for(i=0; bname[i] != '\0'; i++) {
00067 if ( bname[i] == '-' ) IPA_Object_Name[i] = '_';
00068 else IPA_Object_Name[i] = bname[i];
00069 }
00070 IPA_Object_Name[i] = '\0';
00071 }
00072
00073
00074 STR_IDX
00075 Create_Unique_Name (const char* name)
00076 {
00077 static UINT32 g_count = 0;
00078 char *new_name = (char *)alloca (strlen (name)+strlen(IPA_Object_Name)+10);
00079
00080 char *p = new_name;
00081
00082 if (name == 0) {
00083 *p++ = '.';
00084 *p++ = 'f';
00085 } else {
00086 while (*name != 0 && !(name[0] == '.' && name[1] == '.'))
00087 *p++ = *name++;
00088 }
00089
00090 *p++ = '.';
00091 *p++ = '.';
00092
00093 strcpy( p, IPA_Object_Name);
00094 p += strlen(IPA_Object_Name);
00095 UINT i = ++g_count;
00096
00097 do {
00098 *p++ = (i % 16) + 'A';
00099 i /= 16;
00100 } while (i > 0);
00101
00102 *p = 0;
00103
00104 return Save_Str(new_name);
00105
00106 }
00107
00108
00109 struct PIC_OPT
00110 {
00111 BOOL f_call_shared;
00112 BOOL hs_ignore;
00113
00114 PIC_OPT (BOOL cs, BOOL hs) : f_call_shared (cs), hs_ignore (hs) {}
00115
00116 void operator() (UINT32, ST* st) const {
00117
00118
00119
00120 AUX_ST& aux_st = Aux_St_Table[ST_st_idx (st)];
00121 if (AUX_ST_flags (aux_st, (USED_IN_OBJ|USED_IN_DSO))) {
00122 Set_ST_addr_saved (&St_Table[ST_st_idx (st)]);
00123 }
00124
00125 if (ST_sclass (st) == SCLASS_EXTERN) {
00126 if (!ST_is_weak_symbol (st))
00127 return;
00128 else if (ST_strong (st) == st)
00129 return;
00130 }
00131
00132 BOOL address_taken = ST_addr_saved (st) || ST_addr_passed (st);
00133
00134 ST_EXPORT export_class = ST_export(st);
00135
00136 if (export_class == EXPORT_LOCAL ||
00137 export_class == EXPORT_LOCAL_INTERNAL) {
00138 if (ST_class (st) == CLASS_FUNC) {
00139 Set_ST_name_idx (st, Create_Unique_Name (ST_name (st)));
00140 #ifdef KEY
00141
00142 if (!IPA_Enable_Inline)
00143 Clear_PU_is_extern_inline (Pu_Table [ST_pu (st)]);
00144 #endif
00145
00146 if (address_taken)
00147 Set_ST_export (st, EXPORT_HIDDEN);
00148 else
00149 Set_ST_export (st, EXPORT_INTERNAL);
00150 } else if (ST_class (st) == CLASS_VAR) {
00151 if ((ST_sclass (st) == SCLASS_COMMON ||
00152 ST_sclass (st) == SCLASS_DGLOBAL) &&
00153 ST_base_idx (st) != ST_st_idx (st)) {
00154
00155 const ST& base_st = St_Table[ST_base_idx (st)];
00156 if (ST_addr_saved (base_st) || ST_addr_passed (base_st))
00157 address_taken = TRUE;
00158 }
00159 if (!address_taken)
00160 Set_ST_export (st, EXPORT_LOCAL_INTERNAL);
00161 }
00162 return;
00163 }
00164
00165 if (hs_ignore || export_class != EXPORT_PREEMPTIBLE) {
00166 if ((export_class == EXPORT_HIDDEN) && !address_taken) {
00167
00168
00169 Set_ST_export(st, EXPORT_INTERNAL);
00170 } else if (export_class == EXPORT_PREEMPTIBLE &&
00171 (ST_is_weak_symbol (st) &&
00172 ST_st_idx (st) != ST_strong_idx (*st)) ) {
00173
00174
00175
00176
00177
00178 ST_IDX strong_st_idx = ST_strong_idx (*st);
00179 FmtAssert (strong_st_idx != 0, ("Strong symbol expected"));
00180
00181
00182
00183 Set_AUX_ST_flags( Aux_St_Table[strong_st_idx],
00184 USED_IN_OBJ|DEF_IN_DSO|USED_IN_DSO );
00185 Set_AUX_ST_flags ( Aux_St_Table[strong_st_idx],
00186 AUX_ST_flags (Aux_St_Table[ST_st_idx(st)],
00187 USED_IN_OBJ|DEF_IN_DSO|USED_IN_DSO) );
00188 }
00189
00190 if (ST_is_weak_symbol (st) && ST_class (st) == CLASS_VAR) {
00191 if (ST_export (st) != EXPORT_PREEMPTIBLE &&
00192 ST_st_idx (st) != ST_strong_idx (*st)) {
00193 const ST* strong_st = ST_strong(st);
00194 Set_ST_sclass (st, ST_sclass (strong_st));
00195 Clear_ST_is_weak_symbol (st);
00196 Synch_ST_flags(*st, *strong_st);
00197 } else
00198 Set_ST_not_gprel (st);
00199 }
00200
00201 if (ST_is_weak_symbol(st))
00202 return;
00203 }
00204 if(f_call_shared) {
00205
00206
00207 if (AUX_ST_flags(Aux_St_Table[ST_st_idx (st)], (USED_IN_DSO|OBJ_COMMON))){
00208
00209
00210 if (ST_sclass (st) != SCLASS_COMMON) {
00211 Set_ST_export(st, EXPORT_PROTECTED);
00212 }
00213 } else if (address_taken) {
00214 Set_ST_export(st, EXPORT_HIDDEN);
00215 } else {
00216 Set_ST_export(st, EXPORT_INTERNAL);
00217 }
00218 } else if (IPA_Enable_Relocatable_Opt) {
00219 if (ST_sclass (st) != SCLASS_COMMON) {
00220 Set_ST_export(st, EXPORT_PROTECTED);
00221 }
00222 }
00223 if (ST_is_weak_symbol (st) && ST_class (st) == CLASS_VAR) {
00224 if (ST_export (st) != EXPORT_PREEMPTIBLE &&
00225 ST_st_idx (st) != ST_strong_idx (*st)) {
00226 const ST* strong_st = ST_strong (st);
00227 Set_ST_sclass (st, ST_sclass (strong_st));
00228 Clear_ST_is_weak_symbol (st);
00229 Synch_ST_flags (*st, *strong_st);
00230 } else
00231 Set_ST_not_gprel (st);
00232 }
00233 }
00234 };
00235
00236
00237 void
00238 Pic_optimization ()
00239 {
00240 INT f_call_shared = (ld_ipa_opt[LD_IPA_SHARABLE].flag == F_CALL_SHARED);
00241 INT hs_ignore = (ld_ipa_opt[LD_IPA_HIDES].flag == HS_IGNORE);
00242
00243 Get_IPA_Object_Name();
00244
00245 PIC_OPT pic_opt (f_call_shared, hs_ignore);
00246 For_all (St_Table, GLOBAL_SYMTAB, pic_opt);
00247
00248 Verify_SYMTAB (GLOBAL_SYMTAB);
00249 }
00250
00251
00252
00253
00254
00255
00256
00257 struct fix_static_func
00258 {
00259 const unsigned shared_status;
00260
00261 fix_static_func (unsigned cs) : shared_status (cs) {}
00262
00263 void operator() (UINT32, ST* st) const {
00264 BOOL call_shared = (shared_status == F_CALL_SHARED);
00265 BOOL non_shared = (shared_status == F_NON_SHARED);
00266
00267 ST_EXPORT eclass = ST_export (st);
00268 if (eclass != EXPORT_LOCAL && eclass != EXPORT_LOCAL_INTERNAL) {
00269 if (ST_is_weak_symbol (st) && ST_sclass (st) != SCLASS_EXTERN &&
00270 call_shared)
00271 Clear_ST_is_weak_symbol (st);
00272 else if ((ST_sclass(st) != SCLASS_EXTERN) && non_shared)
00273
00274 Set_ST_export (st, EXPORT_HIDDEN);
00275 return;
00276 }
00277
00278 if (ST_class (st) == CLASS_FUNC) {
00279 if (eclass == EXPORT_LOCAL) {
00280 Set_ST_name_idx (st, Create_Unique_Name (ST_name (st)));
00281 Set_ST_export (st, EXPORT_HIDDEN);
00282 #ifdef KEY
00283
00284 if (!IPA_Enable_Inline)
00285 Clear_PU_is_extern_inline (Pu_Table [ST_pu (st)]);
00286 #endif
00287 } else if (eclass == EXPORT_LOCAL_INTERNAL) {
00288 Set_ST_name_idx (st, Create_Unique_Name (ST_name (st)));
00289 Set_ST_export (st, EXPORT_INTERNAL);
00290 }
00291 }
00292 }
00293 };
00294
00295
00296 void
00297 Fix_up_static_functions ()
00298 {
00299 For_all (St_Table, GLOBAL_SYMTAB, fix_static_func (ld_ipa_opt[LD_IPA_SHARABLE].flag));
00300 Verify_SYMTAB (GLOBAL_SYMTAB);
00301 }
00302
00303
00304 struct Opt_global_var
00305 {
00306 void operator() (UINT32, ST* st) const {
00307
00308 if (ST_class (st) != CLASS_VAR)
00309 return;
00310
00311 BOOL common_block_element = FALSE;
00312 ST_EXPORT export_class = ST_export (st);
00313
00314 switch (ST_sclass (st)) {
00315 case SCLASS_COMMON:
00316 case SCLASS_DGLOBAL:
00317 if ((export_class == EXPORT_LOCAL ||
00318 export_class == EXPORT_LOCAL_INTERNAL) &&
00319 ST_base_idx (st) != ST_st_idx (st)) {
00320
00321 common_block_element = TRUE;
00322 ST& base_st = ST_base (*st);
00323 if (ST_addr_saved (st) || ST_addr_passed (st)) {
00324 Clear_ST_is_not_used (base_st);
00325 Clear_ST_is_const_var (base_st);
00326 } else {
00327 if (ST_is_not_used (base_st))
00328 Set_ST_is_not_used (st);
00329 if (ST_is_const_var (base_st))
00330 Set_ST_is_const_var (st);
00331 }
00332 }
00333 if (ST_is_equivalenced (st))
00334 return;
00335
00336
00337 case SCLASS_FSTATIC:
00338 case SCLASS_UGLOBAL:
00339 break;
00340
00341 default:
00342 return;
00343 }
00344
00345 ST_IDX st_idx = ST_st_idx (st);
00346 TY_IDX ty = ST_type (st);
00347 AUX_ST& aux_st = Aux_St_Table[st_idx];
00348 if (TY_is_volatile (ty) ||
00349 (aux_st.flags & USED_IN_OBJ) ||
00350 (aux_st.flags & USED_IN_DSO) ||
00351 (export_class != EXPORT_INTERNAL &&
00352 export_class != EXPORT_LOCAL_INTERNAL &&
00353 export_class != EXPORT_PROTECTED)) {
00354
00355 Set_AUX_ST_flags (aux_st, IGNORE_REFCOUNTS);
00356 return;
00357 }
00358 if (ST_is_weak_symbol (st) && ST_st_idx (st) != ST_base_idx (st)) {
00359 Set_AUX_ST_flags (aux_st, IGNORE_REFCOUNTS);
00360 return;
00361 }
00362
00363 if (ST_addr_saved (st) || ST_addr_passed (st)) {
00364 Set_AUX_ST_flags (aux_st, IGNORE_REFCOUNTS);
00365 return;
00366 }
00367
00368 ST_IDX base_st_idx = ST_base_idx (st);
00369
00370 if (AUX_ST_refcount(Aux_St_Table[base_st_idx]) == 0 &&
00371 IPA_Enable_DVE && !common_block_element) {
00372
00373
00374
00375 Set_ST_is_not_used (st);
00376 if (Trace_IPA || Trace_Perf)
00377 fprintf(TFile, "%s is marked NOT USED\n", ST_name (st));
00378 } else if (AUX_ST_modcount(Aux_St_Table[base_st_idx]) == 0 &&
00379 IPA_Enable_CGI) {
00380 Set_ST_is_const_var (st);
00381 if (Trace_IPA || Trace_Perf) {
00382 fprintf(TFile, "%s is marked CONSTANT ", ST_name (st));
00383 if (ST_is_initialized (st) && !ST_init_value_zero (st)) {
00384 const INITO_IDX idx = ST_To_INITO_Map[ST_st_idx (st) ];
00385 if (idx)
00386 Inito_Table[idx].Print(TFile);
00387 else
00388 fputs ("<unknown>\n", TFile);
00389 } else
00390 fprintf (TFile, "0\n");
00391 }
00392 }
00393 }
00394 };
00395
00396 void
00397 Optimize_Global_Variables ()
00398 {
00399 For_all (St_Table, GLOBAL_SYMTAB, Opt_global_var());
00400 }
00401
00402
00403
00404 typedef UINT32 AUX_IDX;
00405 static AUX_IDX *Refcount_sym_idx;
00406
00407 static inline ST_IDX
00408 next_gp_rel_candidate(const ST_IDX i)
00409 {
00410 return ( make_ST_IDX ( Refcount_sym_idx[i], GLOBAL_SYMTAB) );
00411 }
00412
00413
00414
00415
00416
00417
00418
00419 int
00420 ref_count_cmp (const ST_IDX *p_aux_x, const ST_IDX *q_aux_x)
00421 {
00422 int p_dontcare, q_dontcare;
00423 int p_count, q_count;
00424
00425 if ( *p_aux_x == 0 ) {
00426 return ( -1 );
00427 }
00428 ST & pst = St_Table[make_ST_IDX (*p_aux_x, GLOBAL_SYMTAB)];
00429 ST & qst = St_Table[make_ST_IDX (*q_aux_x, GLOBAL_SYMTAB)];
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 p_dontcare = ( ST_storage_class (pst) == SCLASS_EXTERN ||
00442 ST_class (pst) != CLASS_VAR ||
00443 (ST_storage_class (pst) == SCLASS_COMMON &&
00444 AUX_ST_flags(Aux_St_Tab[*p_aux_x], OBJ_COMMON)) )
00445 ? 1 : 0;
00446 q_dontcare = ( ST_storage_class (qst) == SCLASS_EXTERN ||
00447 ST_class (qst) != CLASS_VAR ||
00448 (ST_storage_class (qst) == SCLASS_COMMON &&
00449 AUX_ST_flags(Aux_St_Tab[*q_aux_x], OBJ_COMMON)) )
00450 ? 1 : 0;
00451
00452 if (p_dontcare || q_dontcare)
00453 return (p_dontcare - q_dontcare);
00454
00455
00456
00457 p_count = AUX_ST_refcount(Aux_St_Tab[*p_aux_x]) +
00458 AUX_ST_modcount(Aux_St_Tab[*p_aux_x]);
00459 q_count = AUX_ST_refcount(Aux_St_Tab[*q_aux_x]) +
00460 AUX_ST_modcount(Aux_St_Tab[*q_aux_x]);
00461 if (p_count == 0 || q_count == 0)
00462 return q_count - p_count;
00463
00464 if (TY_size (ST_type(pst)) < TY_size (ST_type(qst)) ) {
00465 return (-1);
00466 }
00467 else if (TY_size (ST_type(pst)) > TY_size (ST_type(qst)) ) {
00468 return (1);
00469 }
00470
00471 if (p_count > q_count) {
00472 return (-1);
00473 } else if (p_count < q_count) {
00474 return (1);
00475 } else {
00476 return 0;
00477 }
00478 }
00479
00480 void
00481 free_ref_count_array (void)
00482 {
00483 if (Refcount_sym_idx) {
00484 FREE (Refcount_sym_idx);
00485 Refcount_sym_idx = 0;
00486 }
00487 }
00488
00489
00490
00491
00492 void
00493 sort_symbol_ref_count_array(void)
00494 {
00495 if (!Refcount_sym_idx) {
00496 register int i;
00497
00498 INT32 symtab_count = ST_Table_Size ( GLOBAL_SYMTAB );
00499 Refcount_sym_idx = (AUX_IDX *)MALLOC((symtab_count+1)*sizeof(AUX_IDX));
00500 MALLOC_ASSERT(Refcount_sym_idx);
00501 MEMSET(Refcount_sym_idx, 0, symtab_count*sizeof(AUX_IDX));
00502
00503 for (i=0; i<symtab_count; i++) {
00504 Refcount_sym_idx[i] = i;
00505 }
00506 qsort(Refcount_sym_idx, symtab_count, sizeof(AUX_IDX),
00507 (int (*) (const void *, const void *))ref_count_cmp);
00508 }
00509 }
00510
00511
00512 static inline BOOL
00513 can_be_gp_rel (const ST& st)
00514 {
00515 return (ST_export(st) != EXPORT_PREEMPTIBLE &&
00516 !ST_not_gprel(st) && !ST_gprel(st));
00517 }
00518
00519 static INT
00520 IP_tag_symbol_gp_rel (INT avail_gp_area)
00521 {
00522 INT IPA_idx;
00523 INT gp_area_left = avail_gp_area;
00524 ST_IDX i;
00525
00526 #define IMMEDIATE_MAX_VALUE 0x7fff
00527
00528 sort_symbol_ref_count_array();
00529
00530 if (Trace_IPA || Trace_Perf) {
00531 fprintf (TFile,
00532 "Total gp-relative area available for AutoGnum = %"_fmt_v"\n",
00533 avail_gp_area);
00534 if (IPA_user_gnum)
00535 fprintf (TFile, "User-specified gnum = %d\n", IPA_user_gnum);
00536 }
00537
00538
00539 for (i = 1; i < ST_Table_Size ( GLOBAL_SYMTAB ) && gp_area_left > 0; i++) {
00540
00541 ST_IDX next_stx = next_gp_rel_candidate(i);
00542
00543 if (next_stx == 0)
00544 break;
00545 ST& st = St_Table[next_stx];
00546
00547 if (ST_sclass(st) == SCLASS_EXTERN || ST_class (st) != CLASS_VAR ||
00548 ST_base_idx (st) != next_stx)
00549 continue;
00550
00551 if (IPA_user_gnum && TY_size (ST_type(st) > IPA_user_gnum))
00552 break;
00553
00554
00555
00556
00557
00558
00559
00560
00561 if (IPA_Enable_DVE && ST_is_not_used (st) )
00562 continue;
00563
00564 if (IPA_Enable_CGI && ST_is_const_var (st) &&
00565 ST_is_initialized(st))
00566 continue;
00567
00568 if ((ST_sclass (st) == SCLASS_COMMON ||
00569 ST_sclass (st) == SCLASS_UGLOBAL ||
00570 ST_sclass (st) == SCLASS_DGLOBAL ||
00571 ST_sclass (st) == SCLASS_FSTATIC ||
00572 ST_sclass (st) == SCLASS_PSTATIC) &&
00573 can_be_gp_rel (st) &&
00574 !AUX_ST_flags (Aux_St_Tab[ST_IDX_index(next_stx)],
00575 DEF_IN_OBJ|USED_IN_OBJ|USED_IN_DSO)) {
00576
00577
00578
00579
00580
00581
00582
00583 if (ST_storage_class (st) == SCLASS_COMMON &&
00584 (TY_size (ST_type(st)) > IMMEDIATE_MAX_VALUE)) {
00585 if (Trace_IPA || Trace_Perf)
00586 fprintf (TFile, "%s of size (%"_fmt_v") is NOT marked "
00587 "gp-relative because it is a COMMON symbol with"
00588 " size > 32767(0x7fff)\n",
00589 DEMANGLE (ST_name (st)),
00590 (INT)TY_size (ST_type(st)));
00591 continue;
00592 }
00593
00594 if (gp_area_left < TY_size (ST_type(st))) {
00595 if (Trace_IPA || Trace_Perf)
00596 fprintf (TFile, "%s of size (%"_fmt_v") is NOT marked gp-relative because there is NO AutoGnum area left\n",
00597 DEMANGLE (ST_name (st)), (INT)TY_size (ST_type(st)));
00598 break;
00599 }
00600 gp_area_left -= TY_size (ST_type(st));
00601 Set_ST_gprel (st);
00602 #ifdef TODO
00603
00604 IPO_Gprel_Sym_Count++;
00605 #endif
00606
00607 if (Trace_IPA || Trace_Perf)
00608 fprintf (TFile, "%s of size (%"_fmt_v") is marked gp-relative\n",
00609 DEMANGLE (ST_name (st)), (INT)TY_size (ST_type(st)));
00610 } else if (Trace_IPA || Trace_Perf) {
00611 fprintf (TFile, "%s of size (%"_fmt_v") is NOT marked"
00612 " gp-relative by IPA because ", DEMANGLE (ST_name (st)),
00613 (INT)TY_size (ST_type(st)));
00614 if (!(ST_export(st) != EXPORT_LOCAL &&
00615 ST_export(st) != EXPORT_LOCAL_INTERNAL))
00616 fprintf (TFile, "it is NOT defined as GLOBAL");
00617 if (ST_class (st) != CLASS_VAR)
00618 fprintf (TFile, "it is NOT defined as DATA");
00619 if (AUX_ST_flags(Aux_St_Tab[ST_IDX_index(next_stx)],
00620 USED_IN_OBJ|USED_IN_DSO))
00621 fprintf (TFile, "it is used by real object");
00622 if (!((ST_export(st) == EXPORT_INTERNAL) ||
00623 (ST_export(st) == EXPORT_HIDDEN) ||
00624 (ST_export(st) == EXPORT_PROTECTED))) {
00625 fprintf (TFile, "it is preemptible");
00626 }
00627 if (ST_not_gprel(st))
00628 fprintf (TFile, "it is marked FORCE_NO_GP_REL");
00629 if ( ST_gprel(st) )
00630 fprintf (TFile, "it is already marked FORCE_GP_REL");
00631 fprintf (TFile, ".\n");
00632 }
00633 }
00634 free_ref_count_array ();
00635
00636 for (i = 1; i < ST_Table_Size ( GLOBAL_SYMTAB ); ++i) {
00637
00638 ST_IDX idx = make_ST_IDX ( i, GLOBAL_SYMTAB);
00639 ST& st = St_Table[idx];
00640 if ((ST_sclass(st) == SCLASS_COMMON) && (ST_base_idx (st) != ST_st_idx (st))) {
00641 const ST& base_st = St_Table[ST_base_idx(st)];
00642 if (ST_gprel(base_st))
00643 Set_ST_gprel(st);
00644 }
00645 }
00646 return (avail_gp_area - gp_area_left);
00647 }
00648
00649
00650 struct count_WHIRL_external_gots
00651 {
00652 INT& WHIRL_count;
00653
00654 count_WHIRL_external_gots (INT& count) : WHIRL_count (count) {}
00655
00656 void operator() (UINT32, ST* st) const {
00657
00658 if (ST_is_not_used (st))
00659 return;
00660
00661 AUX_ST& aux_st = Aux_St_Table[ST_st_idx (st)];
00662 if (AUX_ST_flags (aux_st, (USED_IN_OBJ|USED_IN_DSO))) {
00663 ++WHIRL_count;
00664 return;
00665 }
00666
00667 if (ST_is_weak_symbol (st)) {
00668 ++WHIRL_count;
00669 return;
00670 }
00671
00672 ST_EXPORT export_class = ST_export(st);
00673 BOOL address_taken = FALSE;
00674 ST_SCLASS sclass = ST_sclass(st);
00675
00676
00677
00678
00679
00680 if (ld_ipa_opt[LD_IPA_SHARABLE].flag == F_CALL_SHARED) {
00681
00682
00683
00684
00685 if (sclass != SCLASS_EXTERN)
00686 address_taken = 0;
00687 else
00688 address_taken = ST_addr_saved (st) || ST_addr_passed (st);
00689 }
00690
00691 if (sclass == SCLASS_EXTERN && (export_class == EXPORT_PREEMPTIBLE ||
00692 address_taken)) {
00693 ++WHIRL_count;
00694 }
00695 }
00696 };
00697
00698 static INT
00699 get_estimate_external_gots (void)
00700 {
00701 static INT count = -1;
00702
00703 if (count != -1)
00704 return (count);
00705
00706 count = 0;
00707 count_WHIRL_external_gots WHIRL_ext_gots (count);
00708 For_all (St_Table, GLOBAL_SYMTAB, WHIRL_ext_gots);
00709 count += Count_elf_external_gots ();
00710 return (count);
00711 }
00712
00713
00714 static inline INT
00715 IP_get_max_gpa_size()
00716 {
00717 return (max_gpa_size-10000);
00718 }
00719
00720
00721 static INT
00722 IP_estimate_got_size ()
00723 {
00724 int num_got;
00725 float factor;
00726 num_got = get_estimate_external_gots();
00727
00728 if (IPA_Has_Fortran)
00729
00730 num_got += IPA_Num_Fortran_Intrinsics;
00731
00732 if (IPA_Extgot_Factor == 0) {
00733 IPA_Extgot_Factor = 210 - (UINT32)((float) num_got /
00734 ((float) IP_get_max_gpa_size() /
00735 sizeof(ELF_ADDR)) * 100);
00736 }
00737
00738 if (Trace_IPA || Trace_Perf) {
00739 if (IPA_Has_Fortran) {
00740 fprintf (TFile,
00741 "Including estimation of FORTRAN INSTRINSIC (total %d), ",
00742 IPA_Num_Fortran_Intrinsics);
00743 }
00744 fprintf (TFile, "number of estimated external got entries = %d, "
00745 "percentage used for estimating the final .got size = %d%%\n",
00746 num_got, IPA_Extgot_Factor);
00747 }
00748 return (((int)((float)num_got * (float)((float)IPA_Extgot_Factor/100)) +1) * sizeof(ELF_ADDR));
00749 }
00750
00751
00752 static inline UINT
00753 Gp_Area_Size ()
00754 {
00755 UINT32 max_gpa_size = IP_get_max_gpa_size ();
00756 #ifdef KEY
00757 return MIN (max_gpa_size, IPA_Gspace);
00758 #else
00759 return min (max_gpa_size, IPA_Gspace);
00760 #endif
00761 }
00762
00763 static void
00764 IPO_tag_sym_gp_rel(void)
00765 {
00766 INT available_gp_area =
00767 Gp_Area_Size () - IP_estimate_got_size () - used_gp_area;
00768
00769 if (available_gp_area > 0) {
00770 available_gp_area -= IP_tag_symbol_gp_rel (available_gp_area);
00771 }
00772
00773 if (Trace_IPA || Trace_Perf) {
00774 fprintf (TFile,
00775 "Total gp area used = %d, available gp area left = %d\n ",
00776 Gp_Area_Size () - available_gp_area, available_gp_area);
00777 }
00778 }
00779
00780
00781
00782
00783
00784 static BOOL
00785 IPO_only_one_got(void)
00786 {
00787
00788
00789
00790 if ( (IP_estimate_got_size() + used_gp_area) > Gp_Area_Size () ) {
00791 return FALSE;
00792 }
00793 return TRUE;
00794 }
00795
00796 void
00797 Autognum_Driver()
00798 {
00799 BOOL one_got = FALSE;
00800 Refcount_sym_idx = 0;
00801 if (IPA_Enable_Picopt || IPA_Enable_Relocatable_Opt ||
00802 IPA_Enable_AutoGnum )
00803 one_got = IPO_only_one_got();
00804
00805
00806
00807
00808 if (one_got == FALSE) {
00809 IPA_Enable_AutoGnum = FALSE;
00810 if (Trace_IPA || Trace_Perf) {
00811 fprintf (TFile,
00812 "AutoGnum optimization are turned off due to multigot\n");
00813 }
00814 }
00815
00816 if (IPA_Enable_AutoGnum) {
00817 Temporary_Error_Phase ephase ("IPA Auto GP-relative Data Layout");
00818 if (Verbose) {
00819 fprintf (stderr, "GP-relative data layout ...");
00820 fflush (stderr);
00821 }
00822 if (Trace_IPA || Trace_Perf) {
00823 fprintf (TFile, "\t<<<GP-relative Data Layout begins>>>\n");
00824 }
00825 IPO_tag_sym_gp_rel ();
00826 if (Trace_IPA || Trace_Perf)
00827 fprintf (TFile,
00828 "\t<<<Auto GP-relative Data Layout completed>>>\n");
00829 }
00830 }