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 #include "cxx_memory.h"
00054 #include "tracing.h"
00055 #include "symtab.h"
00056
00057
00058
00059 static BOOL trace_split_common = FALSE;
00060 static UINT32 IPA_SPLIT_COMMON = 128;
00061
00062
00063 class SPLIT_GROUP
00064 {
00065 private:
00066 UINT64 size;
00067 ST* st;
00068 UINT32 group;
00069
00070 public:
00071 SPLIT_GROUP (ST* s) :
00072 st (s),
00073 size (TY_size (ST_type (s))),
00074 group (0) {}
00075
00076 ST* St () const { return st; }
00077
00078 UINT64 Size () const { return size; }
00079
00080 UINT64 Offset () const { return ST_ofst (st); }
00081
00082 void Set_group (UINT32 g) { group = g; }
00083 UINT32 Group () const { return group; }
00084 };
00085
00086
00087
00088 typedef vector<SPLIT_GROUP, mempool_allocator<SPLIT_GROUP> > COMMON_BLOCK;
00089
00090
00091
00092 class SPLIT_GROUP_DESC
00093 {
00094 private:
00095 UINT64 offset;
00096 UINT64 size;
00097
00098 public:
00099 SPLIT_GROUP_DESC (UINT64 ofst, UINT64 s) : offset (ofst), size (s) {}
00100
00101 UINT64 Offset () const { return offset; }
00102 UINT64 Size () const { return size; }
00103 };
00104
00105
00106
00107 typedef vector<SPLIT_GROUP_DESC, mempool_allocator<SPLIT_GROUP_DESC> >
00108 SPLIT_BLOCK;
00109
00110
00111
00112
00113 struct SPLIT_COMMON_DESC
00114 {
00115 COMMON_BLOCK* common_block;
00116 SPLIT_BLOCK* split_block;
00117
00118 SPLIT_COMMON_DESC () : common_block (NULL), split_block (NULL) {}
00119 };
00120
00121 typedef hash_map<STR_IDX, SPLIT_COMMON_DESC, hash<STR_IDX>,
00122 equal_to<STR_IDX>, mempool_allocator<SPLIT_COMMON_DESC*> >
00123 SPLIT_COMMON_TBL;
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 namespace {
00137
00138
00139 struct collect_commons {
00140 SPLIT_COMMON_TBL& table;
00141 MEM_POOL* pool;
00142
00143 collect_commons (SPLIT_COMMON_TBL& t, MEM_POOL* p) :
00144 table (t), pool (p) {}
00145
00146 void operator() (UINT32, ST* st) const {
00147 if (ST_sclass (st) == SCLASS_COMMON &&
00148 ST_base_idx (st) != ST_st_idx (st)) {
00149
00150 STR_IDX block_name = ST_name_idx (St_Table[ST_base_idx (st)]);
00151 SPLIT_COMMON_DESC& desc = table[block_name];
00152 if (desc.common_block == NULL) {
00153
00154 desc.common_block = CXX_NEW (COMMON_BLOCK (pool), pool);
00155 }
00156
00157 desc.common_block->push_back (SPLIT_GROUP (st));
00158 }
00159 }
00160 };
00161
00162
00163 struct process_block_data {
00164 SPLIT_COMMON_TBL& table;
00165
00166 process_block_data (SPLIT_COMMON_TBL& t) : table (t) {}
00167
00168 void operator() (UINT32, const ST* st) const {
00169 if (ST_sclass (st) == SCLASS_DGLOBAL) {
00170 SPLIT_COMMON_TBL::iterator block =
00171 table.find (ST_name_idx (st));
00172 if (block != table.end ()) {
00173 table.erase (block);
00174 }
00175 }
00176 }
00177 };
00178
00179
00180 struct block_element_compare {
00181
00182 bool operator() (const SPLIT_GROUP& g1, const SPLIT_GROUP& g2) const {
00183 if (g1.Offset () != g2.Offset ())
00184 return g1.Offset () < g2.Offset ();
00185 if (g1.Size () != g2.Size ())
00186 return g1.Size () > g2.Size ();
00187 return g1.St () < g2.St ();
00188 }
00189 };
00190
00191 }
00192
00193
00194
00195 static void
00196 Group_Synonymous_Commons (SPLIT_COMMON_TBL& table, MEM_POOL* pool)
00197 {
00198 For_all (St_Table, GLOBAL_SYMTAB, collect_commons (table, pool));
00199 For_all (St_Table, GLOBAL_SYMTAB, process_block_data (table));
00200
00201 }
00202
00203
00204
00205
00206
00207 struct SPLIT_GROUP_ITERATOR
00208 {
00209 COMMON_BLOCK::iterator iter;
00210 COMMON_BLOCK::const_iterator last;
00211 UINT32 gp_id;
00212
00213 SPLIT_GROUP_ITERATOR (COMMON_BLOCK::iterator i,
00214 COMMON_BLOCK::const_iterator l) :
00215 iter (i), last (l), gp_id ((*i).Group ()) {}
00216
00217 SPLIT_GROUP_ITERATOR (const SPLIT_GROUP_ITERATOR& i) :
00218 iter (i.iter), last (i.last), gp_id (i.gp_id) {}
00219
00220 SPLIT_GROUP_ITERATOR& operator++ () {
00221 while (++iter != last) {
00222 if ((*iter).Group () != gp_id) {
00223 gp_id = (*iter).Group ();
00224 return *this;
00225 }
00226 }
00227 return *this;
00228 }
00229
00230 SPLIT_GROUP& operator* () const {
00231 return *iter;
00232 }
00233
00234 BOOL operator!= (COMMON_BLOCK::const_iterator i) const {
00235 return iter != i;
00236 }
00237
00238 BOOL operator!= (const SPLIT_GROUP_ITERATOR& i) const {
00239 return iter != i.iter;
00240 }
00241 };
00242
00243
00244
00245 static inline void
00246 Update_Group_Idx (COMMON_BLOCK::iterator first,
00247 COMMON_BLOCK::const_iterator last, UINT group_idx)
00248 {
00249 while (first != last) {
00250 (*first).Set_group (group_idx);
00251 ++first;
00252 }
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 static const UINT Primary_Cache = 16*1024;
00277 static const UINT Secondary_Cache = 512*1024;
00278 static const UINT Primary_Delta = 819;
00279 static const UINT Secondary_Delta = 26214;
00280
00281 static inline BOOL
00282 need_to_split (UINT64 offset, UINT64 cache_size, UINT64 delta)
00283 {
00284 offset %= cache_size;
00285 return (offset < delta) || (offset > cache_size - delta);
00286 }
00287
00288
00289 static BOOL
00290 Compute_Split_Regions (SPLIT_COMMON_DESC& common_desc, MEM_POOL* pool)
00291 {
00292 COMMON_BLOCK& common_block = *common_desc.common_block;
00293
00294 SPLIT_GROUP_ITERATOR current_split (common_block.begin (),
00295 common_block.end ());
00296 UINT64 offset = 0;
00297 UINT64 size = 0;
00298 UINT group_idx = 0;
00299
00300 for (SPLIT_GROUP_ITERATOR iter (current_split);
00301 iter != common_block.end ();
00302 ++iter) {
00303
00304 const SPLIT_GROUP& element = *iter;
00305
00306
00307 if (element.Size () < Primary_Cache ||
00308 element.Offset () - offset < Primary_Cache - Primary_Delta) {
00309 size = element.Offset () + element.Size () - offset;
00310 continue;
00311 }
00312
00313 BOOL split_useful = FALSE;
00314 for (SPLIT_GROUP_ITERATOR i (current_split); i != iter; ++i) {
00315
00316 const SPLIT_GROUP& i_elmt = *i;
00317
00318
00319
00320 if (i_elmt.Size () >= Primary_Cache) {
00321 UINT64 current_offset = element.Offset () - i_elmt.Offset ();
00322
00323 if (need_to_split (current_offset, Primary_Cache,
00324 Primary_Delta) ||
00325 need_to_split (current_offset, Secondary_Cache,
00326 Secondary_Delta))
00327 split_useful = TRUE;
00328 }
00329 }
00330
00331 if (split_useful) {
00332 if (common_desc.split_block == NULL)
00333 common_desc.split_block = CXX_NEW (SPLIT_BLOCK (pool), pool);
00334
00335 Is_True (group_idx == common_desc.split_block->size (),
00336 ("Inconsistent split common block descriptor"));
00337
00338
00339
00340 Update_Group_Idx (current_split.iter, iter.iter, group_idx);
00341
00342 common_desc.split_block->push_back (SPLIT_GROUP_DESC (offset, size));
00343 offset = element.Offset ();
00344 size = element.Size ();
00345 current_split = iter;
00346 ++group_idx;
00347 } else
00348 size = element.Offset () + element.Size () - offset;
00349 }
00350
00351 if (common_desc.split_block == NULL)
00352
00353 return FALSE;
00354 else {
00355
00356 Update_Group_Idx (current_split.iter, common_block.end (), group_idx);
00357 common_desc.split_block->push_back (SPLIT_GROUP_DESC (offset, size));
00358 return TRUE;
00359 }
00360 }
00361
00362
00363
00364 static BOOL
00365 Consistent_Layout (COMMON_BLOCK& block)
00366 {
00367 sort (block.begin(), block.end (), block_element_compare ());
00368
00369 UINT64 offset = 0;
00370 UINT64 size = 0;
00371 INT32 group_idx = -1;
00372
00373 for (COMMON_BLOCK::iterator iter = block.begin ();
00374 iter != block.end ();
00375 ++iter) {
00376
00377 SPLIT_GROUP& element = *iter;
00378 UINT64 elm_ofst = element.Offset ();
00379 UINT64 elm_size = element.Size ();
00380
00381 if (elm_ofst >= offset + size) {
00382 ++group_idx;
00383 offset = elm_ofst;
00384 size = elm_size;
00385 } else if (elm_ofst + elm_size > offset + size) {
00386
00387 return FALSE;
00388 }
00389
00390 element.Set_group (group_idx);
00391 }
00392
00393 return group_idx > 0;
00394 }
00395
00396
00397
00398
00399
00400
00401 static BOOL
00402 Split_Common_Possible (SPLIT_COMMON_DESC& common_desc, MEM_POOL* pool)
00403 {
00404
00405 if (!Consistent_Layout (*common_desc.common_block))
00406 return FALSE;
00407
00408 return Compute_Split_Regions (common_desc, pool);
00409
00410 }
00411
00412
00413
00414
00415
00416 static void
00417 Print_Split (const char* name, FILE* fp, const SPLIT_COMMON_DESC& desc)
00418 {
00419 fprintf(fp, "=======Recording Split Information for common %s ======= \n",
00420 name);
00421
00422 if (desc.split_block == NULL)
00423 fputs ("Not splitted\n", fp);
00424 else {
00425 const SPLIT_BLOCK& split = *desc.split_block;
00426 for (COMMON_BLOCK::const_iterator iter (desc.common_block->begin ());
00427 iter != desc.common_block->end ();
00428 ++iter) {
00429
00430 UINT id = (*iter).Group ();
00431 const ST* st = (*iter).St ();
00432 fprintf (fp, "offset = %lld, size = %lld, split = %d: <%d,%d,%s>\n",
00433 split[id].Offset (), split[id].Size (), id,
00434 ST_level (st), ST_index (st), ST_name ((*iter).St ()));
00435 }
00436 }
00437 }
00438
00439
00440
00441
00442
00443 static BOOL
00444 Split_Analysis (SPLIT_COMMON_TBL& split_common_tbl, MEM_POOL* pool)
00445 {
00446 if (trace_split_common)
00447 fprintf(TFile, "+++++ INLINE split common analysis ++++\n");
00448
00449
00450 Group_Synonymous_Commons (split_common_tbl, pool);
00451
00452 BOOL contain_split_common = FALSE;
00453
00454 for (SPLIT_COMMON_TBL::iterator iter = split_common_tbl.begin ();
00455 iter != split_common_tbl.end ();
00456 ++iter) {
00457
00458 STR_IDX name = (*iter).first;
00459 SPLIT_COMMON_DESC& common_desc = (*iter).second;
00460
00461 if (trace_split_common)
00462 fprintf (TFile, "checking split needed for common %s \n",
00463 Index_To_Str (name));
00464
00465
00466 if (Split_Common_Possible (common_desc, pool)) {
00467
00468 contain_split_common = TRUE;
00469
00470 if (trace_split_common) {
00471 const char* common_name = Index_To_Str (name);
00472 fprintf(TFile, "split needed for common %s \n",
00473 common_name);
00474 Print_Split (common_name, TFile, common_desc);
00475 }
00476 } else if (trace_split_common) {
00477 fprintf (TFile, "split not needed for common %s \n",
00478 Index_To_Str (name));
00479 }
00480 }
00481
00482 return contain_split_common;
00483 }
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 namespace {
00516
00517
00518
00519 template <class ST_ITER>
00520 FLD_HANDLE
00521 make_fld (ST_ITER first, ST_ITER last, UINT64 new_ofst)
00522 {
00523 FLD_IDX first_field = FLD_Table_Size ();
00524 FLD_HANDLE fld;
00525
00526 while (first != last) {
00527 const ST* st = *first;
00528 UINT64 offset = ST_ofst (st) - new_ofst;
00529
00530 fld = New_FLD ();
00531 FLD_Init (fld, ST_name_idx (st), ST_type (st), offset);
00532 if (ST_is_equivalenced (st))
00533 Set_FLD_equivalence (fld);
00534 ++first;
00535 }
00536
00537 Set_FLD_last_field (fld);
00538
00539 return FLD_HANDLE (fld);
00540
00541 }
00542
00543
00544
00545 template <class ST_ITER>
00546 void
00547 Update_element (ST_ITER first, ST_ITER last, ST_IDX base, UINT64 offset)
00548 {
00549 while (first != last) {
00550 ST* st = *first;
00551 Set_ST_base_idx (st, base);
00552 Set_ST_ofst (st, ST_ofst (st) - offset);
00553 ++first;
00554 }
00555 }
00556
00557
00558
00559 struct ST_ITERATOR {
00560 COMMON_BLOCK::const_iterator iter;
00561
00562 ST_ITERATOR (COMMON_BLOCK::const_iterator i) : iter (i) {}
00563
00564 ST* operator* () const {
00565 return (*iter).St ();
00566 }
00567
00568 ST_ITERATOR& operator++ () {
00569 ++iter;
00570 return *this;
00571 }
00572
00573 BOOL operator!= (const ST_ITERATOR& i) const {
00574 return iter != i.iter;
00575 }
00576
00577 };
00578
00579 }
00580
00581
00582
00583 static ST*
00584 Create_Split_Common (COMMON_BLOCK::const_iterator first,
00585 COMMON_BLOCK::const_iterator last,
00586 const SPLIT_GROUP_DESC& desc,
00587 const ST* base)
00588 {
00589 FLD_HANDLE fld = make_fld (ST_ITERATOR (first), ST_ITERATOR (last),
00590 desc.Offset ());
00591
00592 TY_IDX idx;
00593 TY& ty = New_TY (idx);
00594 TY_Init (ty, desc.Size (), KIND_STRUCT, MTYPE_M, 0);
00595 Set_TY_fld (ty, fld);
00596 Set_TY_split (ty);
00597
00598
00599 TY_IDX ty_idx = ST_type (base);
00600 Set_TY_IDX_index (ty_idx, TY_IDX_index (idx));
00601
00602
00603 char name[30];
00604 sprintf (name, ".%lld", desc.Offset ());
00605
00606 ST* split_common = New_ST (GLOBAL_SYMTAB);
00607 ST_Init (split_common, Save_Str2 (ST_name (base), name), CLASS_VAR,
00608 SCLASS_COMMON, ST_export (base), ty_idx);
00609 Set_ST_ofst (split_common, 0);
00610 split_common->flags = base->flags;
00611 split_common->flags_ext = base->flags_ext;
00612 Set_ST_is_split_common (split_common);
00613 Set_ST_full_idx (*split_common, ST_st_idx (base));
00614
00615 Update_element (ST_ITERATOR (first), ST_ITERATOR (last),
00616 ST_st_idx (split_common), desc.Offset ());
00617
00618 return split_common;
00619 }
00620
00621
00622
00623
00624 static void
00625 Fixup_Base (const vector<ST*>& split_common, ST* base)
00626 {
00627 FLD_HANDLE fld = make_fld (split_common.begin (), split_common.end (), 0);
00628
00629 TY_IDX idx;
00630 TY& ty = New_TY (idx);
00631 TY_Init (ty, TY_size (ST_type (base)), KIND_STRUCT, MTYPE_M, 0);
00632 Set_TY_fld (ty, fld);
00633
00634 TY_IDX ty_idx = ST_type (base);
00635 Set_TY_IDX_index (ty_idx, TY_IDX_index (idx));
00636
00637 Set_ST_type (base, ty_idx);
00638 Update_element (split_common.begin (), split_common.end (),
00639 ST_st_idx (base), 0);
00640 }
00641
00642
00643 static void
00644 Fixup_Common (COMMON_BLOCK::const_iterator first,
00645 COMMON_BLOCK::const_iterator last,
00646 const SPLIT_BLOCK& split)
00647 {
00648 ST* base = ST_base ((*first).St ());
00649
00650 vector<ST*> split_common_st;
00651 while (first != last) {
00652 UINT group = (*first).Group ();
00653 COMMON_BLOCK::const_iterator split_pt (first);
00654
00655 while (++split_pt != last && (*split_pt).Group () == group);
00656
00657 ST* split_st =
00658 Create_Split_Common (first, split_pt, split[group], base);
00659 split_common_st.push_back (split_st);
00660
00661 first = split_pt;
00662 }
00663
00664 Fixup_Base (split_common_st, base);
00665 }
00666
00667
00668 namespace {
00669 struct split_common_compare {
00670
00671 bool operator() (const SPLIT_GROUP& g1, const SPLIT_GROUP& g2) const {
00672 if (ST_base_idx (g1.St ()) != ST_base_idx (g2.St ()))
00673 return ST_base_idx (g1.St ()) < ST_base_idx (g2.St ());
00674 if (g1.Offset () != g2.Offset ())
00675 return g1.Offset () < g2.Offset ();
00676 if (g1.Size () != g2.Size ())
00677 return g1.Size () < g2.Size ();
00678 return g1.St () < g2.St ();
00679 }
00680 };
00681 }
00682
00683
00684
00685
00686 static void
00687 Split_Common_Block (const SPLIT_COMMON_DESC& common_desc)
00688 {
00689 COMMON_BLOCK& common_block = *common_desc.common_block;
00690
00691
00692
00693 sort (common_block.begin (), common_block.end (),
00694 split_common_compare ());
00695
00696 COMMON_BLOCK::const_iterator first (common_block.begin ());
00697 COMMON_BLOCK::const_iterator last (common_block.end ());
00698 while (first != last) {
00699 ST_IDX base = ST_base_idx ((*first).St ());
00700 COMMON_BLOCK::const_iterator next_block (first);
00701 while (++next_block != last) {
00702 if (ST_base_idx ((*next_block).St ()) != base)
00703 break;
00704 }
00705 Fixup_Common (first, next_block, *common_desc.split_block);
00706 first = next_block;
00707 }
00708 }
00709
00710
00711
00712
00713 static void
00714 Split_Commons (const SPLIT_COMMON_TBL& split_common_tbl)
00715 {
00716 for (SPLIT_COMMON_TBL::const_iterator iter (split_common_tbl.begin ());
00717 iter != split_common_tbl.end ();
00718 ++iter) {
00719
00720 const SPLIT_COMMON_DESC& common_desc = (*iter).second;
00721 if (common_desc.split_block == NULL)
00722 continue;
00723
00724 Split_Common_Block (common_desc);
00725
00726 }
00727 }
00728
00729 void
00730 INLINE_Split_Common ()
00731 {
00732 CXX_MEM_POOL split_pool ("INLINE_split_pool", 0);
00733
00734 trace_split_common = Get_Trace(TP_INLINE, IPA_SPLIT_COMMON);
00735
00736 SPLIT_COMMON_TBL
00737 split_common_tbl (20, hash<STR_IDX> (), equal_to<STR_IDX> (),
00738 split_pool());
00739
00740 if (Split_Analysis (split_common_tbl, split_pool())) {
00741 Split_Commons (split_common_tbl);
00742 #ifdef Is_True_On
00743 Verify_SYMTAB (GLOBAL_SYMTAB);
00744 #endif
00745 }
00746 }