diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1c1a0de3015..16ac20a6ee0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,32 @@ +2005-04-03 Mostafa Hagog + + * cfghooks.c (lv_flush_pending_stmts, + cfg_hook_duplicate_loop_to_header_edge, extract_cond_bb_edges, + lv_adjust_loop_header_phi, lv_add_condition_to_bb): New. + * cfghooks.h (cfg_hook_duplicate_loop_to_header_edge, + lv_add_condition_to_bb, + lv_adjust_loop_header_phi, extract_cond_bb_edges, + flush_pending_stmts): New in cfg_hooks structure. + (cfg_hook_duplicate_loop_to_header_edge, lv_flush_pending_stmts, + extract_cond_bb_edges, lv_adjust_loop_header_phi, + lv_add_condition_to_bb): New declarations. + * cfgloop.h (duplicate_loop_to_header_edge): Change return type to + bool. + (loop_version): Declare. + * cfgloopmanip.c (cfghooks.h): Include. + (duplicate_loop_to_header_edge): Change return type to bool. + (loop_version, lv_adjust_loop_entry_edge): Move here. + * cfgrtl.c (cfgloop.h): Include. + (rtl_verify_flow_info_1): Fix. + (rtl_lv_add_condition_to_bb, rtl_extract_cond_bb_edges): New. + (rtl_cfg_hooks, cfg_layout_rtl_cfg_hook): Add hooks to + initialization. + * tree-cfg.c (tree_lv_adjust_loop_header_phi, + tree_lv_add_condition_to_bb): New. + (tree_cfg_hooks): Add new hooks to initialization. + * tree-ssa-loop-manip.c (lv_adjust_loop_header_phi, + lv_adjust_loop_entry_edge, tree_ssa_loop_version): Remove. + 2005-04-03 Kazu Hirata * config/stormy16/stormy16.h (PREDICATE_CODES): Add SUBREG to diff --git a/gcc/cfghooks.c b/gcc/cfghooks.c index 4f8f18a97c6..eb21afe6fa1 100644 --- a/gcc/cfghooks.c +++ b/gcc/cfghooks.c @@ -823,3 +823,66 @@ execute_on_shrinking_pred (edge e) if (cfg_hooks->execute_on_shrinking_pred) cfg_hooks->execute_on_shrinking_pred (e); } + +/* This is used inside loop versioning when we want to insert + stmts/insns on the edges, which have a different behaviour + in tree's and in RTL, so we made a CFG hook. */ +void +lv_flush_pending_stmts (edge e) +{ + if (cfg_hooks->flush_pending_stmts) + cfg_hooks->flush_pending_stmts (e); +} + +/* Loop versioning uses the duplicate_loop_to_header_edge to create + a new version of the loop basic-blocks, the parameters here are + exactly the same as in duplicate_loop_to_header_edge or + tree_duplicate_loop_to_header_edge; while in tree-ssa there is + additional work to maintain ssa information that's why there is + a need to call the tree_duplicate_loop_to_header_edge rather + than duplicate_loop_to_header_edge when we are in tree mode. */ +bool +cfg_hook_duplicate_loop_to_header_edge (struct loop *loop, edge e, + struct loops *loops, unsigned int ndupl, + sbitmap wont_exit, edge orig, + edge *to_remove, + unsigned int *n_to_remove, int flags) +{ + gcc_assert (cfg_hooks->cfg_hook_duplicate_loop_to_header_edge); + return cfg_hooks->cfg_hook_duplicate_loop_to_header_edge (loop, e, loops, + ndupl, wont_exit, + orig, to_remove, + n_to_remove, flags); +} + +/* Conditional jumps are represented differently in trees and RTL, + this hook takes a basic block that is known to have a cond jump + at its end and extracts the taken and not taken eges out of it + and store it in E1 and E2 respectively. */ +void +extract_cond_bb_edges (basic_block b, edge *e1, edge *e2) +{ + gcc_assert (cfg_hooks->extract_cond_bb_edges); + cfg_hooks->extract_cond_bb_edges (b, e1, e2); +} + +/* Responsible for updating the ssa info (PHI nodes) on the + new conidtion basic block that guargs the versioned loop. */ +void +lv_adjust_loop_header_phi (basic_block first, basic_block second, + basic_block new, edge e) +{ + if (cfg_hooks->lv_adjust_loop_header_phi) + cfg_hooks->lv_adjust_loop_header_phi (first, second, new, e); +} + +/* Conditions in trees and RTL are different so we need + a different handling when we add the condition to the + versioning code. */ +void +lv_add_condition_to_bb (basic_block first, basic_block second, + basic_block new, void *cond) +{ + gcc_assert (cfg_hooks->lv_add_condition_to_bb); + cfg_hooks->lv_add_condition_to_bb (first, second, new, cond); +} diff --git a/gcc/cfghooks.h b/gcc/cfghooks.h index 92a458ed4aa..a05a0154c92 100644 --- a/gcc/cfghooks.h +++ b/gcc/cfghooks.h @@ -108,6 +108,33 @@ struct cfg_hooks /* This function is called immediately before edge E is removed from the edge vector E->dest->preds. */ void (*execute_on_shrinking_pred) (edge); + + /* A hook for duplicating loop in CFG, currently this is used + in loop versioning. */ + bool (*cfg_hook_duplicate_loop_to_header_edge) (struct loop *loop, edge e, + struct loops *loops, + unsigned int ndupl, + sbitmap wont_exit, + edge orig, edge *to_remove, + unsigned int *n_to_remove, + int flags); + + /* Add conition to new basic block and update CFG used in loop + versioning. */ + void (*lv_add_condition_to_bb) (basic_block, basic_block, basic_block, + void *); + /* Update the PHI nodes in case of loop versioning. */ + void (*lv_adjust_loop_header_phi) (basic_block, basic_block, + basic_block, edge); + + /* Given a condition BB extract the true/false taken/not taken edges + (depending if we are on tree's or RTL). */ + void (*extract_cond_bb_edges) (basic_block, edge *, edge *); + + + /* Add PHI arguments queued in PENDINT_STMT list on edge E to edge + E->dest (only in tree-ssa loop versioning. */ + void (*flush_pending_stmts) (edge); }; extern void verify_flow_info (void); @@ -136,6 +163,20 @@ extern bool block_ends_with_condjump_p (basic_block bb); extern int flow_call_edges_add (sbitmap); extern void execute_on_growing_pred (edge); extern void execute_on_shrinking_pred (edge); +extern bool cfg_hook_duplicate_loop_to_header_edge (struct loop *loop, edge, + struct loops *loops, + unsigned int ndupl, + sbitmap wont_exit, + edge orig, edge *to_remove, + unsigned int *n_to_remove, + int flags); + +extern void lv_flush_pending_stmts (edge); +extern void extract_cond_bb_edges (basic_block, edge *, edge*); +extern void lv_adjust_loop_header_phi (basic_block, basic_block, basic_block, + edge); +extern void lv_add_condition_to_bb (basic_block, basic_block, basic_block, + void *); /* Hooks containers. */ extern struct cfg_hooks tree_cfg_hooks; diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index e0dad37ec10..7a5d57fbff0 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -298,11 +298,13 @@ extern bool can_duplicate_loop_p (struct loop *loop); extern struct loop * duplicate_loop (struct loops *, struct loop *, struct loop *); -extern int duplicate_loop_to_header_edge (struct loop *, edge, struct loops *, - unsigned, sbitmap, edge, edge *, - unsigned *, int); +extern bool duplicate_loop_to_header_edge (struct loop *, edge, struct loops *, + unsigned, sbitmap, edge, edge *, + unsigned *, int); extern struct loop *loopify (struct loops *, edge, edge, basic_block, edge, edge, bool); +struct loop * loop_version (struct loops *, struct loop *, void *, + basic_block *); extern bool remove_path (struct loops *, edge); extern edge split_loop_bb (basic_block, void *); diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c index 14769067279..50fad382f65 100644 --- a/gcc/cfgloopmanip.c +++ b/gcc/cfgloopmanip.c @@ -28,6 +28,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "basic-block.h" #include "cfgloop.h" #include "cfglayout.h" +#include "cfghooks.h" #include "output.h" static void duplicate_subloops (struct loops *, struct loop *, struct loop *); @@ -837,7 +838,7 @@ update_single_exits_after_duplication (basic_block *bbs, unsigned nbbs, original LOOP body, the other copies are numbered in order given by control flow through them) into TO_REMOVE array. Returns false if duplication is impossible. */ -int +bool duplicate_loop_to_header_edge (struct loop *loop, edge e, struct loops *loops, unsigned int ndupl, sbitmap wont_exit, edge orig, edge *to_remove, @@ -1354,6 +1355,135 @@ create_loop_notes (void) flow_loops_free (&loops); } +/* This function is called from loop_version. It splits the entry edge + of the loop we want to version, adds the versioning condition, and + adjust the edges to the two versions of the loop appropriately. + e is an incoming edge. Returns the basic block containing the + condition. + + --- edge e ---- > [second_head] + + Split it and insert new conditional expression and adjust edges. + + --- edge e ---> [cond expr] ---> [first_head] + | + +---------> [second_head] +*/ + +static basic_block +lv_adjust_loop_entry_edge (basic_block first_head, + basic_block second_head, + edge e, + tree cond_expr) +{ + basic_block new_head = NULL; + edge e1; + + gcc_assert (e->dest == second_head); + + /* Split edge 'e'. This will create a new basic block, where we can + insert conditional expr. */ + new_head = split_edge (e); + + + lv_add_condition_to_bb (first_head, second_head, new_head, + cond_expr); + + e1 = make_edge (new_head, first_head, EDGE_TRUE_VALUE); + set_immediate_dominator (CDI_DOMINATORS, first_head, new_head); + set_immediate_dominator (CDI_DOMINATORS, second_head, new_head); + + /* Adjust loop header phi nodes. */ + lv_adjust_loop_header_phi (first_head, second_head, new_head, e1); + + return new_head; +} + +/* Main entry point for Loop Versioning transformation. + +This transformation given a condition and a loop, creates +-if (condition) { loop_copy1 } else { loop_copy2 }, +where loop_copy1 is the loop transformed in one way, and loop_copy2 +is the loop transformed in another way (or unchanged). 'condition' +may be a run time test for things that were not resolved by static +analysis (overlapping ranges (anti-aliasing), alignment, etc.). */ + +struct loop * +loop_version (struct loops *loops, struct loop * loop, + void *cond_expr, basic_block *condition_bb) +{ + basic_block first_head, second_head; + edge entry, latch_edge, exit, true_edge, false_edge; + int irred_flag; + struct loop *nloop; + + /* CHECKME: Loop versioning does not handle nested loop at this point. */ + if (loop->inner) + return NULL; + + /* Record entry and latch edges for the loop */ + entry = loop_preheader_edge (loop); + irred_flag = entry->flags & EDGE_IRREDUCIBLE_LOOP; + entry->flags &= ~EDGE_IRREDUCIBLE_LOOP; + + /* Note down head of loop as first_head. */ + first_head = entry->dest; + + /* Duplicate loop. */ + if (!cfg_hook_duplicate_loop_to_header_edge (loop, entry, loops, 1, + NULL, NULL, NULL, NULL, 0)) + return NULL; + + /* After duplication entry edge now points to new loop head block. + Note down new head as second_head. */ + second_head = entry->dest; + + /* Split loop entry edge and insert new block with cond expr. */ + *condition_bb = lv_adjust_loop_entry_edge (first_head, second_head, + entry, cond_expr); + if (!*condition_bb) + { + entry->flags |= irred_flag; + return NULL; + } + + latch_edge = single_succ_edge (loop->latch->rbi->copy); + + extract_cond_bb_edges (*condition_bb, &true_edge, &false_edge); + nloop = loopify (loops, + latch_edge, + single_pred_edge (loop->header->rbi->copy), + *condition_bb, true_edge, false_edge, + false /* Do not redirect all edges. */); + + exit = loop->single_exit; + if (exit) + nloop->single_exit = find_edge (exit->src->rbi->copy, exit->dest); + + /* loopify redirected latch_edge. Update its PENDING_STMTS. */ + lv_flush_pending_stmts (latch_edge); + + /* loopify redirected condition_bb's succ edge. Update its PENDING_STMTS. */ + extract_cond_bb_edges (*condition_bb, &true_edge, &false_edge); + lv_flush_pending_stmts (false_edge); + /* Adjust irreducible flag. */ + if (irred_flag) + { + (*condition_bb)->flags |= BB_IRREDUCIBLE_LOOP; + loop_preheader_edge (loop)->flags |= EDGE_IRREDUCIBLE_LOOP; + loop_preheader_edge (nloop)->flags |= EDGE_IRREDUCIBLE_LOOP; + single_pred_edge ((*condition_bb))->flags |= EDGE_IRREDUCIBLE_LOOP; + } + + /* At this point condition_bb is loop predheader with two successors, + first_head and second_head. Make sure that loop predheader has only + one successor. */ + loop_split_edge_with (loop_preheader_edge (loop), NULL); + loop_split_edge_with (loop_preheader_edge (nloop), NULL); + + return nloop; +} + /* The structure of LOOPS might have changed. Some loops might get removed (and their headers and latches were set to NULL), loop exists might get removed (thus the loop nesting may be wrong), and some blocks and edges diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index d11db10b0e6..d0a50e46a8e 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -57,7 +57,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "cfglayout.h" #include "expr.h" #include "target.h" - +#include "cfgloop.h" /* The labels mentioned in non-jump rtl. Valid during find_basic_blocks. */ /* ??? Should probably be using LABEL_NUSES instead. It would take a @@ -2028,7 +2028,7 @@ rtl_verify_flow_info_1 (void) err = 1; } if (n_branch != 1 && any_condjump_p (BB_END (bb)) - && JUMP_LABEL (BB_END (bb)) != BB_HEAD (fallthru->dest)) + && JUMP_LABEL (BB_END (bb)) == BB_HEAD (fallthru->dest)) { error ("Wrong amount of branch edges after conditional jump %i", bb->index); err = 1; @@ -2997,6 +2997,66 @@ rtl_flow_call_edges_add (sbitmap blocks) return blocks_split; } +/* Add COMP_RTX as a condition at end of COND_BB. FIRST_HEAD is + the conditional branch traget, SECOND_HEAD should be the fall-thru + there is no need to handle this here the loop versioning code handles + this. the reason for SECON_HEAD is that it is needed for condition + in trees, and this should be of the same type since it is a hook. */ +static void +rtl_lv_add_condition_to_bb (basic_block first_head , + basic_block second_head ATTRIBUTE_UNUSED, + basic_block cond_bb, void *comp_rtx) +{ + rtx label, seq, jump; + rtx op0 = XEXP ((rtx)comp_rtx, 0); + rtx op1 = XEXP ((rtx)comp_rtx, 1); + enum rtx_code comp = GET_CODE ((rtx)comp_rtx); + enum machine_mode mode; + + + label = block_label (first_head); + mode = GET_MODE (op0); + if (mode == VOIDmode) + mode = GET_MODE (op1); + + start_sequence (); + op0 = force_operand (op0, NULL_RTX); + op1 = force_operand (op1, NULL_RTX); + do_compare_rtx_and_jump (op0, op1, comp, 0, + mode, NULL_RTX, NULL_RTX, label); + jump = get_last_insn (); + JUMP_LABEL (jump) = label; + LABEL_NUSES (label)++; + seq = get_insns (); + end_sequence (); + + /* Add the new cond , in the new head. */ + emit_insn_after(seq, BB_END(cond_bb)); +} + + +/* Given a block B with unconditional branch at its end, get the + store the return the branch edge and the fall-thru edge in + BRANCH_EDGE and FALLTHRU_EDGE respectively. */ +static void +rtl_extract_cond_bb_edges (basic_block b, edge *branch_edge, + edge *fallthru_edge) +{ + edge e = EDGE_SUCC (b, 0); + + if (e->flags & EDGE_FALLTHRU) + { + *fallthru_edge = e; + *branch_edge = EDGE_SUCC (b, 1); + } + else + { + *branch_edge = e; + *fallthru_edge = EDGE_SUCC (b, 1); + } +} + + /* Implementation of CFG manipulation for linearized RTL. */ struct cfg_hooks rtl_cfg_hooks = { "rtl", @@ -3021,7 +3081,12 @@ struct cfg_hooks rtl_cfg_hooks = { rtl_block_ends_with_condjump_p, rtl_flow_call_edges_add, NULL, /* execute_on_growing_pred */ - NULL /* execute_on_shrinking_pred */ + NULL, /* execute_on_shrinking_pred */ + NULL, /* duplicate loop for trees */ + NULL, /* lv_add_condition_to_bb */ + NULL, /* lv_adjust_loop_header_phi*/ + NULL, /* extract_cond_bb_edges */ + NULL /* flush_pending_stmts */ }; /* Implementation of CFG manipulation for cfg layout RTL, where @@ -3059,6 +3124,11 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = { rtl_block_ends_with_condjump_p, rtl_flow_call_edges_add, NULL, /* execute_on_growing_pred */ - NULL /* execute_on_shrinking_pred */ + NULL, /* execute_on_shrinking_pred */ + duplicate_loop_to_header_edge, /* duplicate loop for trees */ + rtl_lv_add_condition_to_bb, /* lv_add_condition_to_bb */ + NULL, /* lv_adjust_loop_header_phi*/ + rtl_extract_cond_bb_edges, /* extract_cond_bb_edges */ + NULL /* flush_pending_stmts */ }; diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index b1ff8e6d97b..d913759ba8d 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -5687,6 +5687,71 @@ tree_execute_on_shrinking_pred (edge e) remove_phi_args (e); } +/*--------------------------------------------------------------------------- + Helper functions for Loop versioning + ---------------------------------------------------------------------------*/ + +/* Adjust phi nodes for 'first' basic block. 'second' basic block is a copy + of 'first'. Both of them are dominated by 'new_head' basic block. When + 'new_head' was created by 'second's incoming edge it received phi arguments + on the edge by split_edge(). Later, additional edge 'e' was created to + connect 'new_head' and 'first'. Now this routine adds phi args on this + additional edge 'e' that new_head to second edge received as part of edge + splitting. +*/ + +static void +tree_lv_adjust_loop_header_phi (basic_block first, basic_block second, + basic_block new_head, edge e) +{ + tree phi1, phi2; + + /* Browse all 'second' basic block phi nodes and add phi args to + edge 'e' for 'first' head. PHI args are always in correct order. */ + + for (phi2 = phi_nodes (second), phi1 = phi_nodes (first); + phi2 && phi1; + phi2 = PHI_CHAIN (phi2), phi1 = PHI_CHAIN (phi1)) + { + edge e2 = find_edge (new_head, second); + + if (e2) + { + tree def = PHI_ARG_DEF (phi2, e2->dest_idx); + add_phi_arg (phi1, def, e); + } + } +} + +/* Adds a if else statement to COND_BB with condition COND_EXPR. + SECOND_HEAD is the destination of the THEN and FIRST_HEAD is + the destination of the ELSE part. */ +static void +tree_lv_add_condition_to_bb (basic_block first_head, basic_block second_head, + basic_block cond_bb, void *cond_e) +{ + block_stmt_iterator bsi; + tree goto1 = NULL_TREE; + tree goto2 = NULL_TREE; + tree new_cond_expr = NULL_TREE; + tree cond_expr = (tree) cond_e; + edge e0; + + /* Build new conditional expr */ + goto1 = build1 (GOTO_EXPR, void_type_node, tree_block_label (first_head)); + goto2 = build1 (GOTO_EXPR, void_type_node, tree_block_label (second_head)); + new_cond_expr = build3 (COND_EXPR, void_type_node, cond_expr, goto1, goto2); + + /* Add new cond in cond_bb. */ + bsi = bsi_start (cond_bb); + bsi_insert_after (&bsi, new_cond_expr, BSI_NEW_STMT); + /* Adjust edges appropriately to connect new head with first head + as well as second head. */ + e0 = single_succ_edge (cond_bb); + e0->flags &= ~EDGE_FALLTHRU; + e0->flags |= EDGE_FALSE_VALUE; +} + struct cfg_hooks tree_cfg_hooks = { "tree", tree_verify_flow_info, @@ -5711,6 +5776,11 @@ struct cfg_hooks tree_cfg_hooks = { tree_flow_call_edges_add, /* flow_call_edges_add */ tree_execute_on_growing_pred, /* execute_on_growing_pred */ tree_execute_on_shrinking_pred, /* execute_on_shrinking_pred */ + tree_duplicate_loop_to_header_edge, /* duplicate loop for trees */ + tree_lv_add_condition_to_bb, /* lv_add_condition_to_bb */ + tree_lv_adjust_loop_header_phi, /* lv_adjust_loop_header_phi*/ + extract_true_false_edges_from_block, /* extract_cond_bb_edges */ + flush_pending_stmts /* flush_pending_stmts */ }; diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c index 71d34614816..1bb4c4c3aa1 100644 --- a/gcc/tree-ssa-loop-manip.c +++ b/gcc/tree-ssa-loop-manip.c @@ -677,179 +677,3 @@ tree_duplicate_loop_to_header_edge (struct loop *loop, edge e, return true; } -/*--------------------------------------------------------------------------- - Loop versioning - ---------------------------------------------------------------------------*/ - -/* Adjust phi nodes for 'first' basic block. 'second' basic block is a copy - of 'first'. Both of them are dominated by 'new_head' basic block. When - 'new_head' was created by 'second's incoming edge it received phi arguments - on the edge by split_edge(). Later, additional edge 'e' was created to - connect 'new_head' and 'first'. Now this routine adds phi args on this - additional edge 'e' that new_head to second edge received as part of edge - splitting. -*/ - -static void -lv_adjust_loop_header_phi (basic_block first, basic_block second, - basic_block new_head, edge e) -{ - tree phi1, phi2; - - /* Browse all 'second' basic block phi nodes and add phi args to - edge 'e' for 'first' head. PHI args are always in correct order. */ - - for (phi2 = phi_nodes (second), phi1 = phi_nodes (first); - phi2 && phi1; - phi2 = PHI_CHAIN (phi2), phi1 = PHI_CHAIN (phi1)) - { - edge e2 = find_edge (new_head, second); - - if (e2) - { - tree def = PHI_ARG_DEF (phi2, e2->dest_idx); - add_phi_arg (phi1, def, e); - } - } -} - -/* Adjust entry edge for lv. - - e is an incoming edge. - - --- edge e ---- > [second_head] - - Split it and insert new conditional expression and adjust edges. - - --- edge e ---> [cond expr] ---> [first_head] - | - +---------> [second_head] - -*/ - -static basic_block -lv_adjust_loop_entry_edge (basic_block first_head, - basic_block second_head, - edge e, - tree cond_expr) -{ - block_stmt_iterator bsi; - basic_block new_head = NULL; - tree goto1 = NULL_TREE; - tree goto2 = NULL_TREE; - tree new_cond_expr = NULL_TREE; - edge e0, e1; - - gcc_assert (e->dest == second_head); - - /* Split edge 'e'. This will create a new basic block, where we can - insert conditional expr. */ - new_head = split_edge (e); - - /* Build new conditional expr */ - goto1 = build1 (GOTO_EXPR, void_type_node, tree_block_label (first_head)); - goto2 = build1 (GOTO_EXPR, void_type_node, tree_block_label (second_head)); - new_cond_expr = build3 (COND_EXPR, void_type_node, cond_expr, goto1, goto2); - - /* Add new cond. in new head. */ - bsi = bsi_start (new_head); - bsi_insert_after (&bsi, new_cond_expr, BSI_NEW_STMT); - - /* Adjust edges appropriately to connect new head with first head - as well as second head. */ - e0 = single_succ_edge (new_head); - e0->flags &= ~EDGE_FALLTHRU; - e0->flags |= EDGE_FALSE_VALUE; - e1 = make_edge (new_head, first_head, EDGE_TRUE_VALUE); - set_immediate_dominator (CDI_DOMINATORS, first_head, new_head); - set_immediate_dominator (CDI_DOMINATORS, second_head, new_head); - - /* Adjust loop header phi nodes. */ - lv_adjust_loop_header_phi (first_head, second_head, new_head, e1); - - return new_head; -} - -/* Main entry point for Loop Versioning transformation. - -This transformation given a condition and a loop, creates --if (condition) { loop_copy1 } else { loop_copy2 }, -where loop_copy1 is the loop transformed in one way, and loop_copy2 -is the loop transformed in another way (or unchanged). 'condition' -may be a run time test for things that were not resolved by static -analysis (overlapping ranges (anti-aliasing), alignment, etc.). */ - -struct loop * -tree_ssa_loop_version (struct loops *loops, struct loop * loop, - tree cond_expr, basic_block *condition_bb) -{ - edge entry, latch_edge, exit, true_edge, false_edge; - basic_block first_head, second_head; - int irred_flag; - struct loop *nloop; - - /* CHECKME: Loop versioning does not handle nested loop at this point. */ - if (loop->inner) - return NULL; - - /* Record entry and latch edges for the loop */ - entry = loop_preheader_edge (loop); - - /* Note down head of loop as first_head. */ - first_head = entry->dest; - - /* Duplicate loop. */ - irred_flag = entry->flags & EDGE_IRREDUCIBLE_LOOP; - entry->flags &= ~EDGE_IRREDUCIBLE_LOOP; - if (!tree_duplicate_loop_to_header_edge (loop, entry, loops, 1, - NULL, NULL, NULL, NULL, 0)) - { - entry->flags |= irred_flag; - return NULL; - } - - /* After duplication entry edge now points to new loop head block. - Note down new head as second_head. */ - second_head = entry->dest; - - /* Split loop entry edge and insert new block with cond expr. */ - *condition_bb = lv_adjust_loop_entry_edge (first_head, second_head, entry, - cond_expr); - - latch_edge = single_succ_edge (loop->latch->rbi->copy); - - extract_true_false_edges_from_block (*condition_bb, &true_edge, &false_edge); - nloop = loopify (loops, - latch_edge, - single_pred_edge (loop->header->rbi->copy), - *condition_bb, true_edge, false_edge, - false /* Do not redirect all edges. */); - - exit = loop->single_exit; - if (exit) - nloop->single_exit = find_edge (exit->src->rbi->copy, exit->dest); - - /* loopify redirected latch_edge. Update its PENDING_STMTS. */ - flush_pending_stmts (latch_edge); - - /* loopify redirected condition_bb's succ edge. Update its PENDING_STMTS. */ - extract_true_false_edges_from_block (*condition_bb, &true_edge, &false_edge); - flush_pending_stmts (false_edge); - - /* Adjust irreducible flag. */ - if (irred_flag) - { - (*condition_bb)->flags |= BB_IRREDUCIBLE_LOOP; - loop_preheader_edge (loop)->flags |= EDGE_IRREDUCIBLE_LOOP; - loop_preheader_edge (nloop)->flags |= EDGE_IRREDUCIBLE_LOOP; - single_pred_edge ((*condition_bb))->flags |= EDGE_IRREDUCIBLE_LOOP; - } - - /* At this point condition_bb is loop predheader with two successors, - first_head and second_head. Make sure that loop predheader has only - one successor. */ - loop_split_edge_with (loop_preheader_edge (loop), NULL); - loop_split_edge_with (loop_preheader_edge (nloop), NULL); - - return nloop; -} diff --git a/gcc/tree-ssa-loop-unswitch.c b/gcc/tree-ssa-loop-unswitch.c index 29fab9aed31..03631b82636 100644 --- a/gcc/tree-ssa-loop-unswitch.c +++ b/gcc/tree-ssa-loop-unswitch.c @@ -283,6 +283,6 @@ tree_unswitch_loop (struct loops *loops, struct loop *loop, gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2); gcc_assert (loop->inner == NULL); - return tree_ssa_loop_version (loops, loop, unshare_expr (cond), - &condition_bb); + return loop_version (loops, loop, unshare_expr (cond), + &condition_bb); }