diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 47923a1d95e4..244d03414da9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2005-01-07 Jakub Jelinek <jakub@redhat.com> + PR rtl-optimization/18861 + * cfgbuild.c (BLOCK_USED_BY_TABLEJUMP): Define. + (FULL_STATE): Define. + (mark_tablejump_edge): New function. + (purge_dead_tablejump_edges): New function. + (find_bb_boundaries): Use it. + PR tree-optimization/18828 * builtins.c (expand_builtin_next_arg): Remove argument and all the argument checking. diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c index 5761cd2f56e7..a21c726e3c7d 100644 --- a/gcc/cfgbuild.c +++ b/gcc/cfgbuild.c @@ -559,14 +559,73 @@ enum state {BLOCK_NEW = 0, BLOCK_ORIGINAL, BLOCK_TO_SPLIT}; #define STATE(BB) (enum state) ((size_t) (BB)->aux) #define SET_STATE(BB, STATE) ((BB)->aux = (void *) (size_t) (STATE)) +/* Used internally by purge_dead_tablejump_edges, ORed into state. */ +#define BLOCK_USED_BY_TABLEJUMP 32 +#define FULL_STATE(BB) ((size_t) (BB)->aux) + +static void +mark_tablejump_edge (rtx label) +{ + basic_block bb; + + gcc_assert (LABEL_P (label)); + /* See comment in make_label_edge. */ + if (INSN_UID (label) == 0) + return; + bb = BLOCK_FOR_INSN (label); + SET_STATE (bb, FULL_STATE (bb) | BLOCK_USED_BY_TABLEJUMP); +} + +static void +purge_dead_tablejump_edges (basic_block bb, rtx table) +{ + rtx insn = BB_END (bb), tmp; + rtvec vec; + int j; + edge_iterator ei; + edge e; + + if (GET_CODE (PATTERN (table)) == ADDR_VEC) + vec = XVEC (PATTERN (table), 0); + else + vec = XVEC (PATTERN (table), 1); + + for (j = GET_NUM_ELEM (vec) - 1; j >= 0; --j) + mark_tablejump_edge (XEXP (RTVEC_ELT (vec, j), 0)); + + /* Some targets (eg, ARM) emit a conditional jump that also + contains the out-of-range target. Scan for these and + add an edge if necessary. */ + if ((tmp = single_set (insn)) != NULL + && SET_DEST (tmp) == pc_rtx + && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE + && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF) + mark_tablejump_edge (XEXP (XEXP (SET_SRC (tmp), 2), 0)); + + for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) + { + if (FULL_STATE (e->dest) & BLOCK_USED_BY_TABLEJUMP) + SET_STATE (e->dest, FULL_STATE (e->dest) + & ~(size_t) BLOCK_USED_BY_TABLEJUMP); + else if (!(e->flags & (EDGE_ABNORMAL | EDGE_EH))) + { + remove_edge (e); + continue; + } + ei_next (&ei); + } +} + /* Scan basic block BB for possible BB boundaries inside the block and create new basic blocks in the progress. */ static void find_bb_boundaries (basic_block bb) { + basic_block orig_bb = bb; rtx insn = BB_HEAD (bb); rtx end = BB_END (bb); + rtx table; rtx flow_transfer_insn = NULL_RTX; edge fallthru = NULL; @@ -623,6 +682,11 @@ find_bb_boundaries (basic_block bb) followed by cleanup at fallthru edge, so the outgoing edges may be dead. */ purge_dead_edges (bb); + + /* purge_dead_edges doesn't handle tablejump's, but if we have split the + basic block, we might need to kill some edges. */ + if (bb != orig_bb && tablejump_p (BB_END (bb), NULL, &table)) + purge_dead_tablejump_edges (bb, table); } /* Assume that frequency of basic block B is known. Compute frequencies diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e12f5389ac8c..fdfd6012c8a7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2005-01-07 Jakub Jelinek <jakub@redhat.com> + PR rtl-optimization/18861 + * gcc.dg/20050105-1.c: New test. + PR tree-optimization/18828 * gcc.dg/20050105-2.c: New test. diff --git a/gcc/testsuite/gcc.dg/20050105-1.c b/gcc/testsuite/gcc.dg/20050105-1.c new file mode 100644 index 000000000000..46a742ffe63a --- /dev/null +++ b/gcc/testsuite/gcc.dg/20050105-1.c @@ -0,0 +1,31 @@ +/* PR rtl-optimization/18861 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -floop-optimize2" } */ + +extern void abort (void); + +int +foo (int code) +{ + if (code >= 3) + switch (code) + { + case 3: return 4; + case 4: return 3; + case 5: return 6; + case 6: return 7; + case 7: return 8; + case 8: return 5; + default: abort (); + } + switch (code) + { + case 3: return 4; + case 4: return 3; + case 5: return 6; + case 6: return 7; + case 7: return 8; + case 8: return 5; + default: abort (); + } +}