aboutsummaryrefslogtreecommitdiff
path: root/gcc/cfgbuild.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2005-01-07 10:04:01 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2005-01-07 10:04:01 +0100
commit0210ae141eaa9f04636dfb10c1f0922c46a1013d (patch)
tree112f2adfdfdf127f8b17283fa4f93bb7dee66401 /gcc/cfgbuild.c
parent8870e2121de6b86e33178bfc4646aa10bbe7069b (diff)
downloadgcc-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.c64
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