Add flag -ftree-loop-if-convert-stores.
This patch adds a flag that controls the replacement of the memory writes that are in predicated basic blocks with a full write: for (...) if (cond) A[i] = foo is replaced with: for (...) A[i] = cond ? foo : A[i] In order to do this, we have to call gimple_could_trap_p instead of gimple_assign_rhs_could_trap_p, as we have to also check that the LHS of assign stmts does not trap. * common.opt (ftree-loop-if-convert-stores): New flag. * doc/invoke.texi (ftree-loop-if-convert-stores): Documented. * tree-if-conv.c (ifc_temp_var): Pass an extra parameter GSI. Insert the created statement before GSI. (if_convertible_phi_p): Allow virtual phi nodes when flag_loop_if_convert_stores is set. (if_convertible_gimple_assign_stmt_p): Allow memory reads and writes Do not handle types that do not match is_gimple_reg_type. Remove loop and bb parameters. Call gimple_could_trap_p instead of when flag_loop_if_convert_stores is set, as LHS can contain memory refs. (if_convertible_stmt_p): Remove loop and bb parameters. Update calls to if_convertible_gimple_assign_stmt_p. (if_convertible_loop_p): Update call to if_convertible_stmt_p. (replace_phi_with_cond_gimple_assign_stmt): Renamed predicate_scalar_phi. Do not handle virtual phi nodes. (ifconvert_phi_nodes): Renamed predicate_all_scalar_phis. Call predicate_scalar_phi. (insert_gimplified_predicates): Insert the gimplified predicate of a BB just after the labels for flag_loop_if_convert_stores, otherwise insert the predicate in the end of the BB. (predicate_mem_writes): New. (combine_blocks): Call predicate_all_scalar_phis. When flag_loop_if_convert_stores is set, call predicate_mem_writes. (tree_if_conversion): Call mark_sym_for_renaming when flag_loop_if_convert_stores is set. (main_tree_if_conversion): Return TODO_update_ssa_only_virtuals when flag_loop_if_convert_stores is set. * gcc.dg/tree-ssa/ifc-4.c: New. * gcc.dg/tree-ssa/ifc-7.c: New. From-SVN: r163530
This commit is contained in:
parent
3a9abc98c2
commit
bd544141e0
@ -1,3 +1,34 @@
|
||||
2010-08-24 Sebastian Pop <sebastian.pop@amd.com>
|
||||
|
||||
* common.opt (ftree-loop-if-convert-stores): New flag.
|
||||
* doc/invoke.texi (ftree-loop-if-convert-stores): Documented.
|
||||
* tree-if-conv.c (ifc_temp_var): Pass an extra parameter GSI. Insert
|
||||
the created statement before GSI.
|
||||
(if_convertible_phi_p): Allow virtual phi nodes when
|
||||
flag_loop_if_convert_stores is set.
|
||||
(if_convertible_gimple_assign_stmt_p): Allow memory reads and writes
|
||||
Do not handle types that do not match is_gimple_reg_type.
|
||||
Remove loop and bb parameters. Call gimple_could_trap_p instead of
|
||||
when flag_loop_if_convert_stores is set, as LHS can contain
|
||||
memory refs.
|
||||
(if_convertible_stmt_p): Remove loop and bb parameters. Update calls
|
||||
to if_convertible_gimple_assign_stmt_p.
|
||||
(if_convertible_loop_p): Update call to if_convertible_stmt_p.
|
||||
(replace_phi_with_cond_gimple_assign_stmt): Renamed
|
||||
predicate_scalar_phi. Do not handle virtual phi nodes.
|
||||
(ifconvert_phi_nodes): Renamed predicate_all_scalar_phis.
|
||||
Call predicate_scalar_phi.
|
||||
(insert_gimplified_predicates): Insert the gimplified predicate of a BB
|
||||
just after the labels for flag_loop_if_convert_stores, otherwise
|
||||
insert the predicate in the end of the BB.
|
||||
(predicate_mem_writes): New.
|
||||
(combine_blocks): Call predicate_all_scalar_phis. When
|
||||
flag_loop_if_convert_stores is set, call predicate_mem_writes.
|
||||
(tree_if_conversion): Call mark_sym_for_renaming when
|
||||
flag_loop_if_convert_stores is set.
|
||||
(main_tree_if_conversion): Return TODO_update_ssa_only_virtuals when
|
||||
flag_loop_if_convert_stores is set.
|
||||
|
||||
2010-08-24 Anatoly Sokolov <aesok@post.ru>
|
||||
|
||||
* config/pa/pa.c (hppa_register_move_cost, pa_libcall_value,
|
||||
|
@ -712,6 +712,10 @@ ftree-loop-if-convert
|
||||
Common Report Var(flag_tree_loop_if_convert) Init(-1) Optimization
|
||||
Convert conditional jumps in innermost loops to branchless equivalents
|
||||
|
||||
ftree-loop-if-convert-stores
|
||||
Common Report Var(flag_tree_loop_if_convert_stores) Optimization
|
||||
Also if-convert conditional jumps containing memory writes
|
||||
|
||||
; -finhibit-size-directive inhibits output of .size for ELF.
|
||||
; This is used only for compiling crtstuff.c,
|
||||
; and it may be extended to other effects
|
||||
|
@ -383,7 +383,8 @@ Objective-C and Objective-C++ Dialects}.
|
||||
-fstrict-aliasing -fstrict-overflow -fthread-jumps -ftracer -ftree-bit-ccp @gol
|
||||
-ftree-builtin-call-dce -ftree-ccp -ftree-ch -ftree-copy-prop @gol
|
||||
-ftree-copyrename -ftree-dce -ftree-dominator-opts -ftree-dse @gol
|
||||
-ftree-forwprop -ftree-fre -ftree-loop-if-convert -ftree-loop-im @gol
|
||||
-ftree-forwprop -ftree-fre -ftree-loop-if-convert @gol
|
||||
-ftree-loop-if-convert-memory-writes -ftree-loop-im @gol
|
||||
-ftree-phiprop -ftree-loop-distribution -ftree-loop-distribute-patterns @gol
|
||||
-ftree-loop-ivcanon -ftree-loop-linear -ftree-loop-optimize @gol
|
||||
-ftree-parallelize-loops=@var{n} -ftree-pre -ftree-pta -ftree-reassoc @gol
|
||||
@ -6931,6 +6932,23 @@ the innermost loops in order to improve the ability of the
|
||||
vectorization pass to handle these loops. This is enabled by default
|
||||
if vectorization is enabled.
|
||||
|
||||
@item -ftree-loop-if-convert-stores
|
||||
Attempt to also if-convert conditional jumps containing memory writes.
|
||||
This transformation can be unsafe for multi-threaded programs as it
|
||||
transforms conditional memory writes into unconditional memory writes.
|
||||
For example,
|
||||
@smallexample
|
||||
for (i = 0; i < N; i++)
|
||||
if (cond)
|
||||
A[i] = expr;
|
||||
@end smallexample
|
||||
would be transformed to
|
||||
@smallexample
|
||||
for (i = 0; i < N; i++)
|
||||
A[i] = cond ? expr : A[i];
|
||||
@end smallexample
|
||||
potentially producing data races.
|
||||
|
||||
@item -ftree-loop-distribution
|
||||
Perform loop distribution. This flag can improve cache performance on
|
||||
big loop bodies and allow further loop optimizations, like
|
||||
|
@ -1,3 +1,8 @@
|
||||
2010-08-24 Sebastian Pop <sebastian.pop@amd.com>
|
||||
|
||||
* gcc.dg/tree-ssa/ifc-4.c: New.
|
||||
* gcc.dg/tree-ssa/ifc-7.c: New.
|
||||
|
||||
2010-08-24 Mingjie Xing <mingjie.xing@gmail.com>
|
||||
|
||||
* gcc.dg/vect/vect.exp: Check loongson targets
|
||||
|
53
gcc/testsuite/gcc.dg/tree-ssa/ifc-4.c
Normal file
53
gcc/testsuite/gcc.dg/tree-ssa/ifc-4.c
Normal file
@ -0,0 +1,53 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-c -O2 -ftree-vectorize -fdump-tree-ifcvt-stats" { target *-*-* } } */
|
||||
|
||||
struct ht
|
||||
{
|
||||
void * (*alloc_subobject) (int);
|
||||
};
|
||||
typedef struct cpp_reader cpp_reader;
|
||||
typedef struct cpp_token cpp_token;
|
||||
typedef struct cpp_macro cpp_macro;
|
||||
enum cpp_ttype
|
||||
{
|
||||
CPP_PASTE,
|
||||
};
|
||||
struct cpp_token {
|
||||
__extension__ enum cpp_ttype type : 8;
|
||||
} cpp_comment_table;
|
||||
struct cpp_macro {
|
||||
union cpp_macro_u
|
||||
{
|
||||
cpp_token * tokens;
|
||||
} exp;
|
||||
unsigned int count;
|
||||
};
|
||||
struct cpp_reader
|
||||
{
|
||||
struct ht *hash_table;
|
||||
};
|
||||
create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
|
||||
{
|
||||
unsigned int num_extra_tokens = 0;
|
||||
{
|
||||
cpp_token *tokns =
|
||||
(cpp_token *) pfile->hash_table->alloc_subobject (sizeof (cpp_token)
|
||||
* macro->count);
|
||||
{
|
||||
cpp_token *normal_dest = tokns;
|
||||
cpp_token *extra_dest = tokns + macro->count - num_extra_tokens;
|
||||
unsigned int i;
|
||||
for (i = 0; i < macro->count; i++)
|
||||
{
|
||||
if (macro->exp.tokens[i].type == CPP_PASTE)
|
||||
*extra_dest++ = macro->exp.tokens[i];
|
||||
else
|
||||
*normal_dest++ = macro->exp.tokens[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This cannot be if-converted because the stores are to aggregate types. */
|
||||
/* { dg-final { scan-tree-dump-times "Applying if-conversion" 0 "ifcvt" } } */
|
||||
/* { dg-final { cleanup-tree-dump "ifcvt" } } */
|
29
gcc/testsuite/gcc.dg/tree-ssa/ifc-7.c
Normal file
29
gcc/testsuite/gcc.dg/tree-ssa/ifc-7.c
Normal file
@ -0,0 +1,29 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-c -O2 -ftree-vectorize" { target *-*-* } } */
|
||||
|
||||
typedef struct eqn_d
|
||||
{
|
||||
int *coef;
|
||||
} *eqn;
|
||||
typedef struct omega_pb_d
|
||||
{
|
||||
eqn subs;
|
||||
} *omega_pb;
|
||||
|
||||
omega_pb omega_solve_problem (omega_pb);
|
||||
|
||||
omega_pb
|
||||
omega_solve_geq (omega_pb pb, int n)
|
||||
{
|
||||
int i, e;
|
||||
int j = 0;
|
||||
|
||||
for (e = n - 1; e >= 0; e--)
|
||||
if (pb->subs[e].coef[i] != pb->subs[e].coef[j])
|
||||
{
|
||||
pb->subs[e].coef[i] = j;
|
||||
pb->subs[e].coef[j] = i;
|
||||
}
|
||||
|
||||
return omega_solve_problem (pb);
|
||||
}
|
@ -213,11 +213,13 @@ reset_bb_predicate (basic_block bb)
|
||||
init_bb_predicate (bb);
|
||||
}
|
||||
|
||||
/* Create a new temp variable of type TYPE. Add GIMPLE_ASSIGN to assign EXP
|
||||
to the new variable. */
|
||||
/* Returns a new SSA_NAME of type TYPE that is assigned the value of
|
||||
the expression EXPR. Inserts the statement created for this
|
||||
computation before GSI and leaves the iterator GSI at the same
|
||||
statement. */
|
||||
|
||||
static gimple
|
||||
ifc_temp_var (tree type, tree exp)
|
||||
static tree
|
||||
ifc_temp_var (tree type, tree expr, gimple_stmt_iterator *gsi)
|
||||
{
|
||||
const char *name = "_ifc_";
|
||||
tree var, new_name;
|
||||
@ -227,8 +229,8 @@ ifc_temp_var (tree type, tree exp)
|
||||
var = create_tmp_var (type, name);
|
||||
add_referenced_var (var);
|
||||
|
||||
/* Build new statement to assign EXP to new variable. */
|
||||
stmt = gimple_build_assign (var, exp);
|
||||
/* Build new statement to assign EXPR to new variable. */
|
||||
stmt = gimple_build_assign (var, expr);
|
||||
|
||||
/* Get SSA name for the new variable and set make new statement
|
||||
its definition statement. */
|
||||
@ -237,7 +239,8 @@ ifc_temp_var (tree type, tree exp)
|
||||
SSA_NAME_DEF_STMT (new_name) = stmt;
|
||||
update_stmt (stmt);
|
||||
|
||||
return stmt;
|
||||
gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
|
||||
return gimple_assign_lhs (stmt);
|
||||
}
|
||||
|
||||
/* Return true when COND is a true predicate. */
|
||||
@ -388,9 +391,12 @@ bb_with_exit_edge_p (struct loop *loop, basic_block bb)
|
||||
and it belongs to basic block BB.
|
||||
|
||||
PHI is not if-convertible if:
|
||||
- it has more than 2 arguments,
|
||||
- virtual PHI is immediately used in another PHI node,
|
||||
- virtual PHI on BB other than header. */
|
||||
- it has more than 2 arguments.
|
||||
|
||||
When the flag_tree_loop_if_convert_stores is not set, PHI is not
|
||||
if-convertible if:
|
||||
- a virtual PHI is immediately used in another PHI node,
|
||||
- there is a virtual PHI in a BB other than the loop->header. */
|
||||
|
||||
static bool
|
||||
if_convertible_phi_p (struct loop *loop, basic_block bb, gimple phi)
|
||||
@ -408,6 +414,12 @@ if_convertible_phi_p (struct loop *loop, basic_block bb, gimple phi)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flag_tree_loop_if_convert_stores)
|
||||
return true;
|
||||
|
||||
/* When the flag_tree_loop_if_convert_stores is not set, check
|
||||
that there are no memory writes in the branches of the loop to be
|
||||
if-converted. */
|
||||
if (!is_gimple_reg (SSA_NAME_VAR (gimple_phi_result (phi))))
|
||||
{
|
||||
imm_use_iterator imm_iter;
|
||||
@ -416,9 +428,10 @@ if_convertible_phi_p (struct loop *loop, basic_block bb, gimple phi)
|
||||
if (bb != loop->header)
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "Virtual phi not on loop header.\n");
|
||||
fprintf (dump_file, "Virtual phi not on loop->header.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, gimple_phi_result (phi))
|
||||
{
|
||||
if (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI)
|
||||
@ -438,15 +451,13 @@ if_convertible_phi_p (struct loop *loop, basic_block bb, gimple phi)
|
||||
GIMPLE_ASSIGN statement is not if-convertible if,
|
||||
- it is not movable,
|
||||
- it could trap,
|
||||
- LHS is not var decl.
|
||||
|
||||
GIMPLE_ASSIGN is part of block BB, which is inside loop LOOP. */
|
||||
- LHS is not var decl. */
|
||||
|
||||
static bool
|
||||
if_convertible_gimple_assign_stmt_p (struct loop *loop, basic_block bb,
|
||||
gimple stmt)
|
||||
if_convertible_gimple_assign_stmt_p (gimple stmt)
|
||||
{
|
||||
tree lhs = gimple_assign_lhs (stmt);
|
||||
basic_block bb;
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
@ -454,6 +465,9 @@ if_convertible_gimple_assign_stmt_p (struct loop *loop, basic_block bb,
|
||||
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
|
||||
}
|
||||
|
||||
if (!is_gimple_reg_type (TREE_TYPE (lhs)))
|
||||
return false;
|
||||
|
||||
/* Some of these constrains might be too conservative. */
|
||||
if (stmt_ends_bb_p (stmt)
|
||||
|| gimple_has_volatile_ops (stmt)
|
||||
@ -466,6 +480,17 @@ if_convertible_gimple_assign_stmt_p (struct loop *loop, basic_block bb,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flag_tree_loop_if_convert_stores)
|
||||
{
|
||||
if (gimple_could_trap_p (stmt))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, "tree could trap...\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gimple_assign_rhs_could_trap_p (stmt))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
@ -473,9 +498,11 @@ if_convertible_gimple_assign_stmt_p (struct loop *loop, basic_block bb,
|
||||
return false;
|
||||
}
|
||||
|
||||
bb = gimple_bb (stmt);
|
||||
|
||||
if (TREE_CODE (lhs) != SSA_NAME
|
||||
&& bb != loop->header
|
||||
&& !bb_with_exit_edge_p (loop, bb))
|
||||
&& bb != bb->loop_father->header
|
||||
&& !bb_with_exit_edge_p (bb->loop_father, bb))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
@ -492,12 +519,10 @@ if_convertible_gimple_assign_stmt_p (struct loop *loop, basic_block bb,
|
||||
|
||||
A statement is if-convertible if:
|
||||
- it is an if-convertible GIMPLE_ASSGIN,
|
||||
- it is a GIMPLE_LABEL or a GIMPLE_COND.
|
||||
|
||||
STMT is inside BB, which is inside loop LOOP. */
|
||||
- it is a GIMPLE_LABEL or a GIMPLE_COND. */
|
||||
|
||||
static bool
|
||||
if_convertible_stmt_p (struct loop *loop, basic_block bb, gimple stmt)
|
||||
if_convertible_stmt_p (gimple stmt)
|
||||
{
|
||||
switch (gimple_code (stmt))
|
||||
{
|
||||
@ -507,7 +532,7 @@ if_convertible_stmt_p (struct loop *loop, basic_block bb, gimple stmt)
|
||||
return true;
|
||||
|
||||
case GIMPLE_ASSIGN:
|
||||
return if_convertible_gimple_assign_stmt_p (loop, bb, stmt);
|
||||
return if_convertible_gimple_assign_stmt_p (stmt);
|
||||
|
||||
default:
|
||||
/* Don't know what to do with 'em so don't do anything. */
|
||||
@ -878,7 +903,7 @@ if_convertible_loop_p (struct loop *loop)
|
||||
continue;
|
||||
|
||||
for (itr = gsi_start_bb (bb); !gsi_end_p (itr); gsi_next (&itr))
|
||||
if (!if_convertible_stmt_p (loop, bb, gsi_stmt (itr)))
|
||||
if (!if_convertible_stmt_p (gsi_stmt (itr)))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -898,7 +923,7 @@ if_convertible_loop_p (struct loop *loop)
|
||||
static basic_block
|
||||
find_phi_replacement_condition (struct loop *loop,
|
||||
basic_block bb, tree *cond,
|
||||
gimple_stmt_iterator *gsi)
|
||||
gimple_stmt_iterator *gsi)
|
||||
{
|
||||
edge first_edge, second_edge;
|
||||
tree tmp_cond;
|
||||
@ -970,21 +995,16 @@ find_phi_replacement_condition (struct loop *loop,
|
||||
false, NULL_TREE,
|
||||
true, GSI_SAME_STMT);
|
||||
if (!is_gimple_reg (*cond) && !is_gimple_condexpr (*cond))
|
||||
{
|
||||
gimple new_stmt;
|
||||
|
||||
new_stmt = ifc_temp_var (TREE_TYPE (*cond), unshare_expr (*cond));
|
||||
gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
|
||||
*cond = gimple_assign_lhs (new_stmt);
|
||||
}
|
||||
*cond = ifc_temp_var (TREE_TYPE (*cond), unshare_expr (*cond), gsi);
|
||||
|
||||
gcc_assert (*cond);
|
||||
|
||||
return first_edge->src;
|
||||
}
|
||||
|
||||
/* Replace PHI node with conditional modify expr using COND. This
|
||||
routine does not handle PHI nodes with more than two arguments.
|
||||
/* Replace a scalar PHI node with a COND_EXPR using COND as condition.
|
||||
This routine does not handle PHI nodes with more than two
|
||||
arguments.
|
||||
|
||||
For example,
|
||||
S1: A = PHI <x1(1), x2(5)
|
||||
@ -996,18 +1016,22 @@ find_phi_replacement_condition (struct loop *loop,
|
||||
TRUE_BB is selected. */
|
||||
|
||||
static void
|
||||
replace_phi_with_cond_gimple_assign_stmt (gimple phi, tree cond,
|
||||
basic_block true_bb,
|
||||
gimple_stmt_iterator *gsi)
|
||||
predicate_scalar_phi (gimple phi, tree cond,
|
||||
basic_block true_bb,
|
||||
gimple_stmt_iterator *gsi)
|
||||
{
|
||||
gimple new_stmt;
|
||||
basic_block bb;
|
||||
tree rhs;
|
||||
tree arg;
|
||||
tree rhs, res, arg;
|
||||
|
||||
gcc_assert (gimple_code (phi) == GIMPLE_PHI
|
||||
&& gimple_phi_num_args (phi) == 2);
|
||||
|
||||
res = gimple_phi_result (phi);
|
||||
/* Do not handle virtual phi nodes. */
|
||||
if (!is_gimple_reg (SSA_NAME_VAR (res)))
|
||||
return;
|
||||
|
||||
bb = gimple_bb (phi);
|
||||
|
||||
arg = degenerate_phi_result (phi);
|
||||
@ -1029,11 +1053,11 @@ replace_phi_with_cond_gimple_assign_stmt (gimple phi, tree cond,
|
||||
}
|
||||
|
||||
/* Build new RHS using selected condition and arguments. */
|
||||
rhs = build3 (COND_EXPR, TREE_TYPE (PHI_RESULT (phi)),
|
||||
rhs = build3 (COND_EXPR, TREE_TYPE (res),
|
||||
unshare_expr (cond), arg_0, arg_1);
|
||||
}
|
||||
|
||||
new_stmt = gimple_build_assign (PHI_RESULT (phi), rhs);
|
||||
new_stmt = gimple_build_assign (res, rhs);
|
||||
SSA_NAME_DEF_STMT (gimple_phi_result (phi)) = new_stmt;
|
||||
gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
|
||||
update_stmt (new_stmt);
|
||||
@ -1045,11 +1069,11 @@ replace_phi_with_cond_gimple_assign_stmt (gimple phi, tree cond,
|
||||
}
|
||||
}
|
||||
|
||||
/* Replaces in LOOP all the phi nodes other than those in the
|
||||
/* Replaces in LOOP all the scalar phi nodes other than those in the
|
||||
LOOP->header block with conditional modify expressions. */
|
||||
|
||||
static void
|
||||
ifconvert_phi_nodes (struct loop *loop)
|
||||
predicate_all_scalar_phis (struct loop *loop)
|
||||
{
|
||||
basic_block bb;
|
||||
unsigned int orig_loop_num_nodes = loop->num_nodes;
|
||||
@ -1078,7 +1102,7 @@ ifconvert_phi_nodes (struct loop *loop)
|
||||
while (!gsi_end_p (phi_gsi))
|
||||
{
|
||||
phi = gsi_stmt (phi_gsi);
|
||||
replace_phi_with_cond_gimple_assign_stmt (phi, cond, true_bb, &gsi);
|
||||
predicate_scalar_phi (phi, cond, true_bb, &gsi);
|
||||
release_phi_node (phi);
|
||||
gsi_next (&phi_gsi);
|
||||
}
|
||||
@ -1098,7 +1122,7 @@ insert_gimplified_predicates (loop_p loop)
|
||||
for (i = 0; i < loop->num_nodes; i++)
|
||||
{
|
||||
basic_block bb = ifc_bbs[i];
|
||||
gimple_seq stmts = bb_predicate_gimplified_stmts (bb);
|
||||
gimple_seq stmts;
|
||||
|
||||
if (!is_predicated (bb))
|
||||
{
|
||||
@ -1109,15 +1133,30 @@ insert_gimplified_predicates (loop_p loop)
|
||||
continue;
|
||||
}
|
||||
|
||||
stmts = bb_predicate_gimplified_stmts (bb);
|
||||
if (stmts)
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_last_bb (bb);
|
||||
|
||||
if (gsi_end_p (gsi)
|
||||
|| gimple_code (gsi_stmt (gsi)) == GIMPLE_COND)
|
||||
gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
|
||||
if (flag_tree_loop_if_convert_stores)
|
||||
{
|
||||
/* Insert the predicate of the BB just after the label,
|
||||
as the if-conversion of memory writes will use this
|
||||
predicate. */
|
||||
gimple_stmt_iterator gsi = gsi_after_labels (bb);
|
||||
gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
|
||||
}
|
||||
else
|
||||
gsi_insert_seq_after (&gsi, stmts, GSI_SAME_STMT);
|
||||
{
|
||||
/* Insert the predicate of the BB at the end of the BB
|
||||
as this would reduce the register pressure: the only
|
||||
use of this predicate will be in successor BBs. */
|
||||
gimple_stmt_iterator gsi = gsi_last_bb (bb);
|
||||
|
||||
if (gsi_end_p (gsi)
|
||||
|| stmt_ends_bb_p (gsi_stmt (gsi)))
|
||||
gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
|
||||
else
|
||||
gsi_insert_seq_after (&gsi, stmts, GSI_SAME_STMT);
|
||||
}
|
||||
|
||||
/* Once the sequence is code generated, set it to NULL. */
|
||||
set_bb_predicate_gimplified_stmts (bb, NULL);
|
||||
@ -1125,6 +1164,146 @@ insert_gimplified_predicates (loop_p loop)
|
||||
}
|
||||
}
|
||||
|
||||
/* Predicate each write to memory in LOOP.
|
||||
|
||||
This function transforms control flow constructs containing memory
|
||||
writes of the form:
|
||||
|
||||
| for (i = 0; i < N; i++)
|
||||
| if (cond)
|
||||
| A[i] = expr;
|
||||
|
||||
into the following form that does not contain control flow:
|
||||
|
||||
| for (i = 0; i < N; i++)
|
||||
| A[i] = cond ? expr : A[i];
|
||||
|
||||
The original CFG looks like this:
|
||||
|
||||
| bb_0
|
||||
| i = 0
|
||||
| end_bb_0
|
||||
|
|
||||
| bb_1
|
||||
| if (i < N) goto bb_5 else goto bb_2
|
||||
| end_bb_1
|
||||
|
|
||||
| bb_2
|
||||
| cond = some_computation;
|
||||
| if (cond) goto bb_3 else goto bb_4
|
||||
| end_bb_2
|
||||
|
|
||||
| bb_3
|
||||
| A[i] = expr;
|
||||
| goto bb_4
|
||||
| end_bb_3
|
||||
|
|
||||
| bb_4
|
||||
| goto bb_1
|
||||
| end_bb_4
|
||||
|
||||
insert_gimplified_predicates inserts the computation of the COND
|
||||
expression at the beginning of the destination basic block:
|
||||
|
||||
| bb_0
|
||||
| i = 0
|
||||
| end_bb_0
|
||||
|
|
||||
| bb_1
|
||||
| if (i < N) goto bb_5 else goto bb_2
|
||||
| end_bb_1
|
||||
|
|
||||
| bb_2
|
||||
| cond = some_computation;
|
||||
| if (cond) goto bb_3 else goto bb_4
|
||||
| end_bb_2
|
||||
|
|
||||
| bb_3
|
||||
| cond = some_computation;
|
||||
| A[i] = expr;
|
||||
| goto bb_4
|
||||
| end_bb_3
|
||||
|
|
||||
| bb_4
|
||||
| goto bb_1
|
||||
| end_bb_4
|
||||
|
||||
predicate_mem_writes is then predicating the memory write as follows:
|
||||
|
||||
| bb_0
|
||||
| i = 0
|
||||
| end_bb_0
|
||||
|
|
||||
| bb_1
|
||||
| if (i < N) goto bb_5 else goto bb_2
|
||||
| end_bb_1
|
||||
|
|
||||
| bb_2
|
||||
| if (cond) goto bb_3 else goto bb_4
|
||||
| end_bb_2
|
||||
|
|
||||
| bb_3
|
||||
| cond = some_computation;
|
||||
| A[i] = cond ? expr : A[i];
|
||||
| goto bb_4
|
||||
| end_bb_3
|
||||
|
|
||||
| bb_4
|
||||
| goto bb_1
|
||||
| end_bb_4
|
||||
|
||||
and finally combine_blocks removes the basic block boundaries making
|
||||
the loop vectorizable:
|
||||
|
||||
| bb_0
|
||||
| i = 0
|
||||
| if (i < N) goto bb_5 else goto bb_1
|
||||
| end_bb_0
|
||||
|
|
||||
| bb_1
|
||||
| cond = some_computation;
|
||||
| A[i] = cond ? expr : A[i];
|
||||
| if (i < N) goto bb_5 else goto bb_4
|
||||
| end_bb_1
|
||||
|
|
||||
| bb_4
|
||||
| goto bb_1
|
||||
| end_bb_4
|
||||
*/
|
||||
|
||||
static void
|
||||
predicate_mem_writes (loop_p loop)
|
||||
{
|
||||
unsigned int i, orig_loop_num_nodes = loop->num_nodes;
|
||||
|
||||
for (i = 1; i < orig_loop_num_nodes; i++)
|
||||
{
|
||||
gimple_stmt_iterator gsi;
|
||||
basic_block bb = ifc_bbs[i];
|
||||
tree cond = bb_predicate (bb);
|
||||
gimple stmt;
|
||||
|
||||
if (is_true_predicate (cond))
|
||||
continue;
|
||||
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
if ((stmt = gsi_stmt (gsi))
|
||||
&& gimple_assign_single_p (stmt)
|
||||
&& gimple_vdef (stmt))
|
||||
{
|
||||
tree lhs = gimple_assign_lhs (stmt);
|
||||
tree rhs = gimple_assign_rhs1 (stmt);
|
||||
tree type = TREE_TYPE (lhs);
|
||||
|
||||
lhs = ifc_temp_var (type, unshare_expr (lhs), &gsi);
|
||||
rhs = ifc_temp_var (type, unshare_expr (rhs), &gsi);
|
||||
rhs = build3 (COND_EXPR, type, unshare_expr (cond), rhs, lhs);
|
||||
gimple_assign_set_rhs1 (stmt, ifc_temp_var (type, rhs, &gsi));
|
||||
update_stmt (stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove all GIMPLE_CONDs and GIMPLE_LABELs of all the basic blocks
|
||||
other than the exit and latch of the LOOP. Also resets the
|
||||
GIMPLE_DEBUG information. */
|
||||
@ -1181,7 +1360,10 @@ combine_blocks (struct loop *loop)
|
||||
|
||||
remove_conditions_and_labels (loop);
|
||||
insert_gimplified_predicates (loop);
|
||||
ifconvert_phi_nodes (loop);
|
||||
predicate_all_scalar_phis (loop);
|
||||
|
||||
if (flag_tree_loop_if_convert_stores)
|
||||
predicate_mem_writes (loop);
|
||||
|
||||
/* Merge basic blocks: first remove all the edges in the loop,
|
||||
except for those from the exit block. */
|
||||
@ -1283,6 +1465,10 @@ tree_if_conversion (struct loop *loop)
|
||||
blocks into one huge basic block doing the if-conversion
|
||||
on-the-fly. */
|
||||
combine_blocks (loop);
|
||||
|
||||
if (flag_tree_loop_if_convert_stores)
|
||||
mark_sym_for_renaming (gimple_vop (cfun));
|
||||
|
||||
changed = true;
|
||||
|
||||
cleanup:
|
||||
@ -1308,6 +1494,7 @@ main_tree_if_conversion (void)
|
||||
loop_iterator li;
|
||||
struct loop *loop;
|
||||
bool changed = false;
|
||||
unsigned todo = 0;
|
||||
|
||||
if (number_of_loops () <= 1)
|
||||
return 0;
|
||||
@ -1315,7 +1502,13 @@ main_tree_if_conversion (void)
|
||||
FOR_EACH_LOOP (li, loop, 0)
|
||||
changed |= tree_if_conversion (loop);
|
||||
|
||||
return changed ? TODO_cleanup_cfg : 0;
|
||||
if (changed)
|
||||
todo |= TODO_cleanup_cfg;
|
||||
|
||||
if (changed && flag_tree_loop_if_convert_stores)
|
||||
todo |= TODO_update_ssa_only_virtuals;
|
||||
|
||||
return todo;
|
||||
}
|
||||
|
||||
/* Returns true when the if-conversion pass is enabled. */
|
||||
@ -1324,7 +1517,8 @@ static bool
|
||||
gate_tree_if_conversion (void)
|
||||
{
|
||||
return ((flag_tree_vectorize && flag_tree_loop_if_convert != 0)
|
||||
|| flag_tree_loop_if_convert == 1);
|
||||
|| flag_tree_loop_if_convert == 1
|
||||
|| flag_tree_loop_if_convert_stores == 1);
|
||||
}
|
||||
|
||||
struct gimple_opt_pass pass_if_conversion =
|
||||
|
Loading…
Reference in New Issue
Block a user