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
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 #define __STDC_LIMIT_MACROS
00062 #include <stdint.h>
00063 #if defined(BUILD_OS_DARWIN)
00064 #include <darwin_elf.h>
00065 #else
00066 #include <elf.h>
00067 #endif
00068 #include <sys/elf_whirl.h>
00069 #include <alloca.h>
00070
00071 #include <ext/hash_map>
00072
00073 #include <sys/types.h>
00074
00075 #include "defs.h"
00076 #include "erglob.h"
00077 #include "mempool.h"
00078 #include "cxx_memory.h"
00079 #include "wn.h"
00080 #include "wn_util.h"
00081 #include "dwarf_DST.h"
00082 #include "pu_info.h"
00083 #include "ir_bread.h"
00084 #include "region_util.h"
00085
00086 #include "ipc_file.h"
00087 #include "ipc_symtab_merge.h"
00088 #include "ipc_option.h"
00089 #include "ipc_bread.h"
00090 #include "ipa_cprop_annot.h"
00091 #include "ipa_feedback.h"
00092 #include "ipa_option.h"
00093 #include "ipa_summary.h"
00094 #include "ipa_section.h"
00095 #include "ipo_parent.h"
00096 #include "ipo_clone.h"
00097 #include "ipo_defs.h"
00098 #include "ipaa.h"
00099
00100 #include "ipa_nested_pu.h"
00101 #include "ipa_cg.h"
00102 #include "ipa_inline.h"
00103
00104 #include "symtab_idx.h"
00105 #include "ipa_reorder.h"
00106 #include "ipa_option.h"
00107
00108 IPA_CALL_GRAPH* IPA_Call_Graph;
00109 #ifdef KEY
00110
00111 IPA_CALL_GRAPH* IPA_Graph_Undirected;
00112
00113
00114
00115
00116
00117
00118
00119 static IPA_CALL_GRAPH* IPA_Call_Graph_Tmp = NULL;
00120
00121
00122 static hash_map<IPA_NODE*, IPA_NODE*, hashfn, eqnode> node_map;
00123 static vector<Nodes_To_Edge *> q_order;
00124 #endif
00125 BOOL IPA_Call_Graph_Built = FALSE;
00126
00127 typedef hash_map<NODE_INDEX, NODE_INDEX> ALT_ENTRY_MAP;
00128 ALT_ENTRY_MAP *alt_entry_map;
00129
00130 UINT32 Total_Dead_Function_Weight = 0;
00131 UINT32 Orig_Prog_Weight = 0;
00132
00133
00134 UINT32 Orig_Prog_WN_Count = 0;
00135 UINT32 Total_Dead_Function_WN_Count = 0;
00136 #ifdef KEY
00137 FB_FREQ Total_cycle_count_2(0.0);
00138 #else
00139 FB_FREQ Total_cycle_count_2(0);
00140 #endif
00141
00142
00143 INT Total_Must_Inlined = 0;
00144 INT Total_Must_Not_Inlined = 0;
00145 #ifdef KEY
00146 FB_FREQ Total_call_freq(0.0);
00147 FB_FREQ Total_cycle_count(0.0);
00148 #else
00149 FB_FREQ Total_call_freq(0);
00150 FB_FREQ Total_cycle_count(0);
00151 #endif
00152
00153
00154
00155
00156
00157
00158
00159 extern IPA_NODE* Main_Entry(IPA_NODE* ipan_alt)
00160 {
00161 if (alt_entry_map == NULL)
00162 return ipan_alt;
00163 NODE_INDEX alt_entry_index = INVALID_NODE_INDEX;
00164 if (ipan_alt->Summary_Proc()->Is_alt_entry()) {
00165 NODE_INDEX v = ipan_alt->Node_Index();
00166 ALT_ENTRY_MAP::iterator iter = alt_entry_map->find(v);
00167 if (iter != alt_entry_map->end())
00168 alt_entry_index = (*iter).second;
00169 }
00170 if (alt_entry_index == INVALID_NODE_INDEX)
00171 return ipan_alt;
00172 return IPA_Call_Graph->Graph()->Node_User(alt_entry_index);
00173 }
00174
00175
00176 #ifndef _LIGHTWEIGHT_INLINER
00177
00178
00179
00180
00181 void
00182 IPA_update_summary_st_idx (const IP_FILE_HDR& hdr)
00183 {
00184 const IPC_GLOBAL_IDX_MAP* idx_maps = IP_FILE_HDR_idx_maps(hdr);
00185 INT i;
00186
00187
00188 INT32 num_symbols;
00189 SUMMARY_SYMBOL* symbols = IPA_get_symbol_file_array(hdr, num_symbols);
00190 for (i = 0; i < num_symbols; ++i) {
00191
00192
00193 ST_IDX old_st_idx = symbols[i].St_idx();
00194 if (ST_IDX_level(old_st_idx) == GLOBAL_SYMTAB) {
00195 symbols[i].Set_st_idx(idx_maps->st[old_st_idx]);
00196 }
00197
00198 ST_IDX old_func_st_idx = symbols[i].Get_st_idx_func();
00199 if (ST_IDX_level(old_func_st_idx) == GLOBAL_SYMTAB) {
00200 symbols[i].Set_st_idx_func(idx_maps->st[old_func_st_idx]);
00201 }
00202 }
00203
00204
00205 INT32 num_values;
00206 SUMMARY_VALUE* values = IPA_get_value_file_array(hdr, num_values);
00207 for (INT j = 0; j < num_values; ++j) {
00208 if (values[j].Is_const_st()) {
00209 ST_IDX old_const_st_idx = values[j].Get_const_st_idx();
00210 if (ST_IDX_level(old_const_st_idx) == GLOBAL_SYMTAB) {
00211 values[j].Set_const_st_idx(idx_maps->st[old_const_st_idx]);
00212 values[j].Set_merged_const_st_idx();
00213 }
00214 } else if (values[j].Is_global () &&
00215 values[j].Get_global_index () == -1) {
00216 ST_IDX old_global_st_idx = values[j].Get_global_st_idx ();
00217 if (ST_IDX_index (old_global_st_idx) != 0) {
00218 values[j].Set_global_st_idx (idx_maps->st[old_global_st_idx]);
00219 }
00220 }
00221 }
00222
00223
00224 INT32 num_formals;
00225 SUMMARY_FORMAL* formals = IPA_get_formal_file_array(hdr, num_formals);
00226 for (i = 0; i < num_formals; ++i) {
00227 TY_IDX old_ty_idx = formals[i].Get_ty();
00228 if (old_ty_idx) {
00229 formals[i].Set_ty(idx_maps->ty[old_ty_idx]);
00230 }
00231 }
00232
00233
00234 INT32 num_actuals;
00235 SUMMARY_ACTUAL* actuals = IPA_get_actual_file_array(hdr, num_actuals);
00236 for (i = 0; i < num_actuals; ++i) {
00237 TY_IDX old_ty_idx = actuals[i].Get_ty();
00238 if (old_ty_idx) {
00239 actuals[i].Set_ty(idx_maps->ty[old_ty_idx]);
00240 }
00241 }
00242
00243
00244 INT32 num_callsites;
00245 SUMMARY_CALLSITE *callsites = IPA_get_callsite_file_array(hdr, num_callsites);
00246 for (i = 0; i < num_callsites; ++i) {
00247 TY_IDX old_ty_idx = callsites[i].Get_virtual_class();
00248 if (old_ty_idx) {
00249 callsites[i].Set_virtual_class(idx_maps->ty[old_ty_idx]);
00250 }
00251 }
00252
00253
00254 INT32 num_ivars;
00255 IVAR* ivars = IPA_get_ivar_file_array(hdr, num_ivars);
00256 for (i = 0; i < num_ivars; ++i) {
00257 if (!ivars[i].Is_Formal()) {
00258 Is_True(ST_IDX_level(ivars[i].St_Idx()) == GLOBAL_SYMTAB,
00259 ("Non-formal IVAR must have a global ST in IPA"));
00260 ivars[i].Set_St_Idx(idx_maps->st[ivars[i].St_Idx()]);
00261 }
00262 }
00263
00264 #ifdef KEY
00265 INT32 num_ty_infos;
00266 SUMMARY_TY_INFO* ty_infos = IPA_get_ty_info_file_array(hdr, num_ty_infos);
00267 for (i = 0; i < num_ty_infos; ++i) {
00268 TY_IDX old_ty_idx = ty_infos[i].Get_ty();
00269 Is_True (old_ty_idx, ("Non-zero type ids expected in SUMMARY_TYPE"));
00270 if (old_ty_idx) {
00271 ty_infos[i].Set_ty(idx_maps->ty[old_ty_idx]);
00272 if (ty_infos[i].Is_ty_no_split())
00273 Set_TY_no_split (ty_infos[i].Get_ty());
00274 }
00275 }
00276 #endif
00277
00278
00279 if(IPA_Enable_Reorder){
00280 INT32 num_tys,new_ty;
00281 SUMMARY_STRUCT_ACCESS* access_array = IPA_get_struct_access_file_array(hdr, num_tys);
00282 SUMMARY_STRUCT_ACCESS* cur_access;
00283 for (i = 0; i < num_tys; ++i) {
00284 cur_access=&access_array[i];
00285 new_ty=idx_maps->ty[make_TY_IDX (cur_access->Get_ty())];
00286 Merge_struct_access(cur_access,new_ty>>8);
00287
00288 }
00289 }
00290 }
00291 #endif // !_STANDALONE_INLINER
00292
00293 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
00294 #include "inline.h"
00295 #else // _STANDALONE_INLINER
00296
00297
00298
00299
00300 static void
00301 IPA_process_globals (const IP_FILE_HDR& hdr)
00302 {
00303 INT32 sym_size;
00304 SUMMARY_SYMBOL *Symbol_array = IPA_get_symbol_file_array (hdr, sym_size);
00305 INT32 glob_size;
00306 SUMMARY_GLOBAL *Globals_array = IPA_get_global_file_array(hdr, glob_size);
00307
00308 if (glob_size == 0 || sym_size == 0)
00309 return;
00310
00311 for (INT i = 0; i < glob_size; ++i) {
00312 SUMMARY_GLOBAL *gnode = &Globals_array[i];
00313
00314 if (gnode->Get_refcount() || gnode->Get_modcount()) {
00315 SUMMARY_SYMBOL *snode = &Symbol_array[gnode->Get_symbol_index()];
00316 ST_IDX st_idx = snode->St_idx ();
00317 Update_reference_count (&St_Table[st_idx],
00318 gnode->Get_refcount (),
00319 gnode->Get_modcount (),
00320 snode->Is_cmod ());
00321 }
00322 }
00323 }
00324
00325
00326
00327
00328
00329
00330 static void
00331 IPA_mark_commons_used_in_io (const IP_FILE_HDR& hdr)
00332 {
00333 INT32 num_symbols;
00334 SUMMARY_SYMBOL* symbol = IPA_get_symbol_file_array(hdr, num_symbols);
00335 for (INT i = 0; i < num_symbols; ++i, ++symbol) {
00336 if (symbol->Is_common_block() && symbol->Common_read_no_cprop()) {
00337 Set_AUX_ST_flags (Aux_St_Table[symbol->St_idx()], COMMON_USED_IN_IO);
00338 }
00339 }
00340 }
00341
00342 #ifdef KEY
00343 void
00344 IPA_update_ehinfo_in_pu (IPA_NODE *node)
00345 {
00346 if (!(PU_src_lang (node->Get_PU()) & PU_CXX_LANG) ||
00347 !PU_misc_info (node->Get_PU()))
00348 return;
00349
00350 int sym_size;
00351 SUMMARY_SYMBOL* sym_array = IPA_get_symbol_file_array(node->File_Header(), sym_size);
00352 FmtAssert (sym_array != NULL, ("Missing SUMMARY_SYMBOL section"));
00353
00354 INITV_IDX tinfo = INITV_next (INITV_next (INITO_val (PU_misc_info (node->Get_PU()))));
00355 INITO_IDX inito = TCON_uval (INITV_tc_val (tinfo));
00356 if (inito)
00357 {
00358 INITV_IDX idx = INITO_val (inito);
00359 do
00360 {
00361 INITV_IDX st_entry = INITV_blk (idx);
00362 if (INITV_kind (st_entry) == INITVKIND_ZERO)
00363 {
00364 idx = INITV_next (idx);
00365 continue;
00366 }
00367 int st_idx = TCON_uval (INITV_tc_val (st_entry));
00368
00369
00370 if (st_idx < 0 || st_idx >= sym_size)
00371 {
00372 idx = INITV_next (idx);
00373 continue;
00374 }
00375 ST_IDX new_idx = sym_array[st_idx].St_idx();
00376
00377
00378
00379
00380 if (ST_IDX_level(new_idx) == GLOBAL_SYMTAB) {
00381 Set_AUX_ST_flags (Aux_St_Table[new_idx], USED_IN_OBJ);
00382 Clear_ST_is_not_used (St_Table[new_idx]);
00383 INITV_IDX filter = INITV_next (st_entry);
00384 INITV_Set_VAL (Initv_Table[st_entry], Enter_tcon (
00385 Host_To_Targ (MTYPE_U4, new_idx)), 1);
00386 Set_INITV_next (st_entry, filter);
00387 }
00388 idx = INITV_next (idx);
00389 } while (idx);
00390 }
00391 tinfo = INITV_next (tinfo);
00392 inito = TCON_uval (INITV_tc_val (tinfo));
00393 if (inito)
00394 {
00395 INITV_IDX idx = INITV_blk (INITO_val (inito));
00396 do
00397 {
00398 if (INITV_kind (idx) == INITVKIND_ZERO)
00399 {
00400 idx = INITV_next (idx);
00401 continue;
00402 }
00403 int st_idx = TCON_uval (INITV_tc_val (idx));
00404 FmtAssert (st_idx > 0, ("Invalid st entry in eh-spec table"));
00405 ST_IDX new_idx = sym_array[st_idx].St_idx();
00406
00407 if (ST_IDX_level(new_idx) == GLOBAL_SYMTAB) {
00408 Set_AUX_ST_flags (Aux_St_Table[new_idx], USED_IN_OBJ);
00409 Clear_ST_is_not_used (St_Table[new_idx]);
00410 INITV_IDX bkup = INITV_next (idx);
00411 INITV_Set_VAL (Initv_Table[idx], Enter_tcon (
00412 Host_To_Targ (MTYPE_U4, new_idx)), 1);
00413 Set_INITV_next (idx, bkup);
00414 }
00415 idx = INITV_next (idx);
00416 } while (idx);
00417 }
00418 }
00419
00420 static inline IPA_NODE *
00421 pu_info_to_node (PU_Info *pu)
00422 {
00423 return IPA_Call_Graph->Graph()->Node_User (AUX_PU_node(Aux_Pu_Table[ST_pu(St_Table[PU_Info_proc_sym (pu)])]));
00424 }
00425
00426 void
00427 Mark_PUs_With_File_Id (PU_Info * pu, UINT id)
00428 {
00429 for (; pu; pu = PU_Info_next (pu))
00430 {
00431 IPA_NODE * node = pu_info_to_node (pu);
00432 if (node) node->Set_File_Id (id);
00433 if (PU_Info_child (pu))
00434 Mark_PUs_With_File_Id (PU_Info_child (pu), id);
00435 }
00436 }
00437
00438 std::vector<char *> options;
00439
00440 BOOL Opt_Options_Inconsistent = FALSE;
00441 mINT32 IPA_NODE::next_file_id = -1;
00442
00443
00444
00445
00446
00447 static void
00448 IPA_Check_Optimization_Options (IP_FILE_HDR& hdr)
00449 {
00450 static bool warned = false;
00451
00452 if (warned) return;
00453
00454 char * base_addr = (char *)
00455 WN_get_section_base (IP_FILE_HDR_input_map_addr (hdr), WT_COMP_FLAGS);
00456
00457 if (base_addr == (char*) -1)
00458 ErrMsg (EC_IR_Scn_Read, "command line", IP_FILE_HDR_file_name (hdr));
00459
00460 Elf64_Word argc = *((Elf64_Word *) base_addr);
00461
00462
00463
00464 if (!options.empty() && ((argc-1) != options.size()))
00465 {
00466 warned = true;
00467 Opt_Options_Inconsistent = TRUE;
00468 ErrMsg (EC_Ipa_Options);
00469 return;
00470 }
00471
00472 Elf64_Word* args = (Elf64_Word *) (base_addr + sizeof(Elf64_Word));
00473
00474 if (options.empty())
00475 {
00476 options.reserve (sizeof (char *) * (argc-1));
00477 for (int i=1; i<argc; ++i)
00478 options.push_back (base_addr + args[i]);
00479 std::sort (options.begin(), options.end(), option_cmp());
00480 return;
00481 }
00482
00483 Is_True (argc-1 == options.size(), ("IPA_Check_Optimization_Options error"));
00484
00485 std::vector<char *> current_options;
00486
00487 current_options.reserve (sizeof (char *) * (argc-1));
00488 for (int i=1; i<argc; ++i)
00489 current_options.push_back (base_addr + args[i]);
00490
00491 std::sort (current_options.begin(), current_options.end(), option_cmp());
00492
00493 for (int i=0; i<argc-1; ++i)
00494 {
00495 if (strcmp (options[i], current_options[i]))
00496 {
00497 warned = true;
00498 Opt_Options_Inconsistent = TRUE;
00499 current_options.clear();
00500 ErrMsg (EC_Ipa_Options);
00501 return;
00502 }
00503 }
00504 current_options.clear();
00505 return;
00506 }
00507 static void
00508 IPA_update_pragma_in_pu (IPA_NODE *node)
00509 {
00510 int sym_size;
00511 SUMMARY_SYMBOL* sym_array = IPA_get_symbol_file_array(node->File_Header(), sym_size);
00512 FmtAssert (sym_array != NULL, ("Missing SUMMARY_SYMBOL section"));
00513 WN* prags = WN_func_pragmas(node->Whirl_Tree());
00514 prags = WN_first(prags);
00515
00516 while (prags) {
00517 if (WN_opcode(prags) == OPC_PRAGMA &&
00518 WN_pragma(prags) == WN_PRAGMA_THREADPRIVATE) {
00519 ST_IDX new_idx = sym_array[WN_pragma_arg2(prags)].St_idx();
00520 WN_pragma_arg2(prags) = new_idx;
00521 }
00522 prags = WN_next(prags);
00523 }
00524
00525 }
00526 #endif
00527
00528
00529
00530
00531
00532 void
00533 IPA_Process_File (IP_FILE_HDR& hdr)
00534 {
00535 #ifdef KEY
00536 if (IPA_Check_Options)
00537 IPA_Check_Optimization_Options (hdr);
00538 #endif
00539 IP_READ_pu_infos (hdr);
00540
00541 IPA_update_summary_st_idx (hdr);
00542
00543 if (IPA_Enable_AutoGnum || IPA_Enable_CGI || IPA_Enable_DVE)
00544 IPA_process_globals (hdr);
00545
00546 if (IPA_Enable_Common_Const)
00547 IPA_mark_commons_used_in_io (hdr);
00548
00549 }
00550
00551
00552 #endif // !_STANDALONE_INLINER
00553
00554 static void
00555 Mark_inline_overrides(IPA_NODE* ipa_node, ST* st)
00556 {
00557 UINT info = User_Specified_Name_Info(ST_name(st));
00558
00559 if (Is_User_Not_Specified(info)) {
00560 if ((ipa_node->Summary_Proc()->Get_lang() == LANG_F77) ||
00561 (ipa_node->Summary_Proc()->Get_lang() == LANG_F90)) {
00562
00563
00564 int lastchar = strlen(ST_name(st)) - 1;
00565 if (ST_name(st)[lastchar] != '_')
00566 return;
00567 char *newname = strdup(ST_name(st));
00568 newname[lastchar] = '\0';
00569 info = User_Specified_Name_Info(newname);
00570 free(newname);
00571 if (Is_User_Not_Specified(info))
00572 return;
00573 }
00574 else
00575 return;
00576 }
00577
00578
00579 if (Is_User_Must_Inline(info)) {
00580 ipa_node->Set_Must_Inline_Attrib();
00581 Total_Must_Inlined++;
00582 if (Trace_IPA || Trace_Perf)
00583 fprintf (TFile, "%s marked \"must inlined\"\n", DEMANGLE(ST_name(st)));
00584 }
00585 else if (Is_User_No_Inline(info)) {
00586 ipa_node->Set_Noinline_Attrib();
00587 Total_Must_Not_Inlined++;
00588 if (Trace_IPA || Trace_Perf)
00589 fprintf (TFile, "%s marked \"no inlined\"\n", DEMANGLE (ST_name(st)));
00590 }
00591 }
00592
00593
00594 static void
00595 Mark_inline_edge_overrides(IPA_EDGE* ipa_edge)
00596 {
00597 IPA_NODE* caller = IPA_Call_Graph->Caller(ipa_edge->Edge_Index());
00598 IPA_NODE* callee = IPA_Call_Graph->Callee(ipa_edge->Edge_Index());
00599
00600 if ((ipa_edge->Edge_Index() > INLINE_Skip_After) ||
00601 (ipa_edge->Edge_Index() < INLINE_Skip_Before)) {
00602 ipa_edge->Set_Noinline_Attrib();
00603 Total_Must_Not_Inlined++;
00604 if (Trace_IPA || Trace_Perf)
00605 fprintf (TFile, "%s marked \"no inlined\" into %s\n", DEMANGLE(callee->Name()), DEMANGLE(caller->Name()));
00606 }
00607
00608 UINT info = User_Specified_Edge_Info(ipa_edge->Edge_Index());
00609
00610 if (Is_User_Not_Specified(info)) {
00611 return;
00612 }
00613
00614
00615 if (Is_User_Must_Inline(info)) {
00616 ipa_edge->Set_Must_Inline_Attrib();
00617 Total_Must_Inlined++;
00618 if (Trace_IPA || Trace_Perf)
00619 fprintf (TFile, "%s marked \"must inlined\" into %s\n", DEMANGLE(callee->Name()), DEMANGLE(caller->Name()));
00620 }
00621 else if (Is_User_No_Inline(info)) {
00622 ipa_edge->Set_Noinline_Attrib();
00623 Total_Must_Not_Inlined++;
00624 if (Trace_IPA || Trace_Perf)
00625 fprintf (TFile, "%s marked \"no inlined\" into %s\n", DEMANGLE(callee->Name()), DEMANGLE(caller->Name()));
00626 }
00627 }
00628
00629 #include <map>
00630
00631 typedef std::map<UINT64, IPA_NODE*> ADDR_NODE_MAP;
00632 static ADDR_NODE_MAP addr_node_map;
00633
00634 IPA_NODE*
00635 Add_One_Node (IP_FILE_HDR& s, INT32 file_idx, INT i, NODE_INDEX& orig_entry_index)
00636 {
00637
00638 IPA_NODE *ipa_node = NULL;
00639 INT32 size;
00640 SUMMARY_PROCEDURE *Proc_array = IPA_get_procedure_file_array (s, size);
00641 UINT32 sindex = Proc_array[i].Get_symbol_index();
00642
00643 INT32 sym_size;
00644 SUMMARY_SYMBOL* sym_array = IPA_get_symbol_file_array(s, sym_size);
00645 Is_True (sym_array != NULL, ("Missing SUMMARY_SYMBOL section"));
00646
00647 SUMMARY_SYMBOL& sum_symbol = sym_array[sindex];
00648
00649 ST_IDX st_idx = sum_symbol.St_idx ();
00650
00651 FmtAssert (ST_IDX_level (st_idx) == GLOBAL_SYMTAB,
00652 ("Invalid ST_IDX for procedure"));
00653
00654 ST* st = &St_Table[st_idx];
00655
00656 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
00657
00658 NODE_INDEX node_idx = AUX_PU_node(Aux_Pu_Table[ST_pu(st)]);
00659 if (node_idx != INVALID_NODE_INDEX)
00660
00661 return ipa_node;
00662
00663 #endif // _STANDALONE_INLINER
00664
00665 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00666
00667
00668
00669
00670 #ifdef KEY
00671 if (IPA_Call_Graph_Tmp == NULL &&
00672 AUX_PU_file_hdr (Aux_Pu_Table[ST_pu (st)]) != &s)
00673 #else
00674 if (AUX_PU_file_hdr (Aux_Pu_Table[ST_pu (st)]) != &s)
00675 #endif
00676 {
00677 Is_True (ST_export (st) != EXPORT_LOCAL &&
00678 ST_export (st) != EXPORT_LOCAL_INTERNAL,
00679 ("Multiply defined symbols should not be EXPORT_LOCAL"));
00680
00681
00682
00683
00684
00685 if (Trace_IPA || Trace_Perf)
00686 fprintf (TFile, "%s from %s deleted (multiply defined"
00687 " procedure)\n",
00688 DEMANGLE (ST_name (st)), IP_FILE_HDR_file_name(s));
00689
00690 Delete_Function_In_File (s, i);
00691
00692 if (Proc_array[i].Has_alt_entry()) {
00693 while (i + 1 < size) {
00694 if (Proc_array[i+1].Is_alt_entry()) {
00695 Delete_Function_In_File (s, i+1);
00696 i++;
00697 } else
00698 break;
00699 }
00700 }
00701 return ipa_node;
00702 }
00703
00704 #endif // _STANDALONE_INLINER
00705
00706 ipa_node =
00707 IPA_Call_Graph->Add_New_Node (st, file_idx, i, i);
00708
00709 #ifdef KEY
00710 if (IPA_Enable_PU_Reorder == REORDER_BY_EDGE_FREQ && IPA_Call_Graph_Tmp)
00711 {
00712
00713 IPA_NODE * node_dup = IPA_Call_Graph_Tmp->Graph()->Node_User (AUX_PU_node(Aux_Pu_Table[ST_pu(st)]));
00714 node_map [ipa_node] = node_dup;
00715 node_map [node_dup] = ipa_node;
00716 }
00717 else
00718 {
00719 #endif
00720
00721 NODE_INDEX cg_node = ipa_node->Node_Index ();
00722
00723 Set_AUX_PU_node (Aux_Pu_Table[ST_pu (st)], cg_node);
00724
00725 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
00726 ipa_node->Set_Scope(Inliner_Aux_Pu_Table[ST_pu (st)]);
00727 #endif // _STANDALONE_INLINER
00728
00729 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00730 if (IPA_Enable_DFE || IPA_Enable_Picopt || IPA_Enable_Array_Sections
00731 || IPA_Enable_Relocatable_Opt) {
00732 if (Proc_array[i].Has_alt_entry()) {
00733 orig_entry_index = cg_node;
00734 } else if (Proc_array[i].Is_alt_entry()) {
00735 if (alt_entry_map == NULL)
00736 alt_entry_map = CXX_NEW (ALT_ENTRY_MAP(), Malloc_Mem_Pool);
00737 (*alt_entry_map)[cg_node] = orig_entry_index;
00738
00739
00740 ST* orig_st = IPA_Call_Graph->Graph()->Node_User(orig_entry_index)->Func_ST();
00741 if (ST_export(orig_st) > ST_export(st))
00742 Set_ST_export(st, ST_export(orig_st));
00743 } else {
00744 orig_entry_index = INVALID_NODE_INDEX;
00745 }
00746 }
00747
00748 static BOOL reported = FALSE;
00749 if (!reported) {
00750 DevWarn ("TODO: support GP and call graph partitioning");
00751 reported = TRUE;
00752 }
00753
00754 #ifdef KEY
00755
00756 if (IPA_Enable_Pure_Call_Opt &&
00757 ipa_node->Summary_Proc()->Has_pstatic())
00758 ipa_node->Summary_Proc()->Set_has_side_effect();
00759 #endif // KEY
00760 #endif // _STANDALONE_INLINER
00761
00762 Orig_Prog_Weight += ipa_node->Weight ();
00763 Orig_Prog_WN_Count += (UINT32)(ipa_node->Get_wn_count());
00764
00765 if ((ipa_node->Summary_Proc()->Get_lang() == LANG_F77) ||
00766 (ipa_node->Summary_Proc()->Get_lang() == LANG_F90))
00767 IPA_Has_Fortran = TRUE;
00768
00769
00770 #ifdef TODO
00771
00772 #ifndef _STANDALONE_INLINER
00773
00774 if (IPA_Enable_GP_Partition || IPA_Enable_SP_Partition) {
00775 void *pext = linker->IP_get_mext(nme);
00776 if (pext) {
00777 ipa_node->Set_partition_group(linker->IP_get_mext_partition_grp(pext));
00778 if (linker->IP_is_mext_internal_to_partition(pext))
00779 ipa_node->Set_partition_internal();
00780 }
00781 }
00782 #endif
00783 #endif // TODO
00784
00785 if (ipa_node->Has_frequency ()) {
00786 Total_cycle_count += ipa_node->Get_cycle_count ();
00787 Total_cycle_count_2 += ipa_node->Get_cycle_count_2 ();
00788 }
00789
00790
00791
00792 Mark_inline_overrides(ipa_node, st);
00793 #ifdef KEY
00794 }
00795 #endif
00796
00797 #if defined(KEY) && !defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER)
00798
00799
00800 if (!IPA_Enable_PU_Reorder_Set && Annotation_Filename &&
00801 ipa_node && !strcmp (ipa_node->Name(), "main") &&
00802 (PU_src_lang (ipa_node->Get_PU()) & PU_CXX_LANG))
00803 {
00804
00805 Is_True (IPA_Enable_PU_Reorder == REORDER_DISABLE,
00806 ("Attempt to change default of -IPA:pu_reorder"));
00807 IPA_Enable_PU_Reorder = REORDER_BY_NODE_FREQ;
00808 }
00809
00810 const UINT64 runtime_addr = ipa_node->Get_func_runtime_addr ();
00811 if (runtime_addr) addr_node_map[runtime_addr] = ipa_node;
00812 #endif // KEY && !_STANDALONE_INLINER && !_LIGHTWEIGHT_INLINER
00813 return ipa_node;
00814
00815 }
00816
00817
00818
00819
00820
00821 static void
00822 Add_nodes (IP_FILE_HDR& s, INT32 file_idx)
00823 {
00824
00825 INT32 size;
00826 SUMMARY_PROCEDURE *Proc_array = IPA_get_procedure_file_array (s, size);
00827
00828 NODE_INDEX index = INVALID_NODE_INDEX;
00829
00830 if (size == 0)
00831 return;
00832
00833 for (INT i = 0; i < size; ++i) {
00834
00835 (void)Add_One_Node(s, file_idx, i, index );
00836
00837 }
00838
00839 }
00840
00841
00842 static inline void
00843 append_icall_list (IPA_ICALL_LIST& ilist, SUMMARY_CALLSITE *c)
00844 {
00845 IPA_ICALL_NODE *cnode = CXX_NEW (IPA_ICALL_NODE (c), Malloc_Mem_Pool);
00846 ilist.push_back (cnode);
00847 }
00848
00849 #ifdef KEY
00850
00851 static vector<Nodes_To_Edge *>::iterator
00852 find_if_equal (vector<Nodes_To_Edge*>::iterator b, vector<Nodes_To_Edge*>::iterator e, Nodes_To_Edge * ne)
00853 {
00854 vector<Nodes_To_Edge *>::iterator it = b;
00855 for (; it!=e; it++)
00856 if (((*it)->Caller() == ne->Caller() &&
00857 (*it)->Callee() == ne->Callee()) ||
00858
00859 ((*it)->Caller() == ne->Callee() &&
00860 (*it)->Callee() == ne->Caller()))
00861 return b;
00862 return e;
00863 }
00864
00865
00866 static void Update_freq (SUMMARY_CALLSITE *, IPA_EDGE *);
00867 static bool Check_Heuristic(IPA_NODE *, IPA_NODE *, INT64, IPA_CALL_GRAPH *);
00868 #endif
00869
00870 void
00871 Add_Edges_For_Node (IP_FILE_HDR& s, INT i, SUMMARY_PROCEDURE* proc_array, SUMMARY_SYMBOL* symbol_array)
00872 {
00873 #if defined(KEY) && !defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER)
00874 BOOL has_icalls = FALSE;
00875 #endif
00876
00877 if (proc_array == NULL) {
00878 INT32 size;
00879 proc_array = IPA_get_procedure_file_array(s, size);
00880 }
00881
00882 if (symbol_array == NULL) {
00883 INT32 symbol_size;
00884 symbol_array = IPA_get_symbol_file_array (s, symbol_size);
00885 }
00886
00887 UINT32 sindex = proc_array[i].Get_symbol_index();
00888 ST_IDX temp_st_idx = symbol_array[sindex].St_idx ();
00889 const ST* caller_st = &St_Table[temp_st_idx];
00890
00891 NODE_INDEX caller_idx = AUX_PU_node (Aux_Pu_Table[ST_pu(caller_st)]);
00892 IPA_NODE* caller;
00893 #ifdef KEY
00894 if (IPA_Call_Graph_Tmp)
00895 caller = IPA_Call_Graph_Tmp->Graph()->Node_User (caller_idx);
00896 else
00897 #endif
00898 caller = IPA_Call_Graph->Graph()->Node_User (caller_idx);
00899 SUMMARY_CALLSITE *callsite_array = IPA_get_callsite_array (caller);
00900
00901 INT callsite_count = proc_array[i].Get_callsite_count();
00902 INT callsite_index = proc_array[i].Get_callsite_index();
00903
00904 for (INT j = 0; j < callsite_count; ++j, ++callsite_index) {
00905
00906 #ifdef KEY
00907 if (IPA_Enable_Pure_Call_Opt &&
00908 (callsite_array[callsite_index].Is_func_ptr() ||
00909 callsite_array[callsite_index].Is_intrinsic()))
00910 caller->Summary_Proc()->Set_has_side_effect ();
00911 #endif
00912
00913
00914 if ( callsite_array[callsite_index].Is_func_ptr() ) {
00915 if (!IPA_Call_Graph_Tmp) {
00916 #ifdef _LIGHTWEIGHT_INLINER
00917 if (!INLINE_Inlined_Pu_Call_Graph)
00918 #endif // _LIGHTWEIGHT_INLINER
00919 append_icall_list (caller->Icall_List(),
00920 &callsite_array[callsite_index]);
00921 }
00922 }
00923 #if defined(KEY) && !defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER)
00924 else if (callsite_array[callsite_index].Is_icall_target()) {
00925
00926 has_icalls = TRUE;
00927 if (!IPA_Enable_Icall_Opt)
00928 continue;
00929
00930 sindex = callsite_array[callsite_index].Get_symbol_index();
00931 temp_st_idx = symbol_array[sindex].St_idx ();
00932 ST* callee_st = &St_Table[temp_st_idx];
00933
00934 Is_True (!strcmp (ST_name (callee_st), "__dummy_icall_target"),
00935 ("Process_procedure: Expected ICALL target function as callee"));
00936
00937 mUINT64 target_addr = callsite_array[callsite_index].Get_targ_runtime_addr();
00938 IPA_NODE * callee = addr_node_map [target_addr];
00939
00940 if (!callee) continue;
00941
00942 if (IPA_Consult_Inliner_For_Icall_Opt)
00943 {
00944 mUINT64 callee_counter = (mUINT64)
00945 callsite_array[callsite_index].Get_frequency_count().Value();
00946
00947 if (!Check_Heuristic (caller,
00948 callee,
00949 callee_counter,
00950 IPA_Call_Graph))
00951 continue;
00952 }
00953 IPA_EDGE* ipa_edge =
00954 IPA_Call_Graph->Add_New_Edge (&callsite_array[callsite_index],
00955 caller_idx,
00956 callee->Node_Index());
00957 if (ipa_edge->Has_frequency ())
00958 Total_call_freq += ipa_edge->Get_frequency ();
00959 Mark_inline_edge_overrides(ipa_edge);
00960
00961 caller->Set_Pending_Icalls();
00962
00963 callsite_array[callsite_index].Reset_icall_target();
00964 }
00965 #endif // KEY && !_STANDALONE_INLINER && !_LIGHTWEIGHT_INLINER
00966
00967 else if (!callsite_array[callsite_index].Is_intrinsic()) {
00968
00969 sindex = callsite_array[callsite_index].Get_symbol_index();
00970 temp_st_idx = symbol_array[sindex].St_idx ();
00971 ST* callee_st = &St_Table[temp_st_idx];
00972
00973 #ifdef TODO
00974
00975 if (Symbol_array[sindex].Is_local()) {
00976
00977
00978 if (IPA_Enable_SP_Partition)
00979 callee->Set_partition_group(caller->Get_partition_group());
00980 }
00981 #endif
00982
00983 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00984
00985
00986 while (ST_is_weak_symbol (callee_st) &&
00987 ST_st_idx (callee_st) != ST_strong_idx (*callee_st))
00988
00989 callee_st = ST_strong (callee_st);
00990 #endif // _STANDALONE_INLINER
00991
00992 Clear_ST_is_not_used (callee_st);
00993
00994 NODE_INDEX callee_idx = AUX_PU_node (Aux_Pu_Table[ST_pu (callee_st)]);
00995
00996 #ifdef KEY
00997 if (callee_idx == INVALID_NODE_INDEX &&
00998 ST_export (callee_st) == EXPORT_LOCAL) {
00999
01000
01001
01002
01003
01004
01005
01006
01007 IPA_CALL_GRAPH * cg =
01008 (IPA_Enable_PU_Reorder == REORDER_BY_EDGE_FREQ &&
01009 IPA_Call_Graph_Tmp) ? IPA_Call_Graph_Tmp : IPA_Call_Graph;
01010
01011 for (INT count=0; count<Aux_Pu_Table.Size(); count++) {
01012
01013 NODE_INDEX node_idx = AUX_PU_node (Aux_Pu_Table[count]);
01014
01015 if (node_idx != INVALID_NODE_INDEX) {
01016 IPA_NODE * node = cg->Graph()->Node_User (node_idx);
01017
01018 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
01019 if (!strcmp (node->Name(), ST_name (callee_st)))
01020 #else // ipa
01021 const char * cur_node_name = node->Name();
01022
01023
01024
01025 const int callsite_name_len = strlen (ST_name (callee_st));
01026 if (strlen (cur_node_name) > callsite_name_len + 2 &&
01027 !strncmp (cur_node_name, ST_name (callee_st),
01028 callsite_name_len) &&
01029 cur_node_name[callsite_name_len] == '.' &&
01030 cur_node_name[callsite_name_len+1] == '.' &&
01031
01032 caller->File_Index() == node->File_Index())
01033 #endif
01034 {
01035 Is_True (callee_idx == INVALID_NODE_INDEX,
01036 ("Duplicate static fn defn ?"));
01037 callee_idx = node_idx;
01038 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
01039 Is_True (ST_export (node->Func_ST()) == EXPORT_LOCAL,
01040 ("Unexpected export scope for func %s", node->Name()));
01041 #else
01042 Is_True (ST_export (node->Func_ST()) == EXPORT_INTERNAL,
01043 ("Unexpected export scope for func %s", node->Name()));
01044 Set_ST_name_idx (callee_st, ST_name_idx (node->Func_ST()));
01045 #endif
01046 #ifndef Is_True_On
01047 break;
01048 #endif // !Is_True_On
01049 }
01050 }
01051 }
01052 }
01053 #endif
01054
01055
01056
01057 #ifdef KEY
01058 if (callee_idx != INVALID_NODE_INDEX &&
01059 IPA_Enable_PU_Reorder == REORDER_BY_EDGE_FREQ &&
01060 IPA_Call_Graph_Tmp) {
01061 IPA_NODE * callee = IPA_Call_Graph_Tmp->Graph()->Node_User (callee_idx);
01062 IPA_NODE * caller_u = node_map [ caller ];
01063 IPA_NODE * callee_u = node_map [ callee ];
01064 NODE_INDEX caller_idx_u = caller_u->Node_Index();
01065 NODE_INDEX callee_idx_u = callee_u->Node_Index();
01066 Nodes_To_Edge * ne = new Nodes_To_Edge (caller_idx_u, callee_idx_u);
01067 vector<Nodes_To_Edge *>::iterator it;
01068 if ((it = find_if_equal (q_order.begin(), q_order.end(), ne)) == q_order.end())
01069 {
01070 IPA_EDGE * edge_u =
01071 IPA_Call_Graph->Add_New_Edge
01072 (&callsite_array[callsite_index],
01073 caller_idx_u, callee_idx_u);
01074 Nodes_To_Edge * o = new Nodes_To_Edge (caller_idx_u,
01075 callee_idx_u, edge_u);
01076 q_order.push_back (o);
01077 }
01078 else
01079 {
01080 SUMMARY_CALLSITE * c = &callsite_array[callsite_index];
01081 Update_freq (c, (*it)->Edge());
01082 }
01083 delete ne;
01084 continue;
01085 }
01086 #endif
01087 if (callee_idx != INVALID_NODE_INDEX) {
01088 IPA_EDGE* ipa_edge =
01089 IPA_Call_Graph->Add_New_Edge (&callsite_array[callsite_index],
01090 caller_idx,
01091 callee_idx);
01092 if (ipa_edge->Has_frequency ()) {
01093 Total_call_freq += ipa_edge->Get_frequency ();
01094 }
01095 Mark_inline_edge_overrides(ipa_edge);
01096 }
01097 else {
01098 #ifdef _LIGHTWEIGHT_INLINER
01099 if (INLINE_Inlined_Pu_Call_Graph)
01100 continue;
01101 else
01102 #endif // _LIGHTWEIGHT_INLINER
01103 append_icall_list (caller->Ocall_List(),
01104 &callsite_array[callsite_index]);
01105 #ifdef KEY
01106
01107 if (IPA_Enable_EH_Region_Removal &&
01108 (PU_src_lang (Pu_Table [ST_pu (caller->Func_ST())]) &
01109 PU_CXX_LANG))
01110 caller->Set_PU_Can_Throw ();
01111
01112
01113 if (IPA_Enable_Pure_Call_Opt)
01114 caller->Summary_Proc()->Set_has_side_effect ();
01115 #endif
01116 }
01117 }
01118 }
01119
01120 #if defined(KEY) && !defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER)
01121 if (has_icalls) {
01122
01123
01124
01125
01126
01127 INT cs_index = proc_array[i].Get_callsite_index();
01128 INT count = 0;
01129 for (INT j = 0; j < callsite_count; ++j, ++cs_index) {
01130 if (!callsite_array[cs_index].Is_icall_target())
01131 callsite_array[cs_index].Set_callsite_id (count++);
01132 }
01133 }
01134 #endif
01135
01136 return;
01137 }
01138
01139
01140
01141
01142 static void
01143 Add_edges (IP_FILE_HDR& s)
01144 {
01145 INT32 size;
01146 SUMMARY_PROCEDURE *proc_array = IPA_get_procedure_file_array(s, size);
01147 if (size == 0)
01148 return;
01149
01150 INT32 symbol_size;
01151 SUMMARY_SYMBOL* symbol_array = IPA_get_symbol_file_array (s, symbol_size);
01152
01153 for (INT i = 0; i < size; ++i) {
01154
01155 if (IP_PROC_INFO_state (IP_FILE_HDR_proc_info(s)[i]) == IPA_DELETED)
01156 continue;
01157
01158 (void)Add_Edges_For_Node(s, i, proc_array, symbol_array);
01159
01160 }
01161
01162 }
01163
01164
01165 static UINT32
01166 Mark_reachable (NODE_INDEX root, mBOOL* visited)
01167 {
01168 UINT32 count = 0;
01169
01170 if (!visited[root]) {
01171 visited[root] = TRUE;
01172 ++count;
01173 }
01174
01175 NODE_ITER viter(IPA_Call_Graph->Graph(), root);
01176
01177 for (NODE_INDEX vi = viter.First_Succ(); vi != -1; vi = viter.Next_Succ()) {
01178 if (!visited[vi])
01179 count += Mark_reachable(vi, visited);
01180 }
01181
01182 return count;
01183 }
01184
01185
01186 static inline UINT32
01187 connect_to_root (NODE_INDEX node, mBOOL* visited)
01188 {
01189 EDGE_INDEX cg_edge =
01190 IPA_Call_Graph->Graph()->Add_Edge (IPA_Call_Graph->Root(), node, NULL);
01191 return Mark_reachable (node, visited);
01192 }
01193
01194
01195
01196
01197
01198
01199 static void
01200 Connect_call_graph()
01201 {
01202 UINT num_nodes = GRAPH_vcnt (IPA_Call_Graph->Graph());
01203 mBOOL *visited = (mBOOL *) alloca ((GRAPH_vmax(IPA_Call_Graph->Graph())+1) * sizeof(mBOOL));
01204 BZERO (visited, (GRAPH_vmax(IPA_Call_Graph->Graph())+1) * sizeof(mBOOL));
01205
01206 UINT32 visited_count = 0;
01207
01208 if (IPA_Call_Graph->Root() == INVALID_NODE_INDEX) {
01209
01210 NODE_INDEX root = IPA_Call_Graph->Graph()->Add_Node (NULL);
01211 ++num_nodes;
01212 visited[root] = TRUE;
01213 visited_count = 1;
01214 IPA_Call_Graph->Set_Root (root);
01215 } else
01216 visited_count += Mark_reachable (IPA_Call_Graph->Root(), visited);
01217
01218
01219
01220
01221
01222
01223
01224 NODE_INDEX v;
01225 for (v = 0; v < GRAPH_vmax(IPA_Call_Graph->Graph()); ++v) {
01226 if (NODE_fcnt(&GRAPH_v_i(IPA_Call_Graph->Graph(), v)) != -1 &&
01227 IPA_Call_Graph->Graph()->Num_Preds (v) == 0 &&
01228 v != IPA_Call_Graph->Root())
01229 visited_count += connect_to_root (v, visited);
01230 }
01231
01232 if (visited_count == num_nodes)
01233 return;
01234
01235
01236
01237
01238
01239 for (v = 0;
01240 visited_count != num_nodes && v < GRAPH_vmax(IPA_Call_Graph->Graph());
01241 ++v) {
01242 if (NODE_fcnt(&GRAPH_v_i(IPA_Call_Graph->Graph(), v)) != -1 && !visited[v]) {
01243 visited_count += connect_to_root (v, visited);
01244 }
01245 }
01246 }
01247
01248
01249
01250
01251
01252 struct add_nodes
01253 {
01254 void operator() (UINT32 idx, IP_FILE_HDR* hdr) const {
01255 Add_nodes (*hdr, idx);
01256 }
01257 };
01258
01259 struct add_edges
01260 {
01261 void operator() (UINT32, IP_FILE_HDR* hdr) const {
01262 Add_edges (*hdr);
01263 }
01264 };
01265
01266 #ifdef KEY
01267
01268 struct order : public binary_function<IPA_EDGE *, IPA_EDGE *, bool>
01269 {
01270 bool operator() (IPA_EDGE * e1, IPA_EDGE * e2)
01271 {
01272
01273
01274 return (e1->Has_frequency() || e2->Has_frequency()) &&
01275 e1->Get_frequency()._value < e2->Get_frequency()._value;
01276 }
01277 };
01278
01279 static void
01280 Update_freq (SUMMARY_CALLSITE *c, IPA_EDGE *e)
01281 {
01282 FB_FREQ sum = 0.0;
01283 if (c && c->Has_callsite_freq ())
01284 sum = c->Get_frequency_count ();
01285 if (e->Has_frequency())
01286 {
01287 sum += e->Get_frequency ();
01288 e->Set_frequency (sum);
01289 }
01290 }
01291
01292
01293 static vector<IPA_EDGE *> edges;
01294
01295
01296 void
01297 IPA_CALL_GRAPH::Merge_Nodes (NODE_INDEX caller_idx, NODE_INDEX callee_idx)
01298 {
01299 EDGE_INDEX nf;
01300 EDGE_INDEX f = NODE_from (&(_graph->v[callee_idx]));
01301
01302 while (f != INVALID_EDGE_INDEX)
01303 {
01304 nf = EDGE_nfrom (&(_graph->e[f]));
01305 IPA_EDGE * from = _graph->Edge_User (f);
01306
01307 if (!from)
01308 {
01309 f = nf;
01310 continue;
01311 }
01312
01313
01314 NODE_INDEX to_idx = Callee (from)->Node_Index();
01315
01316 Nodes_To_Edge * ne = new Nodes_To_Edge (caller_idx, to_idx);
01317 vector<Nodes_To_Edge *>::iterator it;
01318
01319 if ((it = find_if_equal (q_order.begin(), q_order.end(), ne)) == q_order.end())
01320 {
01321 IPA_EDGE* ipa_edge =
01322 Add_New_Edge (from->Summary_Callsite(), caller_idx, to_idx);
01323 edges.push_back (ipa_edge);
01324
01325
01326 }
01327 else
01328 {
01329 Update_freq (from->Summary_Callsite(), (*it)->Edge());
01330 }
01331 delete ne;
01332 f = nf;
01333 }
01334
01335
01336 EDGE_INDEX nt, t = NODE_to (&(_graph->v[callee_idx]));
01337 while (t != INVALID_EDGE_INDEX)
01338 {
01339 nt = EDGE_nto (&(_graph->e[t]));
01340 IPA_EDGE * to = _graph->Edge_User (t);
01341
01342 if (!to)
01343 {
01344 t = nt;
01345 continue;
01346 }
01347
01348 NODE_INDEX from_idx = Caller (to)->Node_Index();
01349 if (from_idx == caller_idx)
01350 {
01351 t = nt;
01352 continue;
01353 }
01354
01355 Nodes_To_Edge * ne = new Nodes_To_Edge (from_idx, caller_idx);
01356 vector<Nodes_To_Edge *>::iterator it;
01357 if ((it = find_if_equal (q_order.begin(), q_order.end(), ne)) == q_order.end())
01358 {
01359 IPA_EDGE* ipa_edge =
01360 Add_New_Edge (to->Summary_Callsite(), from_idx, caller_idx);
01361 edges.push_back (ipa_edge);
01362 }
01363 else
01364 {
01365 Update_freq (to->Summary_Callsite(), (*it)->Edge());
01366 }
01367 delete ne;
01368 t = nt;
01369 }
01370 _graph->Node_User (caller_idx)->Set_Merged ();
01371 }
01372
01373 NODE_INDEX node_g;
01374 struct matching : public unary_function<IPA_EDGE *, bool>
01375 {
01376 bool operator() (IPA_EDGE * e)
01377 {
01378 return IPA_Call_Graph->Caller(e)->Node_Index() == node_g ||
01379 IPA_Call_Graph->Callee(e)->Node_Index() == node_g;
01380 }
01381 };
01382
01383
01384
01385 vector<IPA_NODE *> emit_order;
01386
01387 #ifdef TODO_KEY
01388 static void
01389 Determine_Affinity (vector<IPA_NODE *> v)
01390 {
01391 FB_FREQ f[] = {0.0, 0.0, 0.0, 0.0};
01392
01393 {
01394 Nodes_To_Edge * ne = new Nodes_To_Edge (v[0]->Node_Index(), v[2]->Node_Index());
01395 vector<Nodes_To_Edge *>::iterator it;
01396 if ((it = find_if_equal (q_order.begin(), q_order.end(), ne)) != q_order.end())
01397 f[0] = (*it)->Edge()->Get_frequency();
01398 delete ne;
01399 }
01400 if (v.size() == 4)
01401 {
01402 Nodes_To_Edge * ne = new Nodes_To_Edge (v[0]->Node_Index(), v[3]->Node_Index());
01403 vector<Nodes_To_Edge *>::iterator it;
01404 if ((it = find_if_equal (q_order.begin(), q_order.end(), ne)) != q_order.end())
01405 f[1] = (*it)->Edge()->Get_frequency();
01406 delete ne;
01407 }
01408 {
01409 Nodes_To_Edge * ne = new Nodes_To_Edge (v[1]->Node_Index(), v[2]->Node_Index());
01410 vector<Nodes_To_Edge *>::iterator it;
01411 if ((it = find_if_equal (q_order.begin(), q_order.end(), ne)) != q_order.end())
01412 f[2] = (*it)->Edge()->Get_frequency();
01413 delete ne;
01414 }
01415 if (v.size() == 4)
01416 {
01417 Nodes_To_Edge * ne = new Nodes_To_Edge (v[1]->Node_Index(), v[3]->Node_Index());
01418 vector<Nodes_To_Edge *>::iterator it;
01419 if ((it = find_if_equal (q_order.begin(), q_order.end(), ne)) != q_order.end())
01420 f[3] = (*it)->Edge()->Get_frequency();
01421 delete ne;
01422 }
01423
01424 bool swapped = false;
01425 if (f[0]+f[1] > f[2]+f[3])
01426 {
01427 IPA_NODE * tmp = v[0];
01428 v[0] = v[1];
01429 v[1] = tmp;
01430 swapped = true;
01431 }
01432 if (v.size() == 4)
01433 {
01434 FB_FREQ f0, f1;
01435 if (swapped)
01436 {
01437 f0 = f[0];
01438 f1 = f[1];
01439 }
01440 else
01441 {
01442 f0 = f[2];
01443 f1 = f[3];
01444 }
01445 if (f0 < f1)
01446 {
01447 IPA_NODE * tmp = v[2];
01448 v[2] = v[3];
01449 v[3] = tmp;
01450 }
01451 }
01452 for (vector<IPA_NODE *>::iterator it=v.begin(); it!=v.end(); ++it)
01453 emit_order.push_back ((*it));
01454 }
01455 #endif // TODO_KEY
01456
01457
01458 static void
01459 Determine_Emit_Order (IPA_CALL_GRAPH * cg)
01460 {
01461 IPA_NODE_ITER walk (cg, PREORDER);
01462
01463 for (walk.First (); !walk.Is_Empty (); walk.Next ())
01464 {
01465 IPA_NODE * node = walk.Current ();
01466 if (!node) continue;
01467 IPA_SUCC_ITER succ_iter (cg, node);
01468 for (succ_iter.First(); !succ_iter.Is_Empty(); succ_iter.Next())
01469 {
01470 IPA_EDGE * edge = succ_iter.Current_Edge ();
01471 if (edge)
01472 edges.push_back (edge);
01473 }
01474 }
01475 sort (edges.begin(), edges.end(), order());
01476
01477 #ifdef TODO_KEY
01478 vector<IPA_NODE *> last;
01479 #endif
01480 while (!edges.empty())
01481 {
01482 IPA_EDGE * e = edges.back ();
01483 IPA_NODE * caller = IPA_Call_Graph->Caller (e);
01484 IPA_NODE * callee = IPA_Call_Graph->Callee (e);
01485
01486 NODE_INDEX caller_idx = caller->Node_Index();
01487 NODE_INDEX callee_idx = callee->Node_Index();
01488
01489 #ifdef TODO_KEY
01490 if (last.empty())
01491 {
01492 if (!caller->Is_Merged())
01493 last.push_back (node_map[caller]);
01494 if (!callee->Is_Merged())
01495 last.push_back (node_map[callee]);
01496 }
01497 else
01498 {
01499 if (!caller->Is_Merged())
01500 last.push_back (node_map[caller]);
01501 if (!callee->Is_Merged())
01502 last.push_back (node_map[callee]);
01503 if (last.size() <= 2)
01504 {
01505 emit_order.push_back (last[0]);
01506 if (last.size() == 2) emit_order.push_back (last[1]);
01507 }
01508 else Determine_Affinity (last);
01509 last.clear();
01510 }
01511 #else
01512
01513 if (!caller->Is_Merged())
01514 emit_order.push_back (node_map[caller]);
01515 if (!callee->Is_Merged())
01516 emit_order.push_back (node_map[callee]);
01517 #endif
01518
01519
01520 IPA_Call_Graph->Merge_Nodes (caller_idx, callee_idx);
01521 node_g = callee_idx;
01522
01523 vector<IPA_EDGE *>::iterator new_end = remove_if (edges.begin(), edges.end(), matching());
01524 edges.erase (new_end, edges.end());
01525
01526 IPA_Call_Graph->Graph()->Delete_Node (callee_idx);
01527
01528 sort (edges.begin(), edges.end(), order());
01529 }
01530 }
01531 #endif
01532
01533 void
01534 Build_Call_Graph ()
01535 {
01536 IPA_Call_Graph = CXX_NEW(IPA_CALL_GRAPH(Malloc_Mem_Pool), Malloc_Mem_Pool);
01537 #ifdef KEY
01538 if (IPA_Enable_PU_Reorder == REORDER_BY_EDGE_FREQ)
01539 IPA_Graph_Undirected = CXX_NEW(IPA_CALL_GRAPH(Malloc_Mem_Pool), Malloc_Mem_Pool);
01540 for (int iter=0; iter<2; ++iter)
01541 {
01542 #endif
01543
01544 For_all_entries (IP_File_header, add_nodes ());
01545
01546 For_all_entries (IP_File_header, add_edges ());
01547
01548 Connect_call_graph();
01549 #ifdef KEY
01550 if (IPA_Enable_PU_Reorder != REORDER_BY_EDGE_FREQ)
01551 break;
01552 else if (!iter)
01553 {
01554 IPA_Call_Graph_Tmp = IPA_Call_Graph;
01555 IPA_Call_Graph = IPA_Graph_Undirected;
01556 }
01557 else
01558 {
01559 Determine_Emit_Order (IPA_Call_Graph);
01560 FmtAssert (IPA_Call_Graph == IPA_Graph_Undirected, (""));
01561 IPA_Call_Graph = IPA_Call_Graph_Tmp;
01562 IPA_Call_Graph_Tmp = NULL;
01563 q_order.clear();
01564 node_map.clear();
01565 }
01566 }
01567 #endif
01568
01569 IPA_Call_Graph_Built = TRUE;
01570
01571 if (Get_Trace(TP_IPA, IPA_TRACE_TUNING)) {
01572 FILE *tmp_call_graph = fopen("cg_dump.log", "w");
01573 if (tmp_call_graph != NULL) {
01574 IPA_Call_Graph->Print_vobose(tmp_call_graph);
01575 fclose(tmp_call_graph);
01576 }
01577 }
01578 }
01579
01580
01581 #if 0
01582
01583 #include "wn_util.h"
01584 #include "ir_reader.h"
01585 #include <map>
01586
01587 static void IPA_Collect_Runtime_Addr( IPA_CALL_GRAPH* cg )
01588 {
01589 IPA_NODE_ITER cg_iter( cg, PREORDER );
01590
01591 for( cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next() ){
01592 IPA_NODE* node = cg_iter.Current();
01593 if( node == NULL || node->PU_Info() == NULL || node->Should_Be_Skipped() )
01594 continue;
01595
01596 IPA_NODE_CONTEXT context(node);
01597
01598 if( Cur_PU_Feedback != NULL ){
01599 const UINT64 addr = Cur_PU_Feedback->Get_Runtime_Func_Addr();
01600 addr_node_map[addr] = node;
01601 }
01602 }
01603 }
01604
01605 static BOOL Is_Return_Store_Stmt( WN *wn )
01606 {
01607 if ( wn && WN_operator( wn ) == OPR_STID ) {
01608 WN *val = WN_kid( wn, 0 );
01609 if ( WN_operator( val ) == OPR_LDID ) {
01610 ST *st = WN_st( val );
01611 if ( ST_sym_class( st ) == CLASS_PREG
01612 && ( st == Return_Val_Preg ) )
01613 return TRUE;
01614 }
01615 }
01616
01617 return FALSE;
01618 }
01619
01620 #endif
01621
01622 static bool Check_Heuristic( IPA_NODE* caller,
01623 IPA_NODE* callee,
01624 INT64 edge_freq,
01625 IPA_CALL_GRAPH* cg )
01626 {
01627
01628
01629
01630 if( !IPA_Enable_Inline )
01631 return false;
01632
01633 if( callee->Should_Be_Skipped() )
01634 return false;
01635
01636 if( !IPA_Enable_Inline_Nested_PU && caller->Is_Nested_PU () )
01637 return false;
01638
01639 if( caller == callee && !INLINE_Recursive )
01640 return false;
01641
01642 if( callee->Has_Varargs() )
01643 return false;
01644
01645 if( callee->Summary_Proc()->Is_alt_entry() ||
01646 callee->Summary_Proc()->Has_alt_entry() ||
01647 caller->Summary_Proc()->Is_alt_entry() )
01648 return false;
01649
01650 if( callee->Summary_Proc()->Has_formal_pragma() )
01651 return false;
01652
01653 if( callee->Summary_Proc()->Has_mp_needs_lno() )
01654 return false;
01655
01656 if( callee->Summary_Proc()->Has_noinline_parallel_pragma() )
01657 return false;
01658
01659 if( (caller->Summary_Proc()->Has_parallel_pragma() ||
01660 caller->Summary_Proc()->Has_parallel_region_pragma()) &&
01661 callee->Summary_Proc()->Has_var_dim_array() )
01662 return false;
01663
01664 if( caller->Summary_Proc()->Has_parallel_region_pragma() &&
01665 callee->Summary_Proc()->Has_pdo_pragma() )
01666 return false;
01667
01668 if( callee->Summary_Proc()->Is_exc_inline() && !IPA_Enable_Exc )
01669 return false;
01670
01671 if( callee->Summary_Proc()->Is_exc_inline() &&
01672 callee->Summary_Proc()->Has_pstatic() )
01673 return false;
01674
01675 if( (UINT)cg->Node_Depth(callee) > IPA_Max_Depth )
01676 return false;
01677
01678 if( !IPA_Enable_Lang ){
01679 if( (callee->Summary_Proc()->Get_lang() == LANG_F77) ||
01680 (caller->Summary_Proc()->Get_lang() == LANG_F77) ){
01681 if( (callee->Summary_Proc()->Get_lang() != LANG_F77) ||
01682 (caller->Summary_Proc()->Get_lang() != LANG_F77) )
01683 return false;
01684
01685 else if( (callee->Summary_Proc()->Get_lang() == LANG_F90) ||
01686 (caller->Summary_Proc()->Get_lang() == LANG_F90) ){
01687 if( (callee->Summary_Proc()->Get_lang() != LANG_F90) ||
01688 (caller->Summary_Proc()->Get_lang() != LANG_F90) )
01689 return false;
01690 }
01691 }
01692 }
01693
01694 return true;
01695
01696
01697
01698
01699 UINT32 callee_weight = callee->Weight();
01700
01701 if( IPA_Use_Effective_Size && callee->Has_frequency() ){
01702 SUMMARY_FEEDBACK* fb = callee->Get_feedback();
01703 callee_weight = PU_Weight( fb->Get_effective_bb_count(),
01704 fb->Get_effective_stmt_count(),
01705 callee->PU_Size().Call_Count() );
01706 }
01707
01708 const FB_FREQ cycle_ratio = (edge_freq / callee->Get_frequency() *
01709 callee->Get_cycle_count()) / Total_cycle_count;
01710 const float cycle_ratio_float = cycle_ratio.Value();
01711 const float size_ratio = (float)callee_weight / (float)Orig_Prog_Weight;
01712 const float hotness = ( 100.0 * cycle_ratio_float / size_ratio );
01713
01714 if( hotness < (float)IPA_Min_Hotness ){
01715 return false;
01716 }
01717
01718 return true;
01719 }
01720
01721 #if 0
01722
01723 static void Convert_Icall( IPA_CALL_GRAPH* cg, IPA_NODE* node )
01724 {
01725 if( node == NULL ||
01726 node->Total_Succ() == 0 ||
01727 node->PU_Info() == NULL ||
01728 node->Should_Be_Skipped() ){
01729 return;
01730 }
01731
01732 FmtAssert( !node->Is_Visited(), ("node is visited") );
01733
01734
01735 IPA_NODE_CONTEXT context(node);
01736
01737 if( Cur_PU_Feedback == NULL )
01738 return;
01739
01740 SUMMARY_PROCEDURE* node_summary = node->Summary_Proc();
01741 SUMMARY_CALLSITE* callsite_array =
01742 IPA_get_callsite_array( node ) + node_summary->Get_callsite_index();
01743
01744 int intr_call_count = 0;
01745 int callsite_id = 0;
01746
01747
01748 std::map<WN*,UINT16> wn_cs_id_map;
01749 int* new_call_id =
01750 (int*)alloca( sizeof(new_call_id[0]) * node_summary->Get_callsite_count() );
01751 BZERO( new_call_id, sizeof(new_call_id[0]) * node_summary->Get_callsite_count() );
01752
01753 std::map<UINT16,ST*> new_st_map;
01754
01755 for( WN_ITER* wni = WN_WALK_TreeIter(node->Whirl_Tree(FALSE) );
01756 wni != NULL;
01757 wni = WN_WALK_TreeNext(wni) ){
01758 WN* wn = WN_ITER_wn (wni);
01759
01760 switch( WN_operator(wn) ){
01761 case OPR_INTRINSIC_CALL:
01762 intr_call_count++;
01763
01764 case OPR_CALL:
01765 if( WN_opcode(wn) == OPC_VCALL &&
01766 WN_Fake_Call_EH_Region( wn, Parent_Map ) ){
01767 break;
01768 }
01769
01770 case OPR_ICALL:
01771 wn_cs_id_map[wn] = callsite_id;
01772 callsite_id++;
01773 break;
01774 }
01775 }
01776
01777 const int freq_threshold = 200;
01778 const int orig_call_count = node_summary->Get_call_count();
01779
01780 for( WN_ITER* wni = WN_WALK_SCFIter(node->Whirl_Tree(FALSE));
01781 wni != NULL;
01782 wni = WN_WALK_SCFNext(wni) ){
01783 if( WN_operator(WN_ITER_wn(wni)) != OPR_BLOCK )
01784 continue;
01785
01786 WN* block = WN_ITER_wn(wni);
01787
01788 for( WN* wn = WN_first(block); wn != NULL; wn = WN_next(wn) ){
01789 if( WN_operator(wn) != OPR_ICALL )
01790 continue;
01791
01792 const FB_Info_Call& info_call = Cur_PU_Feedback->Query_call(wn);
01793
01794 if( !info_call.freq_entry.Known() ){
01795 continue;
01796 }
01797
01798 if( info_call.freq_entry.Value() < freq_threshold ){
01799 continue;
01800 }
01801
01802 FB_Info_Icall info_icall = Cur_PU_Feedback->Query_icall(wn);
01803
01804 if( info_icall.Is_uninit() )
01805 continue;
01806
01807
01808
01809
01810
01811
01812 if( info_icall.tnv._exec_counter < info_call.freq_entry.Value() ){
01813 const UINT64 gap = (UINT64)info_call.freq_entry.Value() -
01814 info_icall.tnv._exec_counter;
01815 info_icall.tnv._exec_counter += gap;
01816 info_icall.tnv._counters[0] += gap;
01817 Cur_PU_Feedback->Annot_icall( wn, info_icall );
01818 }
01819
01820 const UINT64 exec_counter = info_icall.tnv._exec_counter;
01821 const UINT64 callee_counter = info_icall.tnv._counters[0];
01822 const UINT64 callee_addr = info_icall.tnv._values[0];
01823
01824 if( exec_counter == 0 || callee_counter == 0 ){
01825 continue;
01826 }
01827
01828 if( Trace_IPA || Trace_Perf ){
01829 fprintf( TFile, "icall table entries --->\n" );
01830
01831 for( int i = 0; i < FB_TNV_SIZE; i++ ){
01832 if( info_icall.tnv._values[i] == 0 )
01833 break;
01834
01835 char* p = addr_node_map[info_icall.tnv._values[i]]->Name();
01836 const float ratio = (float)info_icall.tnv._counters[i] / exec_counter;
01837
01838 fprintf( TFile, "\t%s(%llu,%f)\n", p, info_icall.tnv._counters[i], ratio );
01839 }
01840 }
01841
01842 IPA_NODE* callee = addr_node_map[callee_addr];
01843 if( callee == NULL ){
01844
01845 continue;
01846 }
01847
01848 ST* st_callee = WN_st( PU_Info_tree_ptr( callee->PU_Info() ) );
01849 TY_IDX ty_callee = ST_pu_type( st_callee );
01850 char* callee_name = callee->Name();
01851
01852
01853
01854
01855
01856 if( !Check_Heuristic( node, callee, callee_counter , cg ) ){
01857
01858 if( Trace_IPA || Trace_Perf ){
01859 fprintf( TFile, "Convert_Icall: target %s will not be converted",
01860 callee_name );
01861 }
01862
01863 continue;
01864 }
01865
01866 if( Trace_IPA || Trace_Perf ){
01867 fprintf( TFile,
01868 "map addr 0x%llx to func %s (freq:%llu/%llu)\n",
01869 callee_addr, callee_name, callee_counter, exec_counter);
01870 }
01871
01872 SUMMARY_CALLSITE* callsite = NULL;
01873
01874 for( int i = node_summary->Get_call_count();
01875 i < node_summary->Get_callsite_count();
01876 i++ ){
01877 if( callsite_array[i].Is_icall_target() ){
01878 callsite = &callsite_array[i];
01879 break;
01880 }
01881 }
01882
01883 FmtAssert( callsite->Get_callsite_id() == callsite - callsite_array,
01884 ("callsite_id mismatch") );
01885 FmtAssert( callsite != NULL, ("Convert_Icall: no available callsite found") );
01886
01887 node_summary->Incr_call_count();
01888 callsite->Reset_icall_target();
01889 callsite->Set_param_count( WN_num_actuals(wn) );
01890 callsite->Set_return_type( WN_rtype(wn) );
01891 callsite->Set_callsite_freq();
01892 callsite->Set_frequency_count( (INT64)callee_counter );
01893 callsite->Set_probability( -1 );
01894 callsite->Set_symbol_index( 0 );
01895
01896 new_st_map[wn_cs_id_map[wn]] = st_callee;
01897 new_call_id[wn_cs_id_map[wn]] = callsite->Get_callsite_id();
01898
01899 IPA_EDGE* edge = cg->Add_New_Edge( callsite,
01900 node->Node_Index(),
01901 callee->Node_Index() );
01902
01903
01904
01905
01906 WN* tmpkid0 = WN_CreateLda( Use_32_Bit_Pointers ? OPC_U4LDA : OPC_U8LDA,
01907 0, Make_Pointer_Type(ty_callee),st_callee );
01908 WN* tmpkid1 = WN_COPY_Tree_With_Map( WN_kid(wn,WN_kid_count(wn)-1) );
01909 WN* test = WN_Create( Use_32_Bit_Pointers ? OPC_U4U4EQ : OPC_U8U8EQ, 2 );
01910
01911 WN_kid0(test) = tmpkid0;
01912 WN_kid1(test) = tmpkid1;
01913
01914 WN* if_then = WN_Create(WN_opcode(wn),WN_kid_count(wn)-1);
01915 WN* if_then_block = WN_CreateBlock();
01916 WN_set_operator( if_then, OPR_CALL );
01917
01918 edge->Set_Whirl_Node( if_then );
01919
01920 for( int i = 0; i < WN_kid_count(if_then); i++ ){
01921 WN_kid(if_then,i) = WN_COPY_Tree_With_Map( WN_kid(wn,i) );
01922 }
01923
01924 WN_st_idx(if_then) = ST_st_idx(st_callee);
01925
01926 WN_Set_Parent( if_then, if_then_block,
01927 node->Parent_Map(), node->Map_Table() );
01928 WN_INSERT_BlockLast( if_then_block, if_then );
01929 WN_Parentize( if_then, node->Parent_Map(), node->Map_Table() );
01930
01931 WN* if_else = WN_COPY_Tree_With_Map( wn );
01932 WN* if_else_block = WN_CreateBlock();
01933 WN_INSERT_BlockLast(if_else_block,if_else);
01934
01935 for( WN* stmt = WN_next(wn);
01936 stmt != NULL && Is_Return_Store_Stmt( stmt ); ){
01937 WN_INSERT_BlockLast( if_then_block, WN_COPY_Tree(stmt) );
01938 WN_INSERT_BlockLast( if_else_block, WN_COPY_Tree(stmt) );
01939
01940
01941 WN* ret_wn = stmt;
01942 stmt = WN_next( stmt );
01943
01944 WN_EXTRACT_FromBlock( block, ret_wn );
01945 }
01946
01947 WN* wn_if = WN_CreateIf( test, if_then_block, if_else_block );
01948 Cur_PU_Feedback->FB_lower_icall( wn, if_else, if_then, wn_if );
01949
01950
01951 Cur_PU_Feedback->Delete(wn);
01952
01953
01954 WN_INSERT_BlockAfter( block, wn, wn_if );
01955 WN_EXTRACT_FromBlock( block, wn );
01956
01957 wn = wn_if;
01958 }
01959 }
01960
01961 if( node_summary->Get_call_count() == orig_call_count )
01962 return;
01963
01964 WN_verifier( node->Whirl_Tree(FALSE) );
01965
01966
01967
01968 const int callsite_count = node_summary->Get_call_count() + intr_call_count;
01969 node_summary->Set_callsite_count( callsite_count );
01970
01971 const size_t aux_callsite_size = callsite_count * sizeof( SUMMARY_CALLSITE );
01972 SUMMARY_CALLSITE* aux_callsite = (SUMMARY_CALLSITE*)alloca( aux_callsite_size );
01973 BZERO( aux_callsite, aux_callsite_size );
01974
01975 std::map<UINT16,ST*> aux_st_map;
01976
01977 int new_callsite_id = 0;
01978
01979 for( int callsite_id = 0;
01980 callsite_id < orig_call_count + intr_call_count;
01981 callsite_id++, new_callsite_id++ ){
01982 const int org_callsite = new_call_id[callsite_id];
01983 if( org_callsite > 0 ){
01984 aux_st_map[new_callsite_id] = new_st_map[callsite_id];
01985 aux_callsite[new_callsite_id++] = callsite_array[org_callsite];
01986 }
01987
01988 aux_callsite[new_callsite_id] = callsite_array[callsite_id];
01989 }
01990
01991 FmtAssert( new_callsite_id == callsite_count, ("callsite count mismatch") );
01992
01993 for( int i = 0; i < callsite_count; i++ ){
01994 callsite_array[i] = aux_callsite[i];
01995 callsite_array[i].Set_callsite_id( i );
01996 }
01997
01998
01999
02000 EDGE_INDEX* out_edges =
02001 (EDGE_INDEX*) alloca (cg->Num_Out_Edges(node) * sizeof(EDGE_INDEX));
02002
02003 int out_count = 0;
02004 IPA_SUCC_ITER succ_iter (cg, node);
02005 for( succ_iter.First(); !succ_iter.Is_Empty(); succ_iter.Next() ){
02006 out_edges[out_count++] = succ_iter.Current_Edge_Index();
02007 }
02008
02009 for( int i = 0; i < out_count; i++ ){
02010 cg->Graph()->Delete_Edge (out_edges[i]);
02011 }
02012
02013 node->Icall_List().clear();
02014 node->Ocall_List().clear();
02015
02016 SUMMARY_SYMBOL* symbol_array = IPA_get_symbol_array (node);
02017
02018 for( int j = 0; j < callsite_count; j++ ){
02019 FmtAssert( !callsite_array[j].Is_icall_target(),
02020 ("callsite is an icall target") );
02021
02022 if( callsite_array[j].Is_func_ptr() ){
02023 append_icall_list (node->Icall_List(), &callsite_array[j] );
02024 continue;
02025 }
02026
02027 if( callsite_array[j].Is_intrinsic() ){
02028 continue;
02029 }
02030
02031 const INT32 callee_sym_index = callsite_array[j].Get_symbol_index();
02032 ST* callee_st = callee_sym_index == 0
02033 ? aux_st_map[j] : ST_ptr(symbol_array[callee_sym_index].St_idx());
02034
02035 FmtAssert( callee_st != NULL, ("Unknown callee") );
02036
02037
02038 while (ST_is_weak_symbol (callee_st) &&
02039 ST_st_idx (callee_st) != ST_base_idx (callee_st)) {
02040 callee_st = ST_base (callee_st);
02041 }
02042 Clear_ST_is_not_used (callee_st);
02043
02044 NODE_INDEX callee_idx = AUX_PU_node(Aux_Pu_Table[ST_pu(callee_st)]);
02045 if( callee_idx != INVALID_NODE_INDEX ){
02046 IPA_EDGE* edge = cg->Add_New_Edge(&callsite_array[j],
02047 node->Node_Index(),
02048 callee_idx);
02049 IPA_NODE* callee = cg->Graph()->Node_User(callee_idx);
02050 if (callee->Has_Propagated_Const()) {
02051 edge->Set_Propagated_Const();
02052 }
02053
02054 } else {
02055 append_icall_list( node->Ocall_List(), &callsite_array[j] );
02056 }
02057 }
02058
02059 return;
02060 }
02061
02062
02063 void IPA_Convert_Icalls( IPA_CALL_GRAPH* cg )
02064 {
02065 IPA_Collect_Runtime_Addr( cg );
02066
02067 IPA_NODE_ITER cg_iter( cg, PREORDER );
02068
02069 for( cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next() ){
02070 Convert_Icall( cg, cg_iter.Current() );
02071 }
02072 }
02073 #endif
02074
02075
02076
02077
02078
02079
02080 enum DFE_STATE
02081 {
02082 NOT_VISITED = 0,
02083 VISITED_BUT_UNDECIDED,
02084 VISITED_AND_KEEP,
02085 VISITED_AND_DELETE
02086 };
02087
02088
02089 enum DFE_ACTION
02090 {
02091 MARK_USED,
02092 SEARCH_FOR_USED,
02093
02094 MARK_DELETED
02095 };
02096
02097
02098
02099
02100 static void
02101 Mark_Deletable_Funcs (NODE_INDEX v, DFE_ACTION action, mUINT8 *visited)
02102 {
02103 IPA_NODE* node = IPA_Call_Graph->Graph()->Node_User(v);
02104
02105 NODE_INDEX alt_entry_index = INVALID_NODE_INDEX;
02106
02107 if (node->Summary_Proc()->Is_alt_entry()) {
02108 ALT_ENTRY_MAP::iterator iter = alt_entry_map->find (v);
02109 if (iter != alt_entry_map->end())
02110 alt_entry_index = (*iter).second;
02111 }
02112
02113 switch (action) {
02114
02115 case MARK_USED:
02116 node->Clear_Deletable ();
02117 if (node->Is_Externally_Callable() || node->Is_Undeletable()) {
02118 node->Set_Undeletable();
02119 }
02120 visited[v] = VISITED_AND_KEEP;
02121 break;
02122
02123 case SEARCH_FOR_USED:
02124 if (node->Is_Externally_Callable() || node->Is_Undeletable()) {
02125 node->Clear_Deletable ();
02126 node->Set_Undeletable();
02127 action = MARK_USED;
02128 visited[v] = VISITED_AND_KEEP;
02129 } else if (visited[v] == 0)
02130 visited[v] = VISITED_BUT_UNDECIDED;
02131 break;
02132
02133 case MARK_DELETED:
02134 if (node->Is_Externally_Callable () || node->Is_Undeletable() ||
02135 PU_has_global_pragmas (node->Get_PU ())
02136 #ifdef TODO
02137 || node->Should_Be_Skipped()
02138 #endif
02139 ) {
02140
02141 node->Clear_Deletable ();
02142 node->Set_Undeletable();
02143 action = MARK_USED;
02144 visited[v] = VISITED_AND_KEEP;
02145 } else {
02146 node->Set_Deletable ();
02147 IP_FILE_HDR& s = node->File_Header ();
02148 s.proc_info[node->Proc_Info_Index()].state = IPA_UNUSED;
02149 visited[v] = VISITED_AND_DELETE;
02150 }
02151 break;
02152 }
02153
02154 #ifdef KEY
02155 BOOL alt_entry_update = FALSE;
02156 #endif
02157
02158 if (alt_entry_index != INVALID_NODE_INDEX && action == MARK_USED &&
02159 visited[alt_entry_index] != VISITED_AND_KEEP) {
02160 IPA_NODE *n = IPA_Call_Graph->Graph()->Node_User(alt_entry_index);
02161 n->Clear_Deletable ();
02162 IP_FILE_HDR& s = n->File_Header();
02163 if (s.proc_info[node->Proc_Info_Index()].state == IPA_UNUSED)
02164 s.proc_info[node->Proc_Info_Index()].state = IPA_ORIG;
02165 if (n->Is_Externally_Callable() || n->Is_Undeletable()) {
02166 n->Set_Undeletable();
02167 }
02168 visited[alt_entry_index] = VISITED_AND_KEEP;
02169 #ifdef KEY
02170 alt_entry_update = TRUE;
02171 #endif
02172 }
02173
02174 #ifdef TODO
02175 if (IPA_Enable_daVinci) {
02176 switch (action) {
02177 case MARK_USED:
02178 cg_display->Mark_Used (v);
02179 break;
02180 case MARK_DELETED:
02181 cg_display->Mark_Deleted (v);
02182 break;
02183 }
02184 }
02185 #endif
02186
02187 NODE_ITER vitr(IPA_Call_Graph->Graph(), v);
02188 for (NODE_INDEX vi = vitr.First_Succ(); vi != -1; vi = vitr.Next_Succ()) {
02189 if (visited[vi] == 0 || (action != SEARCH_FOR_USED &&
02190 visited[vi] == VISITED_BUT_UNDECIDED))
02191 Mark_Deletable_Funcs (vi, action, visited);
02192 }
02193
02194 #ifdef KEY
02195 if (alt_entry_update)
02196 {
02197
02198
02199 Is_True (alt_entry_index != INVALID_NODE_INDEX,
02200 ("Mark_Deletable_Funcs: Invalid alternate entry point"));
02201 NODE_ITER vitr(IPA_Call_Graph->Graph(), alt_entry_index);
02202 for (NODE_INDEX vi = vitr.First_Succ(); vi != -1; vi = vitr.Next_Succ()) {
02203 if (visited[vi] == 0 || (action != SEARCH_FOR_USED &&
02204 visited[vi] == VISITED_BUT_UNDECIDED))
02205 Mark_Deletable_Funcs (vi, action, visited);
02206 }
02207 }
02208 #endif
02209
02210 }
02211
02212
02213 #ifndef _LIGHTWEIGHT_INLINER
02214
02215 static void
02216 Reset_modref_count (IPA_NODE *node)
02217 {
02218
02219 IP_FILE_HDR& hdr = node->File_Header ();
02220 SUMMARY_SYMBOL* sym_table = IPA_get_symbol_array (node);
02221 SUMMARY_GLOBAL* gnode = IPA_get_global_array (node);
02222
02223 if (gnode == NULL || sym_table == NULL)
02224 return;
02225
02226 SUMMARY_PROCEDURE *pnode = node->Summary_Proc();
02227 INT32 max_size = pnode->Get_global_index () + pnode->Get_global_count ();
02228
02229 gnode += pnode->Get_global_index ();
02230 for (INT i = pnode->Get_global_index (); i < max_size; i++, gnode++)
02231 if (gnode->Get_refcount () || gnode->Get_modcount ()) {
02232 SUMMARY_SYMBOL *snode = sym_table + gnode->Get_symbol_index ();
02233 ST_IDX st_idx = snode->St_idx ();
02234 Update_reference_count (&St_Table[st_idx],
02235 - gnode->Get_refcount (),
02236 - gnode->Get_modcount (),
02237 snode->Is_cmod ());
02238 }
02239 }
02240 #endif // _LIGHTWEIGHT_INLINER
02241
02242
02243 static UINT32
02244 Delete_Function (NODE_INDEX node, BOOL update_modref_count, mUINT8 *visited)
02245 {
02246 IPA_PRED_ITER pred_iter (node);
02247
02248 for (pred_iter.First (); !pred_iter.Is_Empty (); pred_iter.Next ()) {
02249 IPA_EDGE *edge = pred_iter.Current_Edge ();
02250 if (edge) {
02251 pred_iter.Set_Current_Edge(0);
02252 }
02253 }
02254
02255 IPA_SUCC_ITER succ_iter (node);
02256
02257 for (succ_iter.First (); !succ_iter.Is_Empty (); succ_iter.Next ()) {
02258 IPA_EDGE *edge = succ_iter.Current_Edge ();
02259 if (edge) {
02260 succ_iter.Set_Current_Edge(0);
02261 }
02262 }
02263
02264 IPA_NODE* ipa_node = (IPA_NODE*) IPA_Call_Graph->Graph()->Delete_Node (node);
02265
02266 if (Trace_IPA || Trace_Perf)
02267 fprintf (TFile, "%s deleted (unused)\n",
02268 ipa_node->Name ());
02269
02270 #ifndef _LIGHTWEIGHT_INLINER
02271
02272 if (update_modref_count)
02273 Reset_modref_count (ipa_node);
02274
02275 #endif // _LIGHTWEIGHT_INLINER
02276
02277 Set_ST_is_not_used (ipa_node->Func_ST ());
02278
02279 Delete_Function_In_File (ipa_node->File_Header (),
02280 ipa_node->Proc_Info_Index ());
02281
02282 const PU_Info* pu = ipa_node->PU_Info ();
02283 UINT32 size = 0;
02284 if (pu != NULL) {
02285 for (pu = PU_Info_child (pu); pu; pu = PU_Info_next (pu)) {
02286
02287
02288 const AUX_PU& aux_pu =
02289 Aux_Pu_Table [ST_pu (St_Table [PU_Info_proc_sym (pu)])];
02290 IPA_NODE* child = IPA_Call_Graph->Graph()->Node_User (AUX_PU_node (aux_pu));
02291 if (child) {
02292 NODE_INDEX c_vi = child->Node_Index();
02293 visited[c_vi] = VISITED_AND_KEEP;
02294 size += Delete_Function (c_vi, update_modref_count, visited);
02295 Orig_Prog_WN_Count -= (UINT32)(child->Get_wn_count());
02296 }
02297 }
02298 }
02299
02300 Orig_Prog_WN_Count -= (UINT32)(ipa_node->Get_wn_count());
02301 return ipa_node->Weight () + size;
02302 }
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313 UINT32
02314 Eliminate_Dead_Func (BOOL update_modref_count)
02315 {
02316 mUINT8 *visited = (mUINT8 *)
02317 alloca (GRAPH_vmax (IPA_Call_Graph->Graph()) * sizeof(mUINT8));
02318 BZERO (visited, sizeof(mUINT8) * GRAPH_vmax(IPA_Call_Graph->Graph()));
02319
02320 NODE_INDEX vi;
02321
02322
02323 NODE_ITER vitr(IPA_Call_Graph->Graph(), IPA_Call_Graph->Root());
02324 for (vi = vitr.First_Succ(); vi != -1; vi = vitr.Next_Succ())
02325 Mark_Deletable_Funcs (vi, SEARCH_FOR_USED, visited);
02326
02327
02328 new (&vitr) NODE_ITER (IPA_Call_Graph->Graph(), IPA_Call_Graph->Root());
02329
02330
02331 for (vi = vitr.First_Succ(); vi != -1; vi = vitr.Next_Succ())
02332 if (visited[vi] == 0 || visited[vi] == VISITED_BUT_UNDECIDED)
02333 Mark_Deletable_Funcs (vi, MARK_DELETED, visited);
02334
02335 UINT32 size = 0;
02336 for (vi = 0; vi < GRAPH_vmax(IPA_Call_Graph->Graph()); vi++)
02337 if (visited[vi] == VISITED_AND_DELETE)
02338 size += Delete_Function (vi, update_modref_count, visited);
02339
02340 DevWarn ("TODO: implement *skip* option");
02341
02342
02343
02344 Connect_call_graph();
02345
02346 return size;
02347 }
02348
02349
02350
02351
02352
02353
02354
02355 void
02356 IPA_NODE::Read_PU (BOOL readtree)
02357 {
02358 if (!Is_Mempool_Initialized()) {
02359 Set_Mempool_Initialized();
02360 MEM_POOL_Initialize(Mem_Pool(),Name(),1);
02361 MEM_POOL_Push(Mem_Pool());
02362 }
02363
02364 if (readtree)
02365 IP_READ_pu (this, File_Header(), Proc_Info_Index(), Mem_Pool() );
02366
02367 if (Cur_PU_Feedback)
02368 Set_Feedback ();
02369
02370 if (!Parent_Map()) {
02371 ::PU_Info *pu = PU_Info();
02372 Current_Map_Tab = PU_Info_maptab(pu);
02373 Set_Parent_Map(WN_MAP_Create(Mem_Pool()));
02374 WN_Parentize(PU_Info_tree_ptr(pu), Parent_Map(), Current_Map_Tab);
02375 }
02376 }
02377
02378 static void
02379 read_pu_including_parents(IPA_NODE* node)
02380 {
02381
02382 IPA_NODE* parent = Get_Parent_Of_Nested_PU(node);
02383 if (parent != NULL) {
02384 read_pu_including_parents(parent);
02385 }
02386
02387 if (node->Scope_Table() == NULL) {
02388 node->Read_PU(TRUE);
02389 node->Set_Scope(Scope_tab);
02390 }
02391 else {
02392
02393
02394 node->Read_PU(FALSE);
02395 SYMTAB_IDX lexical_level = node->Lexical_Level();
02396 Scope_tab[lexical_level] = node->Scope_Table()[lexical_level];
02397 }
02398
02399 }
02400
02401
02402
02403 void
02404 IPA_NODE::Un_Read_PU ()
02405 {
02406 MEM_POOL_Pop(Mem_Pool());
02407 MEM_POOL_Delete(Mem_Pool());
02408 Clear_Mempool_Initialized();
02409 WN_MAP_Delete(Parent_Map());
02410 Set_Scope(NULL);
02411 Set_Parent_Map(0);
02412 }
02413
02414
02415 SCOPE *
02416 IPA_NODE::Scope()
02417 {
02418 SCOPE* old_scope = Scope_tab;
02419
02420 if (_scope_tab != NULL) {
02421 Scope_tab = _scope_tab;
02422 #ifdef KEY
02423
02424 if (!this->Is_Builtin())
02425 #endif
02426 read_pu_including_parents(this);
02427
02428 Scope_tab = old_scope;
02429 return _scope_tab;
02430 }
02431
02432
02433 INT size = (Lexical_Level()+1) * sizeof(SCOPE);
02434 SCOPE *new_scope_tab = (SCOPE *)
02435 MEM_POOL_Alloc (Malloc_Mem_Pool, size);
02436 BZERO(new_scope_tab, size);
02437
02438
02439 memcpy(new_scope_tab, Scope_tab, sizeof(SCOPE)*2);
02440 #if 0
02441 SYMTAB_IDX i;
02442 for (i = 0; i < Lexical_Level(); ++i) {
02443 new_scope_tab[i] = Scope_tab[i];
02444 }
02445 #endif
02446
02447 Scope_tab = new_scope_tab;
02448
02449
02450 #ifdef KEY
02451
02452 if (!this->Is_Builtin())
02453 #endif
02454 read_pu_including_parents(this);
02455
02456 Scope_tab = old_scope;
02457 return new_scope_tab;
02458 }
02459
02460
02461
02462
02463 WN*
02464 IPA_NODE::Whirl_Tree (BOOL readtree)
02465 {
02466 ::PU_Info *pu = PU_Info();
02467 if (PU_Info_state(pu, WT_TREE) != Subsect_InMem) {
02468 if (!readtree) return NULL;
02469 Read_PU(TRUE);
02470 }
02471 return PU_Info_tree_ptr(pu);
02472 }
02473
02474
02475
02476
02477 void
02478 IPA_NODE::Set_Whirl_Tree (WN *wn)
02479 {
02480 ::PU_Info *pu = this->PU_Info();
02481 Set_PU_Info_tree_ptr(pu, wn);
02482 Set_PU_Info_state(pu, WT_TREE, Subsect_InMem);
02483 }
02484
02485 #if defined(KEY) && !defined(_LIGHTWEIGHT_INLINER)
02486 #include "be_ipa_util.h"
02487
02488 static void
02489 Add_Mod_Ref_Info (IPA_NODE * node)
02490 {
02491 UINT32 index;
02492
02493
02494
02495
02496 const INT bits_per_byte = 8;
02497 const int bitsize = sizeof (mUINT8) * bits_per_byte;
02498 const IPAA_NODE_INFO * info = node->Mod_Ref_Info();
02499
02500 Is_True (info, ("Add_Mod_Ref_Info: Node should have mod-ref info"));
02501 New_Mod_Ref_Info (index);
02502
02503
02504 Mod_Ref_Info_Table[index].pu_idx = ST_pu (node->Func_ST());
02505
02506
02507 INT bv_size = ST_Table_Size (GLOBAL_SYMTAB);
02508 if (bv_size % bits_per_byte > 0)
02509 bv_size = bv_size / bits_per_byte + 1;
02510 else
02511 bv_size /= bits_per_byte;
02512
02513
02514 mUINT8 * MOD = CXX_NEW_ARRAY (mUINT8, bv_size, Malloc_Mem_Pool);
02515 BZERO (MOD, bv_size);
02516
02517
02518 mUINT8 * REF = CXX_NEW_ARRAY (mUINT8, bv_size, Malloc_Mem_Pool);
02519 BZERO (REF, bv_size);
02520
02521 for (INT i=1; i<ST_Table_Size (GLOBAL_SYMTAB); i++)
02522 {
02523 ST * st = &St_Table(GLOBAL_SYMTAB, i);
02524 if (ST_class (st) != CLASS_VAR) continue;
02525
02526 BOOL mod_info = info->Is_def_elmt (i);
02527 BOOL ref_info = info->Is_eref_elmt (i);
02528
02529 mUINT8 bit_to_set = 1 << (bitsize - 1 - (i % bitsize));
02530
02531 if (mod_info)
02532 *(MOD + i / bitsize) |= bit_to_set;
02533
02534 if (ref_info)
02535 *(REF + i / bitsize) |= bit_to_set;
02536 }
02537
02538 Mod_Ref_Info_Table[index].mod = MOD;
02539 Mod_Ref_Info_Table[index].ref = REF;
02540
02541 Mod_Ref_Info_Table[index].size = bv_size;
02542 }
02543 #endif // KEY && !_LIGHTWEIGHT_INLINER
02544
02545
02546
02547
02548 void
02549 IPA_NODE::Write_PU ()
02550 {
02551 IP_FILE_HDR& file_hdr = File_Header();
02552 IP_PROC_INFO& proc_info = IP_FILE_HDR_proc_info (file_hdr)[Proc_Info_Index()];
02553
02554 if (Summary_Proc()->Is_alt_entry()) {
02555 Set_IP_PROC_INFO_state (proc_info, IPA_DELETED);
02556 Inc_IP_FILE_HDR_num_procs_processed (file_hdr);
02557 } else {
02558 IPA_NODE_CONTEXT context(this);
02559 #ifdef Is_True
02560 WN* w = Whirl_Tree(FALSE);
02561 if (w && !Is_Nested_PU()) {
02562 WN_verifier(w);
02563 }
02564 #endif
02565 if ((IP_PROC_INFO_state (proc_info) != IPA_WRITTEN) || !Has_Recursive_In_Edge())
02566 {
02567 #if defined(KEY) && !defined(_LIGHTWEIGHT_INLINER)
02568
02569 if (Mod_Ref_Info())
02570 Add_Mod_Ref_Info (this);
02571 #endif
02572 IP_WRITE_pu(&file_hdr, Proc_Info_Index());
02573 #ifdef KEY
02574
02575
02576 Set_PU_Write_Complete ();
02577 #endif
02578 }
02579 }
02580 }
02581
02582
02583
02584
02585
02586
02587 BOOL
02588 IPA_NODE::Is_Externally_Callable ()
02589 {
02590
02591
02592
02593 const ST* func_st = Func_ST ();
02594
02595 if (ST_addr_saved(func_st) || ST_addr_passed (func_st))
02596 return TRUE;
02597
02598 if (ST_export (func_st) == EXPORT_LOCAL_INTERNAL ||
02599 ST_export (func_st) == EXPORT_LOCAL)
02600 return FALSE;
02601
02602 #ifndef _LIGHTWEIGHT_INLINER
02603 const AUX_ST& aux_st = Aux_St_Table[ST_st_idx (func_st)];
02604
02605 if (AUX_ST_flags (aux_st, USED_IN_OBJ|USED_IN_DSO|ADDR_TAKEN_IN_OBJ))
02606 return TRUE;
02607 #endif // _LIGHTWEIGHT_INLINER
02608
02609 if (ST_export (func_st) == EXPORT_INTERNAL ||
02610 ST_export (func_st) == EXPORT_HIDDEN )
02611 return FALSE;
02612
02613 return TRUE;
02614
02615 }
02616
02617
02618
02619
02620 void
02621 IPA_NODE::Clear_Cloned_Symtab ()
02622 {
02623 if (Cloned_Symtab()) {
02624 CXX_DELETE (Cloned_Symtab(), Malloc_Mem_Pool);
02625 Set_Cloned_Symtab(NULL);
02626 }
02627 }
02628
02629
02630
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641 void
02642 IPA_EDGE::Print ( const FILE* fp,
02643 const IPA_CALL_GRAPH* cg,
02644 BOOL invert ) const
02645 {
02646 IPA_NODE* caller = cg->Caller(Edge_Index());
02647 IPA_NODE* callee = cg->Callee(Edge_Index());
02648
02649 fprintf ( (FILE*) fp,
02650 "name = %-20s (ix:%d, f:%02x:%02x, @%p)\n",
02651 invert ? caller->Name() : callee->Name(),
02652 Edge_Index(),
02653 _flags,
02654 EDGE_etype(&GRAPH_e_i(cg->Graph(), Edge_Index())),
02655 this );
02656 }
02657
02658
02659 void
02660 IPA_EDGE::Trace ( const IPA_CALL_GRAPH *cg, BOOL invert ) const
02661 {
02662 Print ( TFile, cg, invert );
02663 }
02664
02665
02666 IPA_NODE* Get_Node_From_PU(PU_Info* pu)
02667 {
02668 Is_True(pu != 0, ("Get_Node_From_PU: pu must not be null"));
02669 Is_True(IPA_Call_Graph->Graph() != 0, ("Get_Node_From_PU: Call graph not initialized"));
02670
02671
02672 ST_IDX idx = PU_Info_proc_sym(pu);
02673 Is_True(ST_IDX_level(idx) == GLOBAL_SYMTAB,
02674 ("Get_Node_From_PU: bad st index level %d, should be %d",
02675 ST_IDX_level(idx), GLOBAL_SYMTAB));
02676
02677
02678 PU_IDX pu_idx = ST_pu(St_Table[idx]);
02679 Is_True(pu_idx > PU_IDX_ZERO && pu_idx < PU_Table_Size(),
02680 ("Get_Node_From_PU: bad pu index %d, not in range 0 <= idx < %d",
02681 pu_idx, PU_Table_Size()));
02682
02683
02684 NODE_INDEX node_idx = AUX_PU_node(Aux_Pu_Table[pu_idx]);
02685 IPA_NODE* result = IPA_Call_Graph->Graph()->Node_User(node_idx);
02686
02687 #ifdef KEY
02688
02689
02690
02691 if (result == NULL)
02692 return NULL;
02693
02694
02695 if (result->Is_Builtin())
02696 return result;
02697 #else
02698
02699 Is_True(result != 0, ("Get_Node_From_PU: null call graph node"));
02700 #endif
02701 Is_True(result->PU_Info() != 0, ("Get_Node_From_PU: node has null pu"));
02702 Is_True(PU_Info_proc_sym(result->PU_Info()) == idx,
02703 ("Get_Node_From_PU: pu has st idx %ld, node has st_idx %ld",
02704 PU_Info_proc_sym(result->PU_Info()), idx));
02705
02706 return result;
02707 }
02708
02709
02710
02711
02712
02713
02714
02715
02716
02717 INT32
02718 IPA_CALL_GRAPH::Num_Calls (IPA_NODE* caller, IPA_NODE* callee) const
02719 {
02720 INT32 count = 0;
02721 NODE_INDEX callee_idx = callee->Node_Index();
02722 NODE_INDEX caller_idx = caller->Node_Index();
02723
02724 for (EDGE_INDEX e = NODE_from(&GRAPH_v_i(_graph, caller_idx));
02725 e != -1;
02726 e = EDGE_nfrom(&GRAPH_e_i(_graph, e))) {
02727
02728 if (EDGE_to(&GRAPH_e_i(_graph, e)) == callee_idx) {
02729 ++count;
02730 }
02731 }
02732
02733 return count;
02734 }
02735
02736
02737
02738
02739
02740 void
02741 IPA_CALL_GRAPH::Map_Callsites (IPA_NODE* caller)
02742 {
02743
02744 if (caller->Is_Visited()) {
02745 return;
02746 }
02747 caller->Set_Visited();
02748
02749
02750 if (caller->Total_Succ() == 0) {
02751 return;
02752 }
02753
02754 WN** callsite_map = (WN**) alloca (caller->Total_Succ() * sizeof(WN*));
02755 UINT32 num_calls = 0;
02756
02757 for (WN_ITER* wni = WN_WALK_TreeIter(caller->Whirl_Tree(FALSE));
02758 wni != NULL;
02759 wni = WN_WALK_TreeNext(wni)) {
02760
02761 WN* wn = WN_ITER_wn (wni);
02762
02763 switch (WN_operator(wn)) {
02764
02765 case OPR_CALL:
02766 if (WN_opcode(wn) == OPC_VCALL &&
02767 WN_Fake_Call_EH_Region (wn, Parent_Map))
02768 break;
02769
02770 case OPR_ICALL:
02771 case OPR_INTRINSIC_CALL:
02772 callsite_map[num_calls++] = wn;
02773 break;
02774 }
02775 }
02776
02777 IPA_SUCC_ITER succ_iter (caller);
02778
02779 for (succ_iter.First(); !succ_iter.Is_Empty(); succ_iter.Next()) {
02780 IPA_EDGE *edge = succ_iter.Current_Edge();
02781 if (edge) {
02782 edge->Set_Whirl_Node (callsite_map[edge->Callsite_Id()]);
02783 }
02784 }
02785 }
02786
02787
02788 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
02789
02790 extern void
02791 Rename_Call_To_Cloned_PU (IPA_NODE *caller,
02792 IPA_NODE *callee,
02793 IPA_EDGE *e,
02794 IPA_CALL_GRAPH *cg);
02795
02796
02797
02798
02799
02800 static INT32
02801 IPA_add_new_procedure (const IPA_NODE* node)
02802 {
02803 static INT32* max_proc_in_file = NULL;
02804
02805 if (max_proc_in_file == NULL) {
02806 UINT32 bytes = IP_File_header.size() * sizeof(INT32);
02807 max_proc_in_file = (INT32*) MEM_POOL_Alloc(Malloc_Mem_Pool, bytes);
02808 BZERO (max_proc_in_file, bytes);
02809 }
02810
02811 INT32& max_proc_size = max_proc_in_file[node->File_Index()];
02812 IP_FILE_HDR& file_hdr = node->File_Header();
02813 SUMMARY_FILE_HEADER* summary_header = IP_FILE_HDR_file_header (file_hdr);
02814
02815 INT32 num_proc;
02816 SUMMARY_PROCEDURE* old_proc_array =
02817 IPA_get_procedure_file_array (file_hdr, num_proc);
02818 SUMMARY_PROCEDURE* new_proc_array;
02819 INT32 num_bytes = num_proc * sizeof(SUMMARY_PROCEDURE);
02820
02821
02822 if (max_proc_size == 0) {
02823 max_proc_size = num_proc * 2;
02824 new_proc_array = (SUMMARY_PROCEDURE*)
02825 MEM_POOL_Alloc (Malloc_Mem_Pool, num_bytes * 2);
02826 memcpy (new_proc_array, old_proc_array, num_bytes);
02827 Elf64_Word new_offset = summary_header->Get_proc_offset() +
02828 ((char*) new_proc_array - (char*) old_proc_array);
02829 summary_header->Set_proc_offset (new_offset);
02830 }
02831
02832 else if (max_proc_size <= num_proc) {
02833 max_proc_size = num_proc * 2;
02834 new_proc_array = (SUMMARY_PROCEDURE*)
02835 MEM_POOL_Realloc(Malloc_Mem_Pool, old_proc_array, num_bytes,num_bytes*2);
02836 Elf64_Word new_offset = summary_header->Get_proc_offset() +
02837 ((char*) new_proc_array - (char*) old_proc_array);
02838 summary_header->Set_proc_offset (new_offset);
02839 }
02840 else {
02841 new_proc_array = old_proc_array;
02842 }
02843
02844 summary_header->Set_proc_size(num_proc + 1);
02845
02846 return num_proc;
02847 }
02848
02849
02850
02851
02852
02853 IPA_NODE*
02854 IPA_CALL_GRAPH::Create_Clone (IPA_NODE* node)
02855 {
02856 IPA_NODE* clone = Add_New_Node (node->Func_ST(),
02857 node->File_Index(),
02858 node->Proc_Info_Index(),
02859 node->Summary_Proc_Index());
02860
02861
02862 if (_clone_to_orig_node_map == NULL) {
02863 _clone_to_orig_node_map =
02864 CXX_NEW (IPA_CLONE_TO_IPA_NODE_MAP (31, _pool), _pool);
02865 _orig_node_to_clones_map =
02866 CXX_NEW (IPA_NODE_TO_IPA_CLONES_MAP (31, _pool), _pool);
02867 }
02868
02869
02870 _clone_to_orig_node_map->Enter (clone, node);
02871
02872
02873 IPA_CLONE_ARRAY* clone_array = Clone_Array (node);
02874 if (clone_array == NULL) {
02875 clone_array = CXX_NEW (IPA_CLONE_ARRAY (_pool), _pool);
02876 _orig_node_to_clones_map->Enter (node, clone_array);
02877 }
02878 clone_array->AddElement (clone);
02879
02880
02881 EDGE_INDEX* out_edges =
02882 (EDGE_INDEX*) alloca (Num_Out_Edges(node) * sizeof(EDGE_INDEX));
02883
02884
02885 INT32 out_count = 0;
02886 IPA_SUCC_ITER succ_iter (this, node);
02887 for (succ_iter.First(); !succ_iter.Is_Empty(); succ_iter.Next()) {
02888
02889 IPA_EDGE* edge = succ_iter.Current_Edge();
02890 IPA_NODE* callee = Callee (edge);
02891
02892 if (callee == node) {
02893 Add_Edge (clone, clone, edge);
02894 }
02895 else {
02896 Add_Edge (clone, callee, edge);
02897 }
02898
02899
02900 out_edges[out_count++] = succ_iter.Current_Edge_Index();
02901 }
02902
02903
02904
02905 EDGE_INDEX* in_edges =
02906 (EDGE_INDEX*) alloca (Num_In_Edges(node) * sizeof(EDGE_INDEX));
02907
02908
02909
02910 INT32 in_count = 0;
02911 IPA_PRED_ITER pred_iter (this, node);
02912 for (pred_iter.First(); !pred_iter.Is_Empty(); pred_iter.Next()) {
02913
02914 IPA_EDGE* edge = pred_iter.Current_Edge();
02915
02916 if (edge) {
02917 IPA_NODE* caller = Caller (edge);
02918
02919
02920 if (caller != node) {
02921 Add_Edge (caller, clone, edge);
02922
02923
02924 if (caller->Node_Index() != Root()) {
02925 in_edges[in_count++] = pred_iter.Current_Edge_Index();
02926 }
02927 }
02928 }
02929 }
02930
02931 INT32 i;
02932
02933 for (i = 0; i < in_count; ++i) {
02934 _graph->Delete_Edge (in_edges[i]);
02935 }
02936
02937
02938 for (i = 0 ; i < out_count; ++i) {
02939 _graph->Delete_Edge (out_edges[i]);
02940 }
02941
02942
02943 clone->Set_Clone();
02944
02945
02946 MEM_POOL_Initialize (clone->Mem_Pool(), node->Name(), 1);
02947 MEM_POOL_Push (clone->Mem_Pool());
02948 clone->Set_Mempool_Initialized();
02949
02950 clone->Set_Total_Succ (node->Total_Succ());
02951 clone->Set_Mod_Ref_Info (CXX_NEW (IPAA_NODE_INFO (*(node->Mod_Ref_Info ())),
02952 Malloc_Mem_Pool));
02953 clone->Set_Cprop_Annot (node->Cprop_Annot());
02954
02955
02956
02957 IPO_Clone (node, clone);
02958
02959
02960 clone->Set_Summary_Proc_Index (IPA_add_new_procedure (clone));
02961 *(clone->Summary_Proc()) = *(node->Summary_Proc());
02962
02963
02964 return clone;
02965 }
02966
02967
02968
02969
02970
02971
02972 static void
02973 Copy_edge_cprop_annot (IPA_EDGE* src_edge, IPA_EDGE* dst_edge)
02974 {
02975 VALUE_DYN_ARRAY* dst_annot;
02976 VALUE_DYN_ARRAY* src_annot = src_edge->Cprop_Annot();
02977 if (src_annot != NULL && src_annot != (void*)-1) {
02978 dst_annot =
02979 CXX_NEW (VALUE_DYN_ARRAY (MEM_local_nz_pool_ptr), MEM_local_nz_pool_ptr);
02980 *dst_annot = *src_annot;
02981 }
02982 else {
02983 dst_annot = src_annot;
02984 }
02985 dst_edge->Set_Cprop_Annot (dst_annot);
02986 }
02987
02988
02989
02990
02991
02992
02993
02994
02995
02996
02997
02998
02999
03000
03001
03002
03003
03004
03005 IPA_NODE*
03006 IPA_CALL_GRAPH::Create_Quasi_Clone (IPA_EDGE* call_edge)
03007 {
03008
03009 Is_True (Caller(call_edge) != Callee(call_edge),
03010 ("Self-recursive edge in IPA_CALL_GRAPH::Create_Quasi_Clone"));
03011
03012 IPA_NODE* node = Callee (call_edge);
03013
03014
03015 IPA_NODE* clone = Add_New_Node (node->Func_ST(),
03016 node->File_Index(),
03017 node->Proc_Info_Index(),
03018 node->Summary_Proc_Index());
03019 clone->Set_Quasi_Clone();
03020
03021
03022 if (_clone_to_orig_node_map == NULL) {
03023 _clone_to_orig_node_map =
03024 CXX_NEW (IPA_CLONE_TO_IPA_NODE_MAP (31, _pool), _pool);
03025 _orig_node_to_clones_map =
03026 CXX_NEW (IPA_NODE_TO_IPA_CLONES_MAP (31, _pool), _pool);
03027 }
03028
03029
03030 _clone_to_orig_node_map->Enter (clone, node);
03031
03032
03033 IPA_CLONE_ARRAY* clone_array = _orig_node_to_clones_map->Find (node);
03034 if (clone_array == NULL) {
03035 clone_array = CXX_NEW (IPA_CLONE_ARRAY (_pool), _pool);
03036 _orig_node_to_clones_map->Enter (node, clone_array);
03037 }
03038 clone_array->AddElement (clone);
03039
03040
03041 clone->Set_Mod_Ref_Info (CXX_NEW (IPAA_NODE_INFO (*(node->Mod_Ref_Info ())),
03042 Malloc_Mem_Pool));
03043 Init_Cprop_Annotations (clone);
03044
03045
03046 EDGE_INDEX* in_edges =
03047 (EDGE_INDEX*) alloca (Num_In_Edges(node) * sizeof(EDGE_INDEX));
03048
03049 INT32 in_count = 0;
03050 IPA_PRED_ITER pred_iter (this, node);
03051 for (pred_iter.First(); !pred_iter.Is_Empty(); pred_iter.Next()) {
03052
03053 IPA_EDGE* edge = pred_iter.Current_Edge();
03054
03055
03056
03057 if (edge && Edges_Have_Equiv_Cprop_Annots (edge, call_edge)) {
03058
03059 Add_Edge (Caller(edge), clone, edge);
03060 in_edges[in_count++] = pred_iter.Current_Edge_Index();
03061 }
03062 }
03063
03064
03065 EDGE_INDEX* out_edges =
03066 (EDGE_INDEX*) alloca (Num_Out_Edges (node) * sizeof(EDGE_INDEX));
03067
03068
03069 INT32 out_count = 0;
03070 IPA_SUCC_ITER succ_iter (this, node);
03071 for (succ_iter.First(); !succ_iter.Is_Empty(); succ_iter.Next()) {
03072
03073
03074 IPA_EDGE* edge = succ_iter.Current_Edge();
03075 if (edge) {
03076 IPA_EDGE* ecopy = Add_New_Edge (edge->Summary_Callsite(),
03077 clone->Node_Index(),
03078 Callee(edge)->Node_Index());
03079 Copy_edge_cprop_annot (edge, ecopy);
03080 }
03081 }
03082
03083
03084 for (INT32 i = 0; i < in_count; ++i) {
03085 _graph->Delete_Edge (in_edges[i]);
03086 }
03087
03088
03089
03090 if (Num_In_Edges (node) == 0) {
03091 _graph->Add_Edge (GRAPH_root(_graph), node->Node_Index(), NULL);
03092 }
03093
03094
03095 return clone;
03096 }
03097
03098
03099
03100
03101
03102 void
03103 IPA_CALL_GRAPH::Quasi_To_Real_Clone (IPA_NODE* clone)
03104 {
03105 Is_True(clone->Is_Quasi_Clone(),
03106 ("IPA_CALL_GRAPH::Quasi_to_real_clone called on a non-quasi node"));
03107
03108 clone->Clear_Quasi_Clone();
03109 clone->Set_Clone();
03110 clone->Clear_Clone_Candidate();
03111
03112
03113 MEM_POOL_Initialize (clone->Mem_Pool(), clone->Name(), 1);
03114 MEM_POOL_Push (clone->Mem_Pool());
03115 clone->Set_Mempool_Initialized();
03116
03117 IPA_NODE* origin = Clone_Origin (clone);
03118
03119
03120 IPA_NODE_CONTEXT context (origin);
03121
03122
03123
03124 IPO_Clone (origin, clone);
03125
03126
03127 clone->Set_Summary_Proc_Index (IPA_add_new_procedure (clone));
03128 *(clone->Summary_Proc()) = *(origin->Summary_Proc());
03129
03130
03131 if (origin->Has_Aliased_Formal()) {
03132 clone->Set_Aliased_Formal();
03133 }
03134
03135
03136
03137
03138
03139 IPA_PRED_ITER pred_iter (this, clone);
03140 for (pred_iter.First(); !pred_iter.Is_Empty(); pred_iter.Next()) {
03141 IPA_EDGE* edge = pred_iter.Current_Edge();
03142 if (edge) {
03143 IPA_NODE* caller = Caller (edge);
03144 if (caller->Is_Quasi_Clone()) {
03145 Quasi_To_Real_Clone (caller);
03146 }
03147 else {
03148 IPA_CLONE_ARRAY* caller_clones = Clone_Array (caller);
03149 if (caller_clones) {
03150 for (UINT32 i = 0; i < caller_clones->Elements(); ++i) {
03151 if (((*caller_clones)[i])->Is_Quasi_Clone()) {
03152 Quasi_To_Real_Clone((*caller_clones)[i]);
03153 }
03154 }
03155 }
03156 }
03157 }
03158 }
03159
03160
03161 new (&pred_iter) IPA_PRED_ITER (this, clone);
03162 for (pred_iter.First(); !pred_iter.Is_Empty(); pred_iter.Next()) {
03163 IPA_EDGE* edge = pred_iter.Current_Edge();
03164 if (edge) {
03165 Rename_Call_To_Cloned_PU (Caller(edge), clone, edge, this);
03166 }
03167 }
03168
03169 }
03170
03171
03172
03173
03174 void
03175 IPA_CALL_GRAPH::Remove_Quasi_Clone (IPA_NODE* clone)
03176 {
03177
03178
03179 IPA_SUCC_ITER succ_iter (this, clone);
03180 for (succ_iter.First(); !succ_iter.Is_Empty(); succ_iter.Next()) {
03181 IPA_NODE* callee = Callee (succ_iter.Current_Edge());
03182 if (callee->Is_Quasi_Clone()) {
03183 Remove_Quasi_Clone (callee);
03184 }
03185 }
03186
03187
03188 IPA_NODE* origin = Clone_Origin (clone);
03189
03190 EDGE_INDEX* in_edges =
03191 (EDGE_INDEX*) alloca (Num_In_Edges(clone) * sizeof(EDGE_INDEX));
03192
03193 INT32 in_count = 0;
03194 IPA_PRED_ITER pred_iter (this, clone);
03195 for (pred_iter.First(); !pred_iter.Is_Empty(); pred_iter.Next()) {
03196 IPA_EDGE* edge = pred_iter.Current_Edge();
03197 Add_Edge (Caller(edge), origin, edge);
03198 in_edges[in_count++] = pred_iter.Current_Edge_Index();
03199 }
03200
03201
03202 for (INT32 i = 0; i < in_count; ++i) {
03203 _graph->Delete_Edge (in_edges[i]);
03204 }
03205
03206
03207 Union_Quasi_Clone_Cprop_Annot (origin, clone);
03208
03209
03210 (void) _graph->Delete_Node (clone->Node_Index());
03211 }
03212
03213
03214
03215
03216
03217
03218
03219
03220
03221 void
03222 IPA_CALL_GRAPH::Update_Node_After_Preopt (IPA_NODE* node,
03223 WN* opt_wn,
03224 SUMMARY_CALLSITE* callsite_array,
03225 IPL_SUMMARY_PTRS* summary_ptrs)
03226 {
03227
03228 node->Icall_List().clear();
03229 node->Ocall_List().clear();
03230
03231
03232 EDGE_INDEX* out_edges =
03233 (EDGE_INDEX*) alloca (Num_Out_Edges(node) * sizeof(EDGE_INDEX));
03234
03235 INT32 out_count = 0;
03236 IPA_SUCC_ITER succ_iter (this, node);
03237 for (succ_iter.First(); !succ_iter.Is_Empty(); succ_iter.Next()) {
03238 out_edges[out_count++] = succ_iter.Current_Edge_Index();
03239 }
03240
03241 for (INT32 i = 0; i < out_count; ++i) {
03242 _graph->Delete_Edge (out_edges[i]);
03243 }
03244
03245
03246
03247
03248 node->Clear_Visited();
03249
03250
03251 node->Set_Whirl_Tree (opt_wn);
03252 node->Set_Preoptimized();
03253 WN_Parentize (opt_wn, node->Parent_Map(), node->Map_Table());
03254
03255 SUMMARY_PROCEDURE* summary_proc = node->Summary_Proc();
03256 UINT16 callsite_count = summary_proc->Get_callsite_count();
03257 node->Set_Total_Succ (callsite_count);
03258 node->Set_PU_Size (PU_SIZE (summary_proc->Get_bb_count(),
03259 summary_proc->Get_stmt_count(),
03260 summary_proc->Get_call_count()));
03261
03262 SUMMARY_SYMBOL* symbol_array = IPA_get_symbol_array (node);
03263
03264
03265 for (UINT16 j = 0; j < callsite_count; ++j) {
03266
03267
03268 if (callsite_array[j].Is_func_ptr()) {
03269 append_icall_list (node->Icall_List(), &callsite_array[j]);
03270 }
03271 else if (!callsite_array[j].Is_intrinsic()) {
03272
03273 INT32 callee_sym_index = callsite_array[j].Get_symbol_index();
03274 ST* callee_st = ST_ptr(symbol_array[callee_sym_index].St_idx());
03275
03276
03277 while (ST_is_weak_symbol (callee_st) &&
03278 ST_st_idx (callee_st) != ST_base_idx (callee_st)) {
03279 callee_st = ST_base (callee_st);
03280 }
03281 Clear_ST_is_not_used (callee_st);
03282
03283
03284
03285
03286 NODE_INDEX callee_idx = AUX_PU_node(Aux_Pu_Table[ST_pu(callee_st)]);
03287 if (callee_idx != INVALID_NODE_INDEX) {
03288 IPA_EDGE* edge = Add_New_Edge(&callsite_array[j],
03289 node->Node_Index(),
03290 callee_idx);
03291 IPA_NODE* callee = _graph->Node_User(callee_idx);
03292 if (callee->Has_Propagated_Const()) {
03293 edge->Set_Propagated_Const();
03294 }
03295 }
03296 else {
03297 append_icall_list (node->Ocall_List(), &callsite_array[j]);
03298 }
03299 }
03300 }
03301
03302
03303
03304 if (_preopt_node_to_new_summary_map == 0) {
03305 _preopt_node_to_new_summary_map =
03306 CXX_NEW (IPA_NODE_TO_IPL_SUMMARY_MAP (32, _pool), _pool);
03307 }
03308 _preopt_node_to_new_summary_map->Enter (node, summary_ptrs);
03309
03310 }
03311
03312 #endif // _STANDALONE_INLINER
03313
03314
03315 char*
03316 IPA_Node_Name(IPA_NODE* node)
03317 {
03318 if (!node->Is_Quasi_Clone()) {
03319 return node->Name();
03320 }
03321
03322 IPA_NODE* origin = IPA_Call_Graph->Clone_Origin(node);
03323 IPA_CLONE_ARRAY* clone_array = IPA_Call_Graph->Clone_Array(origin);
03324 UINT32 clone_num;
03325 for (clone_num = 0; clone_num < clone_array->Elements(); ++clone_num) {
03326 if ((*clone_array)[clone_num] == node) {
03327 break;
03328 }
03329 }
03330
03331 size_t size = strlen(origin->Name())+15;
03332 char* name = TYPE_MEM_POOL_ALLOC_N(char, Malloc_Mem_Pool, size);
03333 sprintf(name, "%s..clone..%u", origin->Name(), clone_num);
03334
03335 return name;
03336 }
03337
03338
03339
03340
03341
03342 void
03343 IPA_CALL_GRAPH::Print (FILE* fp)
03344 {
03345 Print(fp, PREORDER);
03346 }
03347 void
03348 IPA_CALL_GRAPH::Print_vobose (FILE* fp)
03349 {
03350 Print_vobose(fp, PREORDER);
03351 }
03352 UINT32
03353 EFFECTIVE_WEIGHT (const IPA_NODE* node) {
03354 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
03355 if (IPA_Use_Effective_Size && node->Has_frequency ()) {
03356 SUMMARY_FEEDBACK *fb = node->Get_feedback ();
03357 return PU_Weight (fb->Get_effective_bb_count (),
03358 fb->Get_effective_stmt_count (),
03359 node->PU_Size().Call_Count ());
03360 } else
03361 #endif // _STANDALONE_INLINER
03362 return node->Weight ();
03363 }
03364
03365 void
03366 IPA_CALL_GRAPH::Print_vobose (FILE* fp, TRAVERSAL_ORDER order)
03367 {
03368 char YN;
03369 float hotness=-1.0;
03370 float hotness2=-1.0;
03371 float density = -1.0;
03372 vector<IPA_EDGE_INDEX> callsite_list;
03373 #ifdef KEY
03374
03375
03376 IPA_NODE_ITER cg_iter(this, order);
03377 AUX_IPA_EDGE<INT32> cost_vector (this, _pool);
03378 #else
03379 IPA_NODE_ITER cg_iter(IPA_Call_Graph, order);
03380 AUX_IPA_EDGE<INT32> cost_vector (IPA_Call_Graph, _pool);
03381 #endif
03382
03383 fprintf(fp, "Finally, Total_Prog_Size = %d\n", Total_Prog_Size);
03384 fprintf(fp, SBar);
03385 fprintf(fp, "Reason0: callee is skipped\n");
03386 fprintf(fp, "Reason1: edge is skipped\n");
03387 fprintf(fp, "Reason2: call deleted by DCE\n");
03388 fprintf(fp, "Reason3: caller is a nested procedure\n");
03389 fprintf(fp, "Reason4: callee has nested procedure(s) so ignore user MUST inline request\n");
03390 fprintf(fp, "Reason5: callee has nested procedure(s)\n");
03391 fprintf(fp, "Reason6: callee is recursive\n");
03392 fprintf(fp, "Reason7: callee is varargs\n");
03393 fprintf(fp, "Reason8: function with alternate entry point\n");
03394 fprintf(fp, "Reason9: number of parameters mismatched\n");
03395 fprintf(fp, "Reason10: callee has pragmas which are associated with formals\n");
03396 fprintf(fp, "Reason11: callee has flag that suggested that it should be MPed\n");
03397 fprintf(fp, "Reason12: callee has parallel pragmas that suggest turning off inlining\n");
03398 fprintf(fp, "Reason13: callee has VLAs and caller has parallel_pragma\n");
03399 fprintf(fp, "Reason14: callee has PDO pramgas and caller has parallel_pragma\n");
03400 fprintf(fp, "Reason15: callsite pragma requested not to inline\n");
03401 fprintf(fp, "Reason16: exception handling function\n");
03402 fprintf(fp, "Reason17: exception handling code with pstatics\n");
03403 fprintf(fp, "Reason18: depth in call graph exceeds specified maximum\n");
03404 fprintf(fp, "Reason19: user requested not to inline\n");
03405 fprintf(fp, "Reason20: function has local fstatics and is set preemptible\n");
03406 fprintf(fp, "Reason21: function is preemptible and has not been set to mustinline\n");
03407 fprintf(fp, "Reason22: incompatible return types\n");
03408 fprintf(fp, "Reason23: incompatible parameter types\n");
03409 fprintf(fp, "Reason24: not inlining across language boundaries\n");
03410 fprintf(fp, "Reason25: not inlining across language boundaries\n");
03411
03412 fprintf(fp, "Reason26: $combined_weight exceeds -IPA:plimit=%d\n", IPA_PU_Limit);
03413 fprintf(fp, "Reason27: $hotness < -IPA:min_hotness %d\n", IPA_Min_Hotness);
03414 fprintf(fp, "Reason28: $callee_weight > -IPA:callee_limit=%d\n", IPA_Small_Callee_Limit);
03415 fprintf(fp, "Reason29: $callee_weight > -INLINE:aggressive=off callee limit %d\n", IPA_PU_Minimum_Size + (IPA_PU_Minimum_Size / 2));
03416 fprintf(fp, "Reason30: small, but $combined_weight exceeds hard function size limit %d\n", IPA_PU_Hard_Limit);
03417 fprintf(fp, "Reason31: Olimit $Get_combined_olimit(caller->PU_Size(), callee->PU_Size(), callee) exceeds -OPT:Olimit= %d\n", Olimit);
03418 fprintf(fp, "Reason32: Edge is never invoked\n");
03419 fprintf(fp, "Reason33: Density is too high (infrequent called but contains hot loops) > %d\n",IPA_Max_Density);
03420 #ifdef KEY
03421 fprintf(fp, "Reason34: optimization options are different for caller and callee\n");
03422 fprintf(fp, "Reason35: Trying to do pure-call-optimization for this callsite\n");
03423 fprintf(fp, "Reason36: not inlining C++ with exceptions into non-C++\n");
03424 fprintf(fp, "Reason37: formal parameter is a loop index\n");
03425 fprintf(fp, "Reason38: not inlining nested functions\n");
03426 #endif
03427 fprintf(fp, SBar);
03428
03429 for (cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next())
03430 {
03431 IPA_NODE* node = cg_iter.Current();
03432 if (node) {
03433 IPA_NODE_CONTEXT context (node);
03434 #ifdef KEY
03435 Map_Callsites (node);
03436 #else
03437 IPA_Call_Graph->Map_Callsites (node);
03438 #endif
03439
03440 float caller_freq=-1.0;
03441 float cycle = -1.0;
03442 UINT16 wn_count = 0;
03443 if(node->Has_frequency ()) {
03444 #ifdef KEY
03445 caller_freq = (node->Get_frequency()).Value();
03446 cycle = node->Get_cycle_count_2().Value();
03447 #else
03448 caller_freq = (node->Get_frequency())._value;
03449 cycle = node->Get_cycle_count_2()._value;
03450 #endif
03451 wn_count=node->Get_wn_count();
03452 }
03453
03454 fprintf(fp, "PU %-40s Weight=%-5d Freq=%-10.1f WNs=%-7d Cc=%-15.1f\n", IPA_Node_Name(node), node->Weight(), caller_freq, wn_count, cycle);
03455
03456 BOOL seen_callee = FALSE;
03457 callsite_list.clear ();
03458 #ifdef KEY
03459 Get_Sorted_Callsite_List(node, this, cost_vector, callsite_list);
03460 #else
03461 Get_Sorted_Callsite_List(node, IPA_Call_Graph, cost_vector, callsite_list);
03462 #endif
03463 vector<IPA_EDGE_INDEX>::const_iterator last = callsite_list.end ();
03464 for(vector<IPA_EDGE_INDEX>::iterator first = callsite_list.begin (); first != last; ++first) {
03465 #ifdef KEY
03466 IPA_EDGE* tmp_edge = Edge (*first) ;
03467 #else
03468 IPA_EDGE* tmp_edge = IPA_Call_Graph->Edge (*first) ;
03469 #endif
03470 IPA_EDGE_INDEX idx = tmp_edge->Array_Index ();
03471 INT32 callsite_linenum;
03472 WN* call_wn = tmp_edge->Whirl_Node();
03473 USRCPOS callsite_srcpos;
03474
03475 if (call_wn == NULL) {
03476 callsite_linenum = 0;
03477 }else{
03478 USRCPOS_srcpos(callsite_srcpos) = WN_Get_Linenum (call_wn);
03479 callsite_linenum = USRCPOS_linenum(callsite_srcpos);
03480 }
03481
03482
03483 if (IPA_NODE* callee = Callee(tmp_edge)) {
03484 if(IPA_Enable_Inline && tmp_edge->Has_Inline_Attrib () && !callee->Has_Noinline_Attrib()) {
03485 YN= 'Y';
03486 }else{
03487 YN= 'N';
03488 }
03489
03490 SUMMARY_FEEDBACK *fb = callee->Get_feedback();
03491 INT e_bb_cnt, e_stmt_cnt;
03492 e_bb_cnt= e_stmt_cnt = (unsigned) -1;
03493
03494 if(callee->Has_frequency ()) {
03495 e_bb_cnt = (fb==NULL)? (unsigned) -1 : fb->Get_effective_bb_count ();
03496 e_stmt_cnt = (fb==NULL)? (unsigned) -1 : fb->Get_effective_stmt_count ();
03497 }
03498
03499 if (!seen_callee) {
03500 fprintf(fp, "CALLS: \n");
03501 seen_callee = TRUE;
03502 }
03503
03504 char why[50];
03505 float callee_freq,edge_freq,callee_cycle_count;
03506
03507 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
03508 INT32 cost = callee->Weight ();
03509 #else
03510 INT32 cost = EFFECTIVE_WEIGHT (callee);
03511 #endif
03512 if(callee->Has_frequency ()) {
03513 #ifdef KEY
03514 callee_freq = (callee->Get_frequency()).Value();
03515 callee_cycle_count = (callee->Get_cycle_count()).Value();
03516 #else
03517 callee_freq = (callee->Get_frequency())._value;
03518 callee_cycle_count = callee->Get_cycle_count()._value;
03519 #endif
03520 }else{
03521 callee_freq = -1.0;
03522 callee_cycle_count = -1.0;
03523 }
03524
03525 if(tmp_edge->Has_frequency()) {
03526 #ifdef KEY
03527 edge_freq = (tmp_edge->Get_frequency()).Value();
03528 #else
03529 edge_freq = (tmp_edge->Get_frequency())._value;
03530 #endif
03531 }else{
03532 edge_freq = -1.0;
03533 }
03534
03535
03536 if(tmp_edge->reason_id() > 25){
03537 sprintf(why, "%d,%f", tmp_edge->reason_id(),tmp_edge->reason_data());
03538 }else{
03539 sprintf(why, "%d", tmp_edge->reason_id());
03540 }
03541
03542 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
03543 if (tmp_edge->Has_frequency () && callee->Has_frequency () &&
03544 tmp_edge->Get_frequency().Known() && callee->Get_frequency().Known()) {
03545 hotness = compute_hotness (tmp_edge, callee, EFFECTIVE_WEIGHT(callee));
03546 FB_FREQ cycle_ratio =
03547 (tmp_edge->Get_frequency () / callee->Get_frequency () *
03548 callee->Get_cycle_count_2 ()) / Total_cycle_count_2;
03549
03550 float size_ratio = (float) (callee->Get_wn_count()) / (float) Orig_Prog_WN_Count;
03551 #ifdef KEY
03552 hotness2 = (cycle_ratio.Value() / size_ratio * 100.0);
03553 #else
03554 hotness2 = (cycle_ratio._value / size_ratio * 100.0);
03555 #endif
03556 density = (float) callee->Get_cycle_count().Value() / ((float)EFFECTIVE_WEIGHT (callee) * (float)callee->Get_frequency().Value());
03557 }else if(callee->Summary_Proc()->Is_Never_Invoked()) {
03558 hotness = -1.0;
03559 hotness2 = -1.0;
03560 density = -1.0;
03561 }
03562 #endif
03563
03564
03565 fprintf(fp, "%c %-6.1f %-6.1f %s-->%-20s(l=%-5d eid=%-5d ef=%-10.1f cf=%-10.1f ew=%-5d den=%-5.1f Cc=%-12.1f)[?%s]\n",
03566 YN,
03567 hotness,
03568 hotness2,
03569 IPA_Node_Name(node),
03570 IPA_Node_Name(callee),
03571 callsite_linenum,
03572 tmp_edge->Edge_Index(),
03573 edge_freq,
03574 callee_freq,
03575 EFFECTIVE_WEIGHT (callee),
03576 density,
03577 callee_cycle_count,
03578 why
03579 );
03580 }
03581 }
03582
03583 if (!seen_callee) {
03584 fprintf(fp, "HAS NO CALLS\n");
03585 }
03586 fprintf(fp, "\n");
03587 }
03588 }
03589 for ( cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next() ){
03590 IPA_NODE *node=cg_iter.Current();
03591 if ( node ){
03592 node->Clear_Visited();
03593 }
03594 }
03595 }
03596
03597
03598
03599
03600 void
03601 IPA_CALL_GRAPH::Print (FILE* fp, TRAVERSAL_ORDER order)
03602 {
03603 #ifdef KEY
03604 IPA_NODE_ITER cg_iter(this, order);
03605 #else
03606 IPA_NODE_ITER cg_iter(IPA_Call_Graph, order);
03607 #endif
03608 for (cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next()) {
03609
03610 IPA_NODE* node = cg_iter.Current();
03611 if (node) {
03612
03613
03614 #ifdef KEY
03615 fprintf(fp, "PU %s (freq = %.1f) \n", IPA_Node_Name(node),
03616 (node->Get_frequency()).Value());
03617 #else
03618 fprintf(fp, "PU %s (freq = %.1f) \n", IPA_Node_Name(node),
03619 (node->Get_frequency())._value);
03620 #endif
03621 BOOL seen_callee = FALSE;
03622
03623 IPA_SUCC_ITER succ_iter(node);
03624 for (succ_iter.First(); !succ_iter.Is_Empty(); succ_iter.Next()) {
03625 if (IPA_NODE* callee = Callee(succ_iter.Current_Edge())) {
03626 if (!seen_callee) {
03627 fprintf(fp, "CALLS: \n");
03628 seen_callee = TRUE;
03629 }
03630
03631
03632 #ifdef KEY
03633 fprintf(fp, " %s(%f)->%s(ef= %.1f,cf=%.1f)\n",
03634 IPA_Node_Name(node),
03635 (node->Get_frequency()).Value(),
03636 IPA_Node_Name(callee),
03637 (succ_iter.Current_Edge()->Get_frequency()).Value(),
03638 (callee->Get_frequency()).Value());
03639 #else
03640 fprintf(fp, " %s(%f)->%s(ef= %.1f,cf=%.1f)\n",
03641 IPA_Node_Name(node),
03642 (node->Get_frequency())._value,
03643 IPA_Node_Name(callee),
03644 (succ_iter.Current_Edge()->Get_frequency())._value,
03645 (callee->Get_frequency())._value);
03646 #endif
03647 }
03648 }
03649
03650 if (!seen_callee) {
03651 fprintf(fp, "HAS NO CALLS\n");
03652 }
03653 fprintf(fp, "\n");
03654 }
03655 }
03656 }
03657
03658
03659 #ifdef _LIGHTWEIGHT_INLINER
03660 void
03661 IPA_NODE::Free_inlined_list()
03662 {
03663 const INLINED_BODY_LIST& inlined_list = Inlined_list ();
03664
03665 for (INLINED_BODY_LIST::const_iterator iter = inlined_list.begin ();
03666 iter != inlined_list.end (); ++iter) {
03667 MEM_POOL_FREE(Malloc_Mem_Pool, *iter);
03668 }
03669 }
03670
03671 BOOL
03672 Is_Node_Inlinable_In_Call_Graph(ST_IDX idx)
03673 {
03674 IPA_NODE_ITER cg_iter (PREORDER, Malloc_Mem_Pool);
03675 for (cg_iter.First (); !cg_iter.Is_Empty(); cg_iter.Next ()) {
03676
03677 IPA_NODE* node = cg_iter.Current ();
03678
03679 if (node && (ST_st_idx(node->Func_ST()) == idx) && node->Has_Inline_Attrib())
03680 return TRUE;
03681 }
03682 return FALSE;
03683 }
03684
03685 BOOL
03686 Pred_Is_Root(const IPA_NODE* node)
03687 {
03688 IPA_PRED_ITER pred_iter (node->Node_Index());
03689
03690 for (pred_iter.First (); !pred_iter.Is_Empty (); pred_iter.Next ()) {
03691 IPA_EDGE *edge = pred_iter.Current_Edge ();
03692
03693 if (edge) {
03694 #if 0
03695 IPA_NODE* caller = IPA_Call_Graph->Caller (edge);
03696
03697 if (caller->Node_Index() == IPA_Call_Graph->Root())
03698 return TRUE;
03699 #endif
03700 }
03701 else
03702 return TRUE;
03703 }
03704 return FALSE;
03705 }
03706
03707 #endif // _LIGHTWEIGHT_INLINER
03708