-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
This is merely an infrastructure patch in preparation for another improvement in the jump threading code. It shouldn't affect the code we generate at all. Let's consider this CFG (from a routine in cfgexpand.c) A / \ B C | / \ | D E | | / \ | | F G \| | \| H / \ I J / \ L M | / \ | N O | | / \ | | P Q \| | \| R As it turns out some blocks have the same condition (A,I), (C,M), (E,O). But because of the merge block H, no threading is possible. What we want to do is make 3 copies of H, each reachable from one predecessor of the original H. To do this we need to know the edge into the joiner block so that we can wire up the copy to the right predecessor. We need the outgoing edge from the joiner block that is threadable and finally we need the destination edge. This is a fairly simple extension to the existing code -- but we're going to need the ability to store more information in the E->aux field. Previously E->aux stored the destination edge for a jump thread. This change allows E->aux to store additional data by changing it from a single edge pointer to instead point to an array of edges. FWIW, the patch to make copies of H to enable threading is probably the limit of what can be done with the current threader. I'm hoping to start prototyping more generic path isolation code shortly. Bootstrapped and regression tested on x86_64-unknown-linux-gnu. OK for trunk? -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/ iQEcBAEBAgAGBQJNvuTiAAoJEBRtltQi2kC75OAIAIe77UqINq3jUeKdYMZ/OII1 +x+al4zcsx9YOCw6wdmMjWUS0Z9IcPmuKQIoPXtgq+R1qnADg5OnAiwKKZvdukIc mhzbp+IBiDezFufv373shlp+hZtPN4QL73TDffWC4F9Eb7mYzADsIuAz2SIRcFVd HB1UAxiiD8nUA4/uVa8Ree4PA91u8M3OGpC2iwW3eq/sBIzbdCs+TEI2Nps6qDLa qmjNab/Zunh5OadJgtGB7Uk9pBv/I6zsbHmHCcZjRyOMyg8UXMCJTDjqpgUWJHAg vIast5ayTI45cwJO69qykqZdrmrNUDpOHf/93HjNMhJvdSqPkB7eHiBvlcy2RdA= =QsON -----END PGP SIGNATURE-----
* tree-ssa-threadupdate.c (remove_ctrl_stmt_and_useless_edges): Clear AUX field of outgoing edges. (craete_edge_and_update_destination_phis): Handle AUX field being an array of edges. Free the AUX field before clearning it. (thread_block, thread_through_loop_header): Likewise. (thread_single_edge, mark_threaded_blocks): Likewise. (redirect_edges): Delay clearing the AUX field. Free the AUX field. (register_jump_thread): Do not attempt to thread to a NULL edge. Index: tree-ssa-threadupdate.c =================================================================== *** tree-ssa-threadupdate.c (revision 173168) --- tree-ssa-threadupdate.c (working copy) *************** remove_ctrl_stmt_and_useless_edges (basi *** 200,209 **** --- 200,215 ---- static void create_block_for_threading (basic_block bb, struct redirection_data *rd) { + edge_iterator ei; + edge e; + /* We can use the generic block duplication code and simply remove the stuff we do not need. */ rd->dup_block = duplicate_block (bb, NULL, NULL); + FOR_EACH_EDGE (e, ei, rd->dup_block->succs) + e->aux = NULL; + /* Zero out the profile, since the block is unreachable for now. */ rd->dup_block->frequency = 0; rd->dup_block->count = 0; *************** create_edge_and_update_destination_phis *** 314,320 **** rescan_loop_exit (e, true, false); e->probability = REG_BR_PROB_BASE; e->count = bb->count; ! e->aux = rd->outgoing_edge->aux; /* If there are any PHI nodes at the destination of the outgoing edge from the duplicate block, then we will need to add a new argument --- 320,335 ---- rescan_loop_exit (e, true, false); e->probability = REG_BR_PROB_BASE; e->count = bb->count; ! ! if (rd->outgoing_edge->aux) ! { ! e->aux = (edge *) xmalloc (sizeof (edge) * 1); ! ((edge *)e->aux)[0] = ((edge *)rd->outgoing_edge->aux)[0]; ! } ! else ! { ! e->aux = NULL; ! } /* If there are any PHI nodes at the destination of the outgoing edge from the duplicate block, then we will need to add a new argument *************** redirect_edges (void **slot, void *data) *** 406,415 **** next = el->next; free (el); - /* Go ahead and clear E->aux. It's not needed anymore and failure - to clear it will cause all kinds of unpleasant problems later. */ - e->aux = NULL; - thread_stats.num_threaded_edges++; if (rd->dup_block) --- 421,426 ---- *************** redirect_edges (void **slot, void *data) *** 429,434 **** --- 440,453 ---- gcc_assert (e == e2); flush_pending_stmts (e2); } + + /* 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); + e->aux = NULL; + + thread_stats.num_threaded_edges++; + } /* Indicate that we actually threaded one or more jumps. */ *************** thread_block (basic_block bb, bool noloo *** 512,518 **** if (loop->header == bb) { e = loop_latch_edge (loop); ! e2 = (edge) e->aux; if (e2 && loop_exit_edge_p (loop, e2)) { --- 531,541 ---- if (loop->header == bb) { e = loop_latch_edge (loop); ! ! if (e->aux) ! e2 = ((edge *) e->aux)[0]; ! else ! e2 = NULL; if (e2 && loop_exit_edge_p (loop, e2)) { *************** thread_block (basic_block bb, bool noloo *** 525,543 **** efficient lookups. */ FOR_EACH_EDGE (e, ei, bb->preds) { ! e2 = (edge) e->aux; if (!e2 /* If NOLOOP_ONLY is true, we only allow threading through the header of a loop to exit edges. */ || (noloop_only && bb == bb->loop_father->header ! && !loop_exit_edge_p (bb->loop_father, e2))) continue; if (e->dest == e2->src) update_bb_profile_for_threading (e->dest, EDGE_FREQUENCY (e), ! e->count, (edge) e->aux); /* Insert the outgoing edge into the hash table if it is not already in the hash table. */ --- 548,569 ---- efficient lookups. */ FOR_EACH_EDGE (e, ei, bb->preds) { ! if (e->aux == NULL) ! continue; ! ! e2 = ((edge *) e->aux)[0]; if (!e2 /* If NOLOOP_ONLY is true, we only allow threading through the header of a loop to exit edges. */ || (noloop_only && bb == bb->loop_father->header ! && (!loop_exit_edge_p (bb->loop_father, e2)))) continue; if (e->dest == e2->src) update_bb_profile_for_threading (e->dest, EDGE_FREQUENCY (e), ! e->count, ((edge *) e->aux)[0]); /* Insert the outgoing edge into the hash table if it is not already in the hash table. */ *************** thread_block (basic_block bb, bool noloo *** 582,588 **** return local_info.jumps_threaded; } ! /* Threads edge E through E->dest to the edge E->aux. Returns the copy of E->dest created during threading, or E->dest if it was not necessary to copy it (E is its single predecessor). */ --- 608,614 ---- return local_info.jumps_threaded; } ! /* Threads edge E through E->dest to the edge E->aux[0]. Returns the copy of E->dest created during threading, or E->dest if it was not necessary to copy it (E is its single predecessor). */ *************** static basic_block *** 590,598 **** thread_single_edge (edge e) { basic_block bb = e->dest; ! edge eto = (edge) e->aux; struct redirection_data rd; e->aux = NULL; thread_stats.num_threaded_edges++; --- 616,625 ---- thread_single_edge (edge e) { basic_block bb = e->dest; ! edge eto = ((edge *) e->aux)[0]; struct redirection_data rd; + free (e->aux); e->aux = NULL; thread_stats.num_threaded_edges++; *************** thread_through_loop_header (struct loop *** 794,800 **** if (latch->aux) { ! tgt_edge = (edge) latch->aux; tgt_bb = tgt_edge->dest; } else if (!may_peel_loop_headers --- 821,827 ---- if (latch->aux) { ! tgt_edge = ((edge *) latch->aux)[0]; tgt_bb = tgt_edge->dest; } else if (!may_peel_loop_headers *************** thread_through_loop_header (struct loop *** 817,823 **** goto fail; } ! tgt_edge = (edge) e->aux; atgt_bb = tgt_edge->dest; if (!tgt_bb) tgt_bb = atgt_bb; --- 844,850 ---- goto fail; } ! tgt_edge = ((edge *) e->aux)[0]; atgt_bb = tgt_edge->dest; if (!tgt_bb) tgt_bb = atgt_bb; *************** thread_through_loop_header (struct loop *** 883,889 **** /* Now consider the case entry edges are redirected to the new entry block. Remember one entry edge, so that we can find the new ! preheader (its destination after threading). */ FOR_EACH_EDGE (e, ei, header->preds) { if (e->aux) --- 910,916 ---- /* Now consider the case entry edges are redirected to the new entry block. Remember one entry edge, so that we can find the new ! preheader (its destination after threading). */ FOR_EACH_EDGE (e, ei, header->preds) { if (e->aux) *************** fail: *** 915,920 **** --- 942,948 ---- /* We failed to thread anything. Cancel the requests. */ FOR_EACH_EDGE (e, ei, header->preds) { + free (e->aux); e->aux = NULL; } return false; *************** mark_threaded_blocks (bitmap threaded_bl *** 946,954 **** for (i = 0; i < VEC_length (edge, threaded_edges); i += 2) { edge e = VEC_index (edge, threaded_edges, i); ! edge e2 = VEC_index (edge, threaded_edges, i + 1); ! e->aux = e2; bitmap_set_bit (tmp, e->dest->index); } --- 974,983 ---- for (i = 0; i < VEC_length (edge, threaded_edges); i += 2) { edge e = VEC_index (edge, threaded_edges, i); ! edge *x = (edge *)xmalloc (sizeof (edge) * 1); ! x[0] = VEC_index (edge, threaded_edges, i + 1); ! e->aux = x; bitmap_set_bit (tmp, e->dest->index); } *************** mark_threaded_blocks (bitmap threaded_bl *** 963,969 **** && !redirection_block_p (bb)) { FOR_EACH_EDGE (e, ei, bb->preds) ! e->aux = NULL; } else bitmap_set_bit (threaded_blocks, i); --- 992,1001 ---- && !redirection_block_p (bb)) { FOR_EACH_EDGE (e, ei, bb->preds) ! { ! free (e->aux); ! e->aux = NULL; ! } } else bitmap_set_bit (threaded_blocks, i); *************** thread_through_all_blocks (bool may_peel *** 1059,1066 **** void register_jump_thread (edge e, edge e2) { if (threaded_edges == NULL) ! threaded_edges = VEC_alloc (edge, heap, 10); if (dump_file && (dump_flags & TDF_DETAILS) && e->dest != e2->src) --- 1091,1103 ---- void register_jump_thread (edge e, edge e2) { + /* This can occur if we're jumping to a constant address or + or something similar. Just get out now. */ + if (e2 == NULL) + return; + if (threaded_edges == NULL) ! threaded_edges = VEC_alloc (edge, heap, 15); if (dump_file && (dump_flags & TDF_DETAILS) && e->dest != e2->src)