Index: basic-block.h =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/basic-block.h,v retrieving revision 1.216 diff -u -r1.216 basic-block.h --- basic-block.h 28 Sep 2004 12:15:48 -0000 1.216 +++ basic-block.h 2 Oct 2004 23:01:15 -0000 @@ -824,6 +824,7 @@ /* In bb-reorder.c */ extern void reorder_basic_blocks (unsigned int); +extern void duplicate_computed_gotos (void); extern void partition_hot_cold_basic_blocks (void); /* In cfg.c */ Index: bb-reorder.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/bb-reorder.c,v retrieving revision 1.84 diff -u -r1.84 bb-reorder.c --- bb-reorder.c 28 Sep 2004 07:59:42 -0000 1.84 +++ bb-reorder.c 2 Oct 2004 23:01:19 -0000 @@ -1172,6 +1172,24 @@ FREE (cold_traces); } +/* Return the total length of instructions in basic block BB. */ + +static int +bb_insn_length (basic_block bb) +{ + rtx insn; + int size = 0; + + for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); + insn = NEXT_INSN (insn)) + { + if (INSN_P (insn)) + size += get_attr_length (insn); + } + + return size; +} + /* Return true when BB can and should be copied. CODE_MAY_GROW is true when code size is allowed to grow by duplication. */ @@ -1196,12 +1214,7 @@ if (code_may_grow && maybe_hot_bb_p (bb)) max_size *= 8; - for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); - insn = NEXT_INSN (insn)) - { - if (INSN_P (insn)) - size += get_attr_length (insn); - } + size = bb_insn_length (bb); if (size <= max_size) return true; @@ -1994,6 +2007,72 @@ timevar_pop (TV_REORDER_BLOCKS); } +/* Duplicate the blocks containing computed gotos. */ + +void +duplicate_computed_gotos (void) +{ + basic_block bb, new_bb; + int max_size; + + if (n_basic_blocks <= 1) + return; + + if (targetm.cannot_modify_jumps_p ()) + return; + + if (!current_function_has_computed_jump) + return; + + timevar_push (TV_REORDER_BLOCKS); + + cfg_layout_initialize (0); + + /* We are estimating the length of uncond jump insn only once since the code + for getting the insn length always returns the minimal length now. */ + if (uncond_jump_length == 0) + uncond_jump_length = get_uncond_jump_length (); + + /* Build the reorder chain for the original order of blocks. */ + FOR_EACH_BB (bb) + { + if (bb->next_bb != EXIT_BLOCK_PTR) + bb->rbi->next = bb->next_bb; + } + + /* Duplicate computed gotos. */ + max_size = optimize_size ? uncond_jump_length : 4 * uncond_jump_length; + FOR_EACH_BB (bb) + { + if (bb->rbi->visited) + continue; + + bb->rbi->visited = 1; + + if (/* BB has one outgoing edge which is not an edge to exit block. */ + (EDGE_COUNT(bb->succs) == 1) && EDGE_SUCC(bb,0) != EXIT_BLOCK_PTR + /* Do not duplicate the successor if it is the next block, + duplicate it in other cases. */ + && ((EDGE_SUCC(bb,0)->dest) != bb->next_bb) + /* The destination has more than one predecessor. */ + && (EDGE_COUNT(EDGE_SUCC(bb,0)->dest->preds) > 1) + /* The last insn is a computed jump. */ + && computed_jump_p (BB_END (EDGE_SUCC(bb,0)->dest)) + /* The block is small enough. */ + && bb_insn_length (EDGE_SUCC(bb,0)->dest) <= max_size) + { + new_bb = duplicate_block (EDGE_SUCC(bb,0)->dest, EDGE_SUCC(bb,0)); + new_bb->rbi->next = bb->rbi->next; + bb->rbi->next = new_bb; + new_bb->rbi->visited = 1; + } + } + + cfg_layout_finalize (); + + timevar_pop (TV_REORDER_BLOCKS); +} + /* This function is the main 'entrance' for the optimization that partitions hot and cold basic blocks into separate sections of the .o file (to improve performance and cache locality). Ideally it Index: passes.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/passes.c,v retrieving revision 2.52 diff -u -r2.52 passes.c --- passes.c 25 Sep 2004 10:05:09 -0000 2.52 +++ passes.c 2 Oct 2004 23:01:23 -0000 @@ -1808,6 +1808,9 @@ rest_of_handle_stack_regs (); #endif + if ((optimize > 0) && !flag_crossjumping) + duplicate_computed_gotos (); + compute_alignments (); if (flag_var_tracking)