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 #ifndef __STDC_LIMIT_MACROS
00026 #define __STDC_LIMIT_MACROS
00027 #endif
00028
00029 #include <queue>
00030 #include <ext/hash_map>
00031 #include <ext/hash_set>
00032 #include "symtab.h"
00033 #include "wn_util.h"
00034 #include "wn_lower.h"
00035 #include "ir_reader.h"
00036 #include "ipo_defs.h"
00037 #include "ipo_parent.h"
00038 #include "ipl_summarize.h"
00039 #include "ipl_summarize_util.h"
00040 #include "ipc_symtab_merge.h"
00041 #include "ipc_ty_hash.h"
00042 #include "ipa_chg.h"
00043 #include "ipa_devirtual.h"
00044
00045 using std::queue;
00046 using __gnu_cxx::hash_map;
00047 using __gnu_cxx::hash_set;
00048
00049
00050 typedef struct {
00051 SUMMARY_CALLSITE *callsite;
00052 TY_INDEX actual_class;
00053 } CONVERSION_CANDIDATE;
00054
00055 #define SUBCLASS_UNSET 0
00056 #define SUBCLASS_MORE_THAN_ONE (TY_INDEX)-1
00057
00058
00059
00060 static hash_map <TY_INDEX, PU_IDX> live_class;
00061
00062
00063
00064
00065
00066 static hash_map <TY_INDEX, TY_INDEX> base_sub_map;
00067
00068
00069 static hash_map <PU_IDX, NODE_INDEX> pu_node_index_map;
00070
00071
00072 static hash_map <ST_IDX, INITO_IDX> st_inito_map;
00073
00074
00075 static queue <CONVERSION_CANDIDATE> conversion_list;
00076
00077
00078
00079
00080 INITO_IDX
00081 Find_inito_by_st(ST_IDX st_idx) {
00082 if (st_inito_map.find(st_idx) == st_inito_map.end()) {
00083 UINT inito_count = INITO_Table_Size(GLOBAL_SYMTAB);
00084 for (UINT i = 1; i < inito_count; i++) {
00085 INITO_IDX idx = make_INITO_IDX(i, GLOBAL_SYMTAB);
00086 if (INITO_st_idx(Inito_Table[idx]) == st_idx) {
00087 st_inito_map[st_idx] = idx;
00088 return idx;
00089 }
00090 }
00091 Is_True(FALSE, ("Cannot find vtable by ST."));
00092 }
00093 return st_inito_map[st_idx];
00094 }
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 ST_IDX
00105 Find_virtual_function(TY_IDX actual_class,
00106 TY_IDX formal_class,
00107 UINT64 formal_vptr_offset,
00108 size_t func_offset)
00109 {
00110 PU_IDX pu_idx = live_class[TY_IDX_index(actual_class)];
00111 IPA_NODE *constructor = IPA_Call_Graph->Node(pu_node_index_map[pu_idx]);
00112 IPA_NODE_CONTEXT context(constructor);
00113 WN *wn_start = constructor->Whirl_Tree(TRUE);
00114 WN *vtab = NULL;
00115 size_t ancestor_offset = IPA_Class_Hierarchy->Get_Ancestor_Offset(TY_IDX_index(actual_class), TY_IDX_index(formal_class));
00116 Is_True(ancestor_offset != BASE_CLASS_NOT_FOUND, ("Wrong ancestor class."));
00117
00118
00119
00120 for(WN_ITER *wni = WN_WALK_StmtIter(wn_start);
00121 wni != NULL; wni = WN_WALK_StmtNext(wni))
00122 {
00123 WN *wn = WN_ITER_wn(wni);
00124 if (WN_operator(wn) == OPR_ISTORE) {
00125 WN *rhs = WN_kid0(wn);
00126 WN *lhs = WN_kid1(wn);
00127 UINT64 add_ofst = 0;
00128 if (WN_operator(lhs) == OPR_ADD) {
00129 add_ofst = WN_const_val(WN_kid1(lhs));
00130 lhs = WN_kid0(lhs);
00131 }
00132 if (WN_operator(rhs) == OPR_LDA && WN_operator(lhs) == OPR_LDID) {
00133 TY_IDX this_class_ptr = ST_type(WN_st(lhs));
00134 if (TY_kind(this_class_ptr) != KIND_POINTER)
00135 continue;
00136 TY_IDX this_class = TY_pointed(this_class_ptr);
00137 if (TY_IDX_index(this_class) == TY_IDX_index(actual_class)) {
00138
00139 UINT64 ofst = WN_store_offset(wn) + add_ofst;
00140
00141 if (ofst == formal_vptr_offset + ancestor_offset) {
00142 vtab = wn;
00143 break;
00144 }
00145 }
00146 }
00147 }
00148 }
00149
00150
00151 if (vtab == NULL)
00152 return ST_IDX_ZERO;
00153
00154
00155 WN *pos = WN_kid0(vtab);
00156
00157 ST *vtab_st = WN_st(pos);
00158
00159 UINT32 base_offset = WN_lda_offset(pos);
00160
00161
00162 INITO_IDX inito_idx = Find_inito_by_st(ST_st_idx(vtab_st));
00163
00164
00165 INITV_IDX initv_idx = INITO_val(inito_idx);
00166
00167
00168 UINT32 offset = base_offset + func_offset;
00169
00170 if (initv_idx <= INITV_IDX_ZERO)
00171 return ST_IDX_ZERO;
00172 do {
00173 if (offset == 0) {
00174 #ifdef TARG_IA64
00175 Is_True(INITV_kind(initv_idx) == INITVKIND_SYMIPLT,
00176 ("Wrong INITV for virtual function."));
00177 #else
00178 Is_True(INITV_kind(initv_idx) == INITVKIND_SYMOFF,
00179 ("Wrong INITV for virtual function."));
00180 #endif
00181 return INITV_st(initv_idx);
00182 }
00183 switch (INITV_kind(initv_idx)) {
00184 case INITVKIND_BLOCK:
00185 initv_idx = INITV_blk(initv_idx);
00186 break;
00187 case INITVKIND_VAL:
00188 case INITVKIND_ZERO:
00189 offset -= Pointer_Size;
00190 initv_idx = INITV_next(initv_idx);
00191 break;
00192 case INITVKIND_SYMOFF:
00193 offset -= Pointer_Size;
00194 initv_idx = INITV_next(initv_idx);
00195 break;
00196 #ifdef TARG_IA64
00197 case INITVKIND_SYMIPLT:
00198 offset -= (Pointer_Size << 1);
00199 initv_idx = INITV_next(initv_idx);
00200 break;
00201 #endif
00202 default:
00203 Is_True(FALSE, ("Unexcepted INITV kind."));
00204 }
00205 } while (initv_idx > INITV_IDX_ZERO);
00206 Is_True(FALSE, ("Initv entry not found."));
00207 return ST_IDX_ZERO;
00208 }
00209
00210
00211
00212 TY_INDEX
00213 Is_constructor(SUMMARY_SYMBOL *func_sym, PU_IDX *sym_pu) {
00214 ST_IDX func_st_idx = func_sym->St_idx();
00215 ST *func_st = &St_Table[func_st_idx];
00216 PU_IDX pui = ST_pu(func_st);
00217 if (PU_is_constructor(Pu_Table[pui])) {
00218 TY_IDX class_ty = PU_base_class(Pu_Table[pui]);
00219 Is_True(TY_kind(class_ty) == KIND_STRUCT, ("Wrong base class."));
00220 *sym_pu = pui;
00221 return TY_IDX_index(class_ty);
00222 }
00223 return TY_IDX_ZERO;
00224 }
00225
00226
00227 void
00228 IPA_collect_class_instances() {
00229 hash_set <TY_INDEX> invoked_base_classes;
00230 IPA_NODE_ITER cg_iter(IPA_Call_Graph, PREORDER);
00231
00232 for (cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next() ){
00233 IPA_NODE *method = cg_iter.Current();
00234 if (method == NULL)
00235 continue;
00236
00237 PU_IDX pui = ST_pu(method->Func_ST());
00238 pu_node_index_map[pui] = method->Node_Index();
00239
00240 invoked_base_classes.clear();
00241
00242 SUMMARY_PROCEDURE* method_summary = method->Summary_Proc();
00243 SUMMARY_CALLSITE* callsite_array =
00244 IPA_get_callsite_array(method) + method_summary->Get_callsite_index();
00245 int count = method_summary->Get_callsite_count();
00246 while (count > 0) {
00247 if (!callsite_array->Is_func_ptr() && !callsite_array->Is_intrinsic()) {
00248 SUMMARY_SYMBOL *sym = IPA_get_symbol_array(method) +
00249 callsite_array->Get_symbol_index();
00250
00251 PU_IDX sym_pu;
00252 TY_INDEX new_class = Is_constructor(sym, &sym_pu);
00253 if (new_class) {
00254 TY_INDEX bclass = TY_IDX_index(PU_base_class(Pu_Table[pui]));
00255
00256
00257
00258 if (IPA_Class_Hierarchy->Is_Sub_Class(new_class, bclass) &&
00259 invoked_base_classes.find(new_class) == invoked_base_classes.end())
00260 invoked_base_classes.insert(new_class);
00261 else
00262 live_class[new_class] = sym_pu;
00263 }
00264 }
00265 callsite_array++;
00266 count--;
00267 }
00268 }
00269 }
00270
00271
00272
00273
00274
00275
00276 TY_INDEX
00277 Class_has_subclass(TY_INDEX base) {
00278 if (base_sub_map.find(base) == base_sub_map.end()) {
00279 TY_INDEX live_sub = SUBCLASS_UNSET;
00280 for (hash_map <TY_INDEX, PU_IDX>::const_iterator iter = live_class.begin();
00281 iter != live_class.end(); iter++)
00282 {
00283 TY_INDEX sub = iter->first;
00284 if (IPA_Class_Hierarchy->Is_Ancestor(base, sub)) {
00285 if (live_sub == SUBCLASS_UNSET) {
00286 live_sub = sub;
00287 }
00288 else if (live_sub != SUBCLASS_MORE_THAN_ONE) {
00289 live_sub = SUBCLASS_MORE_THAN_ONE;
00290 break;
00291 }
00292 }
00293 }
00294 base_sub_map[base] = live_sub;
00295 }
00296 return base_sub_map[base];
00297 }
00298
00299
00300
00301
00302
00303 void
00304 Convert_virtual_call(IPA_NODE *method) {
00305
00306
00307 hash_map <WN_MAP_ID, WN *> wn_map;
00308 IPA_NODE_CONTEXT context(method);
00309
00310 WN *wn_start = method->Whirl_Tree(TRUE);
00311 Is_True(wn_start, ("Whirl node is empty."));
00312
00313
00314 wn_map.clear();
00315 for(WN_ITER *wni = WN_WALK_StmtIter(wn_start);
00316 wni != NULL; wni = WN_WALK_StmtNext(wni))
00317 {
00318 WN *wn = WN_ITER_wn(wni);
00319 if (WN_Call_Is_Virtual(wn))
00320 wn_map[WN_map_id(wn)] = wn;
00321 }
00322
00323
00324 while (!conversion_list.empty()) {
00325
00326
00327 CONVERSION_CANDIDATE cand = conversion_list.front();
00328 conversion_list.pop();
00329
00330
00331 WN_MAP_ID map_id = cand.callsite->Get_map_id();
00332 Is_True(wn_map.find(map_id) != wn_map.end(), ("No corresponding whirl node."));
00333 WN *old_wn = wn_map[cand.callsite->Get_map_id()];
00334
00335 SUMMARY_CALLSITE *callsite = cand.callsite;
00336
00337 TY_IDX orig_class = callsite->Get_virtual_class();
00338
00339 size_t func_offset = callsite->Get_vtable_offset();
00340
00341 UINT64 vptr_ofst = callsite->Get_vptr_offset();
00342
00343 ST_IDX callee_st_idx =
00344 Find_virtual_function(make_TY_IDX(cand.actual_class), orig_class, vptr_ofst, func_offset);
00345
00346
00347 if (callee_st_idx == ST_IDX_ZERO) {
00348 DevWarn("Find virtual function for class %s (offset %lu) failed.",
00349 &Str_Table[TY_name_idx(make_TY_IDX(cand.actual_class))], func_offset);
00350 continue;
00351 }
00352
00353
00354 ST *callee_st = ST_ptr(callee_st_idx);
00355 WN *new_wn = WN_generic_call(OPR_CALL, WN_rtype(old_wn),
00356 WN_desc(old_wn), WN_kid_count(old_wn)-1, callee_st);
00357 for (size_t j = 0; j < WN_kid_count(new_wn); j++) {
00358 WN_kid(new_wn, j) = WN_kid(old_wn, j);
00359 }
00360 WN_set_map_id(new_wn, WN_map_id(old_wn));
00361 WN_set_flag(new_wn, WN_flag(old_wn));
00362 WN_Reset_Call_Is_Virtual(new_wn);
00363 WN *parent = WN_Get_Parent(old_wn, method->Parent_Map(), method->Map_Table());
00364 WN_Set_Parent(new_wn, parent, method->Parent_Map(), method->Map_Table());
00365 WN_INSERT_BlockAfter(parent, old_wn, new_wn);
00366 WN_EXTRACT_FromBlock(parent, old_wn);
00367
00368
00369 for (IPA_ICALL_LIST::iterator iter = method->Icall_List().begin();
00370 iter != method->Icall_List().end(); iter++)
00371 {
00372 if ((*iter)->Callsite() == callsite) {
00373 method->Icall_List().erase(iter);
00374 break;
00375 }
00376 }
00377 callsite->Reset_icall_target();
00378 callsite->Reset_func_ptr();
00379 callsite->Set_param_count(WN_num_actuals(new_wn));
00380 callsite->Set_return_type(WN_rtype(new_wn));
00381 callsite->Set_callsite_freq();
00382 callsite->Set_probability(-1);
00383 callsite->Set_symbol_index(0);
00384
00385
00386 IPA_EDGE* edge = IPA_Call_Graph->Add_New_Edge(callsite,
00387 method->Node_Index(),
00388 pu_node_index_map[ST_pu(callee_st)]);
00389
00390
00391 DevWarn("Convert indirect call (class %s, offset %lu) to direct call %s (class %s) in function %s.",
00392 &Str_Table[TY_name_idx(orig_class)],
00393 func_offset, &Str_Table[ST_name_idx(*callee_st)],
00394 &Str_Table[TY_name_idx(make_TY_IDX(cand.actual_class))],
00395 &Str_Table[ST_name_idx(*(method->Func_ST()))]);
00396 }
00397 }
00398
00399
00400
00401
00402 void
00403 IPA_devirtualization() {
00404
00405 live_class.clear();
00406 base_sub_map.clear();
00407 pu_node_index_map.clear();
00408 st_inito_map.clear();
00409
00410
00411 IPA_collect_class_instances();
00412
00413
00414 IPA_NODE_ITER cg_iter(IPA_Call_Graph, PREORDER);
00415 for (cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next()) {
00416 IPA_NODE *method = cg_iter.Current();
00417 if (method == NULL)
00418 continue;
00419
00420
00421 SUMMARY_PROCEDURE* method_summary = method->Summary_Proc();
00422 SUMMARY_CALLSITE* callsite_array =
00423 IPA_get_callsite_array(method) + method_summary->Get_callsite_index();
00424 int count = method_summary->Get_callsite_count();
00425
00426 Is_True(conversion_list.empty(), ("Conversion list is not empty."));
00427 while (count > 0) {
00428
00429 if (callsite_array->Is_virtual_call()) {
00430
00431 TY_INDEX method_class = TY_IDX_index(callsite_array->Get_virtual_class());
00432
00433 TY_INDEX actual_class = Class_has_subclass(method_class);
00434 if (actual_class != SUBCLASS_UNSET && actual_class != SUBCLASS_MORE_THAN_ONE) {
00435
00436 CONVERSION_CANDIDATE cand;
00437 cand.callsite = callsite_array;
00438 cand.actual_class = actual_class;
00439 conversion_list.push(cand);
00440 }
00441 }
00442 callsite_array++;
00443 count--;
00444 }
00445
00446
00447
00448 if (!conversion_list.empty())
00449 Convert_virtual_call(method);
00450 }
00451 }
00452