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 #define __STDC_LIMIT_MACROS
00058 #ifdef __MINGW32__
00059 #include <WINDOWS.h>
00060 #endif
00061 #include <stdint.h>
00062 #include "defs.h"
00063 #include "tracing.h"
00064 #include "errors.h"
00065
00066 #include "ipa_option.h"
00067
00068 #include "ipa_inline.h"
00069 #include "ipa_nested_pu.h"
00070 #include "ipa_summary.h"
00071 #include "ipc_symtab_merge.h"
00072 #if 0
00073 #include "ipo_defs.h"
00074 #endif
00075
00076 #include "symtab_access.h"
00077
00078
00079 #define MINI_APPLICATION 10000
00080 #define LARGE_APPLICATION 118000 //for GAP benchmark
00081
00082 #define MINI_HOTNESS_THRESHOLD 1
00083 #define MEDIAN_HOTNESS_THRESHOLD 10
00084 #define LARGE_HOTNESS_THRESHOLD 120
00085
00086 #define TINY_SIZE 10
00087
00088 INT Total_Prog_Size = 0;
00089 INT Total_Inlined = 0;
00090 INT Total_Not_Inlined = 0;
00091 static UINT32 Max_Total_Prog_Size;
00092 static INT Real_Orig_Prog_Weight;
00093 static UINT32 non_aggr_callee_limit;
00094 static UINT32 Real_Orig_WN_Count;
00095
00096 FILE *N_inlining;
00097 FILE *Y_inlining;
00098 FILE *e_weight;
00099 FILE *Verbose_inlining;
00100
00101 #define BASETYPE TY_mtype
00102
00103 static OPCODE OPC_UNKNOWN = (OPCODE)0;
00104
00105 static
00106 OPCODE Stid_Opcode [MTYPE_LAST + 1] = {
00107 OPC_UNKNOWN,
00108 OPC_UNKNOWN,
00109 OPC_I1STID,
00110 OPC_I2STID,
00111 OPC_I4STID,
00112 OPC_I8STID,
00113 OPC_U1STID,
00114 OPC_U2STID,
00115 OPC_U4STID,
00116 OPC_U8STID,
00117 OPC_F4STID,
00118 OPC_F8STID,
00119 #ifdef TARG_IA64
00120 OPC_F10STID,
00121 OPC_F16STID,
00122 #elif TARG_X8664
00123 OPC_UNKNOWN,
00124 OPC_UNKNOWN,
00125 #endif
00126 OPC_UNKNOWN,
00127 OPC_FQSTID,
00128 OPC_UNKNOWN,
00129 OPC_C4STID,
00130 OPC_C8STID,
00131 OPC_CQSTID,
00132 OPC_UNKNOWN
00133 #ifdef KEY
00134 ,OPC_BSSTID,
00135 OPC_A4STID,
00136 OPC_A8STID,
00137 OPC_UNKNOWN,
00138 OPC_UNKNOWN,
00139 OPC_UNKNOWN,
00140 OPC_UNKNOWN
00141 #ifdef TARG_X8664
00142 ,OPC_V16C4STID,
00143 OPC_V16C8STID,
00144 OPC_V16I1STID,
00145 OPC_V16I2STID,
00146 OPC_V16I4STID,
00147 OPC_V16I8STID,
00148 OPC_V16F4STID,
00149 OPC_V16F8STID,
00150 OPC_V8I1STID,
00151 OPC_V8I2STID,
00152 OPC_V8I4STID,
00153 OPC_V8F4STID,
00154 OPC_M8I1STID,
00155 OPC_M8I2STID,
00156 OPC_M8I4STID,
00157 OPC_M8F4STID
00158 #endif // TARG_X8664
00159 #endif // KEY
00160 };
00161
00162 #ifdef TODO
00163
00164 extern IPA_FEEDBACK_STRINGS * IPA_Fbk_Strings;
00165 #endif
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 void
00183 Report_Reason (const IPA_NODE *callee, const IPA_NODE *caller,
00184 const char *reason , const IPA_EDGE *edge)
00185 {
00186 INT32 IPA_idx = 0;
00187
00188 if ( ! ( INLINE_List_Actions || Trace_IPA || Trace_Perf ) ) return;
00189
00190 char *callee_name = DEMANGLE (callee->Name());
00191
00192 if ( INLINE_List_Actions ) {
00193 fprintf ( stderr, "%s not inlined into ", callee_name );
00194 }
00195 if ( Trace_IPA || Trace_Perf ) {
00196 fprintf ( TFile, "%s not inlined into ", callee_name );
00197 }
00198
00199 char *caller_name = DEMANGLE (caller->Name());
00200 INT32 caller_index = caller->Node_Index();
00201
00202 if ( INLINE_List_Actions ) {
00203 fprintf ( stderr, "%s", caller_name );
00204 if ( IPA_Skip_Report ) {
00205 fprintf ( stderr, " (%d)", caller_index );
00206 }
00207 fprintf ( stderr, ": %s (edge# %d) \n", reason, edge->Edge_Index () );
00208 }
00209 if ( Trace_IPA || Trace_Perf ) {
00210 fprintf ( TFile, "%s", caller_name );
00211 if ( IPA_Skip_Report ) {
00212 fprintf ( TFile, " (%d)", caller_index );
00213 }
00214 fprintf ( TFile, ": %s (edge# %d) \n", reason, edge->Edge_Index () );
00215 fflush ( TFile );
00216 }
00217 if(Get_Trace ( TP_IPA, IPA_TRACE_TUNING))
00218 {
00219
00220 fprintf(N_inlining, "Report_Reason:[%s] not inlined into [%s] (edge# %d):\n", callee_name, caller_name,edge->Edge_Index () );
00221 fprintf ( N_inlining, "\t {reason: %s}\n", reason );
00222 }
00223 #ifdef TODO
00224 #ifndef _STANDALONE_INLINER
00225 if( IPA_Enable_Feedback ) {
00226
00227 IPA_idx = IPA_Fbk_Strings->Emit_id_string( callee_name);
00228 if ( IPA_idx > 0 ) {
00229 fprintf(IPA_Feedback_prg_fd,
00230 "#pragma noinline %s /* why: %s */\n", callee_name, reason );
00231 }
00232 }
00233 #endif // _STANDALONE_INLINER
00234 #endif // TODO
00235 }
00236
00237 void
00238 Report_Limit_Reason (const IPA_NODE *callee, const IPA_NODE *caller,
00239 const IPA_EDGE *edge,
00240 const char *reason, float limit1, float limit2)
00241 {
00242 INT32 IPA_idx = 0;
00243 if ( ! ( INLINE_List_Actions || Trace_IPA || Trace_Perf ) ) return;
00244
00245 char *callee_name = DEMANGLE (callee->Name());
00246
00247 if ( INLINE_List_Actions ) {
00248 fprintf ( stderr, "%s not inlined into ", callee_name );
00249 }
00250 if ( Trace_IPA || Trace_Perf ) {
00251 fprintf ( TFile, "%s not inlined into ", callee_name );
00252 }
00253 char *caller_name = DEMANGLE (caller->Name());
00254 INT32 caller_index = caller->Node_Index();
00255
00256 if ( INLINE_List_Actions ) {
00257 fprintf ( stderr, "%s", caller_name );
00258 if ( IPA_Skip_Report ) {
00259 fprintf ( stderr, " (%d): ", caller_index );
00260 } else {
00261 fprintf ( stderr, ": " );
00262 }
00263 fprintf ( stderr, reason, limit1, limit2 );
00264 fprintf ( stderr, " (edge# %d)\n" , edge->Edge_Index () );
00265 }
00266 if ( Trace_IPA || Trace_Perf ) {
00267 fprintf ( TFile, "%s", caller_name );
00268 if ( IPA_Skip_Report ) {
00269 fprintf ( TFile, " (%d): ", caller_index );
00270 } else {
00271 fprintf ( TFile, ": " );
00272 }
00273 fprintf ( TFile, reason, limit1, limit2 );
00274 fprintf ( TFile, " (edge# %d)\n", edge->Edge_Index () );
00275 fflush ( TFile );
00276 }
00277 if(Get_Trace ( TP_IPA, IPA_TRACE_TUNING))
00278 {
00279 fprintf ( N_inlining, "Report_Limit_Reason: [%s] not inlIned into [%s] (edge# %d):\n", callee_name, caller_name, edge->Edge_Index () );
00280 fprintf(N_inlining, "\t{reason: " );
00281 fprintf ( N_inlining, reason, limit1, limit2 );
00282 fprintf(N_inlining, "}\n");
00283 }
00284 #ifdef TODO
00285 #ifndef _STANDALONE_INLINER
00286 if( IPA_Enable_Feedback ) {
00287
00288 IPA_idx = IPA_Fbk_Strings->Emit_id_string( callee_name);
00289 if ( IPA_idx > 0 ) {
00290 fprintf(IPA_Feedback_prg_fd,
00291 "#pragma noinline %s /* why: ", callee_name );
00292 fprintf(IPA_Feedback_prg_fd, reason, limit1, limit2 );
00293 fprintf(IPA_Feedback_prg_fd, " */\n");
00294
00295 }
00296 }
00297 #endif // _STANDALONE_INLINER
00298 #endif // TODO
00299 }
00300
00301
00302
00303
00304
00305 UINT32
00306 Get_combined_weight (PU_SIZE s1, PU_SIZE s2, IPA_NODE *callee)
00307 {
00308 s1 += s2;
00309
00310
00311 #ifdef KEY
00312 s1.Inc_PU_Size (-1, 0, -1);
00313 #else
00314 s1.Inc_PU_Size (-1, callee->Num_Formals(), -1);
00315 #endif
00316 return s1.Weight ();
00317 }
00318
00319 UINT32
00320 Get_combined_olimit (PU_SIZE s1, PU_SIZE s2, IPA_NODE *callee)
00321 {
00322 s1 += s2;
00323
00324
00325 #ifdef KEY
00326 s1.Inc_PU_Size (-1, 0, -1);
00327 #else
00328 s1.Inc_PU_Size (-1, callee->Num_Formals(), -1);
00329 #endif
00330 return s1.Olimit ();
00331 }
00332
00333
00334
00335 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00336
00337 typedef AUX_IPA_NODE<UINT32> INLINE_COUNTER_ARRAY;
00338
00339
00340
00341 static INLINE_COUNTER_ARRAY* inline_count;
00342
00343 static inline BOOL
00344 All_Calls_Inlined (const IPA_NODE* node, const IPA_CALL_GRAPH* cg)
00345 {
00346 Is_True (IPA_Enable_DFE, ("Expecting -IPA:dfe=on"));
00347
00348 return cg->Num_In_Edges (node) == (*inline_count)[node];
00349 }
00350
00351 #endif // (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00352
00353 static void
00354 Init_inline_parameters (void)
00355 {
00356 UINT64 bloat_size;
00357 UINT64 current_size = Real_Orig_Prog_Weight =
00358 MIN (Total_Prog_Size, Orig_Prog_Weight);
00359
00360 Real_Orig_WN_Count = Orig_Prog_WN_Count;
00361
00362 #ifdef KEY
00363 if (INLINE_Ignore_Bloat && ! IPA_Bloat_Factor_Set)
00364 IPA_Bloat_Factor = UINT32_MAX;
00365 #endif // KEY
00366
00367 bloat_size = current_size * (UINT64) IPA_Bloat_Factor;
00368
00369 if (bloat_size > UINT32_MAX || IPA_Bloat_Factor == UINT32_MAX)
00370 Max_Total_Prog_Size = UINT32_MAX;
00371 else
00372 Max_Total_Prog_Size = current_size + bloat_size / 100;
00373
00374 non_aggr_callee_limit = IPA_PU_Minimum_Size + (IPA_PU_Minimum_Size / 2);
00375
00376
00377 if( IPA_Min_Hotness == 10)
00378 {
00379 if(Real_Orig_Prog_Weight< MINI_APPLICATION)
00380 {
00381 IPA_Min_Hotness = MINI_HOTNESS_THRESHOLD;
00382 }else if(Real_Orig_Prog_Weight< LARGE_APPLICATION)
00383 {
00384 IPA_Min_Hotness = MEDIAN_HOTNESS_THRESHOLD;
00385 }else
00386 {
00387 IPA_Min_Hotness = LARGE_HOTNESS_THRESHOLD;
00388 }
00389 }
00390
00391 if (Total_cycle_count.Known() && (Trace_IPA || Trace_Perf|| Get_Trace(TP_IPA, IPA_TRACE_TUNING_NEW))) {
00392 fprintf (TFile, "\tTotal number of calls = ");
00393 Total_call_freq.Print(TFile);
00394 fprintf (TFile, "\n\tTotal cycle count = ");
00395 Total_cycle_count.Print(TFile);
00396 fprintf (TFile, "\n");
00397
00398 fprintf(TFile, "Total cycle_count_2 = ");
00399 Total_cycle_count_2.Print(TFile);
00400 fprintf(TFile, "\nTotal WN_count = %d",Orig_Prog_WN_Count);
00401 fprintf (TFile, "\n");
00402
00403 fprintf(TFile, "\t Real_Orig_Prog_Weight=%d\n",Real_Orig_Prog_Weight);
00404 fprintf(TFile, "\t current_size=%lld\n",current_size);
00405 fprintf(TFile, "\t Max_Total_Prog_Size=%d\n",Max_Total_Prog_Size);
00406 }
00407
00408 if (Trace_IPA || Get_Trace(TP_IPA, IPA_TRACE_TUNING_NEW)) {
00409 fprintf(TFile, "Bloat factor = %u%% \n", IPA_Bloat_Factor);
00410 fprintf(TFile, "PU Limit = %u \n", IPA_PU_Limit);
00411 fprintf(TFile, "PU Hard Limit = %u\n", IPA_PU_Hard_Limit);
00412 fprintf(TFile, "Depth Level = %u \n", IPA_Max_Depth);
00413 if (IPA_Bloat_Factor_Set)
00414 fprintf(TFile, "Bloat Factor set = TRUE \n");
00415 else
00416 fprintf(TFile, "Bloat Factor set = FALSE \n");
00417
00418 if (IPA_PU_Limit_Set)
00419 fprintf(TFile, "PU Limit Set = TRUE \n");
00420 else
00421 fprintf(TFile, "PU Limit Set = FALSE \n");
00422
00423 fprintf(TFile, "IPA_PU_Minimum_Size = %d\n",IPA_PU_Minimum_Size );
00424 fprintf(TFile, "non_aggr_callee_limit = %d\n",non_aggr_callee_limit );
00425 fprintf(TFile, "IPA_Min_Hotness = %d\n",IPA_Min_Hotness );
00426 }
00427
00428 }
00429
00430
00431 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00432 static void
00433 Update_Total_Prog_Size (const IPA_NODE *caller, IPA_NODE *callee,
00434 const IPA_CALL_GRAPH *cg)
00435 {
00436 ++((*inline_count)[callee]);
00437
00438 if (IPA_Enable_Cloning && caller->Is_Clone_Candidate()) {
00439 callee->Set_Undeletable ();
00440 return;
00441 }
00442 if (
00443 #ifdef KEY
00444 OPT_Cyg_Instrument == 0 &&
00445 #endif
00446 ! callee->Is_Undeletable () &&
00447 ! callee->Should_Be_Skipped() &&
00448 All_Calls_Inlined (callee, cg) &&
00449 ! callee->Is_Externally_Callable ()) {
00450
00451 callee->Set_Deletable ();
00452 Total_Prog_Size -= callee->Weight();
00453 }
00454 }
00455 #endif // (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00456
00457
00458 float
00459 compute_hotness (IPA_EDGE *edge, IPA_NODE *callee, INT callee_size)
00460 {
00461 FB_FREQ cycle_ratio = (edge->Get_frequency () / callee->Get_frequency () *
00462 callee->Get_cycle_count ()) / Total_cycle_count;
00463 float cycle_ratio_float = cycle_ratio.Value();
00464 float size_ratio = (float) callee_size / (float) Real_Orig_Prog_Weight;
00465 float result_float = (cycle_ratio_float / size_ratio * 100.0);
00466 return (result_float);
00467 }
00468
00469 UINT32
00470 Effective_weight (const IPA_NODE* node) {
00471 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00472 if (IPA_Use_Effective_Size && node->Has_frequency ()) {
00473 SUMMARY_FEEDBACK *fb = node->Get_feedback ();
00474 return PU_Weight (fb->Get_effective_bb_count (),
00475 fb->Get_effective_stmt_count (),
00476 node->PU_Size().Call_Count ());
00477 } else
00478 #endif // _STANDALONE_INLINER
00479 return node->Weight ();
00480 }
00481
00482 #ifdef KEY
00483 void inline_do_it (IPA_EDGE * ed, IPA_NODE * caller, IPA_NODE * callee,
00484 const IPA_CALL_GRAPH * cg)
00485 {
00486 UINT32 caller_weight = caller->Weight();
00487 UINT32 combined_weight = Get_combined_weight (caller->PU_Size(),
00488 callee->PU_Size(),
00489 callee);
00490 if (Trace_IPA || Trace_Perf) {
00491 UINT32 callee_weight = Effective_weight (callee);
00492 fprintf (stderr, "%s inlined into %s", callee->Name(),caller->Name());
00493 fprintf (TFile, "%s inlined into ", DEMANGLE (callee->Name()));
00494 fprintf (TFile, "%s (size: %d + %d = %d) (edge# %d) \n", DEMANGLE (caller->Name()), callee_weight, caller_weight, combined_weight, ed->Edge_Index());
00495 }
00496
00497 #ifdef TODO
00498 if( IPA_Enable_Feedback ) {
00499
00500 if( callee->File_Index() != caller->File_Index()) {
00501 (callee->Get_fbk_ptr() )->Set_Cross_File_Fnd();
00502 }
00503 }
00504 #endif
00505
00506 Total_Prog_Size += (combined_weight - caller_weight);
00507 caller->UpdateSize (callee, ed);
00508
00509 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00510 if (IPA_Enable_DFE)
00511 Update_Total_Prog_Size (caller, callee, cg);
00512 #endif // _STANDALONE_INLINER
00513
00514 if (callee->Summary_Proc()->Has_var_dim_array()) {
00515 caller->Summary_Proc()->Set_has_var_dim_array();
00516 }
00517 }
00518
00519
00520
00521 static BOOL
00522 trivially_ok_to_inline (const IPA_NODE * node, const IPA_CALL_GRAPH * cg)
00523 {
00524 Is_True (node->Summary_Proc()->Get_bb_count() > 0,
00525 ("How can there be a call without any BB?"));
00526
00527
00528
00529 return node->Summary_Proc()->Get_callsite_count() == 1 &&
00530 cg->Num_Out_Edges (node) == 1 &&
00531 node->Summary_Proc()->Get_bb_count() == 1;
00532 }
00533 #endif // KEY
00534
00535 static BOOL
00536 check_size_and_freq (IPA_EDGE *ed, IPA_NODE *caller,
00537 IPA_NODE *callee, const IPA_CALL_GRAPH *cg)
00538 {
00539 BOOL inline_it = FALSE;
00540 char reason[300] = "{reason: ";
00541 char tmp_decision[300] = "";
00542 char tmp_reason[100]="";
00543 INT32 IPA_idx = 0;
00544 UINT32 caller_weight = caller->Weight ();
00545 UINT32 callee_weight = Effective_weight (callee);
00546 UINT32 combined_weight = Get_combined_weight (caller->PU_Size(), callee->PU_Size(), callee);
00547
00548 if (PU_is_operator(callee->Get_PU()) && ed->Num_Actuals() <= 2)
00549 combined_weight = 1;
00550
00551 #ifdef KEY
00552 float hotness = callee->Get_feedback() == NULL ? 0.0 :
00553 compute_hotness (ed, callee, callee_weight);
00554 #else
00555 float hotness = compute_hotness (ed, callee, callee_weight);
00556 #endif
00557
00558
00559 if(Get_Trace ( TP_IPA, IPA_TRACE_TUNING)) {
00560
00561 SUMMARY_FEEDBACK *fb = callee->Get_feedback();
00562 INT e_bb_cnt, e_stmt_cnt;
00563 e_bb_cnt= e_stmt_cnt = -1;
00564
00565 if(callee->Has_frequency ()) {
00566 e_bb_cnt = (fb==NULL)? unsigned(-1) : fb->Get_effective_bb_count ();
00567 e_stmt_cnt = (fb==NULL)? unsigned(-1) : fb->Get_effective_stmt_count ();
00568 }
00569 fprintf(e_weight, "%-8d%-8d%-8d%-8d%-8d%-8d%-8d%s \n", e_bb_cnt, e_stmt_cnt, callee->PU_Size().Call_Count (),callee_weight, callee->PU_Size().Bb_count(), callee->PU_Size().Stmt_count(),callee->Weight() , callee->Name() );
00570 }
00571
00572 if ( caller->Summary_Proc()->Is_Never_Invoked() == FALSE &&
00573 callee->Summary_Proc()->Is_Never_Invoked() == FALSE) {
00574
00575 if (callee_weight <= TINY_SIZE
00576 #ifdef KEY
00577 || (callee_weight < INLINE_Callee_Limit && PU_is_marked_inline(callee->Get_PU()))
00578 || trivially_ok_to_inline (caller, cg)
00579 #endif
00580 )
00581 {
00582 #ifdef KEY
00583
00584 inline_do_it(ed, caller, callee, cg);
00585 return TRUE;
00586 #else
00587 goto inline_do_it;
00588 #endif
00589 }
00590 }
00591
00592 if (IPA_Force_Depth_Set) {
00593 if (!callee->Has_Noinline_Attrib() && cg->Node_Depth(callee) <= IPA_Force_Depth
00594 #ifdef TODO
00595 && !ed->IsICall()
00596 #endif
00597 ) {
00598 if ( Trace_IPA || Trace_Perf ) {
00599 fprintf ( TFile, "%s inlined into ", DEMANGLE (callee->Name()) );
00600 fprintf (TFile, "%s: because of force depth = (%d)\n", DEMANGLE (caller->Name()), IPA_Force_Depth);
00601 }
00602
00603
00604 if (Get_Trace ( TP_IPA, IPA_TRACE_TUNING)) {
00605 inline_it = TRUE;
00606 sprintf ( tmp_decision, "*[%s] will be Inlined into [%s] (edge=%d)", DEMANGLE (callee->Name()),DEMANGLE (caller->Name()),ed->Edge_Index() );
00607 sprintf(tmp_reason, " because of force depth = (%d)}",IPA_Force_Depth);
00608 strcat (reason, tmp_reason);
00609 }
00610
00611 if ( INLINE_List_Actions ) {
00612 fprintf ( stderr, "%s inlined into ", DEMANGLE (callee->Name()) );
00613 fprintf ( stderr, "%s: because of force depth = (%d)\n", DEMANGLE (caller->Name()), IPA_Force_Depth );
00614 Total_Prog_Size += (combined_weight - caller_weight);
00615 caller->UpdateSize (callee, ed);
00616 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00617 if (IPA_Enable_DFE)
00618 Update_Total_Prog_Size (caller, callee, cg);
00619 #endif // _STANDALONE_INLINER
00620 }
00621 ed->Set_Must_Inline_Attrib();
00622
00623 if (callee->Summary_Proc()->Has_var_dim_array()) {
00624 caller->Summary_Proc()->Set_has_var_dim_array();
00625 }
00626 return TRUE;
00627 }
00628 }
00629
00630
00631
00632
00633 if (!ed->Has_Must_Inline_Attrib() && !callee->Has_Must_Inline_Attrib() && !INLINE_All
00634 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
00635
00636 && (!callee->Summary_Proc()->Is_must_inline())
00637 #endif
00638 ) {
00639
00640 if (Total_Prog_Size >= Max_Total_Prog_Size) {
00641 #ifndef KEY
00642 static BOOL reported = FALSE;
00643
00644 if ( ! reported ) {
00645 #endif // !KEY
00646 if ( Trace_IPA || Trace_Perf ) {
00647 fprintf ( TFile, "Inlining stopped because total " "program size limit exceeded\n" );
00648 }
00649 #ifdef KEY
00650 Report_Reason (callee, caller,
00651 "Total program size limit exceeded", ed);
00652 #else
00653 if ( INLINE_List_Actions ) {
00654 fprintf ( stderr, "Inlining stopped because total " "program size limit exceeded\n" );
00655 }
00656 reported = TRUE;
00657 }
00658 #endif
00659 return FALSE;
00660 }
00661
00662 INT loopnest = ed->Summary_Callsite ()->Get_loopnest ();
00663
00664 if (Trace_IPA) {
00665 fprintf (TFile, "\tcaller: %s (%u) loopnest = %u", DEMANGLE (caller->Name()), caller_weight, loopnest);
00666 fprintf (TFile, ", callee: %s ", DEMANGLE (callee->Name()));
00667 if (callee->PU_Size().Call_Count () == 0)
00668 fprintf (TFile, "(leaf) ");
00669 fprintf (TFile, "(%u)\n", callee_weight);
00670 }
00671
00672 if (ed->Has_frequency ()) {
00673 #ifdef KEY
00674 if(ed->Get_frequency ().Value() == 0.0f)
00675 #else
00676 if(ed->Get_frequency ()._value == 0.0f)
00677 #endif
00678 {
00679 ed->Set_reason_id(32);
00680 Report_Reason (callee, caller, "Edge is never invoked", ed);
00681 return FALSE;
00682 }
00683 }
00684
00685 if ( caller->Summary_Proc()->Is_Never_Invoked() ) {
00686 ed->Set_reason_id(32);
00687 Report_Reason (callee, caller, "Edge is never invoked", ed);
00688 return FALSE;
00689 }
00690
00691 if ( callee->Summary_Proc()->Is_Never_Invoked() ) {
00692 ed->Set_reason_id(32);
00693 Report_Reason (callee, caller, "Edge is never invoked", ed);
00694 return FALSE;
00695 }
00696
00697 if (callee_weight >= non_aggr_callee_limit &&
00698 hotness < (float)IPA_Min_Hotness &&
00699 ed->Summary_Callsite ()->Is_in_case_clause ()) {
00700 ed->Set_reason_id(34);
00701 Report_Reason (callee, caller, "Infrequent callee in switch statements", ed);
00702 return FALSE;
00703 }
00704
00705 if (callee_weight > IPA_PU_Minimum_Size) {
00706 if (combined_weight > IPA_PU_Limit) {
00707 ed->Set_reason_id(26);
00708 ed->Set_reason_data((float)combined_weight);
00709 Report_Limit_Reason (callee, caller, ed, "combined size(%f) exceeds -IPA:plimit=%f",
00710 combined_weight,IPA_PU_Limit);
00711 return FALSE;
00712 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00713 }
00714
00715 if (ed->Has_frequency () && callee->Has_frequency () && ed->Get_frequency().Known() && callee->Get_frequency ().Known()) {
00716 float min_hotness = (float)IPA_Min_Hotness;
00717
00718
00719
00720 float density = (float) callee->Get_cycle_count().Value() / ((float)callee_weight * (float)callee->Get_frequency().Value());
00721
00722
00723 if ( cg->Num_In_Edges(callee) > 1) {
00724 if(hotness < min_hotness) {
00725 ed->Set_reason_id(27);
00726 ed->Set_reason_data(hotness);
00727 Report_Limit_Reason (callee, caller, ed, "hotness (%f) < -IPA:min_hotness (%.1f)", hotness, min_hotness);
00728
00729
00730
00731 return FALSE;
00732 }
00733 if(density > IPA_Max_Density) {
00734 ed->Set_reason_id(33);
00735 ed->Set_reason_data(density);
00736
00737 Report_Limit_Reason (callee, caller, ed, "Density (%f) > Max_density (%f)", density, (float)IPA_Max_Density);
00738 return FALSE;
00739 }
00740 }else{
00741 if(hotness < (min_hotness/2)) {
00742 ed->Set_reason_id(27);
00743 ed->Set_reason_data(hotness);
00744 Report_Limit_Reason (callee, caller, ed, "hotness (%f) < -IPA:min_hotness (%.1f)", hotness, min_hotness);
00745 return FALSE;
00746 }
00747 }
00748 } else if ( callee->Summary_Proc()->Is_Never_Invoked() ) {
00749 ed->Set_reason_id(32);
00750 Report_Reason (callee, caller, "Edge is never invoked", ed);
00751 return FALSE;
00752 #endif // _STANDALONE_INLINER
00753 }else{
00754 if (callee_weight > IPA_Small_Callee_Limit && cg->Num_In_Edges(callee) > 1) {
00755
00756
00757
00758 if (loopnest == 0 || callee->PU_Size().Call_Count () > 0) {
00759 ed->Set_reason_id(28);
00760 ed->Set_reason_data((float)callee_weight);
00761 Report_Limit_Reason (callee, caller, ed, "callee size" " (%f) > -IPA:callee_limit=%f", callee_weight, IPA_Small_Callee_Limit );
00762 return FALSE;
00763 }
00764 }
00765
00766 if (!INLINE_Aggressive && loopnest == 0 && callee->PU_Size().Call_Count() > 0 && callee_weight > non_aggr_callee_limit) {
00767
00768
00769
00770 ed->Set_reason_id(29);
00771 ed->Set_reason_data((float)callee_weight);
00772 Report_Limit_Reason (callee, caller, ed, "callee_size (%.1f) > -INLINE:aggressive=off callee limit (%.1f)", callee_weight, non_aggr_callee_limit );
00773 return FALSE;
00774 }
00775 }
00776 } else {
00777 if (combined_weight > IPA_PU_Hard_Limit) {
00778 ed->Set_reason_id(30);
00779 ed->Set_reason_data((float)combined_weight);
00780 Report_Limit_Reason ( callee, caller, ed, "small, but size (%f) " "exceeds hard function size limit (%f)", combined_weight, IPA_PU_Hard_Limit );
00781 return FALSE;
00782 } else {
00783
00784
00785 #ifdef TODO
00786 if (ed->IsICall () && (IPA_Enable_Cloning && callee->Is_Clone_Candidate()))
00787
00788
00789 callee->Clear_Clone_Candidate ();
00790 #endif
00791
00792 if ( Trace_IPA || Trace_Perf ) {
00793 fprintf ( TFile, "%s inlined into ", DEMANGLE (callee->Name()) );
00794 fprintf (TFile, "%s: forced because of small size (%d) (edge# %d)\n", DEMANGLE (caller->Name()), callee_weight, ed->Edge_Index() );
00795 }
00796
00797
00798 if (Get_Trace ( TP_IPA, IPA_TRACE_TUNING)) {
00799 inline_it = TRUE;
00800 sprintf ( tmp_decision, "*[%s] will be Inlined into [%s] (edge=%d): ", DEMANGLE (callee->Name()) ,DEMANGLE (caller->Name()),ed->Edge_Index() );
00801 sprintf(tmp_reason, " forced because of small size (%d) ",callee_weight);
00802 strcat (reason, tmp_reason);
00803 }
00804
00805 if ( INLINE_List_Actions ) {
00806 fprintf ( stderr, "%s inlined into ", DEMANGLE (callee->Name()) );
00807 fprintf ( stderr, "%s: forced because of small size (%d) (edge# %d)\n", DEMANGLE (caller->Name()), callee_weight, ed->Edge_Index() );
00808 }
00809 }
00810 }
00811
00812 if (Get_combined_olimit (caller->PU_Size(), callee->PU_Size(), callee) > Olimit) {
00813 ed->Set_reason_id(31);
00814 ed->Set_reason_data((float)Get_combined_olimit (caller->PU_Size(), callee->PU_Size(), callee));
00815 Report_Limit_Reason (callee, caller, ed, "Olimit (%f) exceeds -OPT:Olimit=%f", Get_combined_olimit (caller->PU_Size(), callee->PU_Size(), callee), Olimit );
00816 return FALSE;
00817 }
00818
00819 #ifdef KEY
00820 if (IPA_Enable_Branch_Heuristic)
00821 {
00822
00823 if (getenv ("branch"))
00824 IPA_Min_Branch_Prob = atof (getenv("branch"));
00825 float branch_p = ed->Summary_Callsite()->Get_probability();
00826 if (branch_p >= 0 && branch_p < IPA_Min_Branch_Prob)
00827 {
00828 fprintf (stderr, "%s not inlined into %s because branch probability %f < minimum probability %f\n", callee->Name(), caller->Name(), branch_p, IPA_Min_Branch_Prob);
00829 return FALSE;
00830 }
00831 }
00832 #endif
00833 }
00834
00835 #ifdef TODO
00836 if (ed->IsICall () && (IPA_Enable_Cloning && callee->Is_Clone_Candidate())) {
00837
00838 Report_Reason (callee, caller, "cannot inline indirect call to cloned PU", ed);
00839 return FALSE;
00840 }
00841 #endif
00842
00843
00844 #ifdef KEY
00845 inline_do_it (ed, caller, callee, cg);
00846 #else
00847 inline_do_it: if (Trace_IPA || Trace_Perf) {
00848 fprintf (stderr, "%s inlined into %s", callee->Name(),caller->Name());
00849 fprintf (TFile, "%s inlined into ", DEMANGLE (callee->Name()));
00850 fprintf (TFile, "%s (size: %d + %d = %d) (edge# %d) \n", DEMANGLE (caller->Name()), callee_weight, caller_weight, combined_weight, ed->Edge_Index());
00851 }
00852
00853
00854 if(Get_Trace ( TP_IPA, IPA_TRACE_TUNING)) {
00855 if (inline_it==FALSE)
00856 sprintf (tmp_decision, "*[%s] will be Inlined into [%s] (edge=%d)", DEMANGLE (callee->Name()), DEMANGLE (caller->Name()),ed->Edge_Index() );
00857 sprintf(tmp_reason, " and the limits donot filter it out},(size: %d + %d = %d) ",callee_weight, caller_weight, combined_weight );
00858 strcat (reason, tmp_reason);
00859 strcat (reason, "\n");
00860 fprintf(Y_inlining, tmp_decision);
00861 fprintf(Y_inlining, reason);
00862 }
00863
00864 #ifdef TODO
00865 if( IPA_Enable_Feedback ) {
00866
00867 if( callee->File_Index() != caller->File_Index()) {
00868 (callee->Get_fbk_ptr() )->Set_Cross_File_Fnd();
00869 }
00870 }
00871 #endif
00872
00873 Total_Prog_Size += (combined_weight - caller_weight);
00874 caller->UpdateSize (callee, ed);
00875
00876 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
00877 if (IPA_Enable_DFE)
00878 Update_Total_Prog_Size (caller, callee, cg);
00879 #endif // _STANDALONE_INLINER
00880
00881 if (callee->Summary_Proc()->Has_var_dim_array()) {
00882 caller->Summary_Proc()->Set_has_var_dim_array();
00883 }
00884 #endif // KEY
00885 return TRUE;
00886 }
00887
00888
00889
00890
00891 static BOOL
00892 return_types_are_compatible (IPA_NODE* callee_node, IPA_EDGE *ed)
00893 {
00894 if (ed->Summary_Callsite()->Get_return_type() == MTYPE_V)
00895 return TRUE;
00896
00897 ST* callee = callee_node->Func_ST();
00898
00899 Is_True (ST_sym_class (callee) == CLASS_FUNC,
00900 ("Expecting a function ST"));
00901
00902 TY_IDX ty_idx = ST_pu_type (callee);
00903 TY& ty = Ty_Table[ty_idx];
00904
00905 Is_True (TY_kind (ty) == KIND_FUNCTION, ("Expecting a function ST")
00906 );
00907
00908 TY_IDX ret_ty_idx = TYLIST_type (Tylist_Table[TY_tylist (ty)]);
00909
00910 if (ret_ty_idx == 0)
00911 return FALSE;
00912
00913 TY& ret_ty = Ty_Table[ret_ty_idx];
00914
00915 if (TY_kind (ret_ty) == KIND_VOID)
00916 return FALSE;
00917 else {
00918 TYPE_ID callee_mtype = BASETYPE(ret_ty);
00919 TYPE_ID caller_mtype = ed->Summary_Callsite()->Get_return_type();
00920
00921
00922
00923
00924 if ((callee_mtype == caller_mtype) || (callee_mtype == MTYPE_M)
00925 )
00926 return TRUE;
00927 }
00928
00929 return FALSE;
00930 }
00931
00932 static TY_IDX
00933 base_type_of_array(TY_IDX array_type)
00934 {
00935 if (TY_kind(TY_AR_etype(array_type)) != KIND_ARRAY)
00936 return (TY_AR_etype(array_type));
00937 else
00938 return (base_type_of_array(TY_AR_etype(array_type)));
00939 }
00940
00941
00942
00943
00944
00945 static BOOL
00946 types_are_compatible (TY_IDX ty_actual, TY_IDX ty_formal, BOOL lang)
00947 {
00948
00949
00950
00951
00952
00953 TYPE_ID formal_element_size, actual_element_size;
00954
00955 if ((ty_actual == 0) || (ty_formal == 0))
00956 return FALSE;
00957
00958 if (lang) {
00959 BOOL formal_is_array, actual_is_array;
00960
00961 if (TY_kind(ty_formal) == KIND_POINTER) {
00962 ty_formal = TY_pointed(ty_formal);
00963 formal_is_array = (TY_kind(ty_formal) == KIND_ARRAY);
00964 }
00965 else
00966 formal_is_array = (TY_kind(ty_formal) == KIND_ARRAY);
00967
00968 if (TY_kind(ty_actual) == KIND_POINTER) {
00969 ty_actual = TY_pointed(ty_actual);
00970 actual_is_array = (TY_kind(ty_actual) == KIND_ARRAY);
00971 }
00972 else
00973 actual_is_array = (TY_kind(ty_actual) == KIND_ARRAY);
00974
00975 #ifdef KEY
00976 UINT64 formal_type_size, actual_type_size;
00977
00978 if (INLINE_Check_Compatibility == RELAXED_CHECK)
00979 {
00980 formal_type_size = TY_size (ty_formal);
00981 actual_type_size = TY_size (ty_actual);
00982
00983 if (!actual_is_array && formal_is_array &&
00984 (!formal_type_size ||
00985 actual_type_size == formal_type_size))
00986 {
00987
00988 TY_IDX formal = base_type_of_array (ty_formal);
00989 TYPE_ID actual_type = BASETYPE (ty_actual);
00990 TYPE_ID formal_type = BASETYPE (formal);
00991 if (
00992 #if defined(TARG_IA64)
00993 (actual_type == MTYPE_C10 && formal_type == MTYPE_F10) ||
00994 #endif
00995 (actual_type == MTYPE_C8 && formal_type == MTYPE_F8) ||
00996 (actual_type == MTYPE_C4 && formal_type == MTYPE_F4))
00997 return TRUE;
00998
00999
01000
01001 if (
01002 #if defined(TARG_IA64)
01003 (actual_type == MTYPE_C10 && formal_type == MTYPE_C10) ||
01004 #endif
01005 (actual_type == MTYPE_C8 && formal_type == MTYPE_C8) ||
01006 (actual_type == MTYPE_C4 && formal_type == MTYPE_C4))
01007 return TRUE;
01008 }
01009 }
01010 #endif // KEY
01011
01012
01013
01014
01015 if ((!actual_is_array && formal_is_array))
01016 return FALSE;
01017
01018 if (actual_is_array) {
01019 ty_actual = base_type_of_array(ty_actual);
01020 actual_element_size = BASETYPE(ty_actual);
01021 }
01022 else
01023 actual_element_size = BASETYPE(ty_actual);
01024
01025 if (formal_is_array) {
01026 ty_formal = base_type_of_array(ty_formal);
01027 formal_element_size = BASETYPE(ty_formal);
01028 }
01029 else
01030 formal_element_size = BASETYPE(ty_formal);
01031
01032 if (formal_element_size == actual_element_size)
01033 return TRUE;
01034
01035 #ifdef KEY
01036 if (INLINE_Check_Compatibility == RELAXED_CHECK)
01037 {
01038 if (actual_is_array && formal_is_array &&
01039 (
01040 #if defined(TARG_IA64)
01041 (actual_element_size==MTYPE_C10 &&
01042 formal_element_size==MTYPE_F10) ||
01043 #endif
01044 (actual_element_size==MTYPE_C8 &&
01045 formal_element_size==MTYPE_F8) ||
01046 (actual_element_size==MTYPE_C4 &&
01047 formal_element_size==MTYPE_F4)))
01048 {
01049 if (!formal_type_size || !actual_type_size ||
01050 formal_type_size == actual_type_size)
01051 return TRUE;
01052 }
01053
01054 if (actual_is_array && formal_is_array &&
01055 (
01056 #if defined(TARG_IA64)
01057 (actual_element_size==MTYPE_F10 &&
01058 formal_element_size==MTYPE_C10) ||
01059 #endif
01060 (actual_element_size==MTYPE_F8 &&
01061 formal_element_size==MTYPE_C8) ||
01062 (actual_element_size==MTYPE_F4 &&
01063 formal_element_size==MTYPE_C4)))
01064 {
01065 if (!formal_type_size || !actual_type_size ||
01066 formal_type_size == actual_type_size)
01067 return TRUE;
01068 }
01069 }
01070 #endif // KEY
01071
01072 #if 0
01073 else
01074 return FALSE;
01075 #endif
01076 }
01077 #if 0
01078 else {
01079 #endif
01080
01081 TYPE_ID desc = BASETYPE(ty_formal);
01082 if ((desc == 0) && (TY_kind (ty_formal) == KIND_FUNCTION)) {
01083 TY_IDX ret_ty_idx = TYLIST_type (Tylist_Table[TY_tylist (ty_formal)]);
01084
01085 if (ret_ty_idx == 0)
01086 return FALSE;
01087 else
01088 desc = BASETYPE(ret_ty_idx);
01089 }
01090
01091 if (desc == 0)
01092 return FALSE;
01093
01094 OPCODE stid = Stid_Opcode[desc];
01095
01096 if (desc == MTYPE_M)
01097
01098 return (TY_size(ty_formal) == TY_size(ty_actual));
01099
01100 if (stid == OPC_UNKNOWN)
01101 return FALSE;
01102
01103 TYPE_ID rtype = BASETYPE(ty_actual);
01104 TYPE_ID ltype = OPCODE_desc(stid);
01105 #ifdef KEY
01106 if (INLINE_Type_Mismatch || IPO_Types_Are_Compatible(ltype, rtype))
01107 #else
01108 if (IPO_Types_Are_Compatible(ltype, rtype))
01109 #endif
01110 return TRUE;
01111 #if 0
01112 }
01113 #endif
01114
01115 return FALSE;
01116 }
01117
01118
01119
01120
01121 static BOOL
01122 param_types_are_compatible (IPA_NODE* caller_node, IPA_NODE* callee_node, IPA_EDGE *ed)
01123 {
01124 #ifdef KEY
01125
01126
01127 INT num_formals = ed->Num_Actuals() < callee_node->Num_Formals() ?
01128 ed->Num_Actuals() : callee_node->Num_Formals();
01129 #else
01130 INT num_formals = callee_node->Num_Formals();
01131 #endif
01132
01133 if (!num_formals)
01134 return TRUE;
01135
01136 SUMMARY_FORMAL* callee_formal = IPA_get_formal_array(callee_node);
01137 SUMMARY_ACTUAL* call_actual = IPA_get_actual_array(caller_node);
01138 SUMMARY_SYMBOL* caller_symbols = IPA_get_symbol_array(caller_node);
01139 SUMMARY_SYMBOL* callee_symbols = IPA_get_symbol_array(callee_node);
01140
01141 SUMMARY_ACTUAL *actuals = &call_actual[ed->Summary_Callsite()->Get_actual_index()];
01142 SUMMARY_FORMAL *formals = &callee_formal[callee_node->Summary_Proc()->Get_formal_index()];
01143
01144 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
01145 const IPC_GLOBAL_IDX_MAP* callee_idx_maps = IP_FILE_HDR_idx_maps(callee_node->File_Header());
01146 const IPC_GLOBAL_IDX_MAP* caller_idx_maps = IP_FILE_HDR_idx_maps(caller_node->File_Header());
01147 Is_True(callee_idx_maps && caller_idx_maps, ("idx_maps for caller and callee are not set up\n"));
01148 #endif // _STANDALONE_INLINER
01149
01150 BOOL lang = ((callee_node->Summary_Proc()->Get_lang() == LANG_F77) ||
01151 (callee_node->Summary_Proc()->Get_lang() == LANG_F90));
01152
01153 #if 0
01154 IPA_NODE_CONTEXT context(callee_node);
01155 #endif
01156
01157 for (INT i=0; i<num_formals; ++i) {
01158 TY_IDX ty_formal = formals[i].Get_ty();
01159 TY_IDX ty_actual = actuals[i].Get_ty();
01160
01161 if (!IPA_Enable_Inline_Char_Array) {
01162 if (((TY_kind(ty_formal) == KIND_SCALAR) &&
01163 (formals[i].Is_ref_parm() || lang)) &&
01164 actuals[i].Is_value_parm())
01165 return FALSE;
01166
01167 }
01168
01169 if (!IPA_Enable_Inline_Var_Dim_Array && formals[i].Is_var_dim_array())
01170 return FALSE;
01171
01172
01173
01174
01175 if (formals[i].Is_ref_parm() && (TY_kind(ty_formal) == KIND_STRUCT)) {
01176 if (!IPA_Enable_Inline_Struct)
01177 return FALSE;
01178 else {
01179 if (TY_kind(ty_actual) == KIND_POINTER) {
01180 if (TY_kind(TY_pointed(ty_actual)) == KIND_ARRAY)
01181 if (!IPA_Enable_Inline_Struct_Array_Actual)
01182 return FALSE;
01183 }
01184 else {
01185 if (TY_kind(ty_actual) == KIND_ARRAY)
01186 if (!IPA_Enable_Inline_Struct_Array_Actual)
01187 return FALSE;
01188 }
01189 }
01190 }
01191
01192 SUMMARY_SYMBOL* s = callee_symbols + formals[i].Get_symbol_index();
01193
01194 if (actuals[i].Get_symbol_index () >= 0) {
01195 SUMMARY_SYMBOL* caller_sym =
01196 caller_symbols + actuals[i].Get_symbol_index ();
01197
01198 if (s->Is_addr_f90_target () != caller_sym->Is_addr_f90_target ())
01199 return FALSE;
01200 } else if (s->Is_addr_f90_target ())
01201 return FALSE;
01202
01203 if (IPA_Enable_Inline_Optional_Arg && s->Is_optional() &&
01204 (ty_actual == 0))
01205 continue;
01206
01207 if (!types_are_compatible(ty_actual, ty_formal, lang))
01208 return FALSE;
01209 }
01210 return TRUE;
01211 }
01212
01213 void
01214 IPA_NODE::UpdateSize (IPA_NODE *callee, IPA_EDGE *ed)
01215 {
01216 _pu_size += callee->PU_Size();
01217 #ifdef KEY
01218 _pu_size.Inc_PU_Size (-1, 0, -1);
01219 #else
01220 _pu_size.Inc_PU_Size (-1, callee->Num_Formals(), -1);
01221 #endif
01222
01223 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
01224 if (IPA_Use_Effective_Size && Has_frequency() &&
01225 callee->Has_frequency () && ed->Summary_Callsite()->Get_frequency_count().Known()) {
01226 SUMMARY_FEEDBACK *fb = Get_feedback ();
01227 SUMMARY_FEEDBACK *callee_fb = callee->Get_feedback ();
01228 fb->Inc_effective_bb_count (callee_fb->Get_effective_bb_count () - 1);
01229 fb->Inc_effective_stmt_count (callee_fb->Get_effective_stmt_count () +
01230 callee->Num_Formals());
01231 fb->Inc_cycle_count ((ed->Get_frequency () / callee->Get_frequency ()) * callee_fb->Get_cycle_count ());
01232 }
01233 #endif // _STANDALONE_INLINER
01234
01235 }
01236
01237
01238
01239
01240
01241
01242
01243 void
01244 Update_Call_Graph (IPA_NODE *n)
01245 {
01246
01247
01248 PU_SIZE size = n->PU_Size ();
01249 size.Inc_PU_Size (-1, 0, -1);
01250 n->Set_PU_Size (size);
01251
01252 size.Set_PU_Size (1, 0, 1);
01253 Total_Prog_Size -= size.Weight ();
01254
01255 n->Summary_Proc()->Decr_call_count ();
01256 n->Summary_Proc()->Decr_callsite_count ();
01257
01258
01259 }
01260
01261
01262
01263
01264
01265
01266 static BOOL
01267 no_inline_pu_with_nested_pus(IPA_NODE* caller, IPA_GRAPH* cg)
01268 {
01269 const PU_Info* pu = caller->PU_Info ();
01270 if (pu == NULL)
01271 return TRUE;
01272 for (pu = PU_Info_child (pu); pu; pu = PU_Info_next (pu)) {
01273
01274 const AUX_PU& aux_pu =
01275 Aux_Pu_Table [ST_pu (St_Table [PU_Info_proc_sym (pu)])];
01276 const IPA_NODE* child = cg->Node_User (AUX_PU_node (aux_pu));
01277 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
01278 if (child && (!(child->Has_Inline_Attrib() ||
01279 child->Has_Must_Inline_Attrib())))
01280 #else
01281 if (child && !child->Is_Deletable ())
01282 #endif
01283 return TRUE;
01284 }
01285 return FALSE;
01286 }
01287
01288 #ifdef KEY
01289 #include "ir_bread.h"
01290 #include "sys/elf_whirl.h"
01291
01292 static void
01293 get_command_options (IPA_NODE * node, vector<char *> &v)
01294 {
01295 PU_IDX pu = ST_pu (node->Func_ST ());
01296 const IP_FILE_HDR& hdr = *AUX_PU_file_hdr (Aux_Pu_Table [pu]);
01297
01298 char * base_addr = (char *)
01299 WN_get_section_base (IP_FILE_HDR_input_map_addr (hdr), WT_COMP_FLAGS);
01300 if (base_addr == (char *) -1)
01301 ErrMsg (EC_IR_Scn_Read, "command line", IP_FILE_HDR_file_name (hdr));
01302
01303 Elf64_Word argc = *((Elf64_Word *) base_addr);
01304 Elf64_Word * args = (Elf64_Word *) (base_addr + sizeof (Elf64_Word));
01305
01306 v.reserve (sizeof (char *) * (argc - 1));
01307 for (INT i=1; i<argc; ++i)
01308 v.push_back (base_addr + args[i]);
01309 }
01310
01311 static BOOL
01312 different_options (IPA_NODE * caller, IPA_NODE * callee)
01313 {
01314 vector<char *> caller_opt;
01315 get_command_options (caller, caller_opt);
01316
01317 vector<char *> callee_opt;
01318 get_command_options (callee, callee_opt);
01319
01320 if (caller_opt.size() != callee_opt.size())
01321 return TRUE;
01322
01323 sort (caller_opt.begin(), caller_opt.end(), option_cmp());
01324 sort (callee_opt.begin(), callee_opt.end(), option_cmp());
01325
01326 UINT size = caller_opt.size();
01327
01328 for (UINT i=0; i<size; ++i)
01329 if (strcmp (caller_opt[i], callee_opt[i]))
01330 return TRUE;
01331
01332 return FALSE;
01333 }
01334
01335 #if !defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER)
01336
01337 static bool check_node (IPA_NODE * node)
01338 {
01339 WN * func = node->Whirl_Tree(FALSE);
01340 Is_True (WN_operator(func) == OPR_FUNC_ENTRY, ("Unexpected WN node"));
01341
01342 WN * body = WN_func_body (func);
01343 WN * first = WN_first (body);
01344 Is_True (first, ("No code in function body"));
01345
01346 WN * last = WN_last (body);
01347
01348 if (WN_operator (first) == OPR_PRAGMA)
01349 first = WN_next (first);
01350 Is_True (first, ("No code in function body"));
01351
01352 Is_True (WN_operator (first) != OPR_PRAGMA, ("Unexpected pragma"));
01353
01354
01355 if (first == last && WN_operator (first) == OPR_RETURN_VAL)
01356 return FALSE;
01357
01358
01359 if (WN_operator (last) == OPR_RETURN)
01360 return FALSE;
01361
01362
01363 for (; first != last; first = WN_next (first))
01364 {
01365 if (OPERATOR_is_scf (WN_operator (first)) ||
01366 OPERATOR_is_non_scf (WN_operator (first)))
01367 return TRUE;
01368 }
01369
01370 return FALSE;
01371 }
01372
01373
01374
01375
01376
01377
01378 static BOOL
01379 formal_is_loop_index (IPA_NODE * caller_node, IPA_NODE * callee_node, IPA_EDGE * ed)
01380 {
01381
01382
01383 INT num_formals = ed->Num_Actuals() < callee_node->Num_Formals() ?
01384 ed->Num_Actuals() : callee_node->Num_Formals();
01385
01386 if (!num_formals)
01387 return FALSE;
01388
01389 BOOL lang = ((callee_node->Summary_Proc()->Get_lang() == LANG_F77) ||
01390 (callee_node->Summary_Proc()->Get_lang() == LANG_F90));
01391
01392 if (!lang)
01393 return FALSE;
01394
01395 SUMMARY_FORMAL* callee_formal = IPA_get_formal_array(callee_node);
01396 SUMMARY_ACTUAL* call_actual = IPA_get_actual_array(caller_node);
01397
01398 SUMMARY_ACTUAL *actuals = &call_actual[ed->Summary_Callsite()->Get_actual_index()];
01399 SUMMARY_FORMAL *formals = &callee_formal[callee_node->Summary_Proc()->Get_formal_index()];
01400
01401 for (INT i=0; i<num_formals; ++i) {
01402 if (formals[i].Is_loop_index() && actuals[i].Get_pass_type() == PASS_ARRAY)
01403 return TRUE;
01404 }
01405 return FALSE;
01406 }
01407 #endif // ! _STANDALONE_INLINER && ! _LIGHTWEIGHT_INLINER
01408 #endif // KEY
01409
01410
01411
01412
01413 static BOOL
01414 do_inline (IPA_EDGE *ed, IPA_NODE *caller,
01415 IPA_NODE *callee, const IPA_CALL_GRAPH *cg)
01416 {
01417 BOOL result = TRUE;
01418 const char *reason = 0;
01419
01420 #ifdef KEY
01421 if (cg->Graph()->Is_Recursive_Edge (ed->Edge_Index ())) {
01422 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
01423 if (caller == callee)
01424 {
01425
01426 caller->Set_Undeletable ();
01427 caller->Set_Recursive ();
01428 }
01429 BOOL set_recursive_in_edge = TRUE;
01430 if (ed->Has_frequency () && callee->Has_frequency () &&
01431 ed->Get_frequency().Known() && callee->Get_frequency ().Known()) {
01432 if (compute_hotness (ed, callee, Effective_weight (callee))
01433 < IPA_Min_Hotness)
01434 set_recursive_in_edge = FALSE;
01435 }
01436
01437 if (set_recursive_in_edge)
01438 #endif // _STANDALONE_INLINER
01439 callee->Set_Recursive_In_Edge();
01440 }
01441 #endif
01442 #if 0
01443
01444
01445
01446 if ((IPA_Enable_GP_Partition ||
01447 (IPA_Enable_SP_Partition && (IPA_Space_Access_Mode == SAVE_SPACE_MODE))) &&
01448 ((caller->Get_partition_group() == COMMON_PARTITION) ||
01449 (callee->Get_partition_group() != COMMON_PARTITION)) &&
01450 (caller->Get_partition_group() != callee->Get_partition_group()))
01451 return FALSE;
01452 #endif
01453
01454
01455
01456 if (callee->Should_Be_Skipped()) {
01457 reason = "callee is skipped";
01458 ed->Set_reason_id (0);
01459 result = FALSE;
01460 }
01461 else if (ed->Has_Noinline_Attrib()) {
01462 reason = "edge is skipped";
01463 ed->Set_reason_id (1);
01464 result = FALSE;
01465 }
01466 else if (IPA_Enable_DCE && ed->Is_Deletable ()) {
01467
01468 reason = "call deleted by DCE";
01469 ed->Set_reason_id (2);
01470 result = FALSE;
01471 }
01472 else if (!IPA_Enable_Inline_Nested_PU && caller->Is_Nested_PU ()) {
01473
01474 result = FALSE;
01475 reason = "caller is a nested procedure";
01476 ed->Set_reason_id (3);
01477 } else if ( PU_uplevel (callee->Get_PU ()) &&
01478 ((!IPA_Enable_Inline_Nested_PU) ||
01479 no_inline_pu_with_nested_pus(callee, cg->Graph ()))) {
01480 if (callee->Has_Must_Inline_Attrib()) {
01481 callee->Clear_Must_Inline_Attrib ();
01482 reason = "callee has nested procedure(s) so ignore user MUST inline request";
01483 ed->Set_reason_id (4);
01484 }
01485 else
01486 reason = "callee has nested procedure(s)";
01487 ed->Set_reason_id (5);
01488 callee->Set_Noinline_Attrib ();
01489 result = FALSE;
01490 #ifdef KEY
01491
01492 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
01493 } else if (cg->Graph()->Is_Recursive_Edge (ed->Edge_Index ()) &&
01494 (caller != callee || !INLINE_Recursive)) {
01495 #else
01496 } else if (cg->Graph()->Is_Recursive_Edge (ed->Edge_Index ())) {
01497 #endif
01498 #else // for KEY
01499 } else if (cg->Graph()->Is_Recursive_Edge (ed->Edge_Index ())) {
01500 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
01501 BOOL set_recursive_in_edge = TRUE;
01502 if (ed->Has_frequency () && callee->Has_frequency () &&
01503 ed->Get_frequency().Known() && callee->Get_frequency ().Known()) {
01504 if (compute_hotness (ed, callee, Effective_weight (callee))
01505 < IPA_Min_Hotness)
01506 set_recursive_in_edge = FALSE;
01507 }
01508
01509 if (set_recursive_in_edge)
01510 #endif // _STANDALONE_INLINER
01511 callee->Set_Recursive_In_Edge ();
01512 #endif // KEY
01513 result = FALSE;
01514 reason = "callee is recursive";
01515 ed->Set_reason_id (6);
01516 } else if (callee->Has_Varargs()) {
01517 result = FALSE;
01518 reason = "callee is varargs";
01519 ed->Set_reason_id (7);
01520 } else if (callee->Summary_Proc()->Is_alt_entry() ||
01521 callee->Summary_Proc()->Has_alt_entry() ||
01522 caller->Summary_Proc()->Is_alt_entry()) {
01523 result = FALSE;
01524 reason = "function with alternate entry point";
01525 ed->Set_reason_id (8);
01526 }
01527 #ifdef KEY
01528 else if (!INLINE_Param_Mismatch
01529 && ed->Num_Actuals() < callee->Num_Formals())
01530 #else
01531 else if (ed->Num_Actuals() < callee->Num_Formals())
01532 #endif
01533 {
01534 result = FALSE;
01535 reason = "number of parameters mismatched";
01536 ed->Set_reason_id (9);
01537 } else if (callee->Summary_Proc()->Has_formal_pragma()) {
01538 result = FALSE;
01539 reason = "callee has pragmas which are associated with formals";
01540 ed->Set_reason_id (10);
01541 } else if (callee->Summary_Proc()->Has_mp_needs_lno()) {
01542 result = FALSE;
01543 reason = "callee has flag that suggested that it should be MP'ed";
01544 ed->Set_reason_id (11);
01545 } else if (callee->Summary_Proc()->Has_noinline_parallel_pragma()) {
01546 result = FALSE;
01547 reason = "callee has parallel pragmas that suggest turning off inlining";
01548 ed->Set_reason_id (12);
01549 } else if ((caller->Summary_Proc()->Has_parallel_pragma() ||
01550 caller->Summary_Proc()->Has_parallel_region_pragma()) &&
01551 callee->Summary_Proc()->Has_var_dim_array()) {
01552 result = FALSE;
01553 reason = "callee has VLAs and caller has parallel_pragma";
01554 ed->Set_reason_id (13);
01555 } else if (caller->Summary_Proc()->Has_parallel_region_pragma() &&
01556 callee->Summary_Proc()->Has_pdo_pragma()) {
01557 result = FALSE;
01558 reason = "callee has PDO pramgas and caller has parallel_pragma";
01559 ed->Set_reason_id (14);
01560 } else if (ed->Summary_Callsite()->Is_no_inline()) {
01561
01562 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
01563
01564
01565 if ( !ed->Has_Must_Inline_Attrib() && !callee->Has_Must_Inline_Attrib()) {
01566 #endif // _STANDALONE_INLINER
01567
01568 result = FALSE;
01569 reason = "callsite pragma requested not to inline";
01570 ed->Set_reason_id (15);
01571 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
01572 }
01573 #endif // _STANDALONE_INLINER
01574
01575 } else if (ed->Summary_Callsite()->Is_must_inline() &&
01576 !callee->Has_Noinline_Attrib()) {
01577
01578
01579
01580 ed->Set_Must_Inline_Attrib();
01581
01582 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
01583 } else if (callee->Summary_Proc()->Is_exc_inline() && !INLINE_Exceptions) {
01584 #else // _STANDALONE_INLINER
01585 } else if (callee->Summary_Proc()->Is_exc_inline() && !IPA_Enable_Exc) {
01586 #endif // _STANDALONE_INLINER
01587 result = FALSE;
01588 reason = "exception handling function";
01589 ed->Set_reason_id (16);
01590 } else if (callee->Summary_Proc()->Is_exc_inline() &&
01591 callee->Summary_Proc()->Has_pstatic()) {
01592 result = FALSE;
01593 reason = "exception handling code with pstatics";
01594 ed->Set_reason_id (17);
01595 } else if ((UINT) cg->Node_Depth(callee) > IPA_Max_Depth) {
01596 result = FALSE;
01597 reason = "depth in call graph exceeds specified maximum";
01598 ed->Set_reason_id (18);
01599 } else if (!ed->Has_Must_Inline_Attrib() &&
01600 (callee->Has_Noinline_Attrib() ||
01601 (callee->Summary_Proc()->Is_no_inline() && result) ||
01602 (!callee->Has_Must_Inline_Attrib() && INLINE_None ))) {
01603 result = FALSE;
01604 reason = "user requested not to inline";
01605 ed->Set_reason_id (19);
01606 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
01607
01608
01609
01610
01611
01612 } else if ( ( (!callee->Summary_Proc()->Is_may_inline() &&
01613 !callee->Summary_Proc()->Is_must_inline()) &&
01614 !INLINE_Preemptible ) &&
01615 ( !callee->Has_Must_Inline_Attrib() ) &&
01616 !ed->Summary_Callsite()->Is_must_inline() &&
01617 !ed->Has_Must_Inline_Attrib()) {
01618 result = FALSE;
01619 if ( callee->Summary_Proc()->Has_fstatic())
01620 {
01621 reason = "function has local fstatics and is set preemptible";
01622 ed->Set_reason_id (20);
01623 }
01624 else
01625 {
01626 reason = "function is preemptible and has not been set to mustinline";
01627 ed->Set_reason_id (21);
01628 }
01629
01630 #endif // _STANDALONE_INLINER
01631 }
01632 else if (!return_types_are_compatible(callee, ed)) {
01633 reason = "incompatible return types";
01634 ed->Set_reason_id (22);
01635 result = FALSE;
01636 }
01637 else if (INLINE_Check_Compatibility != AGGRESSIVE &&
01638 !param_types_are_compatible(caller, callee, ed)) {
01639 reason = "incompatible parameter types";
01640 ed->Set_reason_id (23);
01641 result = FALSE;
01642 }
01643 #if defined(KEY) && !defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER)
01644 else if (Opt_Options_Inconsistent &&
01645 caller->File_Id() != callee->File_Id()) {
01646
01647
01648 if (different_options (caller, callee)) {
01649 result = FALSE;
01650 reason = "optimization options are different for caller and callee";
01651 ed->Set_reason_id (34);
01652 }
01653 }
01654 else if (IPA_Enable_Pure_Call_Opt &&
01655 !callee->Summary_Proc()->Has_side_effect() &&
01656 !callee->Summary_Proc()->Is_must_inline() &&
01657 !ed->Has_Must_Inline_Attrib() &&
01658 !callee->Has_Must_Inline_Attrib() &&
01659
01660
01661 check_node (callee)) {
01662 result = FALSE;
01663 reason = "Trying to do pure-call-optimization for this callsite";
01664 ed->Set_reason_id (35);
01665 }
01666
01667 else if (callee->Is_Lang_CXX() && !caller->Is_Lang_CXX() &&
01668 PU_has_exc_scopes (callee->Get_PU())) {
01669 result = FALSE;
01670 reason = "not inlining C++ with exceptions into non-C++";
01671 ed->Set_reason_id (36);
01672 }
01673 else if (formal_is_loop_index(caller, callee, ed)) {
01674 result = FALSE;
01675 reason = "formal parameter is a loop index";
01676 ed->Set_reason_id (37);
01677 }
01678 #endif // KEY && !_STANDALONE_INLINER && !_LIGHTWEIGHT_INLINER
01679 #ifdef KEY
01680 else if (PU_is_nested_func(caller->Get_PU()) ||
01681 PU_is_nested_func(callee->Get_PU()) ||
01682 PU_uplevel(callee->Get_PU())) {
01683 result = FALSE;
01684 reason = "not inlining nested functions";
01685 ed->Set_reason_id (38);
01686 }
01687 #endif
01688
01689 else if (!IPA_Enable_Lang) {
01690 if ((callee->Summary_Proc()->Get_lang() == LANG_F77) ||
01691 (caller->Summary_Proc()->Get_lang() == LANG_F77)) {
01692 if ((callee->Summary_Proc()->Get_lang() != LANG_F77) ||
01693 (caller->Summary_Proc()->Get_lang() != LANG_F77)) {
01694 result = FALSE;
01695 reason = "not inlining across language boundaries";
01696 ed->Set_reason_id (24);
01697 }
01698 }
01699 else if ((callee->Summary_Proc()->Get_lang() == LANG_F90) ||
01700 (caller->Summary_Proc()->Get_lang() == LANG_F90)) {
01701 if ((callee->Summary_Proc()->Get_lang() != LANG_F90) ||
01702 (caller->Summary_Proc()->Get_lang() != LANG_F90)) {
01703 result = FALSE;
01704 reason = "not inlining across language boundaries";
01705 ed->Set_reason_id (25);
01706 }
01707 }
01708 }
01709
01710 if ( result == FALSE ) {
01711 Report_Reason ( callee, caller, reason , ed);
01712 return FALSE;
01713 }
01714
01715 #if 0 // def _STANDALONE_INLINER
01716 return result;
01717 #else
01718 return check_size_and_freq (ed, caller, callee, cg);
01719 #endif // _STANDALONE_INLINER
01720 }
01721
01722
01723
01724
01725 typedef AUX_IPA_EDGE<INT32> INVOCATION_COST;
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740 static INT32
01741 Estimated_Invocation_Cost (IPA_EDGE* edge, const IPA_CALL_GRAPH* cg)
01742 {
01743 IPA_NODE* callee = cg->Callee (edge);
01744
01745 INT loopnest = edge->Summary_Callsite ()->Get_loopnest ();
01746
01747 #if (defined(_STANDALONE_INLINER) || defined(_LIGHTWEIGHT_INLINER))
01748 INT32 cost = callee->Weight ();
01749 #else
01750 INT32 cost = Effective_weight (callee);
01751
01752 if (edge->Has_frequency () && callee->Has_frequency () &&
01753 edge->Get_frequency().Known() && callee->Get_frequency ().Known()) {
01754
01755
01756 return INT32_MAX - (INT32)compute_hotness (edge, callee, cost);
01757 }
01758 #endif // _STANDALONE_INLINER
01759
01760 if (loopnest < 100)
01761
01762 cost += ((100 - loopnest) << 11);
01763
01764 if (callee->PU_Size().Call_Count () != 0) {
01765 if (loopnest > 0)
01766 cost += (1 << 22);
01767 else
01768 cost += (callee->PU_Size().Call_Count () << 22);
01769 }
01770
01771 return cost;
01772
01773 }
01774
01775
01776
01777 struct INVOCATION_COST_COMP
01778 {
01779 const INVOCATION_COST& cost_vector;
01780
01781 INVOCATION_COST_COMP (const INVOCATION_COST& c) : cost_vector (c) {}
01782
01783 BOOL operator() (IPA_EDGE_INDEX e1, IPA_EDGE_INDEX e2) const {
01784 return cost_vector[e1] < cost_vector[e2];
01785 }
01786 };
01787
01788
01789
01790
01791 typedef vector<IPA_EDGE_INDEX> EDGE_INDEX_VECTOR;
01792
01793 void
01794 Get_Sorted_Callsite_List (IPA_NODE *n, IPA_CALL_GRAPH *cg,
01795 INVOCATION_COST& cost_vector,
01796 EDGE_INDEX_VECTOR& callsite_list)
01797 {
01798 if (cg->Num_Out_Edges(n) == 0)
01799 return;
01800
01801 Is_True (callsite_list.empty (), ("Uninitialized callsite list"));
01802
01803 IPA_SUCC_ITER edge_iter (cg, n);
01804 for (edge_iter.First (); !edge_iter.Is_Empty (); edge_iter.Next ()) {
01805 IPA_EDGE *edge = edge_iter.Current_Edge ();
01806
01807 if (edge) {
01808 IPA_EDGE_INDEX idx = edge->Array_Index ();
01809 cost_vector[idx] = Estimated_Invocation_Cost (edge, cg);
01810 callsite_list.push_back (idx);
01811 }
01812 }
01813
01814 sort (callsite_list.begin (), callsite_list.end (),
01815 INVOCATION_COST_COMP (cost_vector));
01816 }
01817
01818
01819
01820 static void
01821 Analyze_call (IPA_NODE* caller, IPA_EDGE* edge, const IPA_CALL_GRAPH* cg)
01822 {
01823 IPA_NODE* callee = cg->Callee (edge);
01824
01825 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
01826
01827 if (IPA_Enable_DCE) {
01828
01829
01830 if (!callee->Summary_Proc()->Has_pragma_side_effect() &&
01831 ((edge->Is_Deletable () ||
01832
01833 (
01834 #ifdef KEY
01835 callee->Summary_Proc()->Get_callsite_count() == 0 &&
01836 #else
01837 cg->Node_Depth (callee) == 0 &&
01838 #endif
01839 !callee->Has_Direct_Mod_Ref() &&
01840 !callee->Summary_Proc()->Is_alt_entry () &&
01841 !callee->Summary_Proc()->Has_alt_entry () &&
01842 !caller->Summary_Proc()->Is_alt_entry () &&
01843 return_types_are_compatible (callee, edge))))) {
01844
01845
01846 Is_True (callee->Summary_Proc()->Get_callsite_count() ||
01847 !callee->Summary_Proc()->Get_call_count(),
01848 ("Callsite and call counts don't match"));
01849
01850 edge->Set_Deletable();
01851 if (Trace_IPA || Trace_Perf) {
01852 fprintf (TFile, "%s called from ",
01853 DEMANGLE (callee->Name()));
01854 fprintf(TFile, "%s deleted\n",
01855 DEMANGLE (caller->Name()));
01856 }
01857
01858 Update_Call_Graph (caller);
01859
01860 if (IPA_Enable_DFE)
01861 Update_Total_Prog_Size (caller, callee, cg);
01862
01863 return;
01864 }
01865 }
01866
01867 if (! IPA_Enable_Inline)
01868 return;
01869
01870 #endif // _STANDALONE_INLINER
01871
01872 if (do_inline (edge, caller, callee, cg)) {
01873
01874 if(Get_Trace ( TP_IPA, IPA_TRACE_TUNING)) {
01875 fprintf(Verbose_inlining,"YYY\t(%p)%-20s -------<%p>--------> (%p)%-20s\n",caller,caller->Name(),edge,callee,callee->Name());
01876 }
01877
01878 edge->Set_Inline_Attrib ();
01879 Total_Inlined++;
01880
01881 } else {
01882 edge->Clear_All_Inline_Attrib ();
01883
01884 if(Get_Trace ( TP_IPA, IPA_TRACE_TUNING)) {
01885 fprintf(Verbose_inlining,"NNN\t(%p)%-20s -------<%p>--------> (%p)%-20s\n",caller,caller->Name(),edge,callee,callee->Name());
01886 }
01887 #if 0
01888 if (callee->Has_Must_Inline_Attrib())
01889 callee->Clear_Must_Inline_Attrib ();
01890 #endif
01891 if (callee->Has_Inline_Attrib())
01892 callee->Clear_Inline_Attrib ();
01893 Total_Not_Inlined++;
01894 }
01895 }
01896
01897
01898
01899
01900
01901
01902 #ifdef KEY
01903
01904
01905 typedef AUX_IPA_EDGE<float> INVOCATION_FREQ;
01906
01907
01908 struct INVOCATION_FREQ_COMP
01909 {
01910 const INVOCATION_FREQ& freq_vector;
01911
01912 INVOCATION_FREQ_COMP( const INVOCATION_FREQ& c ) : freq_vector (c) {}
01913
01914 BOOL operator() (IPA_EDGE_INDEX e1, IPA_EDGE_INDEX e2) const {
01915 return freq_vector[e1] > freq_vector[e2];
01916 }
01917 };
01918
01919
01920 void Perform_Inline_Analysis2( IPA_CALL_GRAPH* cg, MEM_POOL* pool )
01921 {
01922 INVOCATION_FREQ freq_vector( cg, pool );
01923
01924 if( Get_Trace ( TP_IPA, IPA_TRACE_TUNING) ){
01925 Verbose_inlining = fopen ("Verbose_inlining.log", "w");
01926 N_inlining = fopen ("N_inlining.log", "w");
01927 Y_inlining = fopen ("Y_inlining.log", "w");
01928 e_weight = fopen ("callee_wght.log","w");
01929 }
01930
01931 Init_inline_parameters ();
01932
01933 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
01934 if( IPA_Enable_DFE ){
01935 inline_count = CXX_NEW (INLINE_COUNTER_ARRAY (cg, pool), pool);
01936 }
01937 #endif // !_STANDALONE_INLINER
01938
01939 EDGE_INDEX_VECTOR callsite_list;
01940
01941 IPA_NODE_ITER cg_iter( cg, PREORDER, pool );
01942
01943
01944 for( cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next() ){
01945 IPA_NODE* caller = cg_iter.Current();
01946
01947 if( caller == NULL ||
01948 caller->Should_Be_Skipped() ||
01949 cg->Num_Out_Edges(caller) == 0 ){
01950 Total_Not_Inlined++;
01951 continue;
01952 }
01953
01954 IPA_SUCC_ITER edge_iter( cg, caller );
01955
01956 for( edge_iter.First (); !edge_iter.Is_Empty (); edge_iter.Next() ){
01957 IPA_EDGE *edge = edge_iter.Current_Edge ();
01958
01959 if( edge != NULL &&
01960 edge->Has_frequency() ){
01961 const FB_FREQ freq = edge->Get_frequency();
01962
01963 if( freq.Known() &&
01964 freq.Value() > 0 ){
01965 const IPA_EDGE_INDEX idx = edge->Array_Index();
01966 freq_vector[idx] = freq.Value();
01967 callsite_list.push_back (idx);
01968 }
01969 }
01970 }
01971 }
01972
01973 sort( callsite_list.begin(),
01974 callsite_list.end(),
01975 INVOCATION_FREQ_COMP( freq_vector ) );
01976
01977 for( EDGE_INDEX_VECTOR::iterator first = callsite_list.begin();
01978 first != callsite_list.end();
01979 first++ ){
01980 IPA_EDGE* edge = cg->Edge(*first);
01981 Analyze_call( cg->Caller(edge), edge, cg );
01982 }
01983
01984 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
01985 if( IPA_Enable_DFE ){
01986 CXX_DELETE (inline_count, pool);
01987 inline_count = NULL;
01988 }
01989 #endif // !_STANDALONE_INLINER
01990
01991 if( Get_Trace ( TP_IPA, IPA_TRACE_TUNING) ){
01992 fclose(e_weight);
01993 fclose(Y_inlining);
01994 fclose(N_inlining);
01995 fclose(Verbose_inlining);
01996 }
01997
01998
01999 }
02000 #endif // KEY
02001
02002 void
02003 Perform_Inline_Analysis (IPA_CALL_GRAPH* cg, MEM_POOL* pool)
02004 {
02005 INVOCATION_COST cost_vector (cg, pool);
02006
02007 if(Get_Trace ( TP_IPA, IPA_TRACE_TUNING)) {
02008 Verbose_inlining = fopen ("Verbose_inlining.log", "w");
02009 N_inlining = fopen ("N_inlining.log", "w");
02010 Y_inlining = fopen ("Y_inlining.log", "w");
02011 e_weight = fopen ("callee_wght.log","w");
02012 }
02013 Init_inline_parameters ();
02014
02015 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
02016
02017 if (IPA_Enable_DFE)
02018 inline_count = CXX_NEW (INLINE_COUNTER_ARRAY (cg, pool), pool);
02019
02020 #endif // _STANDALONE_INLINER
02021
02022 EDGE_INDEX_VECTOR callsite_list;
02023 IPA_NODE_ITER cg_iter (cg, LEVELORDER, pool);
02024
02025
02026
02027 for (cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next()) {
02028 IPA_NODE* caller = cg_iter.Current();
02029
02030 if (caller == NULL)
02031 continue;
02032
02033 if (caller->Should_Be_Skipped()) {
02034 Total_Inlined++;
02035 continue;
02036 }
02037
02038 callsite_list.clear ();
02039 Get_Sorted_Callsite_List (caller, cg, cost_vector, callsite_list);
02040
02041 EDGE_INDEX_VECTOR::const_iterator last = callsite_list.end ();
02042 for (EDGE_INDEX_VECTOR::iterator first = callsite_list.begin ();
02043 first != last; ++first) {
02044
02045 Analyze_call (caller, cg->Edge (*first), cg);
02046
02047 }
02048 }
02049
02050 #if (!defined(_STANDALONE_INLINER) && !defined(_LIGHTWEIGHT_INLINER))
02051
02052 #ifdef TODO
02053
02054 if( IPA_Enable_Feedback ) {
02055 fprintf(IPA_Feedback_prg_fd,"\nINLINING SUCCESS INFO\n\n");
02056 IPA_NODE_ITER cg_iter (cg, PREORDER);
02057
02058 for (cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next()) {
02059 IPA_NODE* n = (IPA_NODE*)cg_iter.Current();
02060 if (n == NULL) continue;
02061 if ((*inline_count)[caller]) {
02062
02063 if((caller->Get_fbk_ptr() )->Get_Cross_File_Fnd() ) {
02064 fprintf( IPA_Feedback_prg_fd, "#pragma inline %s /* Cross-file - %d inlined - %d calls */\n",
02065 DEMANGLE (caller->Name()),
02066 (*inline_count)[caller],
02067 cg->Num_In_Edges(n));
02068 } else {
02069 fprintf(IPA_Feedback_prg_fd, "#pragma inline %s /* %d inlined - %d calls */\n",
02070 DEMANGLE (caller->Name()),
02071 (*inline_count)[caller],
02072 cg->Num_In_Edges(n));
02073 }
02074 }
02075 }
02076 }
02077 #endif // TODO
02078
02079 if (IPA_Enable_DFE) {
02080 CXX_DELETE (inline_count, pool);
02081 inline_count = 0;
02082 }
02083
02084 #endif // _STANDALONE_INLINER
02085
02086 if(Get_Trace ( TP_IPA, IPA_TRACE_TUNING)) {
02087 fclose(e_weight);
02088 fclose(Y_inlining);
02089 fclose(N_inlining);
02090 fclose(Verbose_inlining);
02091 }
02092 }