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 #include "config.h"
00040 #include "system.h"
00041 #ifdef SGI_MONGOOSE
00042
00043 #include "rtl.h"
00044 #endif
00045 #include "tree.h"
00046 #ifndef SGI_MONGOOSE
00047 #include "rtl.h"
00048 #endif
00049 #include "hard-reg-set.h"
00050 #include "basic-block.h"
00051 #include "regs.h"
00052 #include "flags.h"
00053 #include "output.h"
00054 #include "function.h"
00055 #include "except.h"
00056 #include "toplev.h"
00057 #include "timevar.h"
00058
00059 static int count_basic_blocks PARAMS ((rtx));
00060 static void find_basic_blocks_1 PARAMS ((rtx));
00061 static rtx find_label_refs PARAMS ((rtx, rtx));
00062 static void make_edges PARAMS ((rtx, basic_block,
00063 basic_block, int));
00064 static void make_label_edge PARAMS ((sbitmap *, basic_block,
00065 rtx, int));
00066 static void make_eh_edge PARAMS ((sbitmap *, basic_block, rtx));
00067 static void find_bb_boundaries PARAMS ((basic_block));
00068 static void compute_outgoing_frequencies PARAMS ((basic_block));
00069 static bool inside_basic_block_p PARAMS ((rtx));
00070
00071
00072
00073
00074 static bool
00075 inside_basic_block_p (insn)
00076 rtx insn;
00077 {
00078 switch (GET_CODE (insn))
00079 {
00080 case CODE_LABEL:
00081
00082 return (NEXT_INSN (insn) == 0
00083 || GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
00084 || (GET_CODE (PATTERN (NEXT_INSN (insn))) != ADDR_VEC
00085 && GET_CODE (PATTERN (NEXT_INSN (insn))) != ADDR_DIFF_VEC));
00086
00087 case JUMP_INSN:
00088 return (GET_CODE (PATTERN (insn)) != ADDR_VEC
00089 && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC);
00090
00091 case CALL_INSN:
00092 case INSN:
00093 return true;
00094
00095 case BARRIER:
00096 case NOTE:
00097 return false;
00098
00099 default:
00100 abort ();
00101 }
00102 }
00103
00104
00105
00106
00107 bool
00108 control_flow_insn_p (insn)
00109 rtx insn;
00110 {
00111 rtx note;
00112
00113 switch (GET_CODE (insn))
00114 {
00115 case NOTE:
00116 case CODE_LABEL:
00117 return false;
00118
00119 case JUMP_INSN:
00120
00121 return (GET_CODE (PATTERN (insn)) != ADDR_VEC
00122 && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC);
00123
00124 case CALL_INSN:
00125
00126 return ((nonlocal_goto_handler_labels
00127 && (0 == (note = find_reg_note (insn, REG_EH_REGION,
00128 NULL_RTX))
00129 || INTVAL (XEXP (note, 0)) >= 0))
00130
00131 || can_throw_internal (insn));
00132
00133 case INSN:
00134 return (flag_non_call_exceptions && can_throw_internal (insn));
00135
00136 case BARRIER:
00137
00138
00139
00140 return false;
00141
00142 default:
00143 abort ();
00144 }
00145 }
00146
00147
00148
00149 static int
00150 count_basic_blocks (f)
00151 rtx f;
00152 {
00153 int count = 0;
00154 bool saw_insn = false;
00155 rtx insn;
00156
00157 for (insn = f; insn; insn = NEXT_INSN (insn))
00158 {
00159
00160
00161 if ((GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
00162 && saw_insn)
00163 count++, saw_insn = false;
00164
00165
00166 if (!saw_insn && inside_basic_block_p (insn))
00167 saw_insn = true;
00168
00169
00170 if (saw_insn && control_flow_insn_p (insn))
00171 count++, saw_insn = false;
00172 }
00173
00174 if (saw_insn)
00175 count++;
00176
00177
00178
00179 if (count == 0)
00180 {
00181 emit_insn (gen_rtx_USE (VOIDmode, const0_rtx));
00182 count = 1;
00183 }
00184
00185 return count;
00186 }
00187
00188
00189
00190
00191 static rtx
00192 find_label_refs (f, lvl)
00193 rtx f;
00194 rtx lvl;
00195 {
00196 rtx insn;
00197
00198 for (insn = f; insn; insn = NEXT_INSN (insn))
00199 if (INSN_P (insn) && GET_CODE (insn) != JUMP_INSN)
00200 {
00201 rtx note;
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
00213 if (REG_NOTE_KIND (note) == REG_LABEL)
00214 {
00215 rtx lab = XEXP (note, 0), next;
00216
00217 if ((next = next_nonnote_insn (lab)) != NULL
00218 && GET_CODE (next) == JUMP_INSN
00219 && (GET_CODE (PATTERN (next)) == ADDR_VEC
00220 || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
00221 ;
00222 else if (GET_CODE (lab) == NOTE)
00223 ;
00224 else if (GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
00225 && find_reg_note (NEXT_INSN (insn), REG_LABEL, lab))
00226 ;
00227 else
00228 lvl = alloc_EXPR_LIST (0, XEXP (note, 0), lvl);
00229 }
00230 }
00231
00232 return lvl;
00233 }
00234
00235
00236
00237
00238
00239
00240 static void
00241 make_label_edge (edge_cache, src, label, flags)
00242 sbitmap *edge_cache;
00243 basic_block src;
00244 rtx label;
00245 int flags;
00246 {
00247 if (GET_CODE (label) != CODE_LABEL)
00248 abort ();
00249
00250
00251
00252
00253
00254
00255 if (INSN_UID (label) == 0)
00256 return;
00257
00258 cached_make_edge (edge_cache, src, BLOCK_FOR_INSN (label), flags);
00259 }
00260
00261
00262
00263 static void
00264 make_eh_edge (edge_cache, src, insn)
00265 sbitmap *edge_cache;
00266 basic_block src;
00267 rtx insn;
00268 {
00269 int is_call = GET_CODE (insn) == CALL_INSN ? EDGE_ABNORMAL_CALL : 0;
00270 rtx handlers, i;
00271
00272 handlers = reachable_handlers (insn);
00273
00274 for (i = handlers; i; i = XEXP (i, 1))
00275 make_label_edge (edge_cache, src, XEXP (i, 0),
00276 EDGE_ABNORMAL | EDGE_EH | is_call);
00277
00278 free_INSN_LIST_list (&handlers);
00279 }
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 static void
00290 make_edges (label_value_list, min, max, update_p)
00291 rtx label_value_list;
00292 basic_block min, max;
00293 int update_p;
00294 {
00295 basic_block bb;
00296 sbitmap *edge_cache = NULL;
00297
00298
00299 current_function_has_computed_jump = 0;
00300
00301
00302
00303
00304 if (forced_labels || label_value_list || cfun->max_jumptable_ents > 100)
00305 {
00306 edge_cache = sbitmap_vector_alloc (last_basic_block, last_basic_block);
00307 sbitmap_vector_zero (edge_cache, last_basic_block);
00308
00309 if (update_p)
00310 FOR_BB_BETWEEN (bb, min, max->next_bb, next_bb)
00311 {
00312 edge e;
00313
00314 for (e = bb->succ; e ; e = e->succ_next)
00315 if (e->dest != EXIT_BLOCK_PTR)
00316 SET_BIT (edge_cache[bb->index], e->dest->index);
00317 }
00318 }
00319
00320
00321
00322 if (min == ENTRY_BLOCK_PTR->next_bb)
00323 cached_make_edge (edge_cache, ENTRY_BLOCK_PTR, min,
00324 EDGE_FALLTHRU);
00325
00326 FOR_BB_BETWEEN (bb, min, max->next_bb, next_bb)
00327 {
00328 rtx insn, x;
00329 enum rtx_code code;
00330 int force_fallthru = 0;
00331
00332 if (GET_CODE (bb->head) == CODE_LABEL && LABEL_ALT_ENTRY_P (bb->head))
00333 cached_make_edge (NULL, ENTRY_BLOCK_PTR, bb, 0);
00334
00335
00336
00337
00338 insn = bb->end;
00339 code = GET_CODE (insn);
00340
00341
00342 if (code == JUMP_INSN)
00343 {
00344 rtx tmp;
00345
00346
00347 if (GET_CODE (PATTERN (insn)) == RESX)
00348 make_eh_edge (edge_cache, bb, insn);
00349
00350
00351
00352 else if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
00353 ;
00354
00355
00356 else if ((tmp = JUMP_LABEL (insn)) != NULL_RTX
00357 && (tmp = NEXT_INSN (tmp)) != NULL_RTX
00358 && GET_CODE (tmp) == JUMP_INSN
00359 && (GET_CODE (PATTERN (tmp)) == ADDR_VEC
00360 || GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC))
00361 {
00362 rtvec vec;
00363 int j;
00364
00365 if (GET_CODE (PATTERN (tmp)) == ADDR_VEC)
00366 vec = XVEC (PATTERN (tmp), 0);
00367 else
00368 vec = XVEC (PATTERN (tmp), 1);
00369
00370 for (j = GET_NUM_ELEM (vec) - 1; j >= 0; --j)
00371 make_label_edge (edge_cache, bb,
00372 XEXP (RTVEC_ELT (vec, j), 0), 0);
00373
00374
00375
00376
00377 if ((tmp = single_set (insn)) != NULL
00378 && SET_DEST (tmp) == pc_rtx
00379 && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
00380 && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF)
00381 make_label_edge (edge_cache, bb,
00382 XEXP (XEXP (SET_SRC (tmp), 2), 0), 0);
00383
00384 #ifdef CASE_DROPS_THROUGH
00385
00386
00387 force_fallthru = 1;
00388 #endif
00389 }
00390
00391
00392
00393 else if (computed_jump_p (insn))
00394 {
00395 current_function_has_computed_jump = 1;
00396
00397 for (x = label_value_list; x; x = XEXP (x, 1))
00398 make_label_edge (edge_cache, bb, XEXP (x, 0), EDGE_ABNORMAL);
00399
00400 for (x = forced_labels; x; x = XEXP (x, 1))
00401 make_label_edge (edge_cache, bb, XEXP (x, 0), EDGE_ABNORMAL);
00402 }
00403
00404
00405 else if (returnjump_p (insn))
00406 cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR, 0);
00407
00408
00409 else
00410 {
00411 if (! JUMP_LABEL (insn))
00412 abort ();
00413 make_label_edge (edge_cache, bb, JUMP_LABEL (insn), 0);
00414 }
00415 }
00416
00417
00418
00419
00420
00421 if (code == CALL_INSN && SIBLING_CALL_P (insn))
00422 cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
00423 EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
00424
00425
00426
00427
00428
00429 else if (code == CALL_INSN || flag_non_call_exceptions)
00430 {
00431
00432 make_eh_edge (edge_cache, bb, insn);
00433
00434 if (code == CALL_INSN && nonlocal_goto_handler_labels)
00435 {
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
00446
00447 if (!note || INTVAL (XEXP (note, 0)) >= 0)
00448 for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1))
00449 make_label_edge (edge_cache, bb, XEXP (x, 0),
00450 EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
00451 }
00452 }
00453
00454
00455 insn = next_nonnote_insn (insn);
00456 if (!insn || (bb->next_bb == EXIT_BLOCK_PTR && force_fallthru))
00457 cached_make_edge (edge_cache, bb, EXIT_BLOCK_PTR, EDGE_FALLTHRU);
00458 else if (bb->next_bb != EXIT_BLOCK_PTR)
00459 {
00460 rtx tmp = bb->next_bb->head;
00461 if (GET_CODE (tmp) == NOTE)
00462 tmp = next_nonnote_insn (tmp);
00463 if (force_fallthru || insn == tmp)
00464 cached_make_edge (edge_cache, bb, bb->next_bb, EDGE_FALLTHRU);
00465 }
00466 }
00467
00468 if (edge_cache)
00469 sbitmap_vector_free (edge_cache);
00470 }
00471
00472
00473
00474
00475
00476
00477 static void
00478 find_basic_blocks_1 (f)
00479 rtx f;
00480 {
00481 rtx insn, next;
00482 rtx bb_note = NULL_RTX;
00483 rtx lvl = NULL_RTX;
00484 rtx trll = NULL_RTX;
00485 rtx head = NULL_RTX;
00486 rtx end = NULL_RTX;
00487 basic_block prev = ENTRY_BLOCK_PTR;
00488
00489
00490
00491
00492
00493
00494
00495 for (insn = f; insn; insn = next)
00496 {
00497 enum rtx_code code = GET_CODE (insn);
00498
00499 next = NEXT_INSN (insn);
00500
00501 if ((GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
00502 && head)
00503 {
00504 prev = create_basic_block_structure (head, end, bb_note, prev);
00505 head = end = NULL_RTX;
00506 bb_note = NULL_RTX;
00507 }
00508
00509 if (inside_basic_block_p (insn))
00510 {
00511 if (head == NULL_RTX)
00512 head = insn;
00513 end = insn;
00514 }
00515
00516 if (head && control_flow_insn_p (insn))
00517 {
00518 prev = create_basic_block_structure (head, end, bb_note, prev);
00519 head = end = NULL_RTX;
00520 bb_note = NULL_RTX;
00521 }
00522
00523 switch (code)
00524 {
00525 case NOTE:
00526 {
00527 int kind = NOTE_LINE_NUMBER (insn);
00528
00529
00530
00531
00532
00533 if (kind == NOTE_INSN_BASIC_BLOCK)
00534 {
00535 if (bb_note == NULL_RTX)
00536 bb_note = insn;
00537 else
00538 next = delete_insn (insn);
00539 }
00540 break;
00541 }
00542
00543 case CODE_LABEL:
00544 case JUMP_INSN:
00545 case INSN:
00546 case BARRIER:
00547 break;
00548
00549 case CALL_INSN:
00550 if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
00551 {
00552
00553 lvl = find_label_refs (XEXP (PATTERN (insn), 0), lvl);
00554 lvl = find_label_refs (XEXP (PATTERN (insn), 1), lvl);
00555 lvl = find_label_refs (XEXP (PATTERN (insn), 2), lvl);
00556
00557 if (XEXP (PATTERN (insn), 3) != NULL_RTX)
00558 trll = alloc_EXPR_LIST (0, XEXP (PATTERN (insn), 3), trll);
00559 }
00560 break;
00561
00562 default:
00563 abort ();
00564 }
00565
00566 if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
00567 {
00568 rtx note;
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
00579 if (REG_NOTE_KIND (note) == REG_LABEL)
00580 {
00581 rtx lab = XEXP (note, 0), next;
00582
00583 if ((next = next_nonnote_insn (lab)) != NULL
00584 && GET_CODE (next) == JUMP_INSN
00585 && (GET_CODE (PATTERN (next)) == ADDR_VEC
00586 || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
00587 ;
00588 else if (GET_CODE (lab) == NOTE)
00589 ;
00590 else if (GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
00591 && find_reg_note (NEXT_INSN (insn), REG_LABEL, lab))
00592 ;
00593 else
00594 lvl = alloc_EXPR_LIST (0, XEXP (note, 0), lvl);
00595 }
00596 }
00597 }
00598
00599 if (head != NULL_RTX)
00600 create_basic_block_structure (head, end, bb_note, prev);
00601 else if (bb_note)
00602 delete_insn (bb_note);
00603
00604 if (last_basic_block != n_basic_blocks)
00605 abort ();
00606
00607 label_value_list = lvl;
00608 tail_recursion_label_list = trll;
00609 clear_aux_for_blocks ();
00610 }
00611
00612
00613
00614
00615
00616
00617 void
00618 find_basic_blocks (f, nregs, file)
00619 rtx f;
00620 int nregs ATTRIBUTE_UNUSED;
00621 FILE *file ATTRIBUTE_UNUSED;
00622 {
00623 basic_block bb;
00624
00625 timevar_push (TV_CFG);
00626
00627
00628 if (basic_block_info != NULL)
00629 {
00630 clear_edges ();
00631
00632
00633
00634
00635 FOR_EACH_BB (bb)
00636 bb->aux = NULL;
00637
00638 VARRAY_FREE (basic_block_info);
00639 }
00640
00641 n_basic_blocks = count_basic_blocks (f);
00642 last_basic_block = 0;
00643 ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR;
00644 EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR;
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 VARRAY_BB_INIT (basic_block_info, n_basic_blocks, "basic_block_info");
00655
00656 find_basic_blocks_1 (f);
00657
00658
00659 make_edges (label_value_list, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR->prev_bb, 0);
00660
00661
00662
00663 tidy_fallthru_edges ();
00664
00665 #ifdef ENABLE_CHECKING
00666 verify_flow_info ();
00667 #endif
00668 timevar_pop (TV_CFG);
00669 }
00670
00671
00672 enum state {BLOCK_NEW = 0, BLOCK_ORIGINAL, BLOCK_TO_SPLIT};
00673
00674 #define STATE(BB) (enum state) ((size_t) (BB)->aux)
00675 #define SET_STATE(BB, STATE) ((BB)->aux = (void *) (size_t) (STATE))
00676
00677
00678
00679
00680 static void
00681 find_bb_boundaries (bb)
00682 basic_block bb;
00683 {
00684 rtx insn = bb->head;
00685 rtx end = bb->end;
00686 rtx flow_transfer_insn = NULL_RTX;
00687 edge fallthru = NULL;
00688
00689 if (insn == bb->end)
00690 return;
00691
00692 if (GET_CODE (insn) == CODE_LABEL)
00693 insn = NEXT_INSN (insn);
00694
00695
00696 while (1)
00697 {
00698 enum rtx_code code = GET_CODE (insn);
00699
00700
00701 if (code == CODE_LABEL)
00702 {
00703 fallthru = split_block (bb, PREV_INSN (insn));
00704 if (flow_transfer_insn)
00705 bb->end = flow_transfer_insn;
00706
00707 bb = fallthru->dest;
00708 remove_edge (fallthru);
00709 flow_transfer_insn = NULL_RTX;
00710 if (LABEL_ALT_ENTRY_P (insn))
00711 make_edge (ENTRY_BLOCK_PTR, bb, 0);
00712 }
00713
00714
00715
00716 if (flow_transfer_insn && inside_basic_block_p (insn))
00717 {
00718 fallthru = split_block (bb, PREV_INSN (insn));
00719 bb->end = flow_transfer_insn;
00720 bb = fallthru->dest;
00721 remove_edge (fallthru);
00722 flow_transfer_insn = NULL_RTX;
00723 }
00724
00725 if (control_flow_insn_p (insn))
00726 flow_transfer_insn = insn;
00727 if (insn == end)
00728 break;
00729 insn = NEXT_INSN (insn);
00730 }
00731
00732
00733
00734
00735 if (flow_transfer_insn)
00736 bb->end = flow_transfer_insn;
00737
00738
00739
00740
00741 purge_dead_edges (bb);
00742 }
00743
00744
00745
00746
00747 static void
00748 compute_outgoing_frequencies (b)
00749 basic_block b;
00750 {
00751 edge e, f;
00752
00753 if (b->succ && b->succ->succ_next && !b->succ->succ_next->succ_next)
00754 {
00755 rtx note = find_reg_note (b->end, REG_BR_PROB, NULL);
00756 int probability;
00757
00758 if (!note)
00759 return;
00760
00761 probability = INTVAL (XEXP (find_reg_note (b->end,
00762 REG_BR_PROB, NULL),
00763 0));
00764 e = BRANCH_EDGE (b);
00765 e->probability = probability;
00766 e->count = ((b->count * probability + REG_BR_PROB_BASE / 2)
00767 / REG_BR_PROB_BASE);
00768 f = FALLTHRU_EDGE (b);
00769 f->probability = REG_BR_PROB_BASE - probability;
00770 f->count = b->count - e->count;
00771 }
00772
00773 if (b->succ && !b->succ->succ_next)
00774 {
00775 e = b->succ;
00776 e->probability = REG_BR_PROB_BASE;
00777 e->count = b->count;
00778 }
00779 }
00780
00781
00782
00783
00784 void
00785 find_many_sub_basic_blocks (blocks)
00786 sbitmap blocks;
00787 {
00788 basic_block bb, min, max;
00789
00790 FOR_EACH_BB (bb)
00791 SET_STATE (bb,
00792 TEST_BIT (blocks, bb->index) ? BLOCK_TO_SPLIT : BLOCK_ORIGINAL);
00793
00794 FOR_EACH_BB (bb)
00795 if (STATE (bb) == BLOCK_TO_SPLIT)
00796 find_bb_boundaries (bb);
00797
00798 FOR_EACH_BB (bb)
00799 if (STATE (bb) != BLOCK_ORIGINAL)
00800 break;
00801
00802 min = max = bb;
00803 for (; bb != EXIT_BLOCK_PTR; bb = bb->next_bb)
00804 if (STATE (bb) != BLOCK_ORIGINAL)
00805 max = bb;
00806
00807
00808
00809 make_edges (NULL, min, max, 1);
00810
00811
00812
00813 FOR_BB_BETWEEN (bb, min, max->next_bb, next_bb)
00814 {
00815 edge e;
00816
00817 if (STATE (bb) == BLOCK_ORIGINAL)
00818 continue;
00819 if (STATE (bb) == BLOCK_NEW)
00820 {
00821 bb->count = 0;
00822 bb->frequency = 0;
00823 for (e = bb->pred; e; e=e->pred_next)
00824 {
00825 bb->count += e->count;
00826 bb->frequency += EDGE_FREQUENCY (e);
00827 }
00828 }
00829
00830 compute_outgoing_frequencies (bb);
00831 }
00832
00833 FOR_EACH_BB (bb)
00834 SET_STATE (bb, 0);
00835 }
00836
00837
00838
00839 void
00840 find_sub_basic_blocks (bb)
00841 basic_block bb;
00842 {
00843 basic_block min, max, b;
00844 basic_block next = bb->next_bb;
00845
00846 min = bb;
00847 find_bb_boundaries (bb);
00848 max = next->prev_bb;
00849
00850
00851
00852 make_edges (NULL, min, max, 1);
00853
00854
00855
00856 FOR_BB_BETWEEN (b, min, max->next_bb, next_bb)
00857 {
00858 edge e;
00859
00860 if (b != min)
00861 {
00862 b->count = 0;
00863 b->frequency = 0;
00864 for (e = b->pred; e; e=e->pred_next)
00865 {
00866 b->count += e->count;
00867 b->frequency += EDGE_FREQUENCY (e);
00868 }
00869 }
00870
00871 compute_outgoing_frequencies (b);
00872 }
00873 }