diff options
Diffstat (limited to 'gcc/tree-ssa-threadupdate.c')
-rw-r--r-- | gcc/tree-ssa-threadupdate.c | 424 |
1 files changed, 281 insertions, 143 deletions
diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c index 413112814d6..e791269ebac 100644 --- a/gcc/tree-ssa-threadupdate.c +++ b/gcc/tree-ssa-threadupdate.c @@ -20,16 +20,16 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" #include "tree.h" #include "flags.h" -#include "tm_p.h" #include "basic-block.h" #include "function.h" #include "tree-ssa.h" +#include "tree-ssa-threadupdate.h" #include "dumpfile.h" #include "cfgloop.h" #include "hash-table.h" +#include "dbgcnt.h" /* Given a block B, update the CFG and SSA graph to reflect redirecting one or more in-edges to B to instead reach the destination of an @@ -69,14 +69,14 @@ along with GCC; see the file COPYING3. If not see set of unique destination blocks that the incoming edges should be threaded to. - Block duplication can be further minimized by using B instead of + Block duplication can be further minimized by using B instead of creating B' for one destination if all edges into B are going to be threaded to a successor of B. We had code to do this at one time, but I'm not convinced it is correct with the changes to avoid mucking up the loop structure (which may cancel threading requests, thus a block which we thought was going to become unreachable may still be reachable). This code was also going to get ugly with the introduction of the ability - for a single jump thread request to bypass multiple blocks. + for a single jump thread request to bypass multiple blocks. We further reduce the number of edges and statements we create by not copying all the outgoing edges and the control statement in @@ -115,14 +115,11 @@ struct redirection_data : typed_free_remove<redirection_data> targets a single successor of B. */ basic_block dup_block; - /* An outgoing edge from B. DUP_BLOCK will have OUTGOING_EDGE->dest as - its single successor. */ - edge outgoing_edge; + /* The jump threading path. */ + vec<jump_thread_edge *> *path; - edge intermediate_edge; - - /* A list of incoming edges which we want to thread to - OUTGOING_EDGE->dest. */ + /* A list of incoming edges which we want to thread to the + same path. */ struct el *incoming_edges; /* hash_table support. */ @@ -132,21 +129,36 @@ struct redirection_data : typed_free_remove<redirection_data> static inline int equal (const value_type *, const compare_type *); }; +/* Simple hashing function. For any given incoming edge E, we're going + to be most concerned with the final destination of its jump thread + path. So hash on the block index of the final edge in the path. */ + inline hashval_t redirection_data::hash (const value_type *p) { - edge e = p->outgoing_edge; - return e->dest->index; + vec<jump_thread_edge *> *path = p->path; + return path->last ()->e->dest->index; } +/* Given two hash table entries, return true if they have the same + jump threading path. */ inline int redirection_data::equal (const value_type *p1, const compare_type *p2) { - edge e1 = p1->outgoing_edge; - edge e2 = p2->outgoing_edge; - edge e3 = p1->intermediate_edge; - edge e4 = p2->intermediate_edge; - return e1 == e2 && e3 == e4; + vec<jump_thread_edge *> *path1 = p1->path; + vec<jump_thread_edge *> *path2 = p2->path; + + if (path1->length () != path2->length ()) + return false; + + for (unsigned int i = 1; i < path1->length (); i++) + { + if ((*path1)[i]->type != (*path2)[i]->type + || (*path1)[i]->e != (*path2)[i]->e) + return false; + } + + return true; } /* Data structure of information to pass to hash table traversal routines. */ @@ -167,13 +179,12 @@ struct ssa_local_info_t opportunities as they are discovered. We keep the registered jump threading opportunities in this vector as edge pairs (original_edge, target_edge). */ -static vec<edge> threaded_edges; +static vec<vec<jump_thread_edge *> *> paths; /* When we start updating the CFG for threading, data necessary for jump threading is attached to the AUX field for the incoming edge. Use these macros to access the underlying structure attached to the AUX field. */ -#define THREAD_TARGET(E) ((edge *)(E)->aux)[0] -#define THREAD_TARGET2(E) ((edge *)(E)->aux)[1] +#define THREAD_PATH(E) ((vec<jump_thread_edge *> *)(E)->aux) /* Jump threading statistics. */ @@ -254,13 +265,12 @@ lookup_redirection_data (edge e, enum insert_option insert) { struct redirection_data **slot; struct redirection_data *elt; + vec<jump_thread_edge *> *path = THREAD_PATH (e); /* Build a hash table element so we can see if E is already in the table. */ elt = XNEW (struct redirection_data); - elt->intermediate_edge = THREAD_TARGET2 (e) ? THREAD_TARGET (e) : NULL; - elt->outgoing_edge = THREAD_TARGET2 (e) ? THREAD_TARGET2 (e) - : THREAD_TARGET (e); + elt->path = path; elt->dup_block = NULL; elt->incoming_edges = NULL; @@ -354,17 +364,28 @@ static void create_edge_and_update_destination_phis (struct redirection_data *rd, basic_block bb) { - edge e = make_edge (bb, rd->outgoing_edge->dest, EDGE_FALLTHRU); + edge e = make_edge (bb, rd->path->last ()->e->dest, EDGE_FALLTHRU); rescan_loop_exit (e, true, false); e->probability = REG_BR_PROB_BASE; e->count = bb->count; - if (rd->outgoing_edge->aux) + /* We have to copy path -- which means creating a new vector as well + as all the jump_thread_edge entries. */ + if (rd->path->last ()->e->aux) { - e->aux = XNEWVEC (edge, 2); - THREAD_TARGET(e) = THREAD_TARGET (rd->outgoing_edge); - THREAD_TARGET2(e) = THREAD_TARGET2 (rd->outgoing_edge); + vec<jump_thread_edge *> *path = THREAD_PATH (rd->path->last ()->e); + vec<jump_thread_edge *> *copy = new vec<jump_thread_edge *> (); + + /* Sadly, the elements of the vector are pointers and need to + be copied as well. */ + for (unsigned int i = 0; i < path->length (); i++) + { + jump_thread_edge *x + = new jump_thread_edge ((*path)[i]->e, (*path)[i]->type); + copy->safe_push (x); + } + e->aux = (void *)copy; } else { @@ -375,7 +396,7 @@ create_edge_and_update_destination_phis (struct redirection_data *rd, from the duplicate block, then we will need to add a new argument to them. The argument should have the same value as the argument associated with the outgoing edge stored in RD. */ - copy_phi_args (e->dest, rd->outgoing_edge, e); + copy_phi_args (e->dest, rd->path->last ()->e, e); } /* Wire up the outgoing edges from the duplicate block and @@ -384,15 +405,17 @@ void ssa_fix_duplicate_block_edges (struct redirection_data *rd, ssa_local_info_t *local_info) { + edge e = rd->incoming_edges->e; + vec<jump_thread_edge *> *path = THREAD_PATH (e); + /* If we were threading through an joiner block, then we want to keep its control statement and redirect an outgoing edge. Else we want to remove the control statement & edges, then create a new outgoing edge. In both cases we may need to update PHIs. */ - if (THREAD_TARGET2 (rd->incoming_edges->e)) + if ((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK) { edge victim; edge e2; - edge e = rd->incoming_edges->e; /* This updates the PHIs at the destination of the duplicate block. */ @@ -400,14 +423,15 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd, /* Find the edge from the duplicate block to the block we're threading through. That's the edge we want to redirect. */ - victim = find_edge (rd->dup_block, THREAD_TARGET (e)->dest); - e2 = redirect_edge_and_branch (victim, THREAD_TARGET2 (e)->dest); + victim = find_edge (rd->dup_block, (*path)[1]->e->dest); + e2 = redirect_edge_and_branch (victim, path->last ()->e->dest); + e2->count = path->last ()->e->count; /* If we redirected the edge, then we need to copy PHI arguments at the target. If the edge already existed (e2 != victim case), then the PHIs in the target already have the correct arguments. */ if (e2 == victim) - copy_phi_args (e2->dest, THREAD_TARGET2 (e), e2); + copy_phi_args (e2->dest, path->last ()->e, e2); } else { @@ -488,6 +512,7 @@ ssa_redirect_edges (struct redirection_data **slot, for (el = rd->incoming_edges; el; el = next) { edge e = el->e; + vec<jump_thread_edge *> *path = THREAD_PATH (e); /* Go ahead and free this element from the list. Doing this now avoids the need for another list walk when we destroy the hash @@ -496,18 +521,8 @@ ssa_redirect_edges (struct redirection_data **slot, free (el); thread_stats.num_threaded_edges++; - /* If we are threading through a joiner block, then we have to - find the edge we want to redirect and update some PHI nodes. */ - if (THREAD_TARGET2 (e)) - { - edge e2; - /* We want to redirect the incoming edge to the joiner block (E) - to instead reach the duplicate of the joiner block. */ - e2 = redirect_edge_and_branch (e, rd->dup_block); - flush_pending_stmts (e2); - } - else if (rd->dup_block) + if (rd->dup_block) { edge e2; @@ -521,9 +536,15 @@ ssa_redirect_edges (struct redirection_data **slot, the computation overflows. */ if (rd->dup_block->frequency < BB_FREQ_MAX * 2) rd->dup_block->frequency += EDGE_FREQUENCY (e); - EDGE_SUCC (rd->dup_block, 0)->count += e->count; - /* Redirect the incoming edge to the appropriate duplicate - block. */ + + /* In the case of threading through a joiner block, the outgoing + edges from the duplicate block were updated when they were + redirected during ssa_fix_duplicate_block_edges. */ + if ((*path)[1]->type != EDGE_COPY_SRC_JOINER_BLOCK) + EDGE_SUCC (rd->dup_block, 0)->count += e->count; + + /* Redirect the incoming edge (possibly to the joiner block) to the + appropriate duplicate block. */ e2 = redirect_edge_and_branch (e, rd->dup_block); gcc_assert (e == e2); flush_pending_stmts (e2); @@ -531,7 +552,9 @@ ssa_redirect_edges (struct redirection_data **slot, /* Go ahead and clear E->aux. It's not needed anymore and failure to clear it will cause all kinds of unpleasant problems later. */ - free (e->aux); + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + path->release (); e->aux = NULL; } @@ -614,17 +637,21 @@ thread_block (basic_block bb, bool noloop_only) if (loop->header == bb) { e = loop_latch_edge (loop); + vec<jump_thread_edge *> *path = THREAD_PATH (e); - if (e->aux) - e2 = THREAD_TARGET (e); - else - e2 = NULL; - - if (e2 && loop_exit_edge_p (loop, e2)) + if (path) { - loop->header = NULL; - loop->latch = NULL; - loops_state_set (LOOPS_NEED_FIXUP); + for (unsigned int i = 1; i < path->length (); i++) + { + edge e2 = (*path)[i]->e; + + if (loop_exit_edge_p (loop, e2)) + { + loop->header = NULL; + loop->latch = NULL; + loops_state_set (LOOPS_NEED_FIXUP); + } + } } } @@ -635,15 +662,12 @@ thread_block (basic_block bb, bool noloop_only) if (e->aux == NULL) continue; - if (THREAD_TARGET2 (e)) - e2 = THREAD_TARGET2 (e); - else - e2 = THREAD_TARGET (e); - + vec<jump_thread_edge *> *path = THREAD_PATH (e); + e2 = path->last ()->e; if (!e2 || noloop_only) { /* If NOLOOP_ONLY is true, we only allow threading through the - header of a loop to exit edges. + header of a loop to exit edges. There are two cases to consider. The first when BB is the loop header. We will attempt to thread this elsewhere, so @@ -651,7 +675,7 @@ thread_block (basic_block bb, bool noloop_only) if (bb == bb->loop_father->header && (!loop_exit_edge_p (bb->loop_father, e2) - || THREAD_TARGET2 (e))) + || (*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK)) continue; @@ -667,7 +691,9 @@ thread_block (basic_block bb, bool noloop_only) /* Since this case is not handled by our special code to thread through a loop header, we must explicitly cancel the threading request here. */ - free (e->aux); + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + path->release (); e->aux = NULL; continue; } @@ -675,7 +701,7 @@ thread_block (basic_block bb, bool noloop_only) if (e->dest == e2->src) update_bb_profile_for_threading (e->dest, EDGE_FREQUENCY (e), - e->count, THREAD_TARGET (e)); + e->count, (*THREAD_PATH (e))[1]->e); /* Insert the outgoing edge into the hash table if it is not already in the hash table. */ @@ -741,10 +767,13 @@ static basic_block thread_single_edge (edge e) { basic_block bb = e->dest; - edge eto = THREAD_TARGET (e); struct redirection_data rd; + vec<jump_thread_edge *> *path = THREAD_PATH (e); + edge eto = (*path)[1]->e; - free (e->aux); + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + delete path; e->aux = NULL; thread_stats.num_threaded_edges++; @@ -766,7 +795,13 @@ thread_single_edge (edge e) if (e->dest == eto->src) update_bb_profile_for_threading (bb, EDGE_FREQUENCY (e), e->count, eto); - rd.outgoing_edge = eto; + vec<jump_thread_edge *> *npath = new vec<jump_thread_edge *> (); + jump_thread_edge *x = new jump_thread_edge (e, EDGE_START_JUMP_THREAD); + npath->safe_push (x); + + x = new jump_thread_edge (eto, EDGE_COPY_SRC_BLOCK); + npath->safe_push (x); + rd.path = npath; create_block_for_threading (bb, &rd); remove_ctrl_stmt_and_useless_edges (rd.dup_block, NULL); @@ -965,9 +1000,10 @@ thread_through_loop_header (struct loop *loop, bool may_peel_loop_headers) if (latch->aux) { - if (THREAD_TARGET2 (latch)) + vec<jump_thread_edge *> *path = THREAD_PATH (latch); + if ((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK) goto fail; - tgt_edge = THREAD_TARGET (latch); + tgt_edge = (*path)[1]->e; tgt_bb = tgt_edge->dest; } else if (!may_peel_loop_headers @@ -990,9 +1026,11 @@ thread_through_loop_header (struct loop *loop, bool may_peel_loop_headers) goto fail; } - if (THREAD_TARGET2 (e)) + vec<jump_thread_edge *> *path = THREAD_PATH (e); + + if ((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK) goto fail; - tgt_edge = THREAD_TARGET (e); + tgt_edge = (*path)[1]->e; atgt_bb = tgt_edge->dest; if (!tgt_bb) tgt_bb = atgt_bb; @@ -1087,15 +1125,15 @@ thread_through_loop_header (struct loop *loop, bool may_peel_loop_headers) if (e->aux == NULL) continue; - if (THREAD_TARGET2 (e)) - e2 = THREAD_TARGET2 (e); - else - e2 = THREAD_TARGET (e); + vec<jump_thread_edge *> *path = THREAD_PATH (e); + e2 = path->last ()->e; if (e->src->loop_father != e2->dest->loop_father && e2->dest != loop->header) { - free (e->aux); + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + path->release (); e->aux = NULL; } } @@ -1141,8 +1179,15 @@ fail: /* We failed to thread anything. Cancel the requests. */ FOR_EACH_EDGE (e, ei, header->preds) { - free (e->aux); - e->aux = NULL; + vec<jump_thread_edge *> *path = THREAD_PATH (e); + + if (path) + { + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + path->release (); + e->aux = NULL; + } } return false; } @@ -1202,21 +1247,18 @@ mark_threaded_blocks (bitmap threaded_blocks) This results in less block copying, simpler CFGs. More improtantly, when we duplicate the joiner block, B, in this case we will create a new threading opportunity that we wouldn't be able to optimize - until the next jump threading iteration. + until the next jump threading iteration. So first convert the jump thread requests which do not require a joiner block. */ - for (i = 0; i < threaded_edges.length (); i += 3) + for (i = 0; i < paths.length (); i++) { - edge e = threaded_edges[i]; + vec<jump_thread_edge *> *path = paths[i]; - if (threaded_edges[i + 2] == NULL) + if ((*path)[1]->type != EDGE_COPY_SRC_JOINER_BLOCK) { - edge *x = XNEWVEC (edge, 2); - - e->aux = x; - THREAD_TARGET (e) = threaded_edges[i + 1]; - THREAD_TARGET2 (e) = NULL; + edge e = (*path)[0]->e; + e->aux = (void *)path; bitmap_set_bit (tmp, e->dest->index); } } @@ -1225,18 +1267,15 @@ mark_threaded_blocks (bitmap threaded_blocks) /* Now iterate again, converting cases where we threaded through a joiner block, but ignoring those where we have already threaded through the joiner block. */ - for (i = 0; i < threaded_edges.length (); i += 3) + for (i = 0; i < paths.length (); i++) { - edge e = threaded_edges[i]; + vec<jump_thread_edge *> *path = paths[i]; - if (threaded_edges[i + 2] != NULL - && threaded_edges[i + 1]->aux == NULL) + if ((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK + && (*path)[0]->e->aux == NULL) { - edge *x = XNEWVEC (edge, 2); - - e->aux = x; - THREAD_TARGET (e) = threaded_edges[i + 1]; - THREAD_TARGET2 (e) = threaded_edges[i + 2]; + edge e = (*path)[0]->e; + e->aux = path; bitmap_set_bit (tmp, e->dest->index); } } @@ -1248,10 +1287,10 @@ mark_threaded_blocks (bitmap threaded_blocks) We used to detect this prior to registering the jump thread, but that prohibits propagation of edge equivalences into non-dominated - PHI nodes as the equivalency test might occur before propagation. + PHI nodes as the equivalency test might occur before propagation. This works for now, but will need improvement as part of the FSA - optimization. + optimization. Note since we've moved the thread request data to the edges, we have to iterate on those rather than the threaded_edges vector. */ @@ -1262,18 +1301,21 @@ mark_threaded_blocks (bitmap threaded_blocks) { if (e->aux) { - bool have_joiner = THREAD_TARGET2 (e) != NULL; + vec<jump_thread_edge *> *path = THREAD_PATH (e); + bool have_joiner = ((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK); if (have_joiner) { basic_block joiner = e->dest; - edge final_edge = THREAD_TARGET2 (e); + edge final_edge = path->last ()->e; basic_block final_dest = final_edge->dest; edge e2 = find_edge (joiner, final_dest); if (e2 && !phi_args_equal_on_edges (e2, final_edge)) { - free (e->aux); + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + path->release (); e->aux = NULL; } } @@ -1294,8 +1336,14 @@ mark_threaded_blocks (bitmap threaded_blocks) { FOR_EACH_EDGE (e, ei, bb->preds) { - free (e->aux); - e->aux = NULL; + if (e->aux) + { + vec<jump_thread_edge *> *path = THREAD_PATH (e); + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + path->release (); + e->aux = NULL; + } } } else @@ -1305,7 +1353,69 @@ mark_threaded_blocks (bitmap threaded_blocks) else bitmap_copy (threaded_blocks, tmp); - BITMAP_FREE(tmp); + /* Look for jump threading paths which cross multiple loop headers. + + The code to thread through loop headers will change the CFG in ways + that break assumptions made by the loop optimization code. + + We don't want to blindly cancel the requests. We can instead do better + by trimming off the end of the jump thread path. */ + EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi) + { + basic_block bb = BASIC_BLOCK (i); + FOR_EACH_EDGE (e, ei, bb->preds) + { + if (e->aux) + { + vec<jump_thread_edge *> *path = THREAD_PATH (e); + + /* Basically we're looking for a situation where we can see + 3 or more loop structures on a jump threading path. */ + + struct loop *first_father = (*path)[0]->e->src->loop_father; + struct loop *second_father = NULL; + for (unsigned int i = 0; i < path->length (); i++) + { + /* See if this is a loop father we have not seen before. */ + if ((*path)[i]->e->dest->loop_father != first_father + && (*path)[i]->e->dest->loop_father != second_father) + { + /* We've already seen two loop fathers, so we + need to trim this jump threading path. */ + if (second_father != NULL) + { + /* Trim from entry I onwards. */ + for (unsigned int j = i; j < path->length (); j++) + delete (*path)[j]; + path->truncate (i); + + /* Now that we've truncated the path, make sure + what's left is still valid. We need at least + two edges on the path and the last edge can not + be a joiner. This should never happen, but let's + be safe. */ + if (path->length () < 2 + || (path->last ()->type + == EDGE_COPY_SRC_JOINER_BLOCK)) + { + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + path->release (); + e->aux = NULL; + } + break; + } + else + { + second_father = (*path)[i]->e->dest->loop_father; + } + } + } + } + } + } + + BITMAP_FREE (tmp); } @@ -1333,7 +1443,7 @@ thread_through_all_blocks (bool may_peel_loop_headers) /* We must know about loops in order to preserve them. */ gcc_assert (current_loops != NULL); - if (!threaded_edges.exists ()) + if (!paths.exists ()) return false; threaded_blocks = BITMAP_ALLOC (NULL); @@ -1372,7 +1482,7 @@ thread_through_all_blocks (bool may_peel_loop_headers) BITMAP_FREE (threaded_blocks); threaded_blocks = NULL; - threaded_edges.release (); + paths.release (); if (retval) loops_state_set (LOOPS_NEED_FIXUP); @@ -1380,6 +1490,38 @@ thread_through_all_blocks (bool may_peel_loop_headers) return retval; } +/* Dump a jump threading path, including annotations about each + edge in the path. */ + +static void +dump_jump_thread_path (FILE *dump_file, vec<jump_thread_edge *> path) +{ + fprintf (dump_file, + " Registering jump thread: (%d, %d) incoming edge; ", + path[0]->e->src->index, path[0]->e->dest->index); + + for (unsigned int i = 1; i < path.length (); i++) + { + /* We can get paths with a NULL edge when the final destination + of a jump thread turns out to be a constant address. We dump + those paths when debugging, so we have to be prepared for that + possibility here. */ + if (path[i]->e == NULL) + continue; + + if (path[i]->type == EDGE_COPY_SRC_JOINER_BLOCK) + fprintf (dump_file, " (%d, %d) joiner; ", + path[i]->e->src->index, path[i]->e->dest->index); + if (path[i]->type == EDGE_COPY_SRC_BLOCK) + fprintf (dump_file, " (%d, %d) normal;", + path[i]->e->src->index, path[i]->e->dest->index); + if (path[i]->type == EDGE_NO_COPY_SRC_BLOCK) + fprintf (dump_file, " (%d, %d) nocopy;", + path[i]->e->src->index, path[i]->e->dest->index); + } + fputc ('\n', dump_file); +} + /* Register a jump threading opportunity. We queue up all the jump threading opportunities discovered by a pass and update the CFG and SSA form all at once. @@ -1389,43 +1531,39 @@ thread_through_all_blocks (bool may_peel_loop_headers) after fixing the SSA graph. */ void -register_jump_thread (vec<edge> path, bool through_joiner) +register_jump_thread (vec<jump_thread_edge *> *path) { - /* Convert PATH into 3 edge representation we've been using. This - is temporary until we convert this file to use a path representation - throughout. */ - edge e = path[0]; - edge e2 = path[1]; - edge e3; - - if (!through_joiner) - e3 = NULL; - else - e3 = path[path.length () - 1]; + if (!dbg_cnt (registered_jump_thread)) + { + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + path->release (); + return; + } + + /* First make sure there are no NULL outgoing edges on the jump threading + path. That can happen for jumping to a constant address. */ + for (unsigned int i = 0; i < path->length (); i++) + if ((*path)[i]->e == NULL) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + "Found NULL edge in jump threading path. Cancelling jump thread:\n"); + dump_jump_thread_path (dump_file, *path); + } - /* This can occur if we're jumping to a constant address or - or something similar. Just get out now. */ - if (e2 == NULL) - return; + for (unsigned int i = 0; i < path->length (); i++) + delete (*path)[i]; + path->release (); + return; + } if (dump_file && (dump_flags & TDF_DETAILS)) - { - unsigned int i; + dump_jump_thread_path (dump_file, *path); - fprintf (dump_file, - " Registering jump thread %s:", - through_joiner ? "(through joiner block)" : ""); - - for (i = 0; i < path.length (); i++) - fprintf (dump_file, " (%d, %d); ", - path[i]->src->index, path[i]->dest->index); - fputc ('\n', dump_file); - } - - if (!threaded_edges.exists ()) - threaded_edges.create (15); + if (!paths.exists ()) + paths.create (5); - threaded_edges.safe_push (e); - threaded_edges.safe_push (e2); - threaded_edges.safe_push (e3); + paths.safe_push (path); } |