------- Additional Comments From law at redhat dot com 2004-11-22 17:15 ------- Subject: Re: [4.0 Regression] jump threading on trees is slow with switch statements with large # of cases
It's clearly getting more difficult to find compile-time improvements for 15524. But that doesn't mean we're done :-) As it turns out we've got more code which is just inlined versions of find_edge, but without the ability to select which list (src->succ or dest->pred) to walk depending on their lengths. This patch replaces those inlined instances of find_edge with calls to find_edge. The big winner is tree CFG construction which goes from .40 seconds to around .04 seconds. There are other wins scattered throughout the various passes. In all we go from 11.63 seconds of total time to 10.97 seconds of total time -- a net improvement of around 5%. [ Please don't close this PR. I still think there's another 4-5% that we'll be able to get without major surgery. ] Bootstrapped and regression tested on i686-pc-linux-gnu. * cfg.c (cached_make_edge): Use find_edge rather than an inlined variant. * cfgbuild.c (make_edges): Likewise. * cfghooks.c (can_duplicate_block_p): Likewise. * cfgloop.c (loop_latch_edge): Likewise. * cfgloopmanip.c (force_single_succ_latches): Likewise. * cfgrtl.c (rtl_flow_call_edges_add): Likewise. * predict.c (predict_loops, propagate_freq): Likewise. * tracer.c (tail_duplicate): Likewise. * tree-cfg.c (disband_implicit_edges): Likewise. (tree_forwarder_block_p, tree_flow_call_edges_add): Likewise. Index: cfg.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cfg.c,v retrieving revision 1.76 diff -c -p -r1.76 cfg.c *** cfg.c 22 Nov 2004 12:23:43 -0000 1.76 --- cfg.c 22 Nov 2004 16:57:55 -0000 *************** cached_make_edge (sbitmap *edge_cache, b *** 288,294 **** { int use_edge_cache; edge e; - edge_iterator ei; /* Don't bother with edge cache for ENTRY or EXIT, if there aren't that many edges to them, or we didn't allocate memory for it. */ --- 288,293 ---- *************** cached_make_edge (sbitmap *edge_cache, b *** 309,320 **** /* Fall through. */ case 0: ! FOR_EACH_EDGE (e, ei, src->succs) ! if (e->dest == dst) ! { ! e->flags |= flags; ! return NULL; ! } break; } --- 308,319 ---- /* Fall through. */ case 0: ! e = find_edge (src, dst); ! if (e) ! { ! e->flags |= flags; ! return NULL; ! } break; } Index: cfgbuild.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cfgbuild.c,v retrieving revision 1.55 diff -c -p -r1.55 cfgbuild.c *** cfgbuild.c 28 Sep 2004 07:59:42 -0000 1.55 --- cfgbuild.c 22 Nov 2004 16:57:55 -0000 *************** make_edges (basic_block min, basic_block *** 271,277 **** enum rtx_code code; int force_fallthru = 0; edge e; - edge_iterator ei; if (LABEL_P (BB_HEAD (bb)) && LABEL_ALT_ENTRY_P (BB_HEAD (bb))) --- 271,276 ---- *************** make_edges (basic_block min, basic_block *** 390,401 **** /* Find out if we can drop through to the next block. */ insn = NEXT_INSN (insn); ! FOR_EACH_EDGE (e, ei, bb->succs) ! if (e->dest == EXIT_BLOCK_PTR && e->flags & EDGE_FALLTHRU) ! { ! insn = 0; ! break; ! } while (insn && NOTE_P (insn) && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK) --- 389,398 ---- /* Find out if we can drop through to the next block. */ insn = NEXT_INSN (insn); ! e = find_edge (bb, EXIT_BLOCK_PTR); ! if (e && e->flags & EDGE_FALLTHRU) ! insn = NULL; ! while (insn && NOTE_P (insn) && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK) Index: cfghooks.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cfghooks.c,v retrieving revision 1.19 diff -c -p -r1.19 cfghooks.c *** cfghooks.c 20 Nov 2004 05:02:28 -0000 1.19 --- cfghooks.c 22 Nov 2004 16:57:55 -0000 *************** bool *** 675,681 **** can_duplicate_block_p (basic_block bb) { edge e; - edge_iterator ei; if (!cfg_hooks->can_duplicate_block_p) internal_error ("%s does not support can_duplicate_block_p.", --- 675,680 ---- *************** can_duplicate_block_p (basic_block bb) *** 686,694 **** /* Duplicating fallthru block to exit would require adding a jump and splitting the real last BB. */ ! FOR_EACH_EDGE (e, ei, bb->succs) ! if (e->dest == EXIT_BLOCK_PTR && e->flags & EDGE_FALLTHRU) ! return false; return cfg_hooks->can_duplicate_block_p (bb); } --- 685,693 ---- /* Duplicating fallthru block to exit would require adding a jump and splitting the real last BB. */ ! e = find_edge (bb, EXIT_BLOCK_PTR); ! if (e && (e->flags & EDGE_FALLTHRU)) ! return false; return cfg_hooks->can_duplicate_block_p (bb); } Index: cfgloop.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cfgloop.c,v retrieving revision 1.43 diff -c -p -r1.43 cfgloop.c *** cfgloop.c 22 Nov 2004 12:23:44 -0000 1.43 --- cfgloop.c 22 Nov 2004 16:57:56 -0000 *************** verify_loop_structure (struct loops *loo *** 1499,1512 **** edge loop_latch_edge (const struct loop *loop) { ! edge e; ! edge_iterator ei; ! ! FOR_EACH_EDGE (e, ei, loop->header->preds) ! if (e->src == loop->latch) ! break; ! ! return e; } /* Returns preheader edge of LOOP. */ --- 1499,1505 ---- edge loop_latch_edge (const struct loop *loop) { ! return find_edge (loop->latch, loop->header); } /* Returns preheader edge of LOOP. */ Index: cfgloopmanip.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cfgloopmanip.c,v retrieving revision 1.37 diff -c -p -r1.37 cfgloopmanip.c *** cfgloopmanip.c 22 Nov 2004 12:23:45 -0000 1.37 --- cfgloopmanip.c 22 Nov 2004 16:57:56 -0000 *************** force_single_succ_latches (struct loops *** 1221,1234 **** for (i = 1; i < loops->num; i++) { - edge_iterator ei; loop = loops->parray[i]; if (loop->latch != loop->header && EDGE_COUNT (loop->latch->succs) == 1) continue; ! FOR_EACH_EDGE (e, ei, loop->header->preds) ! if (e->src == loop->latch) ! break; loop_split_edge_with (e, NULL_RTX); } --- 1221,1231 ---- for (i = 1; i < loops->num; i++) { loop = loops->parray[i]; if (loop->latch != loop->header && EDGE_COUNT (loop->latch->succs) == 1) continue; ! e = find_edge (loop->latch, loop->header); loop_split_edge_with (e, NULL_RTX); } Index: cfgrtl.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v retrieving revision 1.147 diff -c -p -r1.147 cfgrtl.c *** cfgrtl.c 22 Nov 2004 12:23:45 -0000 1.147 --- cfgrtl.c 22 Nov 2004 16:57:57 -0000 *************** rtl_flow_call_edges_add (sbitmap blocks) *** 2972,2986 **** if (need_fake_edge_p (insn)) { edge e; - edge_iterator ei; ! FOR_EACH_EDGE (e, ei, bb->succs) ! if (e->dest == EXIT_BLOCK_PTR) ! { ! insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e); ! commit_edge_insertions (); ! break; ! } } } --- 2972,2984 ---- if (need_fake_edge_p (insn)) { edge e; ! e = find_edge (bb, EXIT_BLOCK_PTR); ! if (e) ! { ! insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e); ! commit_edge_insertions (); ! } } } *************** rtl_flow_call_edges_add (sbitmap blocks) *** 3023,3031 **** #ifdef ENABLE_CHECKING if (split_at_insn == BB_END (bb)) { ! edge_iterator ei; ! FOR_EACH_EDGE (e, ei, bb->succs) ! gcc_assert (e->dest != EXIT_BLOCK_PTR); } #endif --- 3021,3028 ---- #ifdef ENABLE_CHECKING if (split_at_insn == BB_END (bb)) { ! e = find_edge (bb, EXIT_BLOCK_PTR); ! gcc_assert (e == NULL); } #endif Index: predict.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/predict.c,v retrieving revision 1.134 diff -c -p -r1.134 predict.c *** predict.c 19 Nov 2004 00:03:14 -0000 1.134 --- predict.c 22 Nov 2004 16:57:58 -0000 *************** predict_loops (struct loops *loops_info, *** 669,681 **** /* Loop branch heuristics - predict an edge back to a loop's head as taken. */ ! FOR_EACH_EDGE (e, ei, bb->succs) ! if (e->dest == loop->header ! && e->src == loop->latch) ! { ! header_found = 1; ! predict_edge_def (e, PRED_LOOP_BRANCH, TAKEN); ! } /* Loop exit heuristics - predict an edge exiting the loop if the conditional has no loop header successors as not taken. */ --- 669,683 ---- /* Loop branch heuristics - predict an edge back to a loop's head as taken. */ ! if (bb == loop->latch) ! { ! e = find_edge (loop->latch, loop->header); ! if (e) ! { ! header_found = 1; ! predict_edge_def (e, PRED_LOOP_BRANCH, TAKEN); ! } ! } /* Loop exit heuristics - predict an edge exiting the loop if the conditional has no loop header successors as not taken. */ *************** propagate_freq (struct loop *loop, bitma *** 1660,1680 **** bitmap_clear_bit (tovisit, bb->index); ! /* Compute back edge frequencies. */ ! FOR_EACH_EDGE (e, ei, bb->succs) ! if (e->dest == head) ! { ! sreal tmp; ! /* EDGE_INFO (e)->back_edge_prob ! = ((e->probability * BLOCK_INFO (bb)->frequency) ! / REG_BR_PROB_BASE); */ ! sreal_init (&tmp, e->probability, 0); ! sreal_mul (&tmp, &tmp, &BLOCK_INFO (bb)->frequency); ! sreal_mul (&EDGE_INFO (e)->back_edge_prob, ! &tmp, &real_inv_br_prob_base); ! } /* Propagate to successor blocks. */ FOR_EACH_EDGE (e, ei, bb->succs) --- 1662,1681 ---- bitmap_clear_bit (tovisit, bb->index); ! e = find_edge (bb, head); ! if (e) ! { ! sreal tmp; ! /* EDGE_INFO (e)->back_edge_prob ! = ((e->probability * BLOCK_INFO (bb)->frequency) ! / REG_BR_PROB_BASE); */ ! sreal_init (&tmp, e->probability, 0); ! sreal_mul (&tmp, &tmp, &BLOCK_INFO (bb)->frequency); ! sreal_mul (&EDGE_INFO (e)->back_edge_prob, ! &tmp, &real_inv_br_prob_base); ! } /* Propagate to successor blocks. */ FOR_EACH_EDGE (e, ei, bb->succs) Index: tracer.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/tracer.c,v retrieving revision 1.22 diff -c -p -r1.22 tracer.c *** tracer.c 28 Sep 2004 07:59:50 -0000 1.22 --- tracer.c 22 Nov 2004 16:57:58 -0000 *************** tail_duplicate (void) *** 275,286 **** && can_duplicate_block_p (bb2)) { edge e; - edge_iterator ei; basic_block old = bb2; ! FOR_EACH_EDGE (e, ei, bb2->preds) ! if (e->src == bb) ! break; nduplicated += counts [bb2->index]; bb2 = duplicate_block (bb2, e); --- 275,283 ---- && can_duplicate_block_p (bb2)) { edge e; basic_block old = bb2; ! e = find_edge (bb, bb2); nduplicated += counts [bb2->index]; bb2 = duplicate_block (bb2, e); Index: tree-cfg.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/tree-cfg.c,v retrieving revision 2.112 diff -c -p -r2.112 tree-cfg.c *** tree-cfg.c 19 Nov 2004 22:14:35 -0000 2.112 --- tree-cfg.c 22 Nov 2004 16:57:59 -0000 *************** disband_implicit_edges (void) *** 2649,2659 **** from cfg_remove_useless_stmts here since it violates the invariants for tree--cfg correspondence and thus fits better here where we do it anyway. */ ! FOR_EACH_EDGE (e, ei, bb->succs) { - if (e->dest != bb->next_bb) - continue; - if (e->flags & EDGE_TRUE_VALUE) COND_EXPR_THEN (stmt) = build_empty_stmt (); else if (e->flags & EDGE_FALSE_VALUE) --- 2649,2657 ---- from cfg_remove_useless_stmts here since it violates the invariants for tree--cfg correspondence and thus fits better here where we do it anyway. */ ! e = find_edge (bb, bb->next_bb); ! if (e) { if (e->flags & EDGE_TRUE_VALUE) COND_EXPR_THEN (stmt) = build_empty_stmt (); else if (e->flags & EDGE_FALSE_VALUE) *************** static bool *** 3892,3899 **** tree_forwarder_block_p (basic_block bb) { block_stmt_iterator bsi; - edge e; - edge_iterator ei; /* BB must have a single outgoing edge. */ if (EDGE_COUNT (bb->succs) != 1 --- 3890,3895 ---- *************** tree_forwarder_block_p (basic_block bb) *** 3911,3920 **** gcc_assert (bb != ENTRY_BLOCK_PTR); #endif ! /* Successors of the entry block are not forwarders. */ ! FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) ! if (e->dest == bb) ! return false; /* Now walk through the statements. We can ignore labels, anything else means this is not a forwarder block. */ --- 3907,3914 ---- gcc_assert (bb != ENTRY_BLOCK_PTR); #endif ! if (find_edge (ENTRY_BLOCK_PTR, bb)) ! return false; /* Now walk through the statements. We can ignore labels, anything else means this is not a forwarder block. */ *************** tree_flow_call_edges_add (sbitmap blocks *** 5206,5212 **** Handle this by adding a dummy instruction in a new last basic block. */ if (check_last_block) { - edge_iterator ei; basic_block bb = EXIT_BLOCK_PTR->prev_bb; block_stmt_iterator bsi = bsi_last (bb); tree t = NULL_TREE; --- 5200,5205 ---- *************** tree_flow_call_edges_add (sbitmap blocks *** 5217,5229 **** { edge e; ! FOR_EACH_EDGE (e, ei, bb->succs) ! if (e->dest == EXIT_BLOCK_PTR) ! { ! bsi_insert_on_edge (e, build_empty_stmt ()); ! bsi_commit_edge_inserts (); ! break; ! } } } --- 5210,5221 ---- { edge e; ! e = find_edge (bb, EXIT_BLOCK_PTR); ! if (e) ! { ! bsi_insert_on_edge (e, build_empty_stmt ()); ! bsi_commit_edge_inserts (); ! } } } *************** tree_flow_call_edges_add (sbitmap blocks *** 5260,5268 **** #ifdef ENABLE_CHECKING if (stmt == last_stmt) { ! edge_iterator ei; ! FOR_EACH_EDGE (e, ei, bb->succs) ! gcc_assert (e->dest != EXIT_BLOCK_PTR); } #endif --- 5252,5259 ---- #ifdef ENABLE_CHECKING if (stmt == last_stmt) { ! e = find_edge (bb, EXIT_BLOCK_PTR); ! gcc_assert (e == NULL); } #endif -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=15524