Commit 7b14477e by Sebastian Pop Committed by Sebastian Pop

Fix PR44483: incrementally gimplify BB predicates to avoid redundant computations.

2010-06-11  Sebastian Pop  <sebastian.pop@amd.com>

	PR middle-end/44483
	* tree-if-conv.c (bb_predicate_s): New struct.
	(bb_predicate_p): New.
	(bb_has_predicate): New.
	(bb_predicate): New.
	(set_bb_predicate): New.
	(bb_predicate_gimplified_stmts): New.
	(set_bb_predicate_gimplified_stmts): New.
	(add_bb_predicate_gimplified_stmts): New.
	(init_bb_predicate): New.
	(free_bb_predicate): New.
	(is_predicated): Use bb_predicate.
	(add_to_predicate_list): Use bb_predicate and set_bb_predicate.
	(predicate_bbs): Same.  Gimplify the condition of the basic blocks
	before processing their successors.
	(clean_predicate_lists): Removed.
	(find_phi_replacement_condition): Use bb_predicate.
	(process_phi_nodes): Renamed ifconvert_phi_nodes.  Avoid useless
	computations.
	(insert_gimplified_predicates): New.
	(combine_blocks): Call insert_gimplified_predicates.
	(tree_if_conversion): Call free_bb_predicate instead of
	clean_predicate_lists.

	* gcc.dg/tree-ssa/pr44483.c: New.

From-SVN: r160625
parent 1021b0e5
2010-06-11 Sebastian Pop <sebastian.pop@amd.com>
PR middle-end/44483
* tree-if-conv.c (bb_predicate_s): New struct.
(bb_predicate_p): New.
(bb_has_predicate): New.
(bb_predicate): New.
(set_bb_predicate): New.
(bb_predicate_gimplified_stmts): New.
(set_bb_predicate_gimplified_stmts): New.
(add_bb_predicate_gimplified_stmts): New.
(init_bb_predicate): New.
(free_bb_predicate): New.
(is_predicated): Use bb_predicate.
(add_to_predicate_list): Use bb_predicate and set_bb_predicate.
(predicate_bbs): Same. Gimplify the condition of the basic blocks
before processing their successors.
(clean_predicate_lists): Removed.
(find_phi_replacement_condition): Use bb_predicate.
(process_phi_nodes): Renamed ifconvert_phi_nodes. Avoid useless
computations.
(insert_gimplified_predicates): New.
(combine_blocks): Call insert_gimplified_predicates.
(tree_if_conversion): Call free_bb_predicate instead of
clean_predicate_lists.
2010-10-11 Paul Brook <paul@codesourcery.com> 2010-10-11 Paul Brook <paul@codesourcery.com>
* doc/invoke.texi: Document ARM -mcpu=cortex-m4. * doc/invoke.texi: Document ARM -mcpu=cortex-m4.
......
2010-06-11 Sebastian Pop <sebastian.pop@amd.com>
PR middle-end/44483
* gcc.dg/tree-ssa/pr44483.c: New.
2010-06-11 Paul Brook <paul@codesourcery.com> 2010-06-11 Paul Brook <paul@codesourcery.com>
* g++.dg/other/arm-neon-1.C: New test. * g++.dg/other/arm-neon-1.C: New test.
......
/* { dg-do compile } */
/* { dg-options "-c -O3" { target *-*-* } } */
int ffesum (void) {
int ch[4], ii, jj, kk;
char asc[32];
for (ii = 0; ii < 4; ii++)
{
for (jj = 0; jj < 4; jj++)
ch[jj] = ii;
for (kk = 0; kk < 13; kk++)
for (jj = 0; jj < 4; jj += 2)
if ((unsigned char) ch[jj] || (unsigned char) ch[jj + 1])
ch[jj]++;
for (jj = 0; jj < 4; jj++)
asc[4 * jj + ii] = ch[jj];
}
return asc[0];
}
...@@ -102,6 +102,106 @@ along with GCC; see the file COPYING3. If not see ...@@ -102,6 +102,106 @@ along with GCC; see the file COPYING3. If not see
/* List of basic blocks in if-conversion-suitable order. */ /* List of basic blocks in if-conversion-suitable order. */
static basic_block *ifc_bbs; static basic_block *ifc_bbs;
/* Structure used to predicate basic blocks. This is attached to the
->aux field of the BBs in the loop to be if-converted. */
typedef struct bb_predicate_s {
/* The condition under which this basic block is executed. */
tree predicate;
/* PREDICATE is gimplified, and the sequence of statements is
recorded here, in order to avoid the duplication of computations
that occur in previous conditions. See PR44483. */
gimple_seq predicate_gimplified_stmts;
} *bb_predicate_p;
/* Returns true when the basic block BB has a predicate. */
static inline bool
bb_has_predicate (basic_block bb)
{
return bb->aux != NULL;
}
/* Returns the gimplified predicate for basic block BB. */
static inline tree
bb_predicate (basic_block bb)
{
return ((bb_predicate_p) bb->aux)->predicate;
}
/* Sets the gimplified predicate COND for basic block BB. */
static inline void
set_bb_predicate (basic_block bb, tree cond)
{
((bb_predicate_p) bb->aux)->predicate = cond;
}
/* Returns the sequence of statements of the gimplification of the
predicate for basic block BB. */
static inline gimple_seq
bb_predicate_gimplified_stmts (basic_block bb)
{
return ((bb_predicate_p) bb->aux)->predicate_gimplified_stmts;
}
/* Sets the sequence of statements STMTS of the gimplification of the
predicate for basic block BB. */
static inline void
set_bb_predicate_gimplified_stmts (basic_block bb, gimple_seq stmts)
{
((bb_predicate_p) bb->aux)->predicate_gimplified_stmts = stmts;
}
/* Adds the sequence of statements STMTS to the sequence of statements
of the predicate for basic block BB. */
static inline void
add_bb_predicate_gimplified_stmts (basic_block bb, gimple_seq stmts)
{
gimple_seq_add_seq
(&(((bb_predicate_p) bb->aux)->predicate_gimplified_stmts), stmts);
}
/* Initializes to TRUE the predicate of basic block BB. */
static inline void
init_bb_predicate (basic_block bb)
{
bb->aux = XNEW (struct bb_predicate_s);
set_bb_predicate_gimplified_stmts (bb, NULL);
set_bb_predicate (bb, NULL_TREE);
}
/* Free the predicate of basic block BB. */
static inline void
free_bb_predicate (basic_block bb)
{
gimple_seq stmts;
if (!bb_has_predicate (bb))
return;
/* Release the SSA_NAMEs created for the gimplification of the
predicate. */
stmts = bb_predicate_gimplified_stmts (bb);
if (stmts)
{
gimple_stmt_iterator i;
for (i = gsi_start (stmts); !gsi_end_p (i); gsi_next (&i))
free_stmt_operands (gsi_stmt (i));
}
free (bb->aux);
bb->aux = NULL;
}
/* Create a new temp variable of type TYPE. Add GIMPLE_ASSIGN to assign EXP /* Create a new temp variable of type TYPE. Add GIMPLE_ASSIGN to assign EXP
to the new variable. */ to the new variable. */
...@@ -145,7 +245,7 @@ is_true_predicate (tree cond) ...@@ -145,7 +245,7 @@ is_true_predicate (tree cond)
static inline bool static inline bool
is_predicated (basic_block bb) is_predicated (basic_block bb)
{ {
return !is_true_predicate ((tree) bb->aux); return !is_true_predicate (bb_predicate (bb));
} }
/* Add condition NEW_COND to the predicate list of basic block BB. */ /* Add condition NEW_COND to the predicate list of basic block BB. */
...@@ -153,12 +253,12 @@ is_predicated (basic_block bb) ...@@ -153,12 +253,12 @@ is_predicated (basic_block bb)
static inline void static inline void
add_to_predicate_list (basic_block bb, tree new_cond) add_to_predicate_list (basic_block bb, tree new_cond)
{ {
tree cond = (tree) bb->aux; tree cond = bb_predicate (bb);
bb->aux = is_true_predicate (cond) ? new_cond : set_bb_predicate (bb, is_true_predicate (cond) ? new_cond :
fold_build2_loc (EXPR_LOCATION (cond), fold_build2_loc (EXPR_LOCATION (cond),
TRUTH_OR_EXPR, boolean_type_node, TRUTH_OR_EXPR, boolean_type_node,
cond, new_cond); cond, new_cond));
} }
/* Add the condition COND to the previous condition PREV_COND, and add /* Add the condition COND to the previous condition PREV_COND, and add
...@@ -471,7 +571,7 @@ get_loop_body_in_if_conv_order (const struct loop *loop) ...@@ -471,7 +571,7 @@ get_loop_body_in_if_conv_order (const struct loop *loop)
/* Returns true when the analysis of the predicates for all the basic /* Returns true when the analysis of the predicates for all the basic
blocks in LOOP succeeded. blocks in LOOP succeeded.
predicate_bbs first clears the ->aux fields of the basic blocks. predicate_bbs first allocates the predicates of the basic blocks.
These fields are then initialized with the tree expressions These fields are then initialized with the tree expressions
representing the predicates under which a basic block is executed representing the predicates under which a basic block is executed
in the LOOP. As the loop->header is executed at each iteration, it in the LOOP. As the loop->header is executed at each iteration, it
...@@ -492,14 +592,33 @@ predicate_bbs (loop_p loop) ...@@ -492,14 +592,33 @@ predicate_bbs (loop_p loop)
unsigned int i; unsigned int i;
for (i = 0; i < loop->num_nodes; i++) for (i = 0; i < loop->num_nodes; i++)
ifc_bbs[i]->aux = NULL; init_bb_predicate (ifc_bbs[i]);
for (i = 0; i < loop->num_nodes; i++) for (i = 0; i < loop->num_nodes; i++)
{ {
basic_block bb = ifc_bbs [i]; basic_block bb = ifc_bbs[i];
tree cond = (tree) bb->aux; tree cond;
gimple_stmt_iterator itr; gimple_stmt_iterator itr;
/* The loop latch is always executed and has no extra conditions
to be processed: skip it. */
if (bb == loop->latch)
{
set_bb_predicate (loop->latch, boolean_true_node);
set_bb_predicate_gimplified_stmts (loop->latch, NULL);
continue;
}
cond = bb_predicate (bb);
if (cond
&& bb != loop->header)
{
gimple_seq stmts;
cond = force_gimple_operand (cond, &stmts, true, NULL_TREE);
add_bb_predicate_gimplified_stmts (bb, stmts);
}
for (itr = gsi_start_bb (bb); !gsi_end_p (itr); gsi_next (&itr)) for (itr = gsi_start_bb (bb); !gsi_end_p (itr); gsi_next (&itr))
{ {
gimple stmt = gsi_stmt (itr); gimple stmt = gsi_stmt (itr);
...@@ -522,11 +641,10 @@ predicate_bbs (loop_p loop) ...@@ -522,11 +641,10 @@ predicate_bbs (loop_p loop)
gimple_cond_lhs (stmt), gimple_cond_lhs (stmt),
gimple_cond_rhs (stmt)); gimple_cond_rhs (stmt));
/* Add new condition into destination's predicate list. */
extract_true_false_edges_from_block (gimple_bb (stmt), extract_true_false_edges_from_block (gimple_bb (stmt),
&true_edge, &false_edge); &true_edge, &false_edge);
/* Add new condition into destination's predicate list. */
/* If C is true, then TRUE_EDGE is taken. */ /* If C is true, then TRUE_EDGE is taken. */
add_to_dst_predicate_list (loop, true_edge, cond, c); add_to_dst_predicate_list (loop, true_edge, cond, c);
...@@ -561,7 +679,9 @@ predicate_bbs (loop_p loop) ...@@ -561,7 +679,9 @@ predicate_bbs (loop_p loop)
} }
/* The loop header is always executed. */ /* The loop header is always executed. */
loop->header->aux = boolean_true_node; set_bb_predicate (loop->header, boolean_true_node);
gcc_assert (bb_predicate_gimplified_stmts (loop->header) == NULL
&& bb_predicate_gimplified_stmts (loop->latch) == NULL);
return true; return true;
} }
...@@ -679,27 +799,12 @@ if_convertible_loop_p (struct loop *loop) ...@@ -679,27 +799,12 @@ if_convertible_loop_p (struct loop *loop)
return true; return true;
} }
/* During if-conversion, the bb->aux field is used to hold a predicate /* Basic block BB has two predecessors. Using predecessor's bb
list. This function cleans for all the basic blocks in the given predicate, set an appropriate condition COND for the PHI node
LOOP their predicate list. */ replacement. Return the true block whose phi arguments are
selected when cond is true. LOOP is the loop containing the
static void if-converted region, GSI is the place to insert the code for the
clean_predicate_lists (struct loop *loop) if-conversion. */
{
unsigned int i;
basic_block *bbs = get_loop_body (loop);
for (i = 0; i < loop->num_nodes; i++)
bbs[i]->aux = NULL;
free (bbs);
}
/* Basic block BB has two predecessors. Using predecessor's bb->aux
field, set appropriate condition COND for the PHI node replacement.
Return true block whose phi arguments are selected when cond is
true. LOOP is the loop containing the if-converted region, GSI is
the place to insert the code for the if-conversion. */
static basic_block static basic_block
find_phi_replacement_condition (struct loop *loop, find_phi_replacement_condition (struct loop *loop,
...@@ -738,7 +843,7 @@ find_phi_replacement_condition (struct loop *loop, ...@@ -738,7 +843,7 @@ find_phi_replacement_condition (struct loop *loop,
See PR23115. */ See PR23115. */
/* Select condition that is not TRUTH_NOT_EXPR. */ /* Select condition that is not TRUTH_NOT_EXPR. */
tmp_cond = (tree) (first_edge->src)->aux; tmp_cond = bb_predicate (first_edge->src);
gcc_assert (tmp_cond); gcc_assert (tmp_cond);
if (TREE_CODE (tmp_cond) == TRUTH_NOT_EXPR) if (TREE_CODE (tmp_cond) == TRUTH_NOT_EXPR)
...@@ -756,7 +861,7 @@ find_phi_replacement_condition (struct loop *loop, ...@@ -756,7 +861,7 @@ find_phi_replacement_condition (struct loop *loop,
|| dominated_by_p (CDI_DOMINATORS, || dominated_by_p (CDI_DOMINATORS,
second_edge->src, first_edge->src)) second_edge->src, first_edge->src))
{ {
*cond = (tree) (second_edge->src)->aux; *cond = bb_predicate (second_edge->src);
if (TREE_CODE (*cond) == TRUTH_NOT_EXPR) if (TREE_CODE (*cond) == TRUTH_NOT_EXPR)
*cond = invert_truthvalue (*cond); *cond = invert_truthvalue (*cond);
...@@ -765,7 +870,7 @@ find_phi_replacement_condition (struct loop *loop, ...@@ -765,7 +870,7 @@ find_phi_replacement_condition (struct loop *loop,
first_edge = second_edge; first_edge = second_edge;
} }
else else
*cond = (tree) (first_edge->src)->aux; *cond = bb_predicate (first_edge->src);
/* Gimplify the condition: the vectorizer prefers to have gimple /* Gimplify the condition: the vectorizer prefers to have gimple
values as conditions. Various targets use different means to values as conditions. Various targets use different means to
...@@ -851,11 +956,11 @@ replace_phi_with_cond_gimple_assign_stmt (gimple phi, tree cond, ...@@ -851,11 +956,11 @@ replace_phi_with_cond_gimple_assign_stmt (gimple phi, tree cond,
} }
} }
/* Process phi nodes for the given LOOP. Replace phi nodes with /* Replaces in LOOP all the phi nodes other than those in the
conditional modify expressions. */ LOOP->header block with conditional modify expressions. */
static void static void
process_phi_nodes (struct loop *loop) ifconvert_phi_nodes (struct loop *loop)
{ {
basic_block bb; basic_block bb;
unsigned int orig_loop_num_nodes = loop->num_nodes; unsigned int orig_loop_num_nodes = loop->num_nodes;
...@@ -873,12 +978,13 @@ process_phi_nodes (struct loop *loop) ...@@ -873,12 +978,13 @@ process_phi_nodes (struct loop *loop)
continue; continue;
phi_gsi = gsi_start_phis (bb); phi_gsi = gsi_start_phis (bb);
gsi = gsi_after_labels (bb); if (gsi_end_p (phi_gsi))
continue;
/* BB has two predecessors. Using predecessor's aux field, set /* BB has two predecessors. Using predecessor's aux field, set
appropriate condition for the PHI node replacement. */ appropriate condition for the PHI node replacement. */
if (!gsi_end_p (phi_gsi)) gsi = gsi_after_labels (bb);
true_bb = find_phi_replacement_condition (loop, bb, &cond, &gsi); true_bb = find_phi_replacement_condition (loop, bb, &cond, &gsi);
while (!gsi_end_p (phi_gsi)) while (!gsi_end_p (phi_gsi))
{ {
...@@ -887,10 +993,40 @@ process_phi_nodes (struct loop *loop) ...@@ -887,10 +993,40 @@ process_phi_nodes (struct loop *loop)
release_phi_node (phi); release_phi_node (phi);
gsi_next (&phi_gsi); gsi_next (&phi_gsi);
} }
set_phi_nodes (bb, NULL); set_phi_nodes (bb, NULL);
} }
} }
/* Insert in each basic block of LOOP the statements produced by the
gimplification of the predicates. */
static void
insert_gimplified_predicates (loop_p loop)
{
unsigned int i;
for (i = 0; i < loop->num_nodes; i++)
{
basic_block bb = ifc_bbs[i];
gimple_seq 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);
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);
}
}
}
/* Remove all GIMPLE_CONDs and GIMPLE_LABELs of all the basic blocks /* Remove all GIMPLE_CONDs and GIMPLE_LABELs of all the basic blocks
other than the exit and latch of the LOOP. Also resets the other than the exit and latch of the LOOP. Also resets the
GIMPLE_DEBUG information. */ GIMPLE_DEBUG information. */
...@@ -903,7 +1039,7 @@ remove_conditions_and_labels (loop_p loop) ...@@ -903,7 +1039,7 @@ remove_conditions_and_labels (loop_p loop)
for (i = 0; i < loop->num_nodes; i++) for (i = 0; i < loop->num_nodes; i++)
{ {
basic_block bb = ifc_bbs [i]; basic_block bb = ifc_bbs[i];
if (bb_with_exit_edge_p (loop, bb) if (bb_with_exit_edge_p (loop, bb)
|| bb == loop->latch) || bb == loop->latch)
...@@ -946,9 +1082,8 @@ combine_blocks (struct loop *loop) ...@@ -946,9 +1082,8 @@ combine_blocks (struct loop *loop)
edge_iterator ei; edge_iterator ei;
remove_conditions_and_labels (loop); remove_conditions_and_labels (loop);
insert_gimplified_predicates (loop);
/* Process phi nodes to prepare blocks for merge. */ ifconvert_phi_nodes (loop);
process_phi_nodes (loop);
/* Merge basic blocks: first remove all the edges in the loop, /* Merge basic blocks: first remove all the edges in the loop,
except for those from the exit block. */ except for those from the exit block. */
...@@ -1052,9 +1187,13 @@ tree_if_conversion (struct loop *loop) ...@@ -1052,9 +1187,13 @@ tree_if_conversion (struct loop *loop)
combine_blocks (loop); combine_blocks (loop);
cleanup: cleanup:
clean_predicate_lists (loop);
if (ifc_bbs) if (ifc_bbs)
{ {
unsigned int i;
for (i = 0; i < loop->num_nodes; i++)
free_bb_predicate (ifc_bbs[i]);
free (ifc_bbs); free (ifc_bbs);
ifc_bbs = NULL; ifc_bbs = NULL;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment