You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This pass implements tree level if-conversion transformation of loops.
Initial goal is to help vectorizer vectorize loops with conditions.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "errors.h"
#include "tree.h"
#include "c-common.h"
#include "flags.h"
#include "target.h"
/* local function prototypes */
-static void main_tree_if_conversion (void);
+static unsigned int main_tree_if_conversion (void);
static tree tree_if_convert_stmt (struct loop *loop, tree, tree,
block_stmt_iterator *);
static void tree_if_convert_cond_expr (struct loop *, tree, tree,
static bool if_convertible_phi_p (struct loop *, basic_block, tree);
static bool if_convertible_modify_expr_p (struct loop *, basic_block, tree);
static bool if_convertible_stmt_p (struct loop *, basic_block, tree);
-static bool if_convertible_bb_p (struct loop *, basic_block, bool);
+static bool if_convertible_bb_p (struct loop *, basic_block, basic_block);
static bool if_convertible_loop_p (struct loop *, bool);
static void add_to_predicate_list (basic_block, tree);
static tree add_to_dst_predicate_list (struct loop * loop, basic_block, tree, tree,
using new condition. */
if (!bb_with_exit_edge_p (loop, bb_for_stmt (stmt)))
{
- bsi_remove (bsi);
+ bsi_remove (bsi, true);
cond = NULL_TREE;
}
return;
BB is inside loop LOOP. */
static bool
-if_convertible_bb_p (struct loop *loop, basic_block bb, bool exit_bb_seen)
+if_convertible_bb_p (struct loop *loop, basic_block bb, basic_block exit_bb)
{
edge e;
edge_iterator ei;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "----------[%d]-------------\n", bb->index);
- if (exit_bb_seen)
+ if (exit_bb)
{
if (bb != loop->latch)
{
fprintf (dump_file, "non empty basic block after exit bb\n");
return false;
}
+ else if (bb == loop->latch
+ && bb != exit_bb
+ && !dominated_by_p (CDI_DOMINATORS, bb, exit_bb))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "latch is not dominated by exit_block\n");
+ return false;
+ }
}
/* Be less adventurous and handle only normal edges. */
unsigned int i;
edge e;
edge_iterator ei;
- bool exit_bb_seen = false;
+ basic_block exit_bb = NULL;
/* Handle only inner most loop. */
if (!loop || loop->inner)
{
bb = ifc_bbs[i];
- if (!if_convertible_bb_p (loop, bb, exit_bb_seen))
+ if (!if_convertible_bb_p (loop, bb, exit_bb))
return false;
/* Check statements. */
return false;
if (bb_with_exit_edge_p (loop, bb))
- exit_bb_seen = true;
+ exit_bb = bb;
}
/* OK. Did not find any potential issues so go ahead in if-convert
tree cond = bb->aux;
if (cond)
- cond = fold (build (TRUTH_OR_EXPR, boolean_type_node,
- unshare_expr (cond), new_cond));
+ cond = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+ unshare_expr (cond), new_cond);
else
cond = new_cond;
bsi_insert_before (bsi, tmp_stmts2, BSI_SAME_STMT);
/* new_cond == prev_cond AND cond */
- tmp = build (TRUTH_AND_EXPR, boolean_type_node,
- unshare_expr (prev_cond), cond);
+ tmp = build2 (TRUTH_AND_EXPR, boolean_type_node,
+ unshare_expr (prev_cond), cond);
tmp_stmt = ifc_temp_var (boolean_type_node, tmp);
bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
new_cond = TREE_OPERAND (tmp_stmt, 0);
{
basic_block first_bb = NULL;
basic_block second_bb = NULL;
- tree tmp_cond;
+ tree tmp_cond, new_stmts;
gcc_assert (EDGE_COUNT (bb->preds) == 2);
first_bb = (EDGE_PRED (bb, 0))->src;
S2: x = c ? b : a;
S2 is preferred over S1. Make 'b' first_bb and use its condition.
-
+
2) Do not make loop header first_bb.
3)
S3: x = (c == d) ? b : a;
S3 is preferred over S1 and S2*, Make 'b' first_bb and use
- its condition. */
+ its condition.
+
+ 4) If pred B is dominated by pred A then use pred B's condition.
+ See PR23115. */
/* Select condition that is not TRUTH_NOT_EXPR. */
tmp_cond = first_bb->aux;
second_bb = tmp_bb;
}
- /* Check if FIRST_BB is loop header or not. */
- if (first_bb == loop->header)
+ /* Check if FIRST_BB is loop header or not and make sure that
+ FIRST_BB does not dominate SECOND_BB. */
+ if (first_bb == loop->header
+ || dominated_by_p (CDI_DOMINATORS, second_bb, first_bb))
{
tmp_cond = second_bb->aux;
if (TREE_CODE (tmp_cond) == TRUTH_NOT_EXPR)
value as condition. Various targets use different means to communicate
condition in vector compare operation. Using gimple value allows compiler
to emit vector compare and select RTL without exposing compare's result. */
+ *cond = force_gimple_operand (*cond, &new_stmts, false, NULL_TREE);
+ if (new_stmts)
+ bsi_insert_before (bsi, new_stmts, BSI_SAME_STMT);
if (!is_gimple_reg (*cond) && !is_gimple_condexpr (*cond))
{
tree new_stmt;
new_stmt = ifc_temp_var (TREE_TYPE (*cond), unshare_expr (*cond));
- bsi_insert_after (bsi, new_stmt, BSI_SAME_STMT);
- bsi_next (bsi);
+ bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
*cond = TREE_OPERAND (new_stmt, 0);
}
}
/* Build new RHS using selected condition and arguments. */
- rhs = build (COND_EXPR, TREE_TYPE (PHI_RESULT (phi)),
- unshare_expr (cond), unshare_expr (arg_0),
- unshare_expr (arg_1));
+ rhs = build3 (COND_EXPR, TREE_TYPE (PHI_RESULT (phi)),
+ unshare_expr (cond), unshare_expr (arg_0),
+ unshare_expr (arg_1));
/* Create new MODIFY expression using RHS. */
- new_stmt = build (MODIFY_EXPR, TREE_TYPE (PHI_RESULT (phi)),
- unshare_expr (PHI_RESULT (phi)), rhs);
+ new_stmt = build2 (MODIFY_EXPR, TREE_TYPE (PHI_RESULT (phi)),
+ unshare_expr (PHI_RESULT (phi)), rhs);
/* Make new statement definition of the original phi result. */
SSA_NAME_DEF_STMT (PHI_RESULT (phi)) = new_stmt;
/* Insert using iterator. */
- bsi_insert_after (bsi, new_stmt, BSI_SAME_STMT);
- bsi_next (bsi);
-
+ bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
update_stmt (new_stmt);
if (dump_file && (dump_flags & TDF_DETAILS))
basic_block bb, exit_bb, merge_target_bb;
unsigned int orig_loop_num_nodes = loop->num_nodes;
unsigned int i;
- unsigned int n_exits;
+ edge e;
+ edge_iterator ei;
- get_loop_exit_edges (loop, &n_exits);
/* Process phi nodes to prepare blocks for merge. */
process_phi_nodes (loop);
+ /* Merge basic blocks. First remove all the edges in the loop, except
+ for those from the exit block. */
exit_bb = NULL;
+ for (i = 0; i < orig_loop_num_nodes; i++)
+ {
+ bb = ifc_bbs[i];
+ if (bb_with_exit_edge_p (loop, bb))
+ {
+ exit_bb = bb;
+ break;
+ }
+ }
+ gcc_assert (exit_bb != loop->latch);
- /* Merge basic blocks */
- merge_target_bb = loop->header;
for (i = 1; i < orig_loop_num_nodes; i++)
{
- edge e;
- block_stmt_iterator bsi;
- tree_stmt_iterator last;
-
bb = ifc_bbs[i];
- if (!exit_bb && bb_with_exit_edge_p (loop, bb))
- exit_bb = bb;
-
- if (bb == exit_bb)
+ for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei));)
{
- edge_iterator ei;
+ if (e->src == exit_bb)
+ ei_next (&ei);
+ else
+ remove_edge (e);
+ }
+ }
+ if (exit_bb != NULL)
+ {
+ if (exit_bb != loop->header)
+ {
/* Connect this node with loop header. */
- make_edge (ifc_bbs[0], bb, EDGE_FALLTHRU);
- set_immediate_dominator (CDI_DOMINATORS, bb, ifc_bbs[0]);
-
- if (exit_bb != loop->latch)
- {
- /* Redirect non-exit edge to loop->latch. */
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- if (!loop_exit_edge_p (loop, e))
- {
- redirect_edge_and_branch (e, loop->latch);
- set_immediate_dominator (CDI_DOMINATORS, loop->latch, bb);
- }
- }
- }
- continue;
+ make_edge (loop->header, exit_bb, EDGE_FALLTHRU);
+ set_immediate_dominator (CDI_DOMINATORS, exit_bb, loop->header);
}
- if (bb == loop->latch && empty_block_p (bb))
- continue;
+ /* Redirect non-exit edges to loop->latch. */
+ FOR_EACH_EDGE (e, ei, exit_bb->succs)
+ {
+ if (!loop_exit_edge_p (loop, e))
+ redirect_edge_and_branch (e, loop->latch);
+ }
+ set_immediate_dominator (CDI_DOMINATORS, loop->latch, exit_bb);
+ }
+ else
+ {
+ /* If the loop does not have exit then reconnect header and latch. */
+ make_edge (loop->header, loop->latch, EDGE_FALLTHRU);
+ set_immediate_dominator (CDI_DOMINATORS, loop->latch, loop->header);
+ }
- /* It is time to remove this basic block. First remove edges. */
- while (EDGE_COUNT (bb->preds) > 0)
- remove_edge (EDGE_PRED (bb, 0));
+ merge_target_bb = loop->header;
+ for (i = 1; i < orig_loop_num_nodes; i++)
+ {
+ block_stmt_iterator bsi;
+ tree_stmt_iterator last;
- /* This is loop latch and loop does not have exit then do not
- delete this basic block. Just remove its PREDS and reconnect
- loop->header and loop->latch blocks. */
- if (bb == loop->latch && n_exits == 0)
- {
- make_edge (loop->header, loop->latch, EDGE_FALLTHRU);
- set_immediate_dominator (CDI_DOMINATORS, loop->latch, loop->header);
- continue;
- }
+ bb = ifc_bbs[i];
- while (EDGE_COUNT (bb->succs) > 0)
- remove_edge (EDGE_SUCC (bb, 0));
+ if (bb == exit_bb || bb == loop->latch)
+ continue;
/* Remove labels and make stmts member of loop->header. */
for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
{
if (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR)
- bsi_remove (&bsi);
+ bsi_remove (&bsi, true);
else
{
set_bb_for_stmt (bsi_stmt (bsi), merge_target_bb);
delete_from_dominance_info (CDI_POST_DOMINATORS, bb);
/* Remove basic block. */
- if (bb == loop->latch)
- loop->latch = merge_target_bb;
remove_bb_from_loops (bb);
expunge_block (bb);
}
This reduces number of basic blocks to 2. Auto vectorizer addresses
loops with two nodes only. FIXME: Use cleanup_tree_cfg(). */
if (exit_bb
- && loop->header != loop->latch
- && exit_bb != loop->latch
- && empty_block_p (loop->latch))
+ && exit_bb != loop->header
+ && can_merge_blocks_p (loop->header, exit_bb))
{
- if (can_merge_blocks_p (loop->header, exit_bb))
- {
- remove_bb_from_loops (exit_bb);
- merge_blocks (loop->header, exit_bb);
- }
+ remove_bb_from_loops (exit_bb);
+ merge_blocks (loop->header, exit_bb);
}
}
/* Create new temporary variable. */
var = create_tmp_var (type, name);
- add_referenced_tmp_var (var);
+ add_referenced_var (var);
/* Build new statement to assign EXP to new variable. */
- stmt = build (MODIFY_EXPR, type, var, exp);
+ stmt = build2 (MODIFY_EXPR, type, var, exp);
/* Get SSA name for the new variable and set make new statement
its definition statement. */
gcc_assert (loop->num_nodes);
gcc_assert (loop->latch != EXIT_BLOCK_PTR);
- blocks = xcalloc (loop->num_nodes, sizeof (basic_block));
+ blocks = XCNEWVEC (basic_block, loop->num_nodes);
visited = BITMAP_ALLOC (NULL);
blocks_in_bfs_order = get_loop_body_in_bfs_order (loop);
/* Tree if-conversion pass management. */
-static void
+static unsigned int
main_tree_if_conversion (void)
{
unsigned i, loop_num;
struct loop *loop;
if (!current_loops)
- return;
+ return 0;
loop_num = current_loops->num;
for (i = 0; i < loop_num; i++)
tree_if_conversion (loop, true);
}
-
+ return 0;
}
static bool