00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 #include <list>
00070 #include "defs.h"
00071 #include "tracing.h"
00072 #include "errors.h"
00073 #include "erglob.h"
00074 #include "mempool.h"
00075 #include "wn.h"
00076 #include "wn_util.h"
00077 #include "opcode.h"
00078 #include "ir_reader.h"
00079 #include "config.h"
00080 #include "xstats.h"
00081 #include "targ_sim.h"
00082 #include "timing.h"
00083 #include "ori.h"
00084 #include "opt_goto.h"
00085 #include "region_util.h"
00086
00087 typedef struct wnlist {
00088 WN *item;
00089 struct wnlist *next;
00090 } WNLIST;
00091 #define WNLIST_item(s) ((s)->item)
00092 #define WNLIST_next(s) ((s)->next)
00093
00094 typedef struct ori_block {
00095 mUINT32 id;
00096 WN *tree;
00097 WN *end_tree;
00098 WN *container;
00099 mINT32 num_stmts;
00100 mINT32 num_bbs;
00101 WNLIST *labels;
00102 struct ori_block *parent;
00103 struct ori_block *child;
00104 struct ori_block *sibling;
00105 mBOOL expanded;
00106 mBOOL no_more_merge;
00107 mBOOL nested_region;
00108 mBOOL never_in_region;
00109 mBOOL illegal;
00110 } ORI_BLOCK;
00111
00112 #define OB_id(b) ((b) ? (b)->id : 0)
00113 #define Set_OB_id(b,v) ((b)->id = v)
00114 #define OB_tree(b) ((b)->tree)
00115 #define OB_end_tree(b) ((b)->end_tree)
00116 #define OB_container(b) ((b)->container)
00117 #define OB_num_stmts(b) ((b)->num_stmts)
00118 #define OB_num_bbs(b) ((b)->num_bbs)
00119 #define OB_labels(b) ((b)->labels)
00120 #define OB_parent(b) ((b)->parent)
00121 #define OB_child(b) ((b)->child)
00122 #define OB_sibling(b) ((b)->sibling)
00123 #define OB_expanded(b) ((b)->expanded)
00124 #define OB_no_more_merge(b) ((b)->no_more_merge)
00125 #define OB_nested_region(b) ((b)->nested_region)
00126 #define OB_never_in_region(b) ((b)->never_in_region)
00127 #define OB_illegal(b) ((b)->illegal)
00128
00129
00130
00131 #define OB_size(b) COMPUTE_OLIMIT(OB_num_bbs(b),OB_num_stmts(b))
00132
00133
00134 #define OB_sub_size(a,b) \
00135 COMPUTE_OLIMIT((OB_num_bbs(a) - OB_num_bbs(b)),(OB_num_stmts(a) - OB_num_stmts(b)))
00136 #define OB_first_sibling(b) (OB_child(OB_parent(b)))
00137
00138 typedef struct oblist {
00139 ORI_BLOCK *item;
00140 struct oblist *next;
00141 } OBLIST;
00142 #define OBLIST_item(s) ((s)->item)
00143 #define OBLIST_next(s) ((s)->next)
00144
00145 static BOOL Trace_ORI = FALSE;
00146 static BOOL Run_Goto_Conversion = FALSE;
00147
00148
00149 static BOOL Trace_Goto_Conversion = FALSE;
00150 static BOOL Trace_Merging = FALSE;
00151 static BOOL Trace_Blocks = FALSE;
00152 static MEM_POOL Ori_pool;
00153 static ORI_BLOCK *pu_block;
00154 static ORI_BLOCK *cur_block;
00155 static INT last_id = 0;
00156 static INT num_regions = 0;
00157
00158 static UINT32 *blocks_in_region;
00159 static INT last_block_in_region_index = 0;
00160 static INT max_block_in_region_index = 0;
00161 static WNLIST **labels_in_region;
00162 static INT last_label_in_region_index = 0;
00163
00164
00165
00166 static OBLIST **label_branches;
00167
00168 static void
00169 Initialize_Trace_Flags (void)
00170 {
00171 Trace_ORI = Get_Trace (TP_ORI, 1);
00172 Trace_Merging = Get_Trace (TP_ORI, 2);
00173 Trace_Blocks = Get_Trace (TP_ORI, 4);
00174 Run_Goto_Conversion = Get_Trace (TP_ORI, 8);
00175 Trace_Goto_Conversion = Get_Trace (TP_ORI, 16);
00176 }
00177
00178
00179
00180 static void
00181 Initialize_ORI (void)
00182 {
00183 num_regions = 0;
00184 last_id = 0;
00185 last_block_in_region_index = 0;
00186 blocks_in_region = NULL;
00187
00188 INT last_label_in_PU = LABEL_Table_Size(CURRENT_SYMTAB);
00189 label_branches = (OBLIST**) MEM_POOL_Alloc (&Ori_pool,
00190 sizeof(OBLIST*) * (last_label_in_PU+1));
00191 INT i;
00192 for (i = 0; i <= last_label_in_PU; i++) {
00193 label_branches[i] = NULL;
00194 }
00195 }
00196
00197 static void
00198 Check_Dump (WN *tree, const char *msg)
00199 {
00200 if (Get_Trace(TKIND_IR, TP_ORI)) {
00201 fputs(DBar, TFile);
00202 fprintf(TFile, "%s\n", msg);
00203 fdump_tree(TFile, tree);
00204 fputs(DBar, TFile);
00205 }
00206 }
00207
00208
00209 static void
00210 Add_Wn_To_List (WN *wn, WNLIST **wnlist)
00211 {
00212 WNLIST *p;
00213 p = (WNLIST *) MEM_POOL_Alloc (&Ori_pool, sizeof(WNLIST));
00214 WNLIST_item(p) = wn;
00215 WNLIST_next(p) = *wnlist;
00216 *wnlist = p;
00217 }
00218
00219
00220
00221
00222 static void
00223 Remove_Wn_From_List (WN *wn, WNLIST **wnlist)
00224 {
00225 WNLIST *p = *wnlist;
00226 WNLIST *prev = NULL;
00227 while (p != NULL) {
00228 if (WNLIST_item(p) == wn) break;
00229 prev = p;
00230 p = WNLIST_next(p);
00231 }
00232 FmtAssert (p != NULL, ("Remove_Wn_From_List didn't find wn"));
00233 if (prev != NULL) {
00234 WNLIST_next(prev) = WNLIST_next(p);
00235 }
00236 else {
00237
00238 *wnlist = WNLIST_next(p);
00239 }
00240 }
00241
00242
00243 static void
00244 Add_Ob_To_List (ORI_BLOCK *ob, OBLIST **oblist)
00245 {
00246 OBLIST *p;
00247
00248 if (*oblist != NULL && OBLIST_item(*oblist) == ob) return;
00249
00250 p = (OBLIST *) MEM_POOL_Alloc (&Ori_pool, sizeof(OBLIST));
00251 OBLIST_item(p) = ob;
00252 OBLIST_next(p) = *oblist;
00253 *oblist = p;
00254 }
00255
00256
00257
00258
00259 static void
00260 Remove_Ob_From_List (ORI_BLOCK *ob, OBLIST **oblist)
00261 {
00262 OBLIST *p = *oblist;
00263 OBLIST *prev = NULL;
00264 while (p != NULL) {
00265 if (OBLIST_item(p) == ob) break;
00266 prev = p;
00267 p = OBLIST_next(p);
00268 }
00269
00270
00271 if (p == NULL)
00272 return;
00273 else if (prev != NULL) {
00274 OBLIST_next(prev) = OBLIST_next(p);
00275 }
00276 else {
00277
00278 *oblist = OBLIST_next(p);
00279 }
00280 }
00281
00282
00283 static ORI_BLOCK *
00284 OB_prev (ORI_BLOCK *b)
00285 {
00286 ORI_BLOCK *prev = OB_first_sibling(b);
00287 for (; prev != NULL; prev = OB_sibling(prev)) {
00288 if (OB_sibling(prev) == b)
00289 return prev;
00290 }
00291 return NULL;
00292 }
00293
00294
00295 static INT
00296 OB_level (ORI_BLOCK *b)
00297 {
00298 INT level = 0;
00299 for (; b != NULL; b = OB_parent(b)) {
00300 level++;
00301 }
00302 return level;
00303 }
00304
00305 static void
00306 Print_Ori_Block (FILE *f, ORI_BLOCK *b)
00307 {
00308 if (b == NULL) return;
00309 fprintf(f, "ORI_BLOCK %d ", OB_id(b));
00310 switch (WN_opcode(OB_tree(b))) {
00311 case OPC_BLOCK:
00312 fprintf(f, "(%s)", (OB_sibling(b) ? "OPC_THEN" : "OPC_ELSE") );
00313 break;
00314 case OPC_LABEL:
00315 fprintf(f, "(OPC_LABEL %d)", WN_label_number(OB_tree(b)) );
00316 break;
00317 case OPC_REGION:
00318 fprintf(f, "(OPC_REGION %d)", WN_region_id(OB_tree(b)) );
00319 break;
00320 default:
00321 fprintf(f, "(%s %d)", OPCODE_name(WN_opcode(OB_tree(b))),
00322 Srcpos_To_Line(WN_linenum(OB_tree(b))) );
00323 break;
00324 }
00325 if (OB_end_tree(b) != OB_tree(b)) {
00326 fprintf(f, " to (%s %d)",
00327 OPCODE_name(WN_opcode(OB_end_tree(b))),
00328 Srcpos_To_Line(WN_linenum(OB_end_tree(b))) );
00329 }
00330 if (OB_expanded(b)) fprintf(f, " [expanded]");
00331 if (OB_no_more_merge(b)) fprintf(f, " [merged]");
00332 if (OB_nested_region(b)) fprintf(f, " [nested]");
00333 if (OB_never_in_region(b)) fprintf(f, " [never]");
00334 if (OB_illegal(b)) fprintf(f, " [illegal]");
00335 fprintf(f, ":\n");
00336 fprintf(f, "\tsize = %d (%d * %d)\n", OB_size(b), OB_num_bbs(b), OB_num_stmts(b));
00337 fprintf(f, "\tparent = %d, child = %d, sibling = %d\n",
00338 OB_id(OB_parent(b)), OB_id(OB_child(b)), OB_id(OB_sibling(b)) );
00339
00340 if (WN_opcode(OB_tree(b)) != OPC_REGION || OB_end_tree(b) != OB_tree(b))
00341 Print_Ori_Block (f, OB_child(b));
00342 Print_Ori_Block (f, OB_sibling(b));
00343 }
00344
00345
00346
00347 static void
00348 Get_First_Stmt_And_Container (ORI_BLOCK *b, WN **stmt, WN **container)
00349 {
00350 WN *tree = OB_tree(b);
00351
00352 while (1) {
00353 switch (WN_opcode(tree)) {
00354 case OPC_BLOCK:
00355 *stmt = WN_first(tree);
00356 *container = tree;
00357 return;
00358 case OPC_FUNC_ENTRY:
00359 tree = WN_func_body(tree);
00360 break;
00361 case OPC_IF:
00362 tree = WN_then(tree);
00363 break;
00364 case OPC_WHILE_DO:
00365 case OPC_DO_WHILE:
00366 tree = WN_while_body(tree);
00367 break;
00368 case OPC_DO_LOOP:
00369 tree = WN_do_body(tree);
00370 break;
00371 case OPC_LABEL:
00372 *stmt = WN_next(tree);
00373 *container = OB_container(b);
00374 return;
00375 case OPC_COMPGOTO:
00376 *stmt = OB_child(b) ? OB_tree(OB_child(b)) : NULL;
00377 *container = OB_container(b);
00378 return;
00379 case OPC_REGION:
00380
00381 *stmt = tree;
00382 *container = OB_container(b);
00383 return;
00384 default:
00385 if (OPCODE_is_stmt(WN_opcode(tree))) {
00386 *stmt = tree;
00387 *container = OB_container(b);
00388 }
00389 else {
00390 FmtAssert (FALSE, ("unexpected opcode in Get_First_Stmt"));
00391 }
00392 return;
00393 }
00394 }
00395 }
00396
00397 static ORI_BLOCK *
00398 New_Ori_Block (WN *tree, ORI_BLOCK *parent)
00399 {
00400 ORI_BLOCK *b;
00401 WN *t;
00402 b = (ORI_BLOCK *) MEM_POOL_Alloc (&Ori_pool, sizeof(ORI_BLOCK));
00403 Set_OB_id(b, ++last_id);
00404 OB_tree(b) = tree;
00405 OB_end_tree(b) = tree;
00406 if (WN_opcode(tree) == OPC_BLOCK)
00407 OB_container(b) = tree;
00408 else if (parent)
00409 Get_First_Stmt_And_Container (parent, &t, &OB_container(b));
00410 else
00411 OB_container(b) = NULL;
00412 OB_parent(b) = parent;
00413 OB_child(b) = OB_sibling(b) = NULL;
00414 OB_labels(b) = NULL;
00415 OB_num_stmts(b) = OB_num_bbs(b) = 0;
00416 OB_expanded(b) = FALSE;
00417 OB_no_more_merge(b) = FALSE;
00418 OB_nested_region(b) = FALSE;
00419 OB_never_in_region(b) = FALSE;
00420 OB_illegal(b) = FALSE;
00421 return b;
00422 }
00423
00424 static void
00425 Propagate_Size_Info (ORI_BLOCK *b, INT32 num_bbs, INT32 num_stmts)
00426 {
00427 while (b != NULL) {
00428 OB_num_bbs(b) += num_bbs;
00429 OB_num_stmts(b) += num_stmts;
00430 b = OB_parent(b);
00431 }
00432 }
00433
00434
00435
00436
00437
00438
00439
00440 static void
00441 Propagate_Child_Info (ORI_BLOCK *b)
00442 {
00443
00444 Propagate_Size_Info (OB_parent(b), OB_num_bbs(b), OB_num_stmts(b));
00445
00446
00447 if (OB_child(b))
00448 Propagate_Child_Info (OB_child(b));
00449 if (OB_sibling(b))
00450 Propagate_Child_Info (OB_sibling(b));
00451 }
00452
00453 #define IS_RETURN_PREG(wn) \
00454 (ST_class(WN_st(wn)) == CLASS_PREG \
00455 && (Is_Return_Preg(WN_load_offset(wn)) \
00456 || WN_st(wn) == Return_Val_Preg ) )
00457
00458
00459
00460
00461 static BOOL Uses_Return_Preg (WN *tree)
00462 {
00463 WN_ITER *wni;
00464 WN *wn;
00465
00466 for (wni = WN_WALK_TreeIter (tree);
00467 wni != NULL;
00468 wni = WN_WALK_TreeNext (wni))
00469 {
00470 wn = WN_ITER_wn (wni);
00471 if (WN_operator(wn) == OPR_LDID && IS_RETURN_PREG(wn) )
00472 return TRUE;
00473 }
00474 return FALSE;
00475 }
00476
00477
00478
00479 static BOOL
00480 Is_Call_With_Alternate_Return (WN *call, WN *stmt)
00481 {
00482 if (call != NULL && OPCODE_is_call(WN_opcode(call))
00483 && WN_opcode(stmt) == OPC_COMPGOTO)
00484 {
00485 WN *val = WN_kid0(stmt);
00486 if (WN_operator(val) == OPR_ADD
00487 && OPCODE_is_load(WN_opcode(WN_kid0(val)))
00488 && IS_RETURN_PREG(WN_kid0(val)) )
00489 {
00490 return TRUE;
00491 }
00492 }
00493 return FALSE;
00494 }
00495
00496
00497
00498 static ORI_BLOCK *
00499 Build_Ori_Blocks (WN *tree, INT32 olimit)
00500 {
00501 OPCODE opcode = WN_opcode(tree);
00502 WN *wn;
00503 ORI_BLOCK *b = NULL;
00504 ORI_BLOCK *save_block = NULL;
00505
00506 std::list<ORI_BLOCK*> switch_list;
00507
00508 switch (opcode) {
00509 case OPC_FUNC_ENTRY:
00510 b = cur_block = New_Ori_Block (tree, NULL);
00511 OB_child(b) = Build_Ori_Blocks (WN_func_body(tree), olimit);
00512 break;
00513 case OPC_BLOCK:
00514 ORI_BLOCK *tmp;
00515
00516 wn = WN_first(tree);
00517 while (wn) {
00518 if (!switch_list.empty() && WN_opcode(wn) == OPC_LABEL)
00519 {
00520 std::list<ORI_BLOCK*>::iterator switch_it;
00521 for (switch_it = switch_list.begin();
00522 switch_it != switch_list.end();
00523 ++switch_it)
00524 {
00525 if (WN_last_label(OB_tree(*switch_it))
00526 == WN_label_number(wn))
00527 break;
00528 }
00529 if (switch_it != switch_list.end()) {
00530
00531 if (Trace_ORI) fprintf(TFile, "ori: found end label %d for switch\n", WN_label_number(wn));
00532
00533
00534
00535
00536 OB_end_tree(*switch_it) = wn;
00537
00538 if (b != NULL && OB_end_tree(b) == NULL) {
00539 OB_end_tree(b) = WN_prev(wn);
00540 }
00541
00542
00543
00544 tmp = New_Ori_Block (wn, *switch_it);
00545 OB_num_bbs(*switch_it)++;
00546 Add_Wn_To_List (wn, &OB_labels(tmp));
00547 if (b != NULL) OB_sibling(b) = tmp;
00548 cur_block = OB_parent(*switch_it);
00549 b = *switch_it;
00550 switch_list.erase(switch_it);
00551
00552 wn = WN_next(wn);
00553 if (wn == NULL) break;
00554 }
00555 }
00556 tmp = Build_Ori_Blocks (wn, olimit);
00557 if (tmp != NULL) {
00558 if (b == NULL) {
00559 b = tmp;
00560 if (!switch_list.empty()) {
00561
00562 OB_child(*switch_list.begin()) = b;
00563 }
00564 else {
00565 save_block = b;
00566 }
00567 }
00568 else if (WN_opcode(wn) == OPC_PRAGMA
00569 && WN_pragma(wn) == WN_PRAGMA_PREAMBLE_END)
00570 {
00571
00572
00573
00574 OB_child(OB_parent(b)) = tmp;
00575 OB_parent(tmp) = OB_parent(b);
00576 if (b == cur_block) cur_block = OB_parent(b);
00577 b = tmp;
00578 save_block = b;
00579 }
00580 else {
00581 OB_sibling(b) = tmp;
00582
00583 if (OB_end_tree(b) == NULL) {
00584 if (wn != OB_tree(tmp)
00585 && !Is_Call_With_Alternate_Return (OB_tree(tmp), wn))
00586 {
00587 DevWarn("ORI: current wn != tree(tmp)");
00588 }
00589
00590 OB_end_tree(b) = WN_prev(OB_tree(tmp));
00591 }
00592
00593
00594
00595 while (tmp != NULL) {
00596 OB_parent(tmp) = OB_parent(b);
00597 OB_container(tmp) = OB_container(b);
00598 tmp = OB_sibling(tmp);
00599 }
00600
00601
00602
00603
00604 if (cur_block == b)
00605 cur_block = OB_parent(b);
00606 }
00607 while (OB_sibling(b) != NULL) {
00608 b = OB_sibling(b);
00609 }
00610 if (WN_opcode(OB_tree(b)) == OPC_COMPGOTO
00611 && WN_last_label(OB_tree(b)) != 0)
00612 {
00613
00614
00615
00616
00617
00618
00619 switch_list.push_front (b);
00620 cur_block = b;
00621 b = NULL;
00622 }
00623 }
00624 wn = WN_next(wn);
00625 }
00626 if (!switch_list.empty())
00627 DevWarn("ORI: didn't find end of switch/compgoto");
00628
00629 if (b != NULL && OB_end_tree(b) == NULL) {
00630 OB_end_tree(b) = WN_last(tree);
00631 }
00632
00633
00634
00635 if (b == cur_block && WN_opcode(OB_tree(b)) != OPC_BLOCK) {
00636 OB_end_tree(cur_block) = WN_last(tree);
00637 }
00638 b = save_block;
00639 break;
00640 case OPC_DO_LOOP:
00641 save_block = cur_block;
00642 b = New_Ori_Block (tree, cur_block);
00643 cur_block = b;
00644 OB_num_bbs(cur_block)++;
00645 OB_child(b) = Build_Ori_Blocks (WN_do_body(tree), olimit);
00646 cur_block = save_block;
00647 break;
00648 case OPC_WHILE_DO:
00649 case OPC_DO_WHILE:
00650 save_block = cur_block;
00651 b = New_Ori_Block (tree, cur_block);
00652 cur_block = b;
00653 OB_num_bbs(cur_block)++;
00654 OB_child(b) = Build_Ori_Blocks (WN_while_body(tree), olimit);
00655 cur_block = save_block;
00656 break;
00657 case OPC_IF:
00658
00659 save_block = cur_block;
00660 b = New_Ori_Block (tree, cur_block);
00661 cur_block = b;
00662 OB_num_bbs(cur_block)++;
00663 if (WN_else(tree) != NULL) OB_num_bbs(cur_block)++;
00664 if (WN_else(tree) == NULL) {
00665
00666 OB_child(b) = Build_Ori_Blocks (WN_then(tree), olimit);
00667 }
00668 else {
00669
00670
00671
00672 ORI_BLOCK *ifb = cur_block;
00673 OB_child(ifb) = New_Ori_Block (WN_then(tree), ifb);
00674 b = OB_child(ifb);
00675 OB_sibling(b) = New_Ori_Block (WN_else(tree), ifb);
00676 cur_block = b;
00677 OB_child(b) = Build_Ori_Blocks (WN_then(tree), olimit);
00678 b = OB_sibling(b);
00679 cur_block = b;
00680 OB_child(b) = Build_Ori_Blocks (WN_else(tree), olimit);
00681 b = ifb;
00682 }
00683 cur_block = save_block;
00684 break;
00685 case OPC_LABEL:
00686 case OPC_EXC_SCOPE_BEGIN:
00687 case OPC_EXC_SCOPE_END:
00688 case OPC_ALTENTRY:
00689
00690
00691 b = New_Ori_Block (tree, cur_block);
00692 OB_end_tree(b) = NULL;
00693 cur_block = b;
00694
00695 if (opcode == OPC_ALTENTRY) {
00696
00697
00698
00699 OB_never_in_region(b) = TRUE;
00700 }
00701 else if (opcode == OPC_LABEL && WN_Label_Is_Handler_Begin(tree)) {
00702
00703
00704
00705 OB_never_in_region(b) = TRUE;
00706 OB_end_tree(b) = tree;
00707 OB_sibling(b) = New_Ori_Block (WN_next(tree), OB_parent(b));
00708 cur_block = OB_sibling(b);
00709 OB_end_tree(cur_block) = NULL;
00710 }
00711 else {
00712
00713
00714
00715 OB_num_bbs(cur_block)++;
00716 Add_Wn_To_List (tree, &OB_labels(b));
00717 }
00718 break;
00719 case OPC_PRAGMA:
00720
00721 if (WN_pragma(tree) == WN_PRAGMA_PREAMBLE_END) {
00722 if (WN_opcode(cur_block->tree) == OPC_ALTENTRY) {
00723
00724 break;
00725 }
00726
00727
00728
00729 b = New_Ori_Block (tree, cur_block);
00730 OB_never_in_region(b) = TRUE;
00731
00732
00733 OB_tree(b) = WN_first(OB_container(b));
00734 OB_num_stmts(b) = OB_num_stmts(cur_block);
00735 OB_num_bbs(b) = OB_num_bbs(cur_block);
00736 OB_num_stmts(cur_block) = 0;
00737 OB_num_bbs(cur_block) = 0;
00738 if (OB_size(b) > olimit) {
00739
00740
00741
00742
00743 DevWarn("ORI: Can't create region before preamble_end");
00744 OB_num_stmts(b) = 0;
00745 OB_num_bbs(b) = 0;
00746 }
00747 }
00748 break;
00749 case OPC_SWITCH:
00750 case OPC_COMPGOTO:
00751 if (WN_last_label(tree) != 0) {
00752
00753
00754
00755
00756
00757 b = New_Ori_Block (tree, cur_block);
00758 if (Trace_ORI) fprintf(TFile, "ori: create block %d around switch body\n", OB_id(b));
00759 cur_block = b;
00760 }
00761 else {
00762
00763
00764
00765 b = New_Ori_Block (tree, cur_block);
00766 OB_never_in_region(b) = TRUE;
00767 if (Is_Call_With_Alternate_Return (WN_prev(tree), tree))
00768 {
00769
00770
00771 OB_tree(b) = WN_prev(tree);
00772
00773 Count_WN_Node (WN_prev(tree),
00774 &OB_num_bbs(b), &OB_num_stmts(b));
00775 OB_num_bbs(cur_block) -= OB_num_bbs(b);
00776 OB_num_stmts(cur_block) -= OB_num_stmts(b);
00777 if (Trace_ORI) fprintf(TFile, "ori: create block %d around call with alternate return\n", OB_id(b));
00778 }
00779 else if (Trace_ORI) fprintf(TFile, "ori: create block %d around compgoto list\n", OB_id(b));
00780 }
00781 OB_num_bbs(b)++;
00782
00783
00784 for (wn = WN_first(WN_switch_table(tree)); wn != NULL; wn = WN_next(wn)) {
00785 Add_Ob_To_List (b, &label_branches[WN_label_number(wn)]);
00786 }
00787 wn = WN_switch_default(tree);
00788 if (wn != NULL) {
00789 Add_Ob_To_List (b, &label_branches[WN_label_number(wn)]);
00790 }
00791 break;
00792 case OPC_CASEGOTO:
00793 Add_Ob_To_List (cur_block, &label_branches[WN_label_number(tree)]);
00794 break;
00795 case OPC_GOTO:
00796 case OPC_TRUEBR:
00797 case OPC_FALSEBR:
00798 OB_num_bbs(cur_block)++;
00799 Add_Ob_To_List (cur_block, &label_branches[WN_label_number(tree)]);
00800 break;
00801 case OPC_IO:
00802 INT32 i;
00803 for (i=0; i<WN_kid_count(tree); i++) {
00804 WN *kid = WN_kid(tree, i);
00805 if (WN_opcode(kid) == OPC_IO_ITEM
00806 && (WN_io_item(kid) == IOC_END
00807 || WN_io_item(kid)==IOC_ERR)
00808 && WN_opcode(WN_kid0(kid)) == OPC_GOTO)
00809 {
00810
00811 WN *branch_wn = WN_kid0(kid);
00812 LABEL_IDX lnum = WN_label_number(branch_wn);
00813
00814
00815 Add_Ob_To_List (cur_block, &label_branches[lnum]);
00816 }
00817 }
00818 Count_WN_Node (tree, &OB_num_bbs(cur_block), &OB_num_stmts(cur_block));
00819 break;
00820 case OPC_REGION:
00821
00822 OB_num_bbs(cur_block)++;
00823 break;
00824 default:
00825 Count_WN_Opcode (opcode, &OB_num_bbs(cur_block), &OB_num_stmts(cur_block));
00826 break;
00827 }
00828 return b;
00829 }
00830
00831
00832
00833 static void
00834 Insert_Region_Around_Block (ORI_BLOCK *b)
00835 {
00836 WN *wn;
00837 WN *region;
00838 Set_PU_has_region(Get_Current_PU());
00839 num_regions++;
00840
00841 if (WN_opcode(OB_tree(b)) == OPC_BLOCK) {
00842
00843
00844 wn = WN_CreateBlock();
00845 WN_first(wn) = WN_first(OB_tree(b));
00846 WN_last(wn) = WN_last(OB_tree(b));
00847 region = WN_CreateRegion (REGION_KIND_OLIMIT, wn, NULL, NULL,
00848 RID_CREATE_NEW_ID, INITO_IDX_ZERO);
00849 WN_first(OB_tree(b)) = WN_last(OB_tree(b)) = region;
00850 }
00851 else {
00852
00853 WN *prev = WN_prev(OB_tree(b));
00854 wn = WN_CreateBlock();
00855 WN_first(wn) = WN_EXTRACT_ItemsFromBlock (
00856 OB_container(b), OB_tree(b), OB_end_tree(b));
00857 WN_last(wn) = OB_end_tree(b);
00858 region = WN_CreateRegion (REGION_KIND_OLIMIT, wn, NULL, NULL,
00859 RID_CREATE_NEW_ID, INITO_IDX_ZERO);
00860 WN_INSERT_BlockAfter (OB_container(b), prev, region);
00861
00862
00863 ORI_BLOCK *parent;
00864 for (parent = OB_parent(b);
00865 parent != NULL && OB_tree(parent) == OB_tree(b);
00866 parent = OB_parent(parent))
00867 {
00868 OB_tree(parent) = region;
00869 }
00870 for (parent = OB_parent(b);
00871 parent != NULL && OB_end_tree(parent) == OB_end_tree(b);
00872 parent = OB_parent(parent))
00873 {
00874 OB_end_tree(parent) = region;
00875 }
00876 }
00877
00878 WN_Set_Linenum(region, WN_Get_Linenum(OB_tree(b)));
00879 if (Trace_ORI) fprintf(TFile, "ori: insert region %d of size %d around block %d\n", WN_region_id(region), OB_size(b), OB_id(b));
00880
00881 Propagate_Size_Info (OB_parent(b), -(OB_num_bbs(b)), -(OB_num_stmts(b)));
00882 OB_nested_region(OB_parent(b)) = TRUE;
00883
00884
00885
00886
00887
00888 OB_num_bbs(b) = OB_num_stmts(b) = 0;
00889
00890 OB_tree(b) = OB_end_tree(b) = region;
00891 }
00892
00893 static void
00894 Move_Branches_To_Child (ORI_BLOCK *parent, ORI_BLOCK *child)
00895 {
00896 WN *stmt;
00897 WN *wn;
00898 OBLIST **branches;
00899 Get_First_Stmt_And_Container (child, &stmt, &wn);
00900 while (stmt != NULL) {
00901 switch (WN_opcode(stmt)) {
00902 case OPC_SWITCH:
00903 case OPC_COMPGOTO:
00904 for (wn = WN_first(WN_switch_table(stmt)); wn != NULL; wn = WN_next(wn)) {
00905 branches = &label_branches[WN_label_number(wn)];
00906 Remove_Ob_From_List (parent, branches);
00907 Add_Ob_To_List (child, branches);
00908 if (Trace_Merging) fprintf(TFile, "ori: move branch to label %d from block %d to block %d\n", WN_label_number(stmt), OB_id(parent), OB_id(child));
00909 }
00910 wn = WN_switch_default(stmt);
00911 if (wn != NULL) {
00912 branches = &label_branches[WN_label_number(wn)];
00913 Remove_Ob_From_List (parent, branches);
00914 Add_Ob_To_List (child, branches);
00915 if (Trace_Merging) fprintf(TFile, "ori: move branch to label %d from block %d to block %d\n", WN_label_number(stmt), OB_id(parent), OB_id(child));
00916 }
00917 break;
00918 case OPC_CASEGOTO:
00919 case OPC_GOTO:
00920 case OPC_TRUEBR:
00921 case OPC_FALSEBR:
00922 branches = &label_branches[WN_label_number(stmt)];
00923 Remove_Ob_From_List (parent, branches);
00924 Add_Ob_To_List (child, branches);
00925 if (Trace_Merging) fprintf(TFile, "ori: move branch to label %d from block %d to block %d\n", WN_label_number(stmt), OB_id(parent), OB_id(child));
00926 break;
00927 }
00928 if (stmt == OB_end_tree(child)) break;
00929 stmt = WN_next(stmt);
00930 }
00931 }
00932
00933
00934 static ORI_BLOCK *
00935 Create_New_Child (ORI_BLOCK *parent, ORI_BLOCK *prev, ORI_BLOCK *sibling, WN *tree, WN *end_tree, INT num_bbs, INT num_stmts)
00936 {
00937 ORI_BLOCK *b;
00938 WN *first_stmt, *container;
00939 Get_First_Stmt_And_Container (parent, &first_stmt, &container);
00940 b = New_Ori_Block (tree, parent);
00941 OB_end_tree(b) = end_tree;
00942 OB_container(b) = container;
00943 OB_sibling(b) = sibling;
00944 if (prev)
00945 OB_sibling(prev) = b;
00946 else
00947 OB_child(parent) = b;
00948 OB_num_bbs(b) = num_bbs;
00949 OB_num_stmts(b) = num_stmts;
00950 if (Trace_ORI) fprintf(TFile, "ori: add block %d as child of %d, sibling of %d\n", OB_id(b), OB_id(parent), OB_id(prev));
00951 Move_Branches_To_Child (parent, b);
00952 return b;
00953 }
00954
00955
00956
00957 static void
00958 Split_Block (ORI_BLOCK *b)
00959 {
00960 INT goal = OB_size(b) / 2;
00961 INT num_bbs = 0;
00962 INT num_stmts = 0;
00963 ORI_BLOCK *first, *second;
00964 WN *first_stmt, *stmt;
00965 WN *container;
00966 WN *end_stmt;
00967 BOOL in_stmt_group = FALSE;
00968
00969 FmtAssert(OB_child(b) == NULL, ("Split_Block: can't handle blocks with chilren"));
00970
00971 Get_First_Stmt_And_Container (b, &first_stmt, &container);
00972
00973
00974 stmt = first_stmt;
00975 while (stmt != NULL && COMPUTE_OLIMIT(num_bbs,num_stmts) < goal) {
00976 Count_WN_Node (stmt, &num_bbs, &num_stmts);
00977 if (WN_opcode(stmt) == OPC_PRAGMA
00978 && WN_pragma(stmt) == WN_PRAGMA_START_STMT_CLUMP)
00979 in_stmt_group = TRUE;
00980 if (WN_opcode(stmt) == OPC_PRAGMA
00981 && WN_pragma(stmt) == WN_PRAGMA_END_STMT_CLUMP)
00982 in_stmt_group = FALSE;
00983 stmt = WN_next(stmt);
00984 }
00985 FmtAssert(stmt != NULL, ("Split_Block: couldn't split %d", OB_id(b)));
00986
00987
00988 if (in_stmt_group && stmt != OB_end_tree(b)) {
00989 if (Trace_ORI) fprintf(TFile, "ori: don't split block %d in middle of stmt group\n", OB_id(b));
00990 }
00991 #if 0
00992
00993 while (in_stmt_group && stmt != OB_end_tree(b)) {
00994 Count_WN_Node (stmt, &num_bbs, &num_stmts);
00995 if (WN_opcode(stmt) == OPC_PRAGMA
00996 && WN_pragma(stmt) == WN_PRAGMA_END_STMT_CLUMP)
00997 in_stmt_group = FALSE;
00998 stmt = WN_next(stmt);
00999 }
01000 FmtAssert(stmt != NULL, ("Split_Block: couldn't split io block %d", OB_id(b)));
01001 FmtAssert(!in_stmt_group, ("ORI Split_Block: couldn't reach end of stmt group"));
01002 #endif
01003
01004
01005
01006
01007
01008 while (Uses_Return_Preg(stmt)) {
01009 Count_WN_Node (stmt, &num_bbs, &num_stmts);
01010 stmt = WN_next(stmt);
01011 }
01012
01013 if (WN_opcode(stmt) == OPC_RETURN) {
01014 Count_WN_Node (stmt, &num_bbs, &num_stmts);
01015 stmt = WN_next(stmt);
01016 }
01017
01018
01019 while (WN_opcode(WN_prev(stmt)) == OPC_PRAGMA
01020 || WN_opcode(WN_prev(stmt)) == OPC_XPRAGMA)
01021 {
01022 Count_WN_Node (stmt, &num_bbs, &num_stmts);
01023 stmt = WN_next(stmt);
01024 }
01025
01026
01027 if (WN_opcode(OB_tree(b)) == OPC_BLOCK)
01028 end_stmt = WN_last(OB_tree(b));
01029 else if (OB_end_tree(b) == OB_tree(b))
01030
01031 end_stmt = WN_last(container);
01032 else
01033 end_stmt = OB_end_tree(b);
01034
01035
01036 first = Create_New_Child (b, NULL, NULL, first_stmt, WN_prev(stmt),
01037 num_bbs, num_stmts);
01038 second = Create_New_Child (b, first, NULL, stmt, end_stmt,
01039 OB_num_bbs(b) - num_bbs, OB_num_stmts(b) - num_stmts);
01040 if (OB_never_in_region(b)) {
01041
01042 OB_never_in_region(first) = TRUE;
01043 }
01044 if (Trace_ORI) fprintf(TFile, "ori: split block %d into %d and %d\n", OB_id(b), OB_id(first), OB_id(second));
01045 if (Trace_Blocks) Print_Ori_Block (TFile, b);
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056 static void
01057 Expand_Sibling_Blocks (ORI_BLOCK *first)
01058 {
01059 ORI_BLOCK *parent = OB_parent(first);
01060 ORI_BLOCK *sibling, *prev;
01061 WN *first_stmt, *stmt;
01062 WN *container;
01063 INT num_bbs, num_stmts;
01064
01065 if (WN_opcode(OB_tree(parent)) == OPC_IF) {
01066
01067 OB_expanded(first) = TRUE;
01068 return;
01069 }
01070 if (Trace_ORI) fprintf(TFile, "ori: expand siblings of %d\n", OB_id(first));
01071
01072
01073 Get_First_Stmt_And_Container (parent, &first_stmt, &container);
01074 stmt = first_stmt;
01075 sibling = first;
01076 prev = NULL;
01077 num_bbs = num_stmts = 0;
01078 while (stmt != NULL) {
01079 Count_WN_Node (stmt, &num_bbs, &num_stmts);
01080 if (sibling && OB_tree(sibling) == stmt) {
01081
01082 if (stmt != first_stmt) {
01083
01084 Create_New_Child (parent, prev, sibling,
01085 first_stmt, WN_prev(stmt),
01086 num_bbs, num_stmts);
01087 }
01088 num_bbs = num_stmts = 0;
01089
01090 while (stmt != OB_end_tree(sibling)) stmt = WN_next(stmt);
01091 first_stmt = WN_next(stmt);
01092 prev = sibling;
01093 sibling = OB_sibling(sibling);
01094 }
01095
01096
01097 if (stmt == OB_end_tree(parent)) {
01098 if (first_stmt == stmt || first_stmt == WN_next(stmt))
01099
01100 first_stmt = NULL;
01101 break;
01102 }
01103 stmt = WN_next(stmt);
01104 }
01105 if (sibling) DevWarn("ORI: nested block not found when expanding siblings for %d", OB_id(sibling));
01106 if (first_stmt != NULL) {
01107
01108
01109
01110 if (stmt == NULL) {
01111 for (stmt = first_stmt; WN_next(stmt) != NULL; stmt = WN_next(stmt))
01112 ;
01113 }
01114 Create_New_Child (parent, prev, NULL,
01115 first_stmt, stmt, num_bbs, num_stmts);
01116 }
01117 OB_expanded(OB_child(parent)) = TRUE;
01118 if (Trace_Blocks) Print_Ori_Block (TFile, parent);
01119 }
01120
01121
01122
01123 static ORI_BLOCK *
01124 Create_Merged_Block (ORI_BLOCK *start, ORI_BLOCK *last, ORI_BLOCK *before_start, ORI_BLOCK *after_last)
01125 {
01126 ORI_BLOCK *b;
01127 b = New_Ori_Block (OB_tree(start), OB_parent(start));
01128 OB_end_tree(b) = OB_end_tree(last);
01129 OB_container(b) = OB_container(start);
01130 OB_labels(b) = OB_labels(start);
01131 OB_expanded(b) = TRUE;
01132 ORI_BLOCK *tmp;
01133 for (tmp = start; tmp != after_last; tmp = OB_sibling(tmp)) {
01134 OB_num_bbs(b) += OB_num_bbs(tmp);
01135 OB_num_stmts(b) += OB_num_stmts(tmp);
01136 OB_parent(tmp) = b;
01137 }
01138 OB_child(b) = start;
01139 OB_sibling(b) = after_last;
01140 OB_sibling(last) = NULL;
01141 if (before_start)
01142 OB_sibling(before_start) = b;
01143 else
01144 OB_child(OB_parent(b)) = b;
01145 if (Trace_ORI) fprintf(TFile, "ori: merge blocks %d to %d into %d\n", OB_id(start), OB_id(last), OB_id(b));
01146 return b;
01147 }
01148
01149
01150
01151 static void
01152 Update_Label_Info (ORI_BLOCK *b)
01153 {
01154 WNLIST *labs;
01155 INT lnum;
01156 INT label_level = OB_level(b);
01157
01158 for (labs = OB_labels(b); labs != NULL; labs = WNLIST_next(labs)) {
01159 if (WN_opcode(WNLIST_item(labs)) != OPC_LABEL)
01160
01161
01162 continue;
01163 lnum = WN_label_number(WNLIST_item(labs));
01164 if (label_branches[lnum] == NULL) {
01165
01166 Remove_Wn_From_List (WNLIST_item(labs), &OB_labels(b));
01167 if (Trace_Merging) fprintf(TFile, "ori: label %d is unused\n", lnum);
01168 }
01169 else {
01170 OBLIST *branches;
01171 ORI_BLOCK *branch, *new_branch;
01172 INT branch_level;
01173 branches = label_branches[lnum];
01174 for (; branches != NULL; branches = OBLIST_next(branches)) {
01175 branch = OBLIST_item(branches);
01176
01177
01178 branch_level = OB_level(branch);
01179 INT i;
01180 i = branch_level - label_level;
01181 if (i == 0) continue;
01182
01183 new_branch = branch;
01184 for (; i > 0; i--) {
01185 new_branch = OB_parent(new_branch);
01186 }
01187
01188 Remove_Ob_From_List (branch, &label_branches[lnum]);
01189 Add_Ob_To_List (new_branch, &label_branches[lnum]);
01190 }
01191 }
01192 }
01193 }
01194
01195
01196 static BOOL
01197 Merge_Across_Labels (ORI_BLOCK **first, INT32 olimit)
01198 {
01199 ORI_BLOCK *cur = *first;
01200 BOOL did_merge = FALSE;
01201 while (cur != NULL) {
01202 if (OB_labels(cur)) {
01203 Update_Label_Info(cur);
01204 if (OB_labels(cur) == NULL) {
01205
01206 did_merge = TRUE;
01207 continue;
01208 }
01209 else if (WNLIST_next(OB_labels(cur))) {
01210
01211
01212 if (Trace_Merging) fprintf(TFile, "ori: too many labels at block %d\n", OB_id(cur));
01213 continue;
01214 }
01215 else if (WN_opcode(WNLIST_item(OB_labels(cur))) != OPC_LABEL) {
01216
01217 continue;
01218 }
01219
01220
01221 INT lnum;
01222 lnum = WN_label_number(WNLIST_item(OB_labels(cur)));
01223 if (OBLIST_next(label_branches[lnum])) {
01224
01225
01226 if (Trace_Merging) fprintf(TFile, "ori: too many branches to label %d\n", lnum);
01227 }
01228 else {
01229
01230 ORI_BLOCK *branch;
01231 branch = OBLIST_item(label_branches[lnum]);
01232 if (Trace_Merging) fprintf(TFile, "ori: try to merge label %d in block %d with branch in block %d\n", lnum, OB_id(cur), OB_id(branch));
01233 INT num_bbs = OB_num_bbs(branch);
01234 INT num_stmts = OB_num_stmts(branch);
01235 ORI_BLOCK *b;
01236 for (b = OB_sibling(branch); b != NULL && b != cur; b = OB_sibling(b)) {
01237 if (OB_never_in_region(b))
01238 break;
01239 if (OB_labels(b))
01240 break;
01241 num_bbs += OB_num_bbs(b);
01242 num_stmts += OB_num_stmts(b);
01243 if (COMPUTE_OLIMIT(num_bbs,num_stmts) > olimit)
01244 break;
01245 }
01246 if (b == cur) {
01247
01248 num_bbs += OB_num_bbs(b);
01249 num_stmts += OB_num_stmts(b);
01250 }
01251 if (b == cur && !OB_never_in_region(branch)
01252 && (COMPUTE_OLIMIT(num_bbs,num_stmts) <= olimit) )
01253 {
01254
01255 cur = Create_Merged_Block (branch, cur,
01256 OB_prev(branch), OB_sibling(cur));
01257 if (branch == *first) *first = cur;
01258 did_merge = TRUE;
01259
01260
01261
01262
01263 return TRUE;
01264 }
01265 }
01266 }
01267 cur = OB_sibling(cur);
01268 }
01269 return did_merge;
01270 }
01271
01272
01273
01274
01275
01276 static void
01277 Merge_Blocks (ORI_BLOCK *first, INT32 olimit)
01278 {
01279 ORI_BLOCK *parent = OB_parent(first);
01280 ORI_BLOCK *start = first;
01281 ORI_BLOCK *cur = first;
01282 ORI_BLOCK *prev = NULL;
01283 ORI_BLOCK *prev_start= NULL;
01284 ORI_BLOCK *b;
01285 INT num_bbs = 0;
01286 INT num_stmts = 0;
01287 BOOL merge_previous = FALSE;
01288 BOOL did_merge = FALSE;
01289 if (Trace_Merging) fprintf(TFile, "ori: must merge siblings of %d\n", OB_id(first));
01290 while (cur != NULL) {
01291 if (COMPUTE_OLIMIT(num_bbs+OB_num_bbs(cur),num_stmts+OB_num_stmts(cur)) > olimit) {
01292 merge_previous = TRUE;
01293 }
01294 if (OB_labels(cur)) {
01295
01296 if (Trace_Merging) fprintf(TFile, "ori: can't merge block %d\n", OB_id(cur));
01297 merge_previous = TRUE;
01298 }
01299 if (OB_never_in_region(cur)) {
01300
01301 merge_previous = TRUE;
01302 }
01303 if (WN_opcode(OB_tree(cur)) == OPC_REGION) {
01304
01305
01306
01307
01308 merge_previous = TRUE;
01309 }
01310 if (merge_previous) {
01311 if (prev && start != prev) {
01312
01313 b = Create_Merged_Block (start, prev,
01314 prev_start, cur);
01315 did_merge = TRUE;
01316 prev = b;
01317 }
01318 prev_start = prev;
01319 start = cur;
01320 num_bbs = num_stmts = 0;
01321 merge_previous = FALSE;
01322 while (cur != NULL && (OB_never_in_region(cur)
01323 || (WN_opcode(OB_tree(cur)) == OPC_REGION)) )
01324 {
01325
01326 prev_start = cur;
01327 cur = OB_sibling(cur);
01328 start = cur;
01329 prev = cur;
01330 }
01331 if (cur == NULL) break;
01332 }
01333 num_bbs += OB_num_bbs(cur);
01334 num_stmts += OB_num_stmts(cur);
01335 prev = cur;
01336 cur = OB_sibling(cur);
01337 }
01338 if (start != prev && start != first) {
01339
01340
01341 b = Create_Merged_Block (start, prev, prev_start, NULL);
01342 did_merge = TRUE;
01343 }
01344
01345 if (!did_merge) {
01346 did_merge = Merge_Across_Labels (&first, olimit);
01347 }
01348 if (!did_merge) {
01349
01350 OB_no_more_merge(OB_child(parent)) = TRUE;
01351 if (Trace_ORI) {
01352 fprintf(TFile, "ori: couldn't merge anything\n");
01353 Print_Ori_Block (TFile, parent);
01354 }
01355 }
01356 if (Trace_Blocks) Print_Ori_Block (TFile, parent);
01357 }
01358
01359
01360
01361 static BOOL
01362 Build_Blocks_In_Region_List (ORI_BLOCK *b, WNLIST *entry_label)
01363 {
01364 if (b == NULL) return TRUE;
01365 if (last_block_in_region_index >= max_block_in_region_index) {
01366
01367 FmtAssert(last_id > max_block_in_region_index, ("ORI overflow in Build_Blocks_In_Region"));
01368 DevWarn("ORI: had to realloc");
01369 blocks_in_region = TYPE_MEM_POOL_REALLOC_N (
01370 UINT32, &Ori_pool, blocks_in_region,
01371 max_block_in_region_index, last_id);
01372 labels_in_region = TYPE_MEM_POOL_REALLOC_N (
01373 WNLIST *, &Ori_pool, labels_in_region,
01374 max_block_in_region_index, last_id);
01375 max_block_in_region_index = last_id;
01376 }
01377 blocks_in_region[last_block_in_region_index++] = OB_id(b);
01378 if (OB_labels(b) != NULL && OB_labels(b) != entry_label
01379 && WN_opcode(WNLIST_item(OB_labels(b))) == OPC_LABEL)
01380 {
01381 labels_in_region[last_label_in_region_index++] = OB_labels(b);
01382 }
01383 if (OB_never_in_region(b)) {
01384 if (Trace_ORI) fprintf(TFile, "ori: region contains never block %d\n", OB_id(b));
01385 return FALSE;
01386 }
01387 BOOL okay = TRUE;
01388 okay = Build_Blocks_In_Region_List (OB_child(b), entry_label);
01389 okay &= Build_Blocks_In_Region_List (OB_sibling(b), entry_label);
01390 return okay;
01391 }
01392
01393
01394 static BOOL
01395 Branch_In_Region_List (UINT32 branch_id)
01396 {
01397 INT i;
01398 for (i = 0; i < last_block_in_region_index; i++) {
01399 if (branch_id == blocks_in_region[i])
01400 return TRUE;
01401 }
01402 return FALSE;
01403 }
01404
01405
01406
01407 static BOOL
01408 Region_Is_Illegal (ORI_BLOCK *b)
01409 {
01410 if (OB_illegal(b)) return TRUE;
01411
01412
01413
01414
01415
01416
01417 if (blocks_in_region == NULL) {
01418 max_block_in_region_index = last_id + 20;
01419 blocks_in_region = (UINT32 *) MEM_POOL_Alloc (&Ori_pool,
01420 sizeof(UINT32) * max_block_in_region_index);
01421 labels_in_region = (WNLIST **) MEM_POOL_Alloc (&Ori_pool,
01422 sizeof(WNLIST *) * max_block_in_region_index);
01423 }
01424 last_block_in_region_index = 0;
01425 last_label_in_region_index = 0;
01426
01427 blocks_in_region[last_block_in_region_index++] = OB_id(b);
01428 BOOL okay;
01429 okay = Build_Blocks_In_Region_List (OB_child(b), OB_labels(b));
01430 if (!okay) {
01431 OB_illegal(b) = TRUE;
01432 return TRUE;
01433 }
01434
01435 INT i;
01436 INT lnum;
01437 INT branch_id;
01438 OBLIST *branches;
01439 for (i = 0; i < last_label_in_region_index; i++) {
01440 lnum = WN_label_number(WNLIST_item(labels_in_region[i]));
01441 branches = label_branches[lnum];
01442 for (; branches != NULL; branches = OBLIST_next(branches)) {
01443 branch_id = OB_id(OBLIST_item(branches));
01444 if ( ! Branch_In_Region_List(branch_id)) {
01445 if (Trace_ORI) fprintf(TFile, "branch in %d to label %d is outside region\n", branch_id, lnum);
01446 OB_illegal(b) = TRUE;
01447 return TRUE;
01448 }
01449
01450 }
01451 }
01452 return FALSE;
01453 }
01454
01455
01456 typedef enum {TOO_SMALL, JUST_RIGHT, TOO_BIG} BLOCK_SIZE;
01457
01458 #define MIN_BLOCK_SIZE(olimit) (olimit / 4)
01459
01460
01461 static BLOCK_SIZE
01462 Olimit_Size (ORI_BLOCK *b, INT32 olimit)
01463 {
01464 INT32 minsize = MIN_BLOCK_SIZE(olimit);
01465 if (OB_size(b) > olimit)
01466 return TOO_BIG;
01467 else if (OB_size(b) < minsize)
01468 return TOO_SMALL;
01469
01470 else if (b != pu_block && OB_sub_size(pu_block,b) < minsize)
01471 return TOO_BIG;
01472 else if (OB_never_in_region(b) || OB_illegal(b))
01473 return TOO_SMALL;
01474 else
01475 return JUST_RIGHT;
01476 }
01477
01478
01479 static ORI_BLOCK *
01480 Find_Largest_Block (ORI_BLOCK *first)
01481 {
01482 ORI_BLOCK *b;
01483 ORI_BLOCK *tmp;
01484 ORI_BLOCK *max = NULL;
01485 INT32 maxsize = 0;
01486 for (b = first; b != NULL; b = OB_sibling(b)) {
01487 if (OB_never_in_region(b)) {
01488
01489 continue;
01490 }
01491 else if (OB_illegal(b)) {
01492 if (OB_size(b) <= maxsize) {
01493 continue;
01494 } else {
01495
01496 tmp = Find_Largest_Block(OB_child(b));
01497 }
01498 }
01499 else {
01500 tmp = b;
01501 }
01502 if (tmp != NULL && OB_size(tmp) > maxsize) {
01503 maxsize = OB_size(tmp);
01504 max = tmp;
01505 }
01506 }
01507 if (max == NULL) {
01508 DevWarn("ORI: size %d > olimit, but can't create anymore regions",
01509 OB_size(OB_parent(first)));
01510 if (Trace_ORI) fprintf(TFile, "ori: couldn't find any nonzero blocks under block %d\n", OB_id(OB_parent(first)));
01511 return NULL;
01512 }
01513 if (Region_Is_Illegal(max)) {
01514
01515 max = Find_Largest_Block(first);
01516 }
01517 return max;
01518 }
01519
01520
01521
01522
01523
01524 static BOOL
01525 Insert_Smaller_Regions (ORI_BLOCK *parent, INT32 olimit)
01526 {
01527 ORI_BLOCK *b;
01528 while (Olimit_Size(parent,olimit) == TOO_BIG) {
01529
01530 if (OB_size(pu_block) <= olimit) break;
01531 b = Find_Largest_Block(OB_child(parent));
01532 if (b == NULL) return FALSE;
01533 if (Trace_ORI) fprintf(TFile, "insert smaller region at block %d of size %d\n", OB_id(b), OB_size(b));
01534 Insert_Region_Around_Block (b);
01535 }
01536 return TRUE;
01537 }
01538
01539
01540 static ORI_BLOCK *
01541 Choose_Region_Block (ORI_BLOCK *b, INT32 olimit, BLOCK_SIZE *bs)
01542 {
01543 *bs = Olimit_Size (b, olimit);
01544 if (*bs == JUST_RIGHT && Region_Is_Illegal(b)) {
01545
01546
01547 if (Trace_ORI) fprintf(TFile, "ori: illegal region %d\n", OB_id(b));
01548 DevWarn ("ORI: wanted to create illegal region");
01549 *bs = TOO_SMALL;
01550 }
01551 switch (*bs) {
01552 case JUST_RIGHT:
01553
01554
01555
01556
01557
01558 if (OB_nested_region(b)) {
01559 ORI_BLOCK *kid = OB_child(b);
01560 for ( ; kid != NULL; kid = OB_sibling(kid)) {
01561 if (WN_opcode(OB_tree(kid)) != OPC_REGION
01562 && Olimit_Size(kid, olimit) == JUST_RIGHT)
01563 return kid;
01564 }
01565
01566 }
01567 return b;
01568 case TOO_BIG:
01569 FmtAssert(WN_opcode(OB_tree(b)) != OPC_EXC_SCOPE_BEGIN,
01570 ("Exception scope is bigger than region olimit size"));
01571 if (OB_child(b)) {
01572 return Choose_Region_Block (OB_child(b), olimit, bs);
01573 }
01574 else {
01575 Split_Block (b);
01576 return Choose_Region_Block (b, olimit, bs);
01577 }
01578 case TOO_SMALL:
01579
01580 if (OB_sibling(b)) {
01581 return Choose_Region_Block (OB_sibling(b), olimit, bs);
01582 }
01583 else {
01584 if (OB_expanded(OB_first_sibling(b))) {
01585
01586 Merge_Blocks (OB_first_sibling(b), olimit);
01587 if (OB_no_more_merge(OB_first_sibling(b))
01588 && Olimit_Size(OB_parent(b), olimit) == TOO_BIG)
01589 {
01590
01591
01592 *bs = TOO_BIG;
01593 return OB_parent(b);
01594 }
01595 }
01596 else {
01597
01598 Expand_Sibling_Blocks (OB_first_sibling(b));
01599 }
01600 return Choose_Region_Block (OB_parent(b), olimit, bs);
01601 }
01602 default:
01603
01604 return NULL;
01605 }
01606 }
01607
01608 extern WN*
01609 Olimit_Region_Insertion (WN *pu_tree, INT32 olimit)
01610 {
01611 ORI_BLOCK *b;
01612 BLOCK_SIZE size;
01613 INT pu_size;
01614 Set_Error_Phase("ORI");
01615 Start_Timer(T_ORI_CU);
01616 Initialize_Trace_Flags();
01617
01618 if (PU_has_alloca(Get_Current_PU())) {
01619 DevWarn("ORI: has alloca, so don't create regions");
01620 return pu_tree;
01621 }
01622 if (PU_has_namelist(Get_Current_PU())) {
01623 DevWarn("ORI: has namelist, so don't create regions");
01624 return pu_tree;
01625 }
01626 if (PU_has_mp(Get_Current_PU())) {
01627 DevWarn("ORI: has MP, so don't create regions");
01628 return pu_tree;
01629 }
01630 if (PU_has_exc_scopes(Get_Current_PU()))
01631 {
01632
01633
01634 DevWarn("ORI: has exception scopes, so don't create regions");
01635 return pu_tree;
01636 }
01637
01638 MEM_POOL_Initialize (&Ori_pool, "ORI_pool", FALSE);
01639 MEM_POOL_Push (&Ori_pool);
01640
01641 if (Run_Goto_Conversion)
01642 {
01643
01644 GOTO_TABLE goto_table( pu_tree, &Ori_pool);
01645 goto_table.Remove_Gotos();
01646 if (Trace_Goto_Conversion) goto_table.Print(TFile);
01647
01648 Check_Dump (pu_tree, "After ORI goto conversion:");
01649 }
01650
01651 Initialize_ORI();
01652
01653
01654 pu_block = Build_Ori_Blocks (pu_tree, olimit);
01655 Propagate_Child_Info (pu_block);
01656 pu_size = OB_size(pu_block);
01657 if (Trace_ORI) Print_Ori_Block (TFile, pu_block);
01658
01659
01660
01661 while (OB_size(pu_block) > olimit) {
01662 b = Choose_Region_Block (pu_block, olimit, &size);
01663
01664
01665
01666
01667
01668 if (size == JUST_RIGHT) {
01669 Insert_Region_Around_Block (b);
01670 }
01671 else {
01672 if (!Insert_Smaller_Regions (b, olimit))
01673 break;
01674 }
01675 if (Trace_ORI) Print_Ori_Block (TFile, pu_block);
01676 }
01677
01678 if (num_regions > 0) {
01679 ErrMsg (EC_ORI_Invoked, ST_name(WN_st(pu_tree)), pu_size);
01680 DevWarn("splitting function %s into %d regions",
01681 ST_name(WN_st(pu_tree)), num_regions);
01682 }
01683 else {
01684 DevWarn("ORI invoked, but no regions created");
01685 }
01686 Check_Dump (pu_tree, "After ORI region insertion:");
01687
01688 MEM_POOL_Pop (&Ori_pool);
01689 MEM_POOL_Delete (&Ori_pool);
01690 Stop_Timer(T_ORI_CU);
01691 return pu_tree;
01692 }
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847
01848