diff options
author | Jakub Jelinek <jakub@redhat.com> | 2005-01-07 10:04:01 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2005-01-07 10:04:01 +0100 |
commit | 0210ae141eaa9f04636dfb10c1f0922c46a1013d (patch) | |
tree | 112f2adfdfdf127f8b17283fa4f93bb7dee66401 /gcc/cfgbuild.c | |
parent | 8870e2121de6b86e33178bfc4646aa10bbe7069b (diff) | |
download | gcc-0210ae141eaa9f04636dfb10c1f0922c46a1013d.zip gcc-0210ae141eaa9f04636dfb10c1f0922c46a1013d.tar.gz gcc-0210ae141eaa9f04636dfb10c1f0922c46a1013d.tar.bz2 |
re PR rtl-optimization/18861 (ICE Segmentation fault in try_crossjump_to_edge at ../../gcc/gcc/cfgcleanup.c:1637 with two switches (table jumps))
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.
* gcc.dg/20050105-1.c: New test.
From-SVN: r93041
Diffstat (limited to 'gcc/cfgbuild.c')
-rw-r--r-- | gcc/cfgbuild.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c index 5761cd2..a21c726 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 |