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
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00086
00087
00088
00089
00090
00091
00092
00093
00094 #ifdef _KEEP_RCS_ID
00095 static char *rcs_id = "$Source: /scratch/mee/2.4-65/kpro64-pending/be/cg/gra_mon/SCCS/s.gra_split.cxx $ $Revision: 1.19 $";
00096 #endif
00097
00098 #ifdef USE_PCH
00099 #include "cg_pch.h"
00100 #endif // USE_PCH
00101 #pragma hdrstop
00102
00103 #include <math.h>
00104 #if 1 // workaround at PathScale for build problem
00105 #include <float.h>
00106 #endif
00107 #include <limits.h>
00108
00109 #include "defs.h"
00110 #include "errors.h"
00111 #include "mempool.h"
00112 #include "bitset.h"
00113 #include "priority_queue.h"
00114 #include "tracing.h"
00115 #include "register.h"
00116 #include "cg.h"
00117 #include "cgir.h"
00118 #include "cg_region.h"
00119 #include "cg_spill.h"
00120 #include "gtn_universe.h"
00121 #include "gtn_set.h"
00122 #include "cg_flags.h"
00123 #include "gra.h"
00124 #include "gra_bb.h"
00125 #include "gra_lunit.h"
00126 #include "gra_lrange.h"
00127 #include "gra_spill.h"
00128 #include "gra_loop.h"
00129 #include "gra_region.h"
00130 #include "gra_trace.h"
00131 #include "gra_interfere.h"
00132 #ifdef TARG_SL //minor_reg_alloc
00133 #include "gra_para_region.h"
00134 #endif
00135
00136 TYPE_PRQ(GRA_BB,GBBPRQ)
00137
00138 #ifdef HAS_STACKED_REGISTERS
00139 extern REGISTER_SET stacked_caller_used;
00140 #endif
00141 #ifdef TARG_IA64
00142 extern BOOL fat_self_recursive;
00143 #endif
00144 BOOL GRA_split_lranges = TRUE;
00145 INT GRA_non_split_tn_id = -1;
00146 #ifdef KEY
00147 BOOL GRA_pu_has_handler = FALSE;
00148 #endif
00149
00150 static LRANGE* split_lrange;
00151 static LRANGE* alloc_lrange;
00152 static LRANGE* deferred_lrange;
00153
00154
00155
00156
00157
00158
00159
00160
00161 static GRA_BB* alloc_gbb_list_head;
00162 static GRA_BB* border_gbb_list_head;
00163 static GBBPRQ gbbprq;
00164 static MEM_POOL prq_pool;
00165 static INT32 lranges_to_pass_count;
00166
00167
00168
00169 static float tot_spill_cost;
00170
00171 static float split_alloc_priority;
00172 static float split_spill_cost;
00173 static float split_restore_cost;
00174
00175 static INT split_lunit_count;
00176
00177
00178
00179 #if 0
00180
00182 static void
00183 Print_Globals(GRA_BB* gbb, ISA_REGISTER_CLASS rc)
00185
00186
00187
00188
00190 {
00191 INTERFERE_ITER iter;
00192
00193 for (iter.Init(gbb->Global_Lranges(rc), gbb->Region()->Subuniverse(rc));
00194 ! iter.Done(); iter.Step()) {
00195 LRANGE* global_lrange = iter.Current();
00196
00197 fprintf(stderr,"TN%d\n",TN_number(LRANGE_tn(global_lrange)));
00198 }
00199 }
00200
00202 static void
00203 Print_Globals_N(INT n, ISA_REGISTER_CLASS rc)
00205
00206
00207
00208
00210 {
00211 BB *bb;
00212
00213 for ( bb = REGION_First_BB; bb != NULL; bb = BB_next(bb) ) {
00214 if ( BB_id(bb) == n )
00215 Print_Globals(GRA_BB_Get(bb),rc);
00216 }
00217 }
00218
00219 #endif
00220
00222 static BOOL
00223 Compare_Frequencies( GRA_BB* gbb0, GRA_BB* gbb1 )
00225
00226
00227
00229 {
00230 return gbb0->Freq() > gbb1->Freq();
00231 }
00232
00234 static void
00235 Initialize_Priority_Queue(void)
00237
00238
00239
00240
00241
00243 {
00244 static BOOL prq_initialized = FALSE;
00245
00246 if ( ! prq_initialized ) {
00247 prq_initialized = TRUE;
00248 MEM_POOL_Initialize(&prq_pool,"GRA BB priority queue for splitting",
00249 FALSE);
00250 }
00251 MEM_POOL_Push(&prq_pool);
00252 GBBPRQ_Initialize(&gbbprq,Compare_Frequencies,NULL,NULL,&prq_pool,
00253 PU_BB_Count+2,
00254 200);
00255 }
00256
00258 static void
00259 Finalize_Priority_Queue(void)
00261
00262
00263
00265 {
00266 MEM_POOL_Pop(&prq_pool);
00267 }
00268
00270 static REGISTER_SET
00271 Regs_Used( TN* tn, GRA_BB* gbb, ISA_REGISTER_CLASS rc, LRANGE* lrange,
00272 BOOL reclaim)
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286 #ifdef KEY
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 #endif
00298 {
00299 REGISTER_SET used = gbb->Registers_Used(rc);
00300
00301 #ifdef TARG_X8664
00302
00303 if (rc == ISA_REGISTER_CLASS_x87 && gbb->mmx_OP())
00304 return REGISTER_CLASS_allocatable(ISA_REGISTER_CLASS_x87);
00305
00306
00307 if (rc == ISA_REGISTER_CLASS_mmx && gbb->x87_OP())
00308 return REGISTER_CLASS_allocatable(ISA_REGISTER_CLASS_mmx);
00309 #endif
00310
00311 #ifdef KEY
00312
00313
00314 if (reclaim) {
00315 REGISTER_SET reclaimable =
00316 REGISTER_SET_Difference(used, gbb->Registers_Referenced(rc));
00317 used = REGISTER_SET_Difference(REGISTER_CLASS_allocatable(rc), reclaimable);
00318 }
00319
00320 if (GRA_optimize_boundary &&
00321 !reclaim) {
00322 REGISTER reg;
00323 if (! lrange->Contains_Internal_BB(gbb)) {
00324
00325
00326
00327 for (reg = REGISTER_SET_Choose(used);
00328 reg != REGISTER_UNDEFINED;
00329 reg = REGISTER_SET_Choose_Next(used, reg)) {
00330 LRANGE_BOUNDARY_BB *boundary_bb = lrange->Get_Boundary_Bb(gbb->Bb());
00331 if (! boundary_bb->Interfere(gbb, rc, reg)) {
00332
00333 used = REGISTER_SET_Difference1(used, reg);
00334 }
00335 }
00336 }
00337 }
00338 #endif
00339
00340 LUNIT* lunit = gbb_mgr.Split_LUNIT(gbb);
00341
00342 if ( lunit != NULL &&
00343 !reclaim) {
00344 REGISTER_SET allowed_prefs = lunit->Allowed_Preferences();
00345
00346 used = REGISTER_SET_Difference(used,allowed_prefs);
00347 }
00348
00349
00350
00351
00352
00353
00354 if (BB_call(gbb->Bb())) {
00355 if (split_lrange->Spans_Infreq_Call() ||
00356 GTN_SET_MemberP(BB_live_out(gbb->Bb()),tn)) {
00357 used = REGISTER_SET_Union(used, REGISTER_CLASS_caller_saves(rc));
00358 #ifdef HAS_STACKED_REGISTERS
00359 #ifdef KEY
00360
00361 FmtAssert(!reclaim,
00362 ("Regs_Used: reclaiming not yet supported for stack regs"));
00363 #endif
00364 if (REGISTER_Has_Stacked_Registers(rc))
00365 used = REGISTER_SET_Union(used, stacked_caller_used);
00366 #endif
00367 if (gbb->Setjmp())
00368 used = REGISTER_SET_Union(used, REGISTER_CLASS_callee_saves(rc));
00369 }
00370 }
00371 if (BB_mod_rotating_registers(gbb->Bb())) {
00372 #ifdef KEY
00373
00374 FmtAssert(!reclaim,
00375 ("Regs_Used: reclaiming not yet supported for rotating regs"));
00376 #endif
00377 used = REGISTER_SET_Union(used, REGISTER_CLASS_rotating(rc));
00378 }
00379 else if (BB_mod_pred_rotating_registers(gbb->Bb()) &&
00380 Is_Predicate_REGISTER_CLASS(rc))
00381 used = REGISTER_SET_Union(used, REGISTER_CLASS_rotating(rc));
00382
00383 #ifdef TARG_SL //minor_reg_alloc
00384
00385 if(BB_rid(gbb->Bb()) && RID_TYPE_minor(BB_rid(gbb->Bb()))) {
00386 RID* rid = BB_rid(gbb->Bb());
00387 GRA_PARA_REGION* region = gra_para_region_mgr.Get(rid);
00388 Is_True((region), ("para region is NULL"));
00389 REGISTER_SET exclude_set = region->Registers_Exclude(rc);
00390 used = REGISTER_SET_Union(used, exclude_set);
00391 }
00392 #endif
00393
00394 return used;
00395 }
00396
00398 static BOOL
00399 Max_Colorable_LUNIT( LUNIT** result, BOOL reclaim )
00401
00402
00403
00404
00405
00407 {
00408 LUNIT* maxlunit;
00409 LRANGE_LUNIT_ITER iter;
00410 BOOL found = FALSE;
00411 ISA_REGISTER_CLASS rc = split_lrange->Rc();
00412 REGISTER_SET all_regs = REGISTER_CLASS_allocatable(rc);
00413 TN* tn = split_lrange->Tn();
00414
00415 if ( split_lrange->Avoid_RA() )
00416 all_regs = REGISTER_SET_Difference1(all_regs,TN_register(RA_TN));
00417
00418 for (iter.Init(split_lrange); ! iter.Done(); iter.Step()) {
00419 REGISTER_SET regs_used;
00420 LUNIT* lunit = iter.Current();
00421
00422
00423 gbb_mgr.Split_LUNIT_Set(lunit->Gbb(), lunit);
00424
00425 regs_used = Regs_Used(tn,lunit->Gbb(),rc,split_lrange, reclaim);
00426
00427
00428
00429
00430
00431
00432
00433 if ( lunit->Has_Exposed_Use() || lunit->Has_Def() ) {
00434 if ( !REGISTER_SET_EmptyP(REGISTER_SET_Difference(all_regs,regs_used)) ) {
00435 if ( ! found || lunit->Priority() > maxlunit->Priority() ) {
00436 found = TRUE;
00437 maxlunit = lunit;
00438 }
00439 }
00440 }
00441 }
00442
00443 *result = maxlunit;
00444 return found;
00445 }
00446
00447
00449 static BOOL
00450 Live_In( GRA_BB* gbb )
00452
00453
00454
00456 {
00457 return GTN_SET_Intersection_MemberP(BB_live_in(gbb->Bb()),
00458 BB_defreach_in(gbb->Bb()),
00459 split_lrange->Tn());
00460 }
00461
00463 static BOOL
00464 Live_Out( GRA_BB* gbb )
00466
00467
00468
00470 {
00471 return GTN_SET_Intersection_MemberP(BB_live_out(gbb->Bb()),
00472 BB_defreach_out(gbb->Bb()),
00473 split_lrange->Tn());
00474 }
00475
00477 static INT
00478 Traverse_Neighbors( GRA_BB_FLOW_NEIGHBOR_ITER* iter, BOOL (*live_fn)(GRA_BB*) )
00480
00481
00482
00483
00484
00486 {
00487
00488 INT not_added_count = 0;
00489 for ( ; ! iter->Done(); iter->Step() ) {
00490 GRA_BB* nbb = iter->Current();
00491 if (live_fn(nbb)) {
00492 if ( !gbb_mgr.Split_In_Alloc_LRANGE(nbb) ) {
00493 not_added_count++;
00494 }
00495 if ( ! gbb_mgr.Split_Queued(nbb) ) {
00496 gbb_mgr.Split_Queued_Set(nbb);
00497 GBBPRQ_Insert(&gbbprq,nbb);
00498 }
00499 }
00500 }
00501 return not_added_count;
00502 }
00503
00505 static bool
00506 Defines_Split_TN(GRA_BB* gbb)
00508
00509
00510
00512 {
00513 LUNIT *lunit = NULL;
00514 (void) split_lrange->Find_LUNIT_For_GBB(gbb, &lunit);
00515 return lunit && lunit->Has_Def();
00516 }
00517
00519 static float
00520 Check_Interior_Predecessor_Spill_Cost(GRA_BB* gbb, float priority)
00522
00523
00524
00525
00526
00527
00528
00530 {
00531 GRA_BB_FLOW_NEIGHBOR_ITER flow_iter;
00532
00533 for (flow_iter.Preds_Init(gbb); ! flow_iter.Done(); flow_iter.Step()) {
00534 GRA_BB* pred = flow_iter.Current();
00535 if (gbb_mgr.Split_In_Alloc_LRANGE(pred)) {
00536 INT border_count = pred->Split_Succ_Border_Count();
00537 LUNIT *p_lunit = NULL;
00538
00539
00540
00541
00542
00543 (void) split_lrange->Find_LUNIT_For_GBB(pred, &p_lunit);
00544 if (pred == gbb || (p_lunit && p_lunit->Spill_Below())) continue;
00545
00546 if (--border_count == 0 && pred->Split_Exit_Count() == 0) {
00547 GRA_Trace_Split_Add_Priority(pred, TRUE);
00548 priority += (pred->Freq() * split_spill_cost);
00549 }
00550 pred->Split_Succ_Border_Count_Set(border_count);
00551 }
00552 }
00553 return priority;
00554 }
00555
00556 #ifdef KEY
00558 static void
00559 Calculate_Interim_Reclaim_Cost(GRA_BB *gbb, BOOL find_spills, float *priority)
00561
00562
00563
00564
00565
00567 {
00568 GRA_BB_FLOW_NEIGHBOR_ITER flow_iter1, flow_iter2;
00569
00570 for (find_spills ? flow_iter1.Preds_Init(gbb) : flow_iter1.Succs_Init(gbb);
00571 ! flow_iter1.Done();
00572 flow_iter1.Step()) {
00573 GRA_BB* gbb1 = flow_iter1.Current();
00574 if (!gbb_mgr.Split_In_Alloc_LRANGE(gbb1)) {
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 BOOL add_spill_restore = TRUE;
00585 for (find_spills ?
00586 flow_iter2.Succs_Init(gbb1) : flow_iter2.Preds_Init(gbb1);
00587 ! flow_iter2.Done();
00588 flow_iter2.Step()) {
00589 GRA_BB* gbb2 = flow_iter2.Current();
00590 if (gbb2 != gbb &&
00591 gbb_mgr.Split_In_Alloc_LRANGE(gbb2)) {
00592
00593 add_spill_restore = FALSE;
00594 break;
00595 }
00596 }
00597
00598 if (add_spill_restore) {
00599 float cost = (gbb1->Freq() *
00600 (find_spills ? split_spill_cost : split_restore_cost));
00601 *priority -= cost;
00602 tot_spill_cost += cost;
00603 GRA_Trace_Split_Reclaim_Sub_Priority(gbb1, find_spills, cost);
00604
00605
00606
00607 if (!find_spills) {
00608 for (flow_iter2.Preds_Init(gbb1);
00609 ! flow_iter2.Done();
00610 flow_iter2.Step()) {
00611 GRA_BB* succ_pred = flow_iter2.Current();
00612 if (succ_pred != gbb &&
00613 !gbb_mgr.Split_In_Alloc_LRANGE(succ_pred)) {
00614 LUNIT *lunit = NULL;
00615
00616 (void) split_lrange->Find_LUNIT_For_GBB(succ_pred, &lunit);
00617 if (!(lunit && lunit->Spill_Below())) {
00618 float cost = (succ_pred->Freq() * split_spill_cost);
00619 *priority -= cost;
00620 tot_spill_cost += cost;
00621 GRA_Trace_Split_Reclaim_Sub_Priority(succ_pred, TRUE,
00622 cost);
00623 }
00624 }
00625 }
00626 }
00627 }
00628 }
00629 }
00630 }
00631
00633 static void
00634 Calculate_Interim_Reclaim_Saving(GRA_BB *gbb, BOOL find_spills, float *priority)
00636
00637
00638
00639
00641 {
00642 GRA_BB_FLOW_NEIGHBOR_ITER flow_iter;
00643
00644
00645
00646 BOOL need_restore = FALSE;
00647 for (flow_iter.Preds_Init(gbb); ! flow_iter.Done(); flow_iter.Step()) {
00648 GRA_BB* pred = flow_iter.Current();
00649 if (!gbb_mgr.Split_In_Alloc_LRANGE(pred)) {
00650 need_restore = TRUE;
00651 break;
00652 }
00653 }
00654 if (!need_restore) {
00655 float cost = (gbb->Freq() * split_restore_cost);
00656 *priority += cost;
00657 tot_spill_cost -= cost;
00658 GRA_Trace_Split_Reclaim_Add_Priority(gbb, FALSE, cost);
00659 }
00660
00661
00662
00663 BOOL need_spill = FALSE;
00664 for (flow_iter.Succs_Init(gbb); ! flow_iter.Done(); flow_iter.Step()) {
00665 GRA_BB* succ = flow_iter.Current();
00666 if (!gbb_mgr.Split_In_Alloc_LRANGE(succ)) {
00667 need_spill = TRUE;
00668 break;
00669 }
00670 }
00671 if (!need_spill) {
00672 float cost = (gbb->Freq() * split_spill_cost);
00673 *priority += cost;
00674 tot_spill_cost -= cost;
00675 GRA_Trace_Split_Reclaim_Add_Priority(gbb, TRUE, cost);
00676 }
00677 }
00678 #endif // KEY
00679
00681 static void
00682 Calculate_Interim_Split_Priority(GRA_BB* gbb, INT spills_needed,
00683 INT restores_needed, BOOL reclaim)
00685
00686
00687
00688
00689
00690
00691
00692
00694 {
00695 float priority = 0.0;
00696 float freq = gbb->Freq();
00697 LUNIT *lunit = NULL;
00698 GRA_BB_FLOW_NEIGHBOR_ITER flow_iter;
00699
00700
00701
00702
00703 (void) split_lrange->Find_LUNIT_For_GBB(gbb, &lunit);
00704 if (lunit) {
00705 split_lunit_count++;
00706 }
00707 gbb->Split_Lunit_Count_Set(split_lunit_count);
00708
00709
00710
00711
00712
00713
00714
00715 if (spills_needed || gbb->Split_Succ_Border_Count() > 0 ||
00716 (lunit && lunit->Spill_Below())) {
00717 gbb->Split_Exit_Count_Set(spills_needed);
00718 if (!Defines_Split_TN(gbb)) {
00719 GRA_Trace_Split_Sub_Priority(gbb, TRUE);
00720 float cost = (freq * split_spill_cost);
00721 priority -= cost;
00722 tot_spill_cost += cost;
00723 }
00724 }
00725
00726
00727
00728
00729
00730 if ((restores_needed && Live_In(gbb)) ||
00731 (lunit && lunit->Restore_Above())) {
00732 gbb->Split_Entry_Count_Set(restores_needed);
00733 if (!(lunit && lunit->Has_Exposed_Use())) {
00734 float cost = (freq * split_restore_cost);
00735 priority -= cost;
00736 tot_spill_cost += cost;
00737 GRA_Trace_Split_Sub_Priority(gbb, FALSE);
00738 }
00739 } else if (lunit && lunit->Has_Exposed_Use()) {
00740 priority += (freq * split_restore_cost);
00741 GRA_Trace_Split_Add_Priority(gbb, FALSE);
00742 }
00743
00744
00745
00746
00747
00748 if (Live_In(gbb)) {
00749 for (flow_iter.Preds_Init(gbb); ! flow_iter.Done(); flow_iter.Step()) {
00750 GRA_BB* pred = flow_iter.Current();
00751 INT border_count = pred->Split_Succ_Border_Count();
00752 LUNIT *p_lunit = NULL;
00753
00754
00755
00756
00757
00758 (void) split_lrange->Find_LUNIT_For_GBB(pred, &p_lunit);
00759 if (pred == gbb || (p_lunit && p_lunit->Spill_Below())) continue;
00760
00761 if (restores_needed) {
00762 pred->Split_Succ_Border_Count_Set(++border_count);
00763 }
00764 if (gbb_mgr.Split_In_Alloc_LRANGE(pred)) {
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774 if (pred->Split_Exit_Count() == 1) {
00775 if (border_count == 0) {
00776 float cost = (pred->Freq() * split_spill_cost);
00777 priority += cost;
00778 tot_spill_cost -= cost;
00779 GRA_Trace_Split_Add_Priority(pred, TRUE);
00780 }
00781 pred->Split_Exit_Count_Set(0);
00782 } else {
00783 pred->Split_Exit_Count_Set(pred->Split_Exit_Count() - 1);
00784 }
00785 }
00786 }
00787 }
00788
00789
00790 if (Live_Out(gbb)) {
00791 for (flow_iter.Succs_Init(gbb); ! flow_iter.Done(); flow_iter.Step()) {
00792 GRA_BB* succ = flow_iter.Current();
00793 LUNIT *s_lunit = NULL;
00794
00795
00796
00797
00798
00799 (void) split_lrange->Find_LUNIT_For_GBB(succ, &s_lunit);
00800 if (succ == gbb || (s_lunit && s_lunit->Restore_Above())) continue;
00801
00802 if (gbb_mgr.Split_In_Alloc_LRANGE(succ)) {
00803
00804
00805
00806
00807
00808
00809
00810 if (succ->Split_Entry_Count() == 1) {
00811 succ->Split_Entry_Count_Set(0);
00812 if (Live_In(succ)) {
00813 float cost = (succ->Freq() * split_restore_cost);
00814 priority += cost;
00815 tot_spill_cost -= cost;
00816 GRA_Trace_Split_Add_Priority(succ, FALSE);
00817 priority = Check_Interior_Predecessor_Spill_Cost(succ, priority);
00818 }
00819 } else {
00820 succ->Split_Entry_Count_Set(succ->Split_Entry_Count()-1);
00821 }
00822 }
00823 }
00824 }
00825
00826 #ifdef KEY
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837 if (reclaim) {
00838
00839 Calculate_Interim_Reclaim_Cost(gbb, FALSE, &priority);
00840
00841
00842 Calculate_Interim_Reclaim_Cost(gbb, TRUE, &priority);
00843
00844
00845
00846
00847
00848 Calculate_Interim_Reclaim_Saving(gbb, FALSE, &priority);
00849 }
00850 #endif
00851
00852
00853 split_alloc_priority += priority;
00854
00855 gbb->Split_Priority_Set(split_alloc_priority);
00856 gbb->Split_Spill_Cost_Set(tot_spill_cost);
00857 GRA_Trace_Split(1,"Split%spriority after adding BB:%d is %f\n",
00858 reclaim ? " (with reclaim) " : " ",
00859 BB_id(gbb->Bb()), split_alloc_priority);
00860 }
00861
00863 static void
00864 Add_To_Colorable_Neighborhood( GRA_BB* gbb, BOOL reclaim )
00866
00867
00868
00869
00870
00872 {
00873 GRA_BB_FLOW_NEIGHBOR_ITER flow_iter;
00874 INT spills_needed;
00875 INT restores_needed;
00876
00877 gbb_mgr.Split_In_Alloc_LRANGE_Set(gbb);
00878 alloc_gbb_list_head = alloc_gbb_list_head->Split_List_Push(gbb);
00879 GRA_Trace_Split(1,"BB:%d in alloc LRANGE",BB_id(gbb->Bb()));
00880
00881
00882 flow_iter.Succs_Init(gbb);
00883 spills_needed = Traverse_Neighbors(&flow_iter,Live_In);
00884 flow_iter.Preds_Init(gbb);
00885 restores_needed = Traverse_Neighbors(&flow_iter,Live_Out);
00886
00887 Calculate_Interim_Split_Priority(gbb, spills_needed, restores_needed,
00888 reclaim);
00889
00890 }
00891
00893 static BOOL
00894 Avoid_Unit_Spill(GRA_BB* gbb, REGISTER_SET allowed_regs,
00895 REGISTER_SET regs_used, REGISTER_SET *loop_allowed,
00896 ISA_REGISTER_CLASS rc, GRA_LOOP *maxloop, BOOL reclaim)
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00909 {
00910 GRA_BB_FLOW_NEIGHBOR_ITER iter;
00911 GRA_LOOP *gloop;
00912 BOOL is_prolog = FALSE;
00913 BOOL region_entry = gbb->Is_Region_Entry_Block();
00914 BOOL region_boundry = region_entry || gbb->Region_Epilog();
00915
00916 if (!GRA_loop_splitting && !region_boundry) {
00917 return FALSE;
00918 }
00919
00920 gloop = gbb->Loop();
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930 if (gloop != NULL && maxloop != NULL && gloop != maxloop &&
00931 !region_boundry &&
00932 gloop->Outermost() == maxloop->Outermost()) {
00933 GRA_LOOP *loop;
00934 for (loop = maxloop; loop != NULL && loop != gloop; loop = loop->Parent());
00935 if (loop != NULL) {
00936 return FALSE;
00937 }
00938 }
00939
00940
00941
00942
00943
00944
00945
00946 if ((gloop != NULL && gloop->Loop_Head() == gbb->Bb() &&
00947 !gbb->Is_Region_Block(FALSE)) || region_entry ) {
00948
00949
00950
00951 if ( Live_In(gbb)) {
00952 is_prolog = TRUE;
00953 *loop_allowed = REGISTER_SET_Difference(allowed_regs, regs_used);
00954 if (region_entry) {
00955 GRA_REGION *region = gbb->Region();
00956 *loop_allowed = REGISTER_SET_Difference(*loop_allowed,
00957 region->Registers_Used(rc));
00958 } else {
00959 REGISTER_SET unavailable = gloop->Registers_Used(rc);
00960 #ifdef KEY
00961
00962
00963
00964 if (reclaim) {
00965 unavailable =
00966 REGISTER_SET_Intersection(unavailable,
00967 gloop->Registers_Referenced(rc));
00968 }
00969 #endif
00970 *loop_allowed = REGISTER_SET_Difference(*loop_allowed, unavailable);
00971 }
00972 if (REGISTER_SET_EmptyP(*loop_allowed)) {
00973 return(TRUE);
00974 }
00975 }
00976 }
00977
00978
00979
00980
00981
00982 if ((gbb->Loop_Epilog() && !gbb->Is_Region_Block(FALSE)) ||
00983 gbb->Region_Epilog()) {
00984 if (!is_prolog) {
00985 *loop_allowed = REGISTER_SET_Difference(allowed_regs, regs_used);
00986 }
00987 for (iter.Preds_Init(gbb); ! iter.Done(); iter.Step()) {
00988 GRA_BB* pred = iter.Current();
00989 gloop = pred->Loop();
00990
00991 if (gbb->Region_Epilog() && pred->Is_Region_Block(FALSE)) {
00992 GRA_REGION *region = pred->Region();
00993 *loop_allowed =
00994 REGISTER_SET_Difference(*loop_allowed, region->Registers_Used(rc));
00995 if (REGISTER_SET_EmptyP(*loop_allowed)) {
00996 return(TRUE);
00997 }
00998 } else {
00999
01000
01001 if (gloop != NULL && Live_Out(pred)) {
01002 *loop_allowed = REGISTER_SET_Difference(*loop_allowed,
01003 gloop->Registers_Used(rc));
01004 if (REGISTER_SET_EmptyP(*loop_allowed)) {
01005 return(TRUE);
01006 }
01007 }
01008 }
01009 }
01010 }
01011 return(FALSE);
01012 }
01013
01015 static INT32
01016 Identify_Max_Colorable_Neighborhood( LUNIT* lunit, BOOL reclaim )
01018
01019
01020
01021
01022
01024 {
01025 INT32 count = 1;
01026 ISA_REGISTER_CLASS rc = split_lrange->Rc();
01027 REGISTER_SET allowed_regs = REGISTER_CLASS_allocatable(rc);
01028 TN* tn = split_lrange->Tn();
01029 LRANGE_LIVE_GBB_ITER iter;
01030
01031
01032
01033
01034 for (iter.Init(split_lrange); ! iter.Done(); iter.Step()) {
01035 GRA_BB* gbb = iter.Current();
01036 gbb->Split_Priority_Set(0.0);
01037 gbb->Split_Entry_Count_Set(0);
01038 gbb->Split_Exit_Count_Set(0);
01039 gbb->Split_Succ_Border_Count_Set(0);
01040 gbb->Split_Lunit_Count_Set(0);
01041 }
01042
01043
01044
01045
01046 split_lunit_count = 0;
01047
01048 if ( split_lrange->Type() != LRANGE_TYPE_LOCAL
01049 && TN_is_save_reg(split_lrange->Tn())
01050 ) {
01051 REGISTER sv_reg = TN_save_reg(split_lrange->Tn());
01052 REGISTER_SET singleton = REGISTER_SET_Union1(REGISTER_SET_EMPTY_SET,sv_reg);
01053 allowed_regs = REGISTER_SET_Intersection(allowed_regs,singleton);
01054 }
01055 else if ( split_lrange->Avoid_RA() ) {
01056 allowed_regs = REGISTER_SET_Difference1(allowed_regs,TN_register(RA_TN));
01057 }
01058
01059 Initialize_Priority_Queue();
01060 border_gbb_list_head = NULL;
01061 alloc_gbb_list_head = NULL;
01062 split_alloc_priority = 0.0;
01063 tot_spill_cost = 0.0;
01064 gbb_mgr.Split_Queued_Set(lunit->Gbb());
01065 Add_To_Colorable_Neighborhood(lunit->Gbb(), reclaim);
01066 allowed_regs =
01067 REGISTER_SET_Difference(allowed_regs,Regs_Used(tn,lunit->Gbb(),rc,
01068 split_lrange, reclaim));
01069
01070 while ( GBBPRQ_Size(&gbbprq) > 0 ) {
01071 GRA_BB* gbb = GBBPRQ_Delete_Top(&gbbprq);
01072 REGISTER_SET regs_used = Regs_Used(tn,gbb,rc, split_lrange, reclaim);
01073 REGISTER_SET loop_allowed = REGISTER_SET_EMPTY_SET;
01074
01075 if ( REGISTER_SET_EmptyP(REGISTER_SET_Difference(allowed_regs,regs_used)) ||
01076 Avoid_Unit_Spill(gbb, allowed_regs, regs_used, &loop_allowed, rc,
01077 lunit->Gbb()->Loop(), reclaim) ) {
01078 border_gbb_list_head = border_gbb_list_head->Split_List_Push(gbb);
01079 GRA_Trace_Split(1,"BB:%d in deferred border",BB_id(gbb->Bb()));
01080 }
01081 else {
01082
01083
01084
01085
01086 if (!REGISTER_SET_EmptyP(loop_allowed)) {
01087 allowed_regs = loop_allowed;
01088 } else {
01089 allowed_regs = REGISTER_SET_Difference(allowed_regs,regs_used);
01090 }
01091 Add_To_Colorable_Neighborhood(gbb, reclaim);
01092 ++count;
01093 }
01094 }
01095 Finalize_Priority_Queue();
01096 return count;
01097 }
01098
01100 static void
01101 Divide_LRANGE(void)
01103
01104
01105
01106
01108 {
01109 LRANGE_LUNIT_ITER iter;
01110
01111 deferred_lrange = split_lrange;
01112 alloc_lrange = lrange_mgr.Create_Duplicate(split_lrange);
01113
01114 GRA_Trace_Split(0,"Divide_LRANGE TN%d split from TN%d",
01115 TN_number(alloc_lrange->Tn()), TN_number(deferred_lrange->Tn()));
01116
01117
01118
01119
01120 iter.Init(split_lrange);
01121 split_lrange->First_Lunit_Reset();
01122
01123 for ( ; ! iter.Done(); iter.Step()) {
01124 LUNIT* lunit = iter.Current();
01125
01126 if ( gbb_mgr.Split_In_Alloc_LRANGE(lunit->Gbb()) ) {
01127 alloc_lrange->Add_LUNIT(lunit);
01128 GRA_Trace_Split(1,"BB%d with LUNIT in alloc_lrange",
01129 BB_id(lunit->Gbb()->Bb()));
01130 } else {
01131 deferred_lrange->Add_LUNIT(lunit);
01132 GRA_Trace_Split(1,"BB%d with LUNIT in deferred_lrange",
01133 BB_id(lunit->Gbb()->Bb()));
01134 }
01135 }
01136 }
01137
01139 static LUNIT*
01140 Get_Possibly_Add_LUNIT( GRA_BB* gbb )
01142
01143
01144
01145
01147 {
01148 LUNIT *lunit = gbb_mgr.Split_LUNIT(gbb);
01149
01150 if ( lunit == NULL ) {
01151 if ( gbb_mgr.Split_In_Alloc_LRANGE(gbb) )
01152 lunit = LUNIT_Create(alloc_lrange,gbb);
01153 else
01154 lunit = LUNIT_Create(deferred_lrange,gbb);
01155
01156 gbb_mgr.Split_LUNIT_Set(gbb, lunit);
01157 lunit->Split_Lunit_Set();
01158 }
01159
01160 return lunit;
01161 }
01162
01164 static void
01165 Split_Store( GRA_BB* gbb )
01167
01168
01169
01170
01172 {
01173
01174
01175
01176
01177
01178
01179 if ( ! gbb_mgr.Split_Has_Store(gbb) ) {
01180 LUNIT* lunit = Get_Possibly_Add_LUNIT(gbb);
01181
01182 gbb_mgr.Split_Has_Store_Set(gbb);
01183 GRA_Note_Save_Below(lunit);
01184 }
01185 }
01186
01188 static void
01189 Split_Load( GRA_BB* gbb )
01191
01192
01193
01194
01195
01196
01197
01199 {
01200 GRA_BB_FLOW_NEIGHBOR_ITER iter;
01201
01202 if ( ! gbb_mgr.Split_Has_Load(gbb) ) {
01203 LUNIT *lunit = Get_Possibly_Add_LUNIT(gbb);
01204 LRANGE *lrange = lunit->Lrange();
01205
01206 gbb_mgr.Split_Has_Load_Set(gbb);
01207
01208 for (iter.Preds_Init(gbb); ! iter.Done(); iter.Step()) {
01209 GRA_BB* pred_bb = iter.Current();
01210 if ( Live_Out(pred_bb) )
01211 Split_Store(pred_bb);
01212 }
01213
01214 gbb->Remove_Live_In_LRANGE(split_lrange);
01215
01216 GRA_Note_Restore_Above(lunit);
01217 }
01218 }
01219
01221
01222 static void
01223 Split_Load_GBB( GRA_BB* gbb, GRA_BB* neighbor )
01225
01226
01227
01228
01229
01231 {
01232 Split_Load(gbb);
01233 }
01234
01236
01237 static void
01238 Split_Load_Neighbor( GRA_BB* gbb, GRA_BB* neighbor )
01240
01241
01242
01243
01244
01246 {
01247 Split_Load(neighbor);
01248 }
01249
01251 static void
01252 Find_Border_Transitions( GRA_BB* gbb,
01253 GRA_BB_FLOW_NEIGHBOR_ITER* iter,
01254 void (gbb_neighbor_fn)(GRA_BB*, GRA_BB*)
01255 )
01257
01258
01259
01260
01261
01263 {
01264 for ( ; ! iter->Done(); iter->Step()) {
01265 GRA_BB* neighbor = iter->Current();
01266
01267 if ( gbb_mgr.Split_In_Alloc_LRANGE(neighbor) ) {
01268
01269 gbb_neighbor_fn(gbb,neighbor);
01270 }
01271 }
01272 }
01273
01275 static void
01276 Add_Spills_And_Restores(void)
01278
01279
01280
01281
01283 {
01284 GRA_BB_SPLIT_LIST_ITER iter;
01285 GRA_BB_FLOW_NEIGHBOR_ITER flow_iter;
01286
01287 for (iter.Init(border_gbb_list_head); ! iter.Done(); iter.Step()) {
01288 GRA_BB* gbb = iter.Current();
01289
01290
01291
01292
01293
01294 if (BB_live_in(gbb->Bb())) {
01295 flow_iter.Preds_Init(gbb);
01296 Find_Border_Transitions(gbb,&flow_iter,Split_Load_GBB);
01297 }
01298
01299
01300
01301
01302
01303
01304 flow_iter.Succs_Init(gbb);
01305 Find_Border_Transitions(gbb,&flow_iter,Split_Load_Neighbor);
01306 }
01307 }
01308
01310 #ifndef KEY
01311 static
01312 #endif
01313 BOOL
01314 Has_Live_In_Successor( GRA_BB* gbb, LRANGE* lrange )
01316
01317
01318
01320 {
01321 GRA_BB_FLOW_NEIGHBOR_ITER iter;
01322
01323 for (iter.Succs_Init(gbb); ! iter.Done(); iter.Step()) {
01324 GRA_BB* succ = iter.Current();
01325
01326 if ( succ->Is_Live_In_LRANGE(lrange) )
01327 return TRUE;
01328 }
01329
01330 return FALSE;
01331 }
01332
01334 static void
01335 Fix_TN_Live_Out_Info( GRA_BB* gbb_list_head, LRANGE* old_lrange,
01336 LRANGE* new_lrange )
01338
01339
01340
01341
01342
01344 {
01345 GRA_BB_SPLIT_LIST_ITER iter;
01346
01347 for (iter.Init(gbb_list_head); ! iter.Done(); iter.Step()) {
01348 GRA_BB* gbb = iter.Current();
01349
01350 if ( gbb->Is_Live_Out_LRANGE(old_lrange) ) {
01351 gbb->Remove_Live_Out_LRANGE(old_lrange);
01352
01353 if (! gbb_mgr.Split_Has_Store(gbb) ||
01354 Has_Live_In_Successor(gbb,old_lrange) ) {
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367 gbb->Add_Live_Out_LRANGE(new_lrange);
01368 }
01369 }
01370 }
01371 }
01372
01374 static void
01375 Fix_TN_Live_Info(void)
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01391 {
01392 GRA_BB_SPLIT_LIST_ITER iter;
01393
01394 TN *split_tn = split_lrange->Tn();
01395 TN *alloc_tn = alloc_lrange->Tn();
01396 TN *deferred_tn = deferred_lrange->Tn();
01397
01398 Fix_TN_Live_Out_Info(alloc_gbb_list_head,split_lrange,alloc_lrange);
01399 Fix_TN_Live_Out_Info(border_gbb_list_head,split_lrange,deferred_lrange);
01400
01401 for (iter.Init(alloc_gbb_list_head); ! iter.Done(); iter.Step()) {
01402 GRA_BB* gbb = iter.Current();
01403
01404 if ( gbb->Is_Live_In_LRANGE(split_lrange) ) {
01405 gbb->Remove_Live_In_LRANGE(split_lrange);
01406 gbb->Add_Live_In_LRANGE(alloc_lrange);
01407 }
01408
01409 GTN_SET_Difference1D(gbb->Needs_A_Register(),split_tn);
01410 gbb->Needs_A_Register_Set(GTN_SET_Union1D(gbb->Needs_A_Register(), alloc_tn,
01411 GRA_pool));
01412 }
01413 }
01414
01416 static void
01417 Rename_TN_References(void)
01419
01420
01421
01423 {
01424 LRANGE_LUNIT_ITER iter;
01425 TN* split_tn = split_lrange->Tn();
01426 TN* alloc_tn = alloc_lrange->Tn();
01427
01428 for (iter.Init(alloc_lrange); ! iter.Done(); iter.Step()) {
01429 LUNIT* lunit = iter.Current();
01430 GRA_BB* gbb = lunit->Gbb();
01431
01432 gbb->Rename_TN_References(split_tn,alloc_tn);
01433 }
01434 }
01435
01437 static void
01438 Calculate_Live_BB_Sets(void)
01440
01441
01442
01443
01444
01446 {
01447 GRA_BB_SPLIT_LIST_ITER iter;
01448
01449
01450
01451
01452
01453 for (iter.Init(alloc_gbb_list_head); ! iter.Done(); iter.Step()) {
01454 GRA_BB* gbb = iter.Current();
01455
01456 alloc_lrange->Add_Live_BB(gbb);
01457 deferred_lrange->Remove_Live_BB(gbb);
01458 }
01459 }
01460
01462 static void
01463 Fix_Local_Interference(void)
01465
01466
01467
01468
01469
01471 {
01472 GRA_BB_SPLIT_LIST_ITER iter;
01473
01474
01475
01476
01477
01478 for (iter.Init(alloc_gbb_list_head); !iter.Done(); iter.Step()) {
01479 GRA_BB* gbb = iter.Current();
01480 gbb->Replace_Global_Interference(split_lrange,alloc_lrange);
01481 }
01482 }
01483
01485 static GTN_SET*
01486 Calculate_Interfering_GTNs( LRANGE* lrange )
01488
01489
01490
01492 {
01493 GTN_SET* result = GTN_SET_Create_Empty(GTN_UNIVERSE_size,&MEM_local_nz_pool);
01494
01495 LRANGE_LIVE_GBB_ITER iter;
01496 for (iter.Init(lrange); ! iter.Done(); iter.Step()) {
01497 GRA_BB *live_gbb = iter.Current();
01498
01499 result = GTN_SET_UnionD(result,live_gbb->Needs_A_Register(),
01500 &MEM_local_nz_pool);
01501 }
01502
01503 return result;
01504 }
01505
01507 static BOOL
01508 Interferes( LRANGE* lrange0, GTN_SET* interfering_gtns, LRANGE* lrange1 )
01510
01511
01512
01513
01514
01516 {
01517 if ( lrange1->Type() == LRANGE_TYPE_COMPLEMENT )
01518 return GTN_SET_MemberP(interfering_gtns, lrange1->Tn());
01519 else
01520 return lrange0->Interferes(lrange1);
01521 }
01522
01523
01525 static void
01526 Fix_Interference(void)
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01560 {
01561 LRANGE_NEIGHBOR_ITER iter;
01562 GTN_SET* alloc_interfering_gtns;
01563 GTN_SET* deferred_interfering_gtns;
01564 GRA_REGION* cregion = gra_region_mgr.Complement_Region();
01565 ISA_REGISTER_CLASS rc = split_lrange->Rc();
01566 REGISTER_SET neighbor_used = REGISTER_SET_EMPTY_SET;
01567
01568 MEM_POOL_Push(&MEM_local_nz_pool);
01569
01570 Calculate_Live_BB_Sets();
01571
01572 alloc_interfering_gtns = Calculate_Interfering_GTNs(alloc_lrange);
01573 deferred_interfering_gtns = Calculate_Interfering_GTNs(deferred_lrange);
01574
01575 deferred_lrange->Calculate_Priority();
01576 lrange_mgr.Clear_One_Set();
01577
01578 lranges_to_pass_count = 0;
01579
01580 lrange_mgr.Begin_Complement_Interference(alloc_lrange);
01581
01582 GRA_Trace_Split(1,"fix interference for TN%d with %d neighbors",TN_number(split_lrange->Tn()),
01583 split_lrange->Neighbors_Left());
01584
01585 for (iter.Init(split_lrange,gra_region_mgr.Complement_Region());
01586 !iter.Done(); iter.Step()) {
01587 LRANGE* neighbor = iter.Current();
01588
01589 if ( ! Interferes(deferred_lrange,deferred_interfering_gtns,neighbor) ) {
01590 deferred_lrange->Remove_Neighbor(neighbor,cregion);
01591 neighbor->Remove_Neighbor(deferred_lrange,cregion);
01592 }
01593 else if ( neighbor->Allocated() ) {
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603 if ( REGISTER_SET_MemberP(neighbor_used, neighbor->Reg()) )
01604 deferred_lrange->Neighbors_Left_Decrement();
01605 else {
01606 neighbor_used = REGISTER_SET_Union1(neighbor_used, neighbor->Reg());
01607 }
01608 }
01609 else if ( neighbor->Spilled() ) {
01610 deferred_lrange->Neighbors_Left_Decrement();
01611 }
01612 else if ( Interferes(alloc_lrange,alloc_interfering_gtns,neighbor) ) {
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628 neighbor->Neighbors_Left_Increment();
01629
01630 if (neighbor->Neighbors_Left() + 1 >= neighbor->Candidate_Reg_Count()
01631 && neighbor->Priority() > deferred_lrange->Priority()
01632 ) {
01633 lrange_mgr.One_Set_Union1(neighbor);
01634 ++lranges_to_pass_count;
01635 }
01636 }
01637
01638 if ( Interferes(alloc_lrange,alloc_interfering_gtns,neighbor) )
01639 lrange_mgr.Complement_Interference(neighbor);
01640 }
01641
01642 lrange_mgr.End_Complement_Interference();
01643
01644 Fix_Local_Interference();
01645
01646 MEM_POOL_Pop(&MEM_local_nz_pool);
01647 }
01648
01650 static void
01651 Add_Deferred_To_Coloring_List( LRANGE_CLIST_ITER* client_iter )
01653
01654
01655
01656
01657
01658
01659
01660
01661
01663 {
01664 LRANGE_CLIST_ITER dup_iter;
01665
01666 #ifdef KEY
01667 for (dup_iter.Init_Following(client_iter);
01668 !dup_iter.Done();
01669 dup_iter.Step()) {
01670 LRANGE* lrange = dup_iter.Current();
01671 if (deferred_lrange->Priority() > lrange->Priority()) {
01672 dup_iter.Push(deferred_lrange);
01673 return;
01674 }
01675 }
01676 dup_iter.Push(deferred_lrange);
01677 #else
01678 if ( lranges_to_pass_count == 0 ) {
01679 client_iter->Splice(deferred_lrange);
01680 return;
01681 }
01682
01683 for (dup_iter.Init_Following(client_iter); ; dup_iter.Step()) {
01684 LRANGE* lrange = dup_iter.Current();
01685
01686 if ( lrange->Interferes(deferred_lrange) ) {
01687 lrange->Neighbors_Left_Decrement();
01688 deferred_lrange->Neighbors_Left_Increment();
01689
01690 if ( lrange_mgr.One_Set_MemberP(lrange) ) {
01691 if ( --lranges_to_pass_count == 0 ) {
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711 dup_iter.Splice(deferred_lrange);
01712 return;
01713 }
01714 }
01715 }
01716 }
01717 #endif
01718 }
01719
01721 static void
01722 Fix_Call_Info( LRANGE* lrange )
01724
01725
01726
01727
01728
01729
01731 {
01732
01733 class LRANGE_LIVE_CALL_GBB_ITER {
01734 BB_SET *set;
01735 BB *current;
01736 public:
01737 LRANGE_LIVE_CALL_GBB_ITER(void) {}
01738 ~LRANGE_LIVE_CALL_GBB_ITER(void) {}
01739
01740 void Init(LRANGE *lrange) {
01741 Is_True(lrange->Type() == LRANGE_TYPE_COMPLEMENT,
01742 ("Iterating over the live_gbbs of a non-complement LRANGE"));
01743 set = lrange->Live_BB_Set();
01744 current = BB_SET_Intersection_Choose(set, gbb_mgr.Blocks_With_Calls());
01745 }
01746 BOOL Done(void) { return current == BB_SET_CHOOSE_FAILURE; }
01747 GRA_BB *Current(void) { return gbb_mgr.Get(current); }
01748 void Step(void) { current = BB_SET_Intersection_Choose_Next(set,
01749 gbb_mgr.Blocks_With_Calls(), current); }
01750 } iter;
01751
01752 lrange->Spans_A_Call_Reset();
01753 lrange->Spans_Infreq_Call_Reset();
01754
01755 for (iter.Init(lrange); ! iter.Done(); iter.Step()) {
01756 GRA_BB* gbb = iter.Current();
01757
01758 if ( gbb != NULL
01759 && gbb->Region() == gra_region_mgr.Complement_Region()
01760 && GTN_SET_MemberP(BB_live_out(gbb->Bb()), lrange->Tn())
01761 ) {
01762 lrange->Spans_A_Call_Set();
01763
01764 if (gbb->Setjmp())
01765 lrange->Spans_A_Setjmp_Set();
01766 #ifdef TARG_X8664
01767 if (gbb->Savexmms())
01768 lrange->Spans_Savexmms_Set();
01769 #endif
01770 return;
01771 }
01772 }
01773 }
01774
01776 static void
01777 Fix_Rot_Reg_Clob_Info( LRANGE* lrange )
01779
01780
01781
01782
01784 {
01785
01786 class LRANGE_ROT_REG_CLOB_BB_ITER {
01787 private:
01788 BB_SET *set;
01789 BB *current;
01790 public:
01791 LRANGE_ROT_REG_CLOB_BB_ITER(void) {}
01792 ~LRANGE_ROT_REG_CLOB_BB_ITER(void) {}
01793
01794 void Init(LRANGE *lrange) { set = lrange->Live_BB_Set();
01795 current = BB_SET_Intersection_Choose(set,
01796 gbb_mgr.Blocks_With_Rot_Reg_Clob()); }
01797 BOOL Done(void) { return current == BB_SET_CHOOSE_FAILURE; }
01798 BB *Current(void) { return current; }
01799 void Step(void) { current = BB_SET_Intersection_Choose_Next(set,
01800 gbb_mgr.Blocks_With_Rot_Reg_Clob(),
01801 current); }
01802 } iter;
01803
01804 lrange->Spans_Rot_Reg_Clob_Reset();
01805
01806 for (iter.Init(lrange); !iter.Done(); iter.Step()) {
01807 BB *bb = iter.Current();
01808 if (BB_mod_rotating_registers(bb)) {
01809 lrange->Spans_Rot_Reg_Clob_Set();
01810 return;
01811 }
01812 else if (BB_mod_pred_rotating_registers(bb) &&
01813 Is_Predicate_REGISTER_CLASS(lrange->Rc())) {
01814 lrange->Spans_Rot_Reg_Clob_Set();
01815 return;
01816 }
01817 }
01818 }
01819
01820 #ifdef TARG_X8664
01822 static void
01823 Fix_x86_Info( LRANGE* lrange )
01825
01826
01827
01829 {
01830
01831 lrange->Spans_x87_OP_Reset();
01832 if (BB_SET_Intersection_Choose(lrange->Live_BB_Set(),
01833 gbb_mgr.Blocks_With_x87_OP())
01834 != BB_SET_CHOOSE_FAILURE) {
01835 lrange->Spans_x87_OP_Set();
01836 }
01837
01838
01839 lrange->Spans_mmx_OP_Reset();
01840 if (BB_SET_Intersection_Choose(lrange->Live_BB_Set(),
01841 gbb_mgr.Blocks_With_mmx_OP())
01842 != BB_SET_CHOOSE_FAILURE) {
01843 lrange->Spans_mmx_OP_Set();
01844 }
01845 }
01846 #endif
01847
01848 #ifdef KEY
01850 static void
01851 Make_Boundary_BBs_At_Border(GRA_BB* border_gbb, GRA_BB* alloc_gbb)
01853
01854
01855
01856
01858 {
01859
01860 if (deferred_lrange->Contains_Internal_BB(border_gbb)) {
01861 deferred_lrange->Remove_Internal_BB(border_gbb);
01862 deferred_lrange->Add_Boundary_BB(border_gbb);
01863 }
01864
01865
01866 if (alloc_lrange->Contains_Internal_BB(alloc_gbb)) {
01867 alloc_lrange->Remove_Internal_BB(alloc_gbb);
01868 alloc_lrange->Add_Boundary_BB(alloc_gbb);
01869 }
01870 }
01871
01873 static void
01874 Fix_Boundary_BBs(void)
01876
01877
01878
01879
01880
01882 {
01883 GRA_BB_SPLIT_LIST_ITER iter;
01884 GRA_BB_FLOW_NEIGHBOR_ITER flow_iter;
01885
01886
01887
01888 for (iter.Init(alloc_gbb_list_head); ! iter.Done(); iter.Step()) {
01889 GRA_BB* gbb = iter.Current();
01890
01891 if (deferred_lrange->Contains_Internal_BB(gbb)) {
01892
01893
01894
01895 alloc_lrange->Add_Internal_BB(gbb);
01896 deferred_lrange->Remove_Internal_BB(gbb);
01897 } else {
01898
01899
01900 LRANGE_BOUNDARY_BB* boundary_bb =
01901 deferred_lrange->Remove_Boundary_Bb(gbb->Bb());
01902 Is_True(boundary_bb != NULL, ("Fix_Boundary_BBs: boundary BB not found"));
01903 alloc_lrange->Boundary_BBs_Push(boundary_bb);
01904 }
01905 }
01906
01907
01908 for (iter.Init(border_gbb_list_head); ! iter.Done(); iter.Step()) {
01909 GRA_BB* gbb = iter.Current();
01910
01911
01912
01913
01914
01915 if (BB_live_in(gbb->Bb())) {
01916 flow_iter.Preds_Init(gbb);
01917 Find_Border_Transitions(gbb,&flow_iter,Make_Boundary_BBs_At_Border);
01918 }
01919
01920
01921
01922
01923
01924 flow_iter.Succs_Init(gbb);
01925 Find_Border_Transitions(gbb,&flow_iter,Make_Boundary_BBs_At_Border);
01926 }
01927
01928
01929 deferred_lrange->Update_Boundary_BBs();
01930 alloc_lrange->Update_Boundary_BBs();
01931 }
01932 #endif
01933
01935 static void
01936 Check_Local_Interferences( LRANGE* lrange )
01938
01939
01940
01941
01943 {
01944 LRANGE_LIVE_GBB_ITER iter;
01945
01946 for (iter.Init(lrange); ! iter.Done(); iter.Step()) {
01947 GRA_BB* gbb = iter.Current();
01948 INTERFERE_ITER liter;
01949
01950 if ( ! gbb->Region_Is_Complement() ) continue;
01951
01952 ISA_REGISTER_CLASS rc = lrange->Rc();
01953 for (liter.Init(gbb->Global_Lranges(rc), gbb->Region()->Subuniverse(rc));
01954 ! liter.Done(); liter.Step()) {
01955 LRANGE* global_lrange = liter.Current();
01956
01957 if ( global_lrange == lrange )
01958 goto NEXT_BB;
01959 }
01960
01961 DevWarn("LRANGE for TN%d not contained in member BB%d global "
01962 "interference set", TN_number(lrange->Tn()), BB_id(gbb->Bb()));
01963 NEXT_BB:;
01964 }
01965 }
01966
01968 static INT
01969 Choose_Best_Split(INT count)
01971
01972
01973
01974
01975
01976
01977
01979 {
01980 INT ret_count = count;
01981
01982 if (GRA_choose_best_split) {
01983 float max_priority = -FLT_MAX;
01984 INT max_lunit_count = 0;
01985 RID* max_rid = BB_rid(alloc_gbb_list_head->Bb());
01986 GRA_BB *max_gbb_list = alloc_gbb_list_head;
01987 GRA_BB_SPLIT_LIST_ITER split_iter;
01988
01989 for (split_iter.Init(alloc_gbb_list_head); ! split_iter.Done();
01990 split_iter.Step(), --count) {
01991 GRA_BB* gbb = split_iter.Current();
01992 float priority = gbb->Split_Priority();
01993
01994 if (priority >= max_priority && count > 1 &&
01995 BB_rid(gbb->Bb()) == max_rid) {
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008 if (priority == max_priority &&
02009 ((max_lunit_count > gbb->Split_Lunit_Count()) ||
02010 TN_is_save_reg(split_lrange->Tn()))) {
02011 continue;
02012 }
02013
02014 max_lunit_count = gbb->Split_Lunit_Count();
02015 max_gbb_list = gbb;
02016 ret_count = count;
02017 max_priority = priority;
02018 }
02019 }
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029 if (max_priority < 0.0 && (!TN_is_save_reg(split_lrange->Tn()) ||
02030 OPT_Space)) {
02031 return -1;
02032 }
02033
02034
02035
02036
02037
02038 if (max_gbb_list != alloc_gbb_list_head) {
02039
02040
02041
02042
02043
02044 if (split_lrange->Spans_Infreq_Call() &&
02045 max_gbb_list->Split_Spill_Cost() >
02046 (CGSPILL_DEFAULT_STORE_COST + CGSPILL_DEFAULT_RESTORE_COST)) {
02047 return -1;
02048 }
02049
02050 for (split_iter.Init(alloc_gbb_list_head);
02051 split_iter.Current() != max_gbb_list;
02052 split_iter.Step()) {
02053 GRA_BB* gbb = split_iter.Current();
02054 gbb_mgr.Split_In_Alloc_LRANGE_Clear(gbb);
02055 GRA_Trace_Split_Removing_Block(gbb);
02056 }
02057 alloc_gbb_list_head = max_gbb_list;
02058
02059
02060 GRA_BB_FLOW_NEIGHBOR_ITER flow_iter;
02061 border_gbb_list_head = NULL;
02062 gbb_mgr.Clear_One_Set();
02063
02064 for (split_iter.Init(alloc_gbb_list_head); ! split_iter.Done();
02065 split_iter.Step()) {
02066 GRA_BB* gbb = split_iter.Current();
02067
02068 for (flow_iter.Preds_Init(gbb); ! flow_iter.Done(); flow_iter.Step()) {
02069 GRA_BB* pred = flow_iter.Current();
02070 if (split_lrange->Contains_BB(pred) &&
02071 !gbb_mgr.Split_In_Alloc_LRANGE(pred) &&
02072 !gbb_mgr.One_Set_MemberP(pred)) {
02073 gbb_mgr.One_Set_Union1(pred);
02074 border_gbb_list_head =
02075 border_gbb_list_head->Split_List_Push(pred);
02076 }
02077 }
02078
02079 for (flow_iter.Succs_Init(gbb); ! flow_iter.Done(); flow_iter.Step()) {
02080 GRA_BB* succ = flow_iter.Current();
02081 if (split_lrange->Contains_BB(succ) &&
02082 !gbb_mgr.Split_In_Alloc_LRANGE(succ) &&
02083 !gbb_mgr.One_Set_MemberP(succ)) {
02084 gbb_mgr.One_Set_Union1(succ);
02085 border_gbb_list_head =
02086 border_gbb_list_head->Split_List_Push(succ);
02087 }
02088 }
02089 }
02090 }
02091 }
02092 return (ret_count);
02093 }
02094
02096 static void
02097 Split_Consistency_Check()
02099
02100
02101
02102
02104 {
02105 Check_Local_Interferences(alloc_lrange);
02106 Check_Local_Interferences(deferred_lrange);
02107 }
02108
02110 static BOOL
02111 Compare_Priorities(float p1, float p2)
02113
02114
02115
02117 {
02118 if (p1 == p2) {
02119 return TRUE;
02120 }
02121 float max = p1 = fabs(p1);
02122 p2 = fabs(p2);
02123 if (max == 0.0 || p2 > max) {
02124 max = p2;
02125 }
02126 return ((fabs(p1-p2)/max) < .01);
02127 }
02128
02130 static BOOL
02131 LRANGE_Do_Split( LRANGE* lrange, LRANGE_CLIST_ITER* iter,
02132 LRANGE** alloc_lrange_p,
02133 BOOL reclaim )
02135
02137 {
02138 INT32 count;
02139 LUNIT* maxlunit;
02140
02141 split_lrange = lrange;
02142
02143 if ( ( split_lrange->Type() != LRANGE_TYPE_COMPLEMENT ) ||
02144 ( GRA_split_lranges == FALSE ) ||
02145 ( TN_number(split_lrange->Tn()) == GRA_non_split_tn_id ) ) {
02146 return FALSE;
02147 }
02148
02149 if (lrange->Cannot_Split())
02150 return FALSE;
02151
02152 if (lrange->Spans_A_Setjmp())
02153 return FALSE;
02154
02155 #ifdef TARG_IA64
02156 if (fat_self_recursive) return FALSE;
02157 GRA_Trace_Color_LRANGE("Splitting",lrange);
02158 #endif
02159
02160 #ifdef KEY // don't split the saved-TNs if PU has any handler entry point
02161 if (lrange->Tn_Is_Save_Reg() && GRA_pu_has_handler)
02162 return FALSE;
02163
02164 if (PU_Has_Nonlocal_Goto_Target)
02165 return FALSE;
02166 #endif
02167
02168 GRA_Trace_Color_LRANGE(reclaim ? "Splitting (with reclaim)" : "Splitting",
02169 lrange);
02170
02171 gbb_mgr.Begin_Split();
02172
02173 if ( ! Max_Colorable_LUNIT(&maxlunit, reclaim) ) {
02174 return FALSE;
02175 }
02176
02177 split_lrange = lrange;
02178
02179
02180
02181
02182 CGSPILL_Cost_Estimate(split_lrange->Tn(), NULL, &split_spill_cost,
02183 &split_restore_cost, CGSPILL_GRA);
02184
02185 GRA_Trace_Split_Priority_On("Interim method");
02186 count = Identify_Max_Colorable_Neighborhood(maxlunit, reclaim);
02187 GRA_Trace_Split_Priority_Off();
02188 if ( count <= 1 ) {
02189 return FALSE;
02190 }
02191
02192 INT new_count = Choose_Best_Split(count);
02193
02194 if (new_count < 1) {
02195 if (split_lrange->Spans_Infreq_Call()) {
02196 GRA_Trace_Split(1,"LRANGE split for infrequent call failed for TN%d\n",
02197 TN_number(split_lrange->Tn()));
02198 }
02199 return FALSE;
02200 }
02201
02202 GRA_Trace_Split(1,"BB%d is maximum frequency LUNIT in alloc_lrange",
02203 BB_id(maxlunit->Gbb()->Bb()));
02204
02205 Divide_LRANGE();
02206 iter->Replace_Current(alloc_lrange);
02207
02208 Add_Spills_And_Restores();
02209 Fix_TN_Live_Info();
02210 Rename_TN_References();
02211
02212 #ifdef KEY
02213 if (GRA_optimize_boundary)
02214 Fix_Boundary_BBs();
02215 #endif
02216
02217 deferred_lrange->Calculate_Priority();
02218 Fix_Interference();
02219
02220 if (GRA_Trace_Check_Splits()) {
02221 GRA_Trace_Split_Priority_On("LRANGE_Calculate_Priority");
02222 alloc_lrange->Calculate_Priority();
02223 GRA_Trace_Split_Priority_Off();
02224 if (!Compare_Priorities(alloc_lrange->Priority(),
02225 alloc_gbb_list_head->Split_Priority())) {
02226 DevWarn("Mismatch in interim(%f) and final(%f) split priorities for TN%d. Orig block count=%d, new =%d\n",
02227 alloc_gbb_list_head->Split_Priority(),
02228 alloc_lrange->Priority(),
02229 TN_number(alloc_lrange->Tn()), count, new_count);
02230 }
02231 }
02232 alloc_lrange->Priority_Set(alloc_gbb_list_head->Split_Priority());
02233
02234 Add_Deferred_To_Coloring_List(iter);
02235 Fix_Call_Info(deferred_lrange);
02236 Fix_Call_Info(alloc_lrange);
02237 Fix_Rot_Reg_Clob_Info(deferred_lrange);
02238 Fix_Rot_Reg_Clob_Info(alloc_lrange);
02239 #ifdef TARG_X8664
02240 Fix_x86_Info(deferred_lrange);
02241 Fix_x86_Info(alloc_lrange);
02242 #endif
02243
02244 if ( Get_Trace(TP_GRA,0x10) )
02245 Split_Consistency_Check();
02246
02247 *alloc_lrange_p = alloc_lrange;
02248
02249 return TRUE;
02250 }
02251
02253 BOOL
02254 LRANGE_Split(LRANGE* lrange, LRANGE_CLIST_ITER* iter,
02255 LRANGE** alloc_lrange_p,
02256 BOOL reclaim)
02258
02259
02261 {
02262 MEM_POOL_Push(&MEM_local_nz_pool);
02263
02264 BOOL ret_val = LRANGE_Do_Split(lrange, iter, alloc_lrange_p, reclaim);
02265 if (!ret_val) {
02266 *alloc_lrange_p = lrange;
02267 if (split_lrange->Spans_Infreq_Call()) {
02268
02269
02270
02271
02272
02273 split_lrange->Spans_Infreq_Call_Reset();
02274 split_lrange->Spans_A_Call_Set();
02275 }
02276 }
02277
02278 MEM_POOL_Pop(&MEM_local_nz_pool);
02279 return ret_val;
02280 }
02281
02282 #ifdef TARG_X8664
02284 static void
02285 Identify_Mixed_x87_MMX_Neighborhood()
02287
02288
02289
02290
02292 {
02293 LRANGE_LIVE_GBB_ITER iter;
02294
02295 border_gbb_list_head = NULL;
02296 alloc_gbb_list_head = NULL;
02297
02298
02299
02300
02301 for (iter.Init(split_lrange); ! iter.Done(); iter.Step()) {
02302 GRA_BB *gbb = iter.Current();
02303 if (gbb->x87_OP() && gbb->mmx_OP()) {
02304 gbb_mgr.Split_In_Alloc_LRANGE_Set(gbb);
02305 alloc_gbb_list_head = alloc_gbb_list_head->Split_List_Push(gbb);
02306 } else {
02307 border_gbb_list_head = border_gbb_list_head->Split_List_Push(gbb);
02308 }
02309 }
02310 }
02311
02313 BOOL
02314 LRANGE_Split_Mixed_x87_MMX (LRANGE* lrange, LRANGE_CLIST_ITER* iter,
02315 LRANGE** alloc_lrange_p)
02317
02318
02319
02320
02322 {
02323 INT32 count;
02324 LUNIT* maxlunit;
02325
02326 split_lrange = lrange;
02327
02328 Is_True(split_lrange->Type() == LRANGE_TYPE_COMPLEMENT,
02329 ("LRANGE_Split_And_Localize_x87_MMX: lrange not complement"));
02330 Is_True(lrange->Rc() == ISA_REGISTER_CLASS_x87 ||
02331 lrange->Rc() == ISA_REGISTER_CLASS_mmx,
02332 ("LRANGE_Split_And_Localize_x87_MMX: lrange not x87 or MMX"));
02333
02334 if (lrange->Cannot_Split())
02335 return FALSE;
02336
02337 MEM_POOL_Push(&MEM_local_nz_pool);
02338
02339 GRA_Trace_Color_LRANGE(
02340 lrange->Rc() == ISA_REGISTER_CLASS_x87 ?
02341 "Splitting x87 lrange to avoid clobbering MMX registers" :
02342 "Splitting MMX lrange to avoid clobbering x87 registers",
02343 lrange);
02344
02345 gbb_mgr.Begin_Split();
02346
02347
02348 LRANGE_LUNIT_ITER lunit_iter;
02349 for (lunit_iter.Init(split_lrange); !lunit_iter.Done(); lunit_iter.Step()) {
02350 LUNIT *lunit = lunit_iter.Current();
02351 gbb_mgr.Split_LUNIT_Set(lunit->Gbb(), lunit);
02352 }
02353
02354 split_lrange = lrange;
02355
02356 Identify_Mixed_x87_MMX_Neighborhood();
02357
02358 Divide_LRANGE();
02359 iter->Replace_Current(alloc_lrange);
02360
02361 Add_Spills_And_Restores();
02362 Fix_TN_Live_Info();
02363 Rename_TN_References();
02364
02365 if (GRA_optimize_boundary)
02366 Fix_Boundary_BBs();
02367
02368 deferred_lrange->Calculate_Priority();
02369 Fix_Interference();
02370
02371 Add_Deferred_To_Coloring_List(iter);
02372 Fix_Call_Info(deferred_lrange);
02373 Fix_Rot_Reg_Clob_Info(deferred_lrange);
02374 Fix_x86_Info(deferred_lrange);
02375
02376 Is_True(!(deferred_lrange->Spans_x87_OP() && deferred_lrange->Spans_mmx_OP()),
02377 ("LRANGE_Split_Mixed_x87_MMX: "
02378 "lrange contains both x87 and MMX after splitting"));
02379
02380 if ( Get_Trace(TP_GRA,0x10) )
02381 Split_Consistency_Check();
02382
02383 *alloc_lrange_p = alloc_lrange;
02384
02385 MEM_POOL_Pop(&MEM_local_nz_pool);
02386
02387 return TRUE;
02388 }
02389 #endif
02390
02391 #ifdef KEY
02393 void
02394 LRANGE_Split_Reclaimed_BBs (LRANGE *lrange, REGISTER reg)
02396
02397
02398
02399
02401 {
02402 LRANGE *from_lrange = NULL;
02403 LRANGE_LIVE_GBB_ITER gbb_iter;
02404
02405
02406
02407
02408
02409
02410
02411 gbb_iter.Init(lrange);
02412 GRA_BB *gbb = gbb_iter.Current();
02413 from_lrange = gbb->Get_LRANGE_Owner(lrange->Rc(), reg);
02414
02415 FmtAssert(from_lrange != NULL,
02416 ("Do_Register_Reclaim: cannot find from_lrange"));
02417
02418 #ifdef Is_True_On
02419 Is_True(from_lrange->Allocated(),
02420 ("Do_Register_Reclaim: the reclaimed lrange is not allocated"));
02421 BB_SET *reclaimed_BBs = BB_SET_Create_Empty(PU_BB_Count + 2,GRA_pool);
02422
02423
02424
02425 for (gbb_iter.Init(lrange); !gbb_iter.Done(); gbb_iter.Step()) {
02426 GRA_BB *gbb = gbb_iter.Current();
02427 Is_True(from_lrange->Contains_BB(gbb),
02428 ("LRANGE_Split_Reclaimed_BBs: BB not in from_lrange"));
02429 reclaimed_BBs = BB_SET_Union1D(reclaimed_BBs, gbb->Bb(), GRA_pool);
02430 }
02431
02432
02433
02434 LRANGE_LUNIT_ITER lunit_iter;
02435 for (lunit_iter.Init(from_lrange); !lunit_iter.Done(); lunit_iter.Step()) {
02436 LUNIT *lunit = lunit_iter.Current();
02437 Is_True(!BB_SET_MemberP(reclaimed_BBs, lunit->Gbb()->Bb()),
02438 ("LRANGE_Split_Reclaimed_BBs: lrange has reference in reclaimed BBs"));
02439 }
02440 #endif
02441
02442
02443 for (gbb_iter.Init(lrange); !gbb_iter.Done(); gbb_iter.Step()) {
02444 GRA_BB *gbb = gbb_iter.Current();
02445 GRA_BB_FLOW_NEIGHBOR_ITER flow_iter;
02446
02447 gbb->Remove_Live_In_LRANGE(from_lrange);
02448 gbb->Remove_Live_Out_LRANGE(from_lrange);
02449
02450
02451 for (flow_iter.Preds_Init(gbb); !flow_iter.Done(); flow_iter.Step()) {
02452 GRA_BB *pred = flow_iter.Current();
02453 if (!lrange->Contains_BB(pred) &&
02454 pred->Is_Live_Out_LRANGE(from_lrange)) {
02455
02456
02457 LUNIT *lunit;
02458 if (!from_lrange->Find_LUNIT_For_GBB(pred, &lunit)) {
02459 lunit = LUNIT_Create(from_lrange, pred);
02460 pred->Make_Register_Referenced(from_lrange->Rc(), from_lrange->Reg(),
02461 from_lrange);
02462 }
02463 GRA_Note_Save_Below(lunit);
02464 }
02465
02466
02467 if (!Has_Live_In_Successor(pred, from_lrange))
02468 pred->Remove_Live_Out_LRANGE(from_lrange);
02469 }
02470
02471
02472 for (flow_iter.Succs_Init(gbb); !flow_iter.Done(); flow_iter.Step()) {
02473 GRA_BB *succ = flow_iter.Current();
02474 if (!lrange->Contains_BB(succ) &&
02475 succ->Is_Live_In_LRANGE(from_lrange)) {
02476
02477
02478 LUNIT *lunit;
02479 if (!from_lrange->Find_LUNIT_For_GBB(succ, &lunit)) {
02480 lunit = LUNIT_Create(from_lrange, succ);
02481 succ->Make_Register_Referenced(from_lrange->Rc(), from_lrange->Reg(),
02482 from_lrange);
02483 }
02484 GRA_Note_Restore_Above(lunit);
02485
02486
02487 GRA_BB_FLOW_NEIGHBOR_ITER iter;
02488 for (iter.Preds_Init(succ); !iter.Done(); iter.Step()) {
02489 GRA_BB *pred = iter.Current();
02490 if (pred->Is_Live_Out_LRANGE(from_lrange)) {
02491 if (!from_lrange->Find_LUNIT_For_GBB(pred, &lunit)) {
02492 lunit = LUNIT_Create(from_lrange, pred);
02493 pred->Make_Register_Referenced(from_lrange->Rc(),
02494 from_lrange->Reg(), from_lrange);
02495 }
02496 GRA_Note_Save_Below(lunit);
02497 }
02498 }
02499 }
02500 }
02501 }
02502 }
02503 #endif