===================================================================
@@ -59,7 +59,7 @@ along with GCC; see the file COPYING3.
/* Pointer set of potentially undefined ssa names, i.e.,
ssa names that are defined by phi with operands that
are not defined or potentially undefined. */
-static struct pointer_set_t *possibly_undefined_names = 0;
+static pointer_set_t *possibly_undefined_names = 0;
/* Bit mask handling macros. */
#define MASK_SET_BIT(mask, pos) mask |= (1 << pos)
@@ -233,7 +233,7 @@ warn_uninitialized_vars (bool warn_possi
continue;
if (always_executed)
- warn_uninit (OPT_Wuninitialized, use,
+ warn_uninit (OPT_Wuninitialized, use,
gimple_assign_rhs1 (stmt), base,
"%qE is used uninitialized in this function",
stmt);
@@ -249,9 +249,9 @@ warn_uninitialized_vars (bool warn_possi
return 0;
}
-/* Checks if the operand OPND of PHI is defined by
- another phi with one operand defined by this PHI,
- but the rest operands are all defined. If yes,
+/* Checks if the operand OPND of PHI is defined by
+ another phi with one operand defined by this PHI,
+ but the rest operands are all defined. If yes,
returns true to skip this this operand as being
redundant. Can be enhanced to be more general. */
@@ -411,7 +411,7 @@ compute_control_dep_chain (basic_block b
if (EDGE_COUNT (bb->succs) < 2)
return false;
- /* Could use a set instead. */
+ /* Could use a set instead. */
cur_chain_len = cur_cd_chain->length ();
if (cur_chain_len > MAX_CHAIN_LEN)
return false;
@@ -419,7 +419,7 @@ compute_control_dep_chain (basic_block b
for (i = 0; i < cur_chain_len; i++)
{
edge e = (*cur_cd_chain)[i];
- /* cycle detected. */
+ /* Cycle detected. */
if (e->src == bb)
return false;
}
@@ -444,7 +444,7 @@ compute_control_dep_chain (basic_block b
(*num_chains)++;
}
found_cd_chain = true;
- /* check path from next edge. */
+ /* Check path from next edge. */
break;
}
@@ -470,30 +470,41 @@ compute_control_dep_chain (basic_block b
return found_cd_chain;
}
-typedef struct use_pred_info
+/* The type to represent a simple predicate */
+
+typedef struct use_def_pred_info
{
- gimple cond;
+ tree pred_lhs;
+ tree pred_rhs;
+ enum tree_code cond_code;
bool invert;
-} *use_pred_info_t;
+} pred_info;
+
+/* The type to represent a sequence of predicates grouped
+ with .AND. operation. */
+typedef vec<pred_info, va_heap, vl_ptr> pred_chain;
+/* The type to represent a sequence of pred_chains grouped
+ with .OR. operation. */
+
+typedef vec<pred_chain, va_heap, vl_ptr> pred_chain_union;
/* Converts the chains of control dependence edges into a set of
predicates. A control dependence chain is represented by a vector
edges. DEP_CHAINS points to an array of dependence chains.
NUM_CHAINS is the size of the chain array. One edge in a dependence
- chain is mapped to predicate expression represented by use_pred_info_t
+ chain is mapped to predicate expression represented by pred_info
type. One dependence chain is converted to a composite predicate that
- is the result of AND operation of use_pred_info_t mapped to each edge.
- A composite predicate is presented by a vector of use_pred_info_t. On
+ is the result of AND operation of pred_info mapped to each edge.
+ A composite predicate is presented by a vector of pred_info. On
return, *PREDS points to the resulting array of composite predicates.
*NUM_PREDS is the number of composite predictes. */
static bool
convert_control_dep_chain_into_preds (vec<edge> *dep_chains,
size_t num_chains,
- vec<use_pred_info_t> **preds,
- size_t *num_preds)
+ pred_chain_union *preds)
{
bool has_valid_pred = false;
size_t i, j;
@@ -502,21 +513,20 @@ convert_control_dep_chain_into_preds (ve
/* Now convert the control dep chain into a set
of predicates. */
- typedef vec<use_pred_info_t> vec_use_pred_info_t_heap;
- *preds = XCNEWVEC (vec_use_pred_info_t_heap, num_chains);
- *num_preds = num_chains;
+ preds->reserve (num_chains);
for (i = 0; i < num_chains; i++)
{
vec<edge> one_cd_chain = dep_chains[i];
has_valid_pred = false;
+ pred_chain t_chain = vNULL;
for (j = 0; j < one_cd_chain.length (); j++)
{
gimple cond_stmt;
gimple_stmt_iterator gsi;
basic_block guard_bb;
- use_pred_info_t one_pred;
+ pred_info one_pred;
edge e;
e = one_cd_chain[j];
@@ -528,7 +538,7 @@ convert_control_dep_chain_into_preds (ve
break;
}
cond_stmt = gsi_stmt (gsi);
- if (gimple_code (cond_stmt) == GIMPLE_CALL
+ if (is_gimple_call (cond_stmt)
&& EDGE_COUNT (e->src->succs) >= 2)
{
/* Ignore EH edge. Can add assertion
@@ -558,15 +568,18 @@ convert_control_dep_chain_into_preds (ve
has_valid_pred = false;
break;
}
- one_pred = XNEW (struct use_pred_info);
- one_pred->cond = cond_stmt;
- one_pred->invert = !!(e->flags & EDGE_FALSE_VALUE);
- (*preds)[i].safe_push (one_pred);
+ one_pred.pred_lhs = gimple_cond_lhs (cond_stmt);
+ one_pred.pred_rhs = gimple_cond_rhs (cond_stmt);
+ one_pred.cond_code = gimple_cond_code (cond_stmt);
+ one_pred.invert = !!(e->flags & EDGE_FALSE_VALUE);
+ t_chain.safe_push (one_pred);
has_valid_pred = true;
}
if (!has_valid_pred)
break;
+ else
+ preds->safe_push (t_chain);
}
return has_valid_pred;
}
@@ -577,8 +590,7 @@ convert_control_dep_chain_into_preds (ve
the phi whose result is used in USE_BB. */
static bool
-find_predicates (vec<use_pred_info_t> **preds,
- size_t *num_preds,
+find_predicates (pred_chain_union *preds,
basic_block phi_bb,
basic_block use_bb)
{
@@ -610,8 +622,7 @@ find_predicates (vec<use_pred_info_t> **
has_valid_pred
= convert_control_dep_chain_into_preds (dep_chains,
num_chains,
- preds,
- num_preds);
+ preds);
/* Free individual chain */
cur_chain.release ();
for (i = 0; i < num_chains; i++)
@@ -629,7 +640,7 @@ find_predicates (vec<use_pred_info_t> **
static void
collect_phi_def_edges (gimple phi, basic_block cd_root,
vec<edge> *edges,
- struct pointer_set_t *visited_phis)
+ pointer_set_t *visited_phis)
{
size_t i, n;
edge opnd_edge;
@@ -680,8 +691,7 @@ collect_phi_def_edges (gimple phi, basic
composite predicates pointed to by PREDS. */
static bool
-find_def_preds (vec<use_pred_info_t> **preds,
- size_t *num_preds, gimple phi)
+find_def_preds (pred_chain_union *preds, gimple phi)
{
size_t num_chains = 0, i, n;
vec<edge> *dep_chains = 0;
@@ -689,7 +699,7 @@ find_def_preds (vec<use_pred_info_t> **p
vec<edge> def_edges = vNULL;
bool has_valid_pred = false;
basic_block phi_bb, cd_root = 0;
- struct pointer_set_t *visited_phis;
+ pointer_set_t *visited_phis;
typedef vec<edge> vec_edge_heap;
dep_chains = XCNEWVEC (vec_edge_heap, MAX_NUM_CHAINS);
@@ -739,8 +749,7 @@ find_def_preds (vec<use_pred_info_t> **p
has_valid_pred
= convert_control_dep_chain_into_preds (dep_chains,
num_chains,
- preds,
- num_preds);
+ preds);
for (i = 0; i < num_chains; i++)
dep_chains[i].release ();
free (dep_chains);
@@ -750,16 +759,16 @@ find_def_preds (vec<use_pred_info_t> **p
/* Dumps the predicates (PREDS) for USESTMT. */
static void
-dump_predicates (gimple usestmt, size_t num_preds,
- vec<use_pred_info_t> *preds,
+dump_predicates (gimple usestmt, pred_chain_union preds,
const char* msg)
{
size_t i, j;
- vec<use_pred_info_t> one_pred_chain;
+ pred_chain one_pred_chain = vNULL;
fprintf (dump_file, msg);
print_gimple_stmt (dump_file, usestmt, 0, 0);
- fprintf (dump_file, "is guarded by :\n");
- /* do some dumping here: */
+ fprintf (dump_file, "is guarded by :\n\n");
+ size_t num_preds = preds.length ();
+ /* Do some dumping here: */
for (i = 0; i < num_preds; i++)
{
size_t np;
@@ -769,37 +778,39 @@ dump_predicates (gimple usestmt, size_t
for (j = 0; j < np; j++)
{
- use_pred_info_t one_pred
- = one_pred_chain[j];
- if (one_pred->invert)
+ pred_info one_pred = one_pred_chain[j];
+ if (one_pred.invert)
fprintf (dump_file, " (.NOT.) ");
- print_gimple_stmt (dump_file, one_pred->cond, 0, 0);
+ print_generic_expr (dump_file, one_pred.pred_lhs, 0);
+ fprintf (dump_file, " %s ", op_symbol_code (one_pred.cond_code));
+ print_generic_expr (dump_file, one_pred.pred_rhs, 0);
if (j < np - 1)
- fprintf (dump_file, "(.AND.)\n");
+ fprintf (dump_file, " (.AND.) ");
+ else
+ fprintf (dump_file, "\n");
}
if (i < num_preds - 1)
fprintf (dump_file, "(.OR.)\n");
+ else
+ fprintf (dump_file, "\n\n");
}
}
/* Destroys the predicate set *PREDS. */
static void
-destroy_predicate_vecs (size_t n,
- vec<use_pred_info_t> * preds)
+destroy_predicate_vecs (pred_chain_union preds)
{
- size_t i, j;
+ size_t i;
+
+ size_t n = preds.length ();
for (i = 0; i < n; i++)
- {
- for (j = 0; j < preds[i].length (); j++)
- free (preds[i][j]);
- preds[i].release ();
- }
- free (preds);
+ preds[i].release ();
+ preds.release ();
}
-/* Computes the 'normalized' conditional code with operand
+/* Computes the 'normalized' conditional code with operand
swapping and condition inversion. */
static enum tree_code
@@ -890,33 +901,33 @@ is_value_included_in (tree val, tree bou
NUM_PRED_CHAIN is the size of array PREDS. */
static bool
-find_matching_predicate_in_rest_chains (use_pred_info_t pred,
- vec<use_pred_info_t> *preds,
+find_matching_predicate_in_rest_chains (pred_info pred,
+ pred_chain_union preds,
size_t num_pred_chains)
{
size_t i, j, n;
- /* trival case */
+ /* Trival case. */
if (num_pred_chains == 1)
return true;
for (i = 1; i < num_pred_chains; i++)
{
bool found = false;
- vec<use_pred_info_t> one_chain = preds[i];
+ pred_chain one_chain = preds[i];
n = one_chain.length ();
for (j = 0; j < n; j++)
{
- use_pred_info_t pred2
- = one_chain[j];
- /* can relax the condition comparison to not
+ pred_info pred2 = one_chain[j];
+ /* Can relax the condition comparison to not
use address comparison. However, the most common
case is that multiple control dependent paths share
a common path prefix, so address comparison should
be ok. */
- if (pred2->cond == pred->cond
- && pred2->invert == pred->invert)
+ if (operand_equal_p (pred2.pred_lhs, pred.pred_lhs, 0)
+ && operand_equal_p (pred2.pred_rhs, pred.pred_rhs, 0)
+ && pred2.invert == pred.invert)
{
found = true;
break;
@@ -934,7 +945,7 @@ is_use_properly_guarded (gimple use_stmt
basic_block use_bb,
gimple phi,
unsigned uninit_opnds,
- struct pointer_set_t *visited_phis);
+ pointer_set_t *visited_phis);
/* Returns true if all uninitialized opnds are pruned. Returns false
otherwise. PHI is the phi node with uninitialized operands,
@@ -971,12 +982,13 @@ is_use_properly_guarded (gimple use_stmt
*/
static bool
-prune_uninit_phi_opnds_in_unrealizable_paths (
- gimple phi, unsigned uninit_opnds,
- gimple flag_def, tree boundary_cst,
- enum tree_code cmp_code,
- struct pointer_set_t *visited_phis,
- bitmap *visited_flag_phis)
+prune_uninit_phi_opnds_in_unrealizable_paths (gimple phi,
+ unsigned uninit_opnds,
+ gimple flag_def,
+ tree boundary_cst,
+ enum tree_code cmp_code,
+ pointer_set_t *visited_phis,
+ bitmap *visited_flag_phis)
{
unsigned i;
@@ -1023,10 +1035,9 @@ prune_uninit_phi_opnds_in_unrealizable_p
/* Now recursively prune the uninitialized phi args. */
uninit_opnds_arg_phi = compute_uninit_opnds_pos (phi_arg_def);
- if (!prune_uninit_phi_opnds_in_unrealizable_paths (
- phi_arg_def, uninit_opnds_arg_phi,
- flag_arg_def, boundary_cst, cmp_code,
- visited_phis, visited_flag_phis))
+ if (!prune_uninit_phi_opnds_in_unrealizable_paths
+ (phi_arg_def, uninit_opnds_arg_phi, flag_arg_def,
+ boundary_cst, cmp_code, visited_phis, visited_flag_phis))
return false;
bitmap_clear_bit (*visited_flag_phis,
@@ -1144,11 +1155,9 @@ prune_uninit_phi_opnds_in_unrealizable_p
static bool
-use_pred_not_overlap_with_undef_path_pred (
- size_t num_preds,
- vec<use_pred_info_t> *preds,
- gimple phi, unsigned uninit_opnds,
- struct pointer_set_t *visited_phis)
+use_pred_not_overlap_with_undef_path_pred (pred_chain_union preds,
+ gimple phi, unsigned uninit_opnds,
+ pointer_set_t *visited_phis)
{
unsigned int i, n;
gimple flag_def = 0;
@@ -1156,9 +1165,10 @@ use_pred_not_overlap_with_undef_path_pre
enum tree_code cmp_code;
bool swap_cond = false;
bool invert = false;
- vec<use_pred_info_t> the_pred_chain;
+ pred_chain the_pred_chain = vNULL;
bitmap visited_flag_phis = NULL;
bool all_pruned = false;
+ size_t num_preds = preds.length ();
gcc_assert (num_preds > 0);
/* Find within the common prefix of multiple predicate chains
@@ -1168,17 +1178,14 @@ use_pred_not_overlap_with_undef_path_pre
n = the_pred_chain.length ();
for (i = 0; i < n; i++)
{
- gimple cond;
tree cond_lhs, cond_rhs, flag = 0;
- use_pred_info_t the_pred
- = the_pred_chain[i];
+ pred_info the_pred = the_pred_chain[i];
- cond = the_pred->cond;
- invert = the_pred->invert;
- cond_lhs = gimple_cond_lhs (cond);
- cond_rhs = gimple_cond_rhs (cond);
- cmp_code = gimple_cond_code (cond);
+ invert = the_pred.invert;
+ cond_lhs = the_pred.pred_lhs;
+ cond_rhs = the_pred.pred_rhs;
+ cmp_code = the_pred.cond_code;
if (cond_lhs != NULL_TREE && TREE_CODE (cond_lhs) == SSA_NAME
&& cond_rhs != NULL_TREE && is_gimple_constant (cond_rhs))
@@ -1204,8 +1211,8 @@ use_pred_not_overlap_with_undef_path_pre
if ((gimple_code (flag_def) == GIMPLE_PHI)
&& (gimple_bb (flag_def) == gimple_bb (phi))
- && find_matching_predicate_in_rest_chains (
- the_pred, preds, num_preds))
+ && find_matching_predicate_in_rest_chains (the_pred, preds,
+ num_preds))
break;
flag_def = 0;
@@ -1235,668 +1242,847 @@ use_pred_not_overlap_with_undef_path_pre
return all_pruned;
}
-/* Returns true if TC is AND or OR */
+/* The helper function returns true if two predicates X1 and X2
+ are equivalent. It assumes the expressions have already
+ properly re-associated. */
static inline bool
-is_and_or_or (enum tree_code tc, tree typ)
+pred_equal_p (pred_info x1, pred_info x2)
{
- return (tc == BIT_IOR_EXPR
- || (tc == BIT_AND_EXPR
- && (typ == 0 || TREE_CODE (typ) == BOOLEAN_TYPE)));
-}
-
-typedef struct norm_cond
-{
- vec<gimple> conds;
- enum tree_code cond_code;
- bool invert;
-} *norm_cond_t;
-
-
-/* Normalizes gimple condition COND. The normalization follows
- UD chains to form larger condition expression trees. NORM_COND
- holds the normalized result. COND_CODE is the logical opcode
- (AND or OR) of the normalized tree. */
+ enum tree_code c1, c2;
+ if (!operand_equal_p (x1.pred_lhs, x2.pred_lhs, 0)
+ || !operand_equal_p (x1.pred_rhs, x2.pred_rhs, 0))
+ return false;
-static void
-normalize_cond_1 (gimple cond,
- norm_cond_t norm_cond,
- enum tree_code cond_code)
-{
- enum gimple_code gc;
- enum tree_code cur_cond_code;
- tree rhs1, rhs2;
+ c1 = x1.cond_code;
+ if (x1.invert != x2.invert)
+ c2 = invert_tree_comparison (x2.cond_code, false);
+ else
+ c2 = x2.cond_code;
- gc = gimple_code (cond);
- if (gc != GIMPLE_ASSIGN)
- {
- norm_cond->conds.safe_push (cond);
- return;
- }
+ return c1 == c2;
+}
- cur_cond_code = gimple_assign_rhs_code (cond);
- rhs1 = gimple_assign_rhs1 (cond);
- rhs2 = gimple_assign_rhs2 (cond);
- if (cur_cond_code == NE_EXPR)
- {
- if (integer_zerop (rhs2)
- && (TREE_CODE (rhs1) == SSA_NAME))
- normalize_cond_1 (
- SSA_NAME_DEF_STMT (rhs1),
- norm_cond, cond_code);
- else if (integer_zerop (rhs1)
- && (TREE_CODE (rhs2) == SSA_NAME))
- normalize_cond_1 (
- SSA_NAME_DEF_STMT (rhs2),
- norm_cond, cond_code);
- else
- norm_cond->conds.safe_push (cond);
+/* Returns true if the predication is testing !=. */
- return;
- }
+static inline bool
+is_neq_relop_p (pred_info pred)
+{
- if (is_and_or_or (cur_cond_code, TREE_TYPE (rhs1))
- && (cond_code == cur_cond_code || cond_code == ERROR_MARK)
- && (TREE_CODE (rhs1) == SSA_NAME && TREE_CODE (rhs2) == SSA_NAME))
- {
- normalize_cond_1 (SSA_NAME_DEF_STMT (rhs1),
- norm_cond, cur_cond_code);
- normalize_cond_1 (SSA_NAME_DEF_STMT (rhs2),
- norm_cond, cur_cond_code);
- norm_cond->cond_code = cur_cond_code;
- }
- else
- norm_cond->conds.safe_push (cond);
+ return (pred.cond_code == NE_EXPR && !pred.invert)
+ || (pred.cond_code == EQ_EXPR && pred.invert);
}
-/* See normalize_cond_1 for details. INVERT is a flag to indicate
- if COND needs to be inverted or not. */
+/* Returns true if pred is of the form X != 0. */
-static void
-normalize_cond (gimple cond, norm_cond_t norm_cond, bool invert)
+static inline bool
+is_neq_zero_form_p (pred_info pred)
{
- enum tree_code cond_code;
+ if (!is_neq_relop_p (pred) || !integer_zerop (pred.pred_rhs)
+ || TREE_CODE (pred.pred_lhs) != SSA_NAME)
+ return false;
+ return true;
+}
- norm_cond->cond_code = ERROR_MARK;
- norm_cond->invert = false;
- norm_cond->conds.create (0);
- gcc_assert (gimple_code (cond) == GIMPLE_COND);
- cond_code = gimple_cond_code (cond);
- if (invert)
- cond_code = invert_tree_comparison (cond_code, false);
+/* The helper function returns true if two predicates X1
+ is equivalent to X2 != 0. */
- if (cond_code == NE_EXPR)
- {
- if (integer_zerop (gimple_cond_rhs (cond))
- && (TREE_CODE (gimple_cond_lhs (cond)) == SSA_NAME))
- normalize_cond_1 (
- SSA_NAME_DEF_STMT (gimple_cond_lhs (cond)),
- norm_cond, ERROR_MARK);
- else if (integer_zerop (gimple_cond_lhs (cond))
- && (TREE_CODE (gimple_cond_rhs (cond)) == SSA_NAME))
- normalize_cond_1 (
- SSA_NAME_DEF_STMT (gimple_cond_rhs (cond)),
- norm_cond, ERROR_MARK);
- else
- {
- norm_cond->conds.safe_push (cond);
- norm_cond->invert = invert;
- }
- }
- else
- {
- norm_cond->conds.safe_push (cond);
- norm_cond->invert = invert;
- }
+static inline bool
+pred_expr_equal_p (pred_info x1, tree x2)
+{
+ if (!is_neq_zero_form_p (x1))
+ return false;
- gcc_assert (norm_cond->conds.length () == 1
- || is_and_or_or (norm_cond->cond_code, NULL));
+ return operand_equal_p (x1.pred_lhs, x2, 0);
}
-/* Returns true if the domain for condition COND1 is a subset of
- COND2. REVERSE is a flag. when it is true the function checks
- if COND1 is a superset of COND2. INVERT1 and INVERT2 are flags
- to indicate if COND1 and COND2 need to be inverted or not. */
+/* Returns true of the domain of single predicate expression
+ EXPR1 is a subset of that of EXPR2. Returns false if it
+ can not be proved. */
static bool
-is_gcond_subset_of (gimple cond1, bool invert1,
- gimple cond2, bool invert2,
- bool reverse)
+is_pred_expr_subset_of (pred_info expr1, pred_info expr2)
{
- enum gimple_code gc1, gc2;
- enum tree_code cond1_code, cond2_code;
- gimple tmp;
- tree cond1_lhs, cond1_rhs, cond2_lhs, cond2_rhs;
+ enum tree_code code1, code2;
- /* Take the short cut. */
- if (cond1 == cond2)
+ if (pred_equal_p (expr1, expr2))
return true;
- if (reverse)
- {
- tmp = cond1;
- cond1 = cond2;
- cond2 = tmp;
- }
-
- gc1 = gimple_code (cond1);
- gc2 = gimple_code (cond2);
-
- if ((gc1 != GIMPLE_ASSIGN && gc1 != GIMPLE_COND)
- || (gc2 != GIMPLE_ASSIGN && gc2 != GIMPLE_COND))
- return cond1 == cond2;
-
- cond1_code = ((gc1 == GIMPLE_ASSIGN)
- ? gimple_assign_rhs_code (cond1)
- : gimple_cond_code (cond1));
-
- cond2_code = ((gc2 == GIMPLE_ASSIGN)
- ? gimple_assign_rhs_code (cond2)
- : gimple_cond_code (cond2));
-
- if (TREE_CODE_CLASS (cond1_code) != tcc_comparison
- || TREE_CODE_CLASS (cond2_code) != tcc_comparison)
+ if ((TREE_CODE (expr1.pred_rhs) != INTEGER_CST)
+ || (TREE_CODE (expr2.pred_rhs) != INTEGER_CST))
return false;
- if (invert1)
- cond1_code = invert_tree_comparison (cond1_code, false);
- if (invert2)
- cond2_code = invert_tree_comparison (cond2_code, false);
-
- cond1_lhs = ((gc1 == GIMPLE_ASSIGN)
- ? gimple_assign_rhs1 (cond1)
- : gimple_cond_lhs (cond1));
- cond1_rhs = ((gc1 == GIMPLE_ASSIGN)
- ? gimple_assign_rhs2 (cond1)
- : gimple_cond_rhs (cond1));
- cond2_lhs = ((gc2 == GIMPLE_ASSIGN)
- ? gimple_assign_rhs1 (cond2)
- : gimple_cond_lhs (cond2));
- cond2_rhs = ((gc2 == GIMPLE_ASSIGN)
- ? gimple_assign_rhs2 (cond2)
- : gimple_cond_rhs (cond2));
+ if (!operand_equal_p (expr1.pred_lhs, expr2.pred_lhs, 0))
+ return false;
- /* Assuming const operands have been swapped to the
- rhs at this point of the analysis. */
+ code1 = expr1.cond_code;
+ if (expr1.invert)
+ code1 = invert_tree_comparison (code1, false);
+ code2 = expr2.cond_code;
+ if (expr2.invert)
+ code2 = invert_tree_comparison (code2, false);
- if (cond1_lhs != cond2_lhs)
+ if (code1 != code2 && code2 != NE_EXPR)
return false;
- if (!is_gimple_constant (cond1_rhs)
- || TREE_CODE (cond1_rhs) != INTEGER_CST)
- return (cond1_rhs == cond2_rhs);
+ if (is_value_included_in (expr1.pred_rhs, expr2.pred_rhs, code2))
+ return true;
- if (!is_gimple_constant (cond2_rhs)
- || TREE_CODE (cond2_rhs) != INTEGER_CST)
- return (cond1_rhs == cond2_rhs);
+ return false;
+}
- if (cond1_code == EQ_EXPR)
- return is_value_included_in (cond1_rhs,
- cond2_rhs, cond2_code);
- if (cond1_code == NE_EXPR || cond2_code == EQ_EXPR)
- return ((cond2_code == cond1_code)
- && tree_int_cst_equal (cond1_rhs, cond2_rhs));
+/* Returns true if the domain of PRED1 is a subset
+ of that of PRED2. Returns false if it can not be proved so. */
- if (((cond1_code == GE_EXPR || cond1_code == GT_EXPR)
- && (cond2_code == LE_EXPR || cond2_code == LT_EXPR))
- || ((cond1_code == LE_EXPR || cond1_code == LT_EXPR)
- && (cond2_code == GE_EXPR || cond2_code == GT_EXPR)))
- return false;
+static bool
+is_pred_chain_subset_of (pred_chain pred1,
+ pred_chain pred2)
+{
+ size_t np1, np2, i1, i2;
- if (cond1_code != GE_EXPR && cond1_code != GT_EXPR
- && cond1_code != LE_EXPR && cond1_code != LT_EXPR)
- return false;
+ np1 = pred1.length ();
+ np2 = pred2.length ();
- if (cond1_code == GT_EXPR)
- {
- cond1_code = GE_EXPR;
- cond1_rhs = fold_binary (PLUS_EXPR, TREE_TYPE (cond1_rhs),
- cond1_rhs,
- fold_convert (TREE_TYPE (cond1_rhs),
- integer_one_node));
- }
- else if (cond1_code == LT_EXPR)
+ for (i2 = 0; i2 < np2; i2++)
{
- cond1_code = LE_EXPR;
- cond1_rhs = fold_binary (MINUS_EXPR, TREE_TYPE (cond1_rhs),
- cond1_rhs,
- fold_convert (TREE_TYPE (cond1_rhs),
- integer_one_node));
+ bool found = false;
+ pred_info info2 = pred2[i2];
+ for (i1 = 0; i1 < np1; i1++)
+ {
+ pred_info info1 = pred1[i1];
+ if (is_pred_expr_subset_of (info1, info2))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return false;
}
-
- if (!cond1_rhs)
- return false;
-
- gcc_assert (cond1_code == GE_EXPR || cond1_code == LE_EXPR);
-
- if (cond2_code == GE_EXPR || cond2_code == GT_EXPR ||
- cond2_code == LE_EXPR || cond2_code == LT_EXPR)
- return is_value_included_in (cond1_rhs,
- cond2_rhs, cond2_code);
- else if (cond2_code == NE_EXPR)
- return
- (is_value_included_in (cond1_rhs,
- cond2_rhs, cond2_code)
- && !is_value_included_in (cond2_rhs,
- cond1_rhs, cond1_code));
- return false;
+ return true;
}
-/* Returns true if the domain of the condition expression
- in COND is a subset of any of the sub-conditions
- of the normalized condtion NORM_COND. INVERT is a flag
- to indicate of the COND needs to be inverted.
- REVERSE is a flag. When it is true, the check is reversed --
- it returns true if COND is a superset of any of the subconditions
- of NORM_COND. */
+/* Returns true if the domain defined by
+ one pred chain ONE_PRED is a subset of the domain
+ of *PREDS. It returns false if ONE_PRED's domain is
+ not a subset of any of the sub-domains of PREDS
+ (corresponding to each individual chains in it), even
+ though it may be still be a subset of whole domain
+ of PREDS which is the union (ORed) of all its subdomains.
+ In other words, the result is conservative. */
static bool
-is_subset_of_any (gimple cond, bool invert,
- norm_cond_t norm_cond, bool reverse)
+is_included_in (pred_chain one_pred, pred_chain_union preds)
{
size_t i;
- size_t len = norm_cond->conds.length ();
+ size_t n = preds.length ();
- for (i = 0; i < len; i++)
+ for (i = 0; i < n; i++)
{
- if (is_gcond_subset_of (cond, invert,
- norm_cond->conds[i],
- false, reverse))
+ if (is_pred_chain_subset_of (one_pred, preds[i]))
return true;
}
+
return false;
}
-/* NORM_COND1 and NORM_COND2 are normalized logical/BIT OR
- expressions (formed by following UD chains not control
- dependence chains). The function returns true of domain
- of and expression NORM_COND1 is a subset of NORM_COND2's.
- The implementation is conservative, and it returns false if
- it the inclusion relationship may not hold. */
+/* Compares two predicate sets PREDS1 and PREDS2 and returns
+ true if the domain defined by PREDS1 is a superset
+ of PREDS2's domain. N1 and N2 are array sizes of PREDS1 and
+ PREDS2 respectively. The implementation chooses not to build
+ generic trees (and relying on the folding capability of the
+ compiler), but instead performs brute force comparison of
+ individual predicate chains (won't be a compile time problem
+ as the chains are pretty short). When the function returns
+ false, it does not necessarily mean *PREDS1 is not a superset
+ of *PREDS2, but mean it may not be so since the analysis can
+ not prove it. In such cases, false warnings may still be
+ emitted. */
static bool
-is_or_set_subset_of (norm_cond_t norm_cond1,
- norm_cond_t norm_cond2)
+is_superset_of (pred_chain_union preds1, pred_chain_union preds2)
{
- size_t i;
- size_t len = norm_cond1->conds.length ();
+ size_t i, n2;
+ pred_chain one_pred_chain = vNULL;
+
+ n2 = preds2.length ();
- for (i = 0; i < len; i++)
+ for (i = 0; i < n2; i++)
{
- if (!is_subset_of_any (norm_cond1->conds[i],
- false, norm_cond2, false))
+ one_pred_chain = preds2[i];
+ if (!is_included_in (one_pred_chain, preds1))
return false;
}
+
return true;
}
-/* NORM_COND1 and NORM_COND2 are normalized logical AND
- expressions (formed by following UD chains not control
- dependence chains). The function returns true of domain
- of and expression NORM_COND1 is a subset of NORM_COND2's. */
+/* Returns true if TC is AND or OR. */
-static bool
-is_and_set_subset_of (norm_cond_t norm_cond1,
- norm_cond_t norm_cond2)
+static inline bool
+is_and_or_or_p (enum tree_code tc, tree type)
{
- size_t i;
- size_t len = norm_cond2->conds.length ();
+ return (tc == BIT_IOR_EXPR
+ || (tc == BIT_AND_EXPR
+ && (type == 0 || TREE_CODE (type) == BOOLEAN_TYPE)));
+}
- for (i = 0; i < len; i++)
- {
- if (!is_subset_of_any (norm_cond2->conds[i],
- false, norm_cond1, true))
- return false;
- }
- return true;
+/* Returns true if X1 is the negate of X2. */
+
+static inline bool
+pred_neg_p (pred_info x1, pred_info x2)
+{
+ enum tree_code c1, c2;
+ if (!operand_equal_p (x1.pred_lhs, x2.pred_lhs, 0)
+ || !operand_equal_p (x1.pred_rhs, x2.pred_rhs, 0))
+ return false;
+
+ c1 = x1.cond_code;
+ if (x1.invert == x2.invert)
+ c2 = invert_tree_comparison (x2.cond_code, false);
+ else
+ c2 = x2.cond_code;
+
+ return c1 == c2;
}
-/* Returns true of the domain if NORM_COND1 is a subset
- of that of NORM_COND2. Returns false if it can not be
- proved to be so. */
+/* 1) ((x IOR y) != 0) AND (x != 0) is equivalent to (x != 0);
+ 2) (X AND Y) OR (!X AND Y) is equivalent to Y;
+ 3) X OR (!X AND Y) is equivalent to (X OR Y);
+ 4) ((x IAND y) != 0) || (x != 0 AND y != 0)) is equivalent to
+ (x != 0 AND y != 0)
+ 5) (X AND Y) OR (!X AND Z) OR (!Y AND Z) is equivalent to
+ (X AND Y) OR Z
-static bool
-is_norm_cond_subset_of (norm_cond_t norm_cond1,
- norm_cond_t norm_cond2)
+ PREDS is the predicate chains, and N is the number of chains. */
+
+/* Helper function to implement rule 1 above. ONE_CHAIN is
+ the AND predication to be simplified. */
+
+static void
+simplify_pred (pred_chain *one_chain)
{
- size_t i;
- enum tree_code code1, code2;
+ size_t i, j, n;
+ bool simplified = false;
+ pred_chain s_chain = vNULL;
- code1 = norm_cond1->cond_code;
- code2 = norm_cond2->cond_code;
+ n = one_chain->length ();
- if (code1 == BIT_AND_EXPR)
+ for (i = 0; i < n; i++)
{
- /* Both conditions are AND expressions. */
- if (code2 == BIT_AND_EXPR)
- return is_and_set_subset_of (norm_cond1, norm_cond2);
- /* NORM_COND1 is an AND expression, and NORM_COND2 is an OR
- expression. In this case, returns true if any subexpression
- of NORM_COND1 is a subset of any subexpression of NORM_COND2. */
- else if (code2 == BIT_IOR_EXPR)
- {
- size_t len1;
- len1 = norm_cond1->conds.length ();
- for (i = 0; i < len1; i++)
+ pred_info *a_pred = &(*one_chain)[i];
+
+ if (!a_pred->pred_lhs)
+ continue;
+ if (!is_neq_zero_form_p (*a_pred))
+ continue;
+
+ gimple def_stmt = SSA_NAME_DEF_STMT (a_pred->pred_lhs);
+ if (gimple_code (def_stmt) != GIMPLE_ASSIGN)
+ continue;
+ if (gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR)
+ {
+ for (j = 0; j < n; j++)
{
- gimple cond1 = norm_cond1->conds[i];
- if (is_subset_of_any (cond1, false, norm_cond2, false))
- return true;
+ pred_info *b_pred = &(*one_chain)[j];
+
+ if (!b_pred->pred_lhs)
+ continue;
+ if (!is_neq_zero_form_p (*b_pred))
+ continue;
+
+ if (pred_expr_equal_p (*b_pred, gimple_assign_rhs1 (def_stmt))
+ || pred_expr_equal_p (*b_pred, gimple_assign_rhs2 (def_stmt)))
+ {
+ /* Mark a_pred for removal. */
+ a_pred->pred_lhs = NULL;
+ a_pred->pred_rhs = NULL;
+ simplified = true;
+ break;
+ }
}
- return false;
- }
- else
- {
- gcc_assert (code2 == ERROR_MARK);
- gcc_assert (norm_cond2->conds.length () == 1);
- return is_subset_of_any (norm_cond2->conds[0],
- norm_cond2->invert, norm_cond1, true);
}
}
- /* NORM_COND1 is an OR expression */
- else if (code1 == BIT_IOR_EXPR)
- {
- if (code2 != code1)
- return false;
- return is_or_set_subset_of (norm_cond1, norm_cond2);
- }
- else
- {
- gcc_assert (code1 == ERROR_MARK);
- gcc_assert (norm_cond1->conds.length () == 1);
- /* Conservatively returns false if NORM_COND1 is non-decomposible
- and NORM_COND2 is an AND expression. */
- if (code2 == BIT_AND_EXPR)
- return false;
+ if (!simplified)
+ return;
- if (code2 == BIT_IOR_EXPR)
- return is_subset_of_any (norm_cond1->conds[0],
- norm_cond1->invert, norm_cond2, false);
-
- gcc_assert (code2 == ERROR_MARK);
- gcc_assert (norm_cond2->conds.length () == 1);
- return is_gcond_subset_of (norm_cond1->conds[0],
- norm_cond1->invert,
- norm_cond2->conds[0],
- norm_cond2->invert, false);
+ for (i = 0; i < n; i++)
+ {
+ pred_info *a_pred = &(*one_chain)[i];
+ if (!a_pred->pred_lhs)
+ continue;
+ s_chain.safe_push (*a_pred);
}
+
+ one_chain->release ();
+ *one_chain = s_chain;
}
-/* Returns true of the domain of single predicate expression
- EXPR1 is a subset of that of EXPR2. Returns false if it
- can not be proved. */
+/* The helper function implements the rule 2 for the
+ OR predicate PREDS.
+
+ 2) (X AND Y) OR (!X AND Y) is equivalent to Y. */
static bool
-is_pred_expr_subset_of (use_pred_info_t expr1,
- use_pred_info_t expr2)
+simplify_preds_2 (pred_chain_union *preds)
{
- gimple cond1, cond2;
- enum tree_code code1, code2;
- struct norm_cond norm_cond1, norm_cond2;
- bool is_subset = false;
+ size_t i, j, n;
+ bool simplified = false;
+ pred_chain_union s_preds = vNULL;
- cond1 = expr1->cond;
- cond2 = expr2->cond;
- code1 = gimple_cond_code (cond1);
- code2 = gimple_cond_code (cond2);
+ /* (X AND Y) OR (!X AND Y) is equivalent to Y.
+ (X AND Y) OR (X AND !Y) is equivalent to X. */
- if (expr1->invert)
- code1 = invert_tree_comparison (code1, false);
- if (expr2->invert)
- code2 = invert_tree_comparison (code2, false);
+ n = preds->length ();
+ for (i = 0; i < n; i++)
+ {
+ pred_info x, y;
+ pred_chain *a_chain = &(*preds)[i];
- /* Fast path -- match exactly */
- if ((gimple_cond_lhs (cond1) == gimple_cond_lhs (cond2))
- && (gimple_cond_rhs (cond1) == gimple_cond_rhs (cond2))
- && (code1 == code2))
- return true;
+ if (a_chain->length () != 2)
+ continue;
+
+ x = (*a_chain)[0];
+ y = (*a_chain)[1];
+
+ for (j = 0; j < n; j++)
+ {
+ pred_chain *b_chain;
+ pred_info x2, y2;
+
+ if (j == i)
+ continue;
+
+ b_chain = &(*preds)[j];
+ if (b_chain->length () != 2)
+ continue;
+
+ x2 = (*b_chain)[0];
+ y2 = (*b_chain)[1];
- /* Normalize conditions. To keep NE_EXPR, do not invert
- with both need inversion. */
- normalize_cond (cond1, &norm_cond1, (expr1->invert));
- normalize_cond (cond2, &norm_cond2, (expr2->invert));
-
- is_subset = is_norm_cond_subset_of (&norm_cond1, &norm_cond2);
-
- /* Free memory */
- norm_cond1.conds.release ();
- norm_cond2.conds.release ();
- return is_subset ;
+ if (pred_equal_p (x, x2) && pred_neg_p (y, y2))
+ {
+ /* Kill a_chain. */
+ a_chain->release ();
+ b_chain->release ();
+ b_chain->safe_push (x);
+ simplified = true;
+ break;
+ }
+ if (pred_neg_p (x, x2) && pred_equal_p (y, y2))
+ {
+ /* Kill a_chain. */
+ a_chain->release ();
+ b_chain->release ();
+ b_chain->safe_push (y);
+ simplified = true;
+ break;
+ }
+ }
+ }
+ /* Now clean up the chain. */
+ if (simplified)
+ {
+ for (i = 0; i < n; i++)
+ {
+ if ((*preds)[i].is_empty ())
+ continue;
+ s_preds.safe_push ((*preds)[i]);
+ }
+ preds->release ();
+ (*preds) = s_preds;
+ s_preds = vNULL;
+ }
+
+ return simplified;
}
-/* Returns true if the domain of PRED1 is a subset
- of that of PRED2. Returns false if it can not be proved so. */
+/* The helper function implements the rule 2 for the
+ OR predicate PREDS.
+
+ 3) x OR (!x AND y) is equivalent to x OR y. */
static bool
-is_pred_chain_subset_of (vec<use_pred_info_t> pred1,
- vec<use_pred_info_t> pred2)
+simplify_preds_3 (pred_chain_union *preds)
{
- size_t np1, np2, i1, i2;
+ size_t i, j, n;
+ bool simplified = false;
- np1 = pred1.length ();
- np2 = pred2.length ();
+ /* Now iteratively simplify X OR (!X AND Z ..)
+ into X OR (Z ...). */
- for (i2 = 0; i2 < np2; i2++)
+ n = preds->length ();
+ if (n < 2)
+ return false;
+
+ for (i = 0; i < n; i++)
{
- bool found = false;
- use_pred_info_t info2
- = pred2[i2];
- for (i1 = 0; i1 < np1; i1++)
+ pred_info x;
+ pred_chain *a_chain = &(*preds)[i];
+
+ if (a_chain->length () != 1)
+ continue;
+
+ x = (*a_chain)[0];
+
+ for (j = 0; j < n; j++)
{
- use_pred_info_t info1
- = pred1[i1];
- if (is_pred_expr_subset_of (info1, info2))
+ pred_chain *b_chain;
+ pred_info x2;
+ size_t k;
+
+ if (j == i)
+ continue;
+
+ b_chain = &(*preds)[j];
+ if (b_chain->length () < 2)
+ continue;
+
+ for (k = 0; k < b_chain->length (); k++)
{
- found = true;
- break;
+ x2 = (*b_chain)[k];
+ if (pred_neg_p (x, x2))
+ {
+ b_chain->unordered_remove (k);
+ simplified = true;
+ break;
+ }
}
}
- if (!found)
- return false;
}
- return true;
+ return simplified;
}
-/* Returns true if the domain defined by
- one pred chain ONE_PRED is a subset of the domain
- of *PREDS. It returns false if ONE_PRED's domain is
- not a subset of any of the sub-domains of PREDS (
- corresponding to each individual chains in it), even
- though it may be still be a subset of whole domain
- of PREDS which is the union (ORed) of all its subdomains.
- In other words, the result is conservative. */
+/* The helper function implements the rule 4 for the
+ OR predicate PREDS.
+
+ 2) ((x AND y) != 0) OR (x != 0 AND y != 0) is equivalent to
+ (x != 0 ANd y != 0). */
static bool
-is_included_in (vec<use_pred_info_t> one_pred,
- vec<use_pred_info_t> *preds,
- size_t n)
+simplify_preds_4 (pred_chain_union *preds)
{
- size_t i;
+ size_t i, j, n;
+ bool simplified = false;
+ pred_chain_union s_preds = vNULL;
+ gimple def_stmt;
+ n = preds->length ();
for (i = 0; i < n; i++)
{
- if (is_pred_chain_subset_of (one_pred, preds[i]))
- return true;
+ pred_info z;
+ pred_chain *a_chain = &(*preds)[i];
+
+ if (a_chain->length () != 1)
+ continue;
+
+ z = (*a_chain)[0];
+
+ if (!is_neq_zero_form_p (z))
+ continue;
+
+ def_stmt = SSA_NAME_DEF_STMT (z.pred_lhs);
+ if (gimple_code (def_stmt) != GIMPLE_ASSIGN)
+ continue;
+
+ if (gimple_assign_rhs_code (def_stmt) != BIT_AND_EXPR)
+ continue;
+
+ for (j = 0; j < n; j++)
+ {
+ pred_chain *b_chain;
+ pred_info x2, y2;
+
+ if (j == i)
+ continue;
+
+ b_chain = &(*preds)[j];
+ if (b_chain->length () != 2)
+ continue;
+
+ x2 = (*b_chain)[0];
+ y2 = (*b_chain)[1];
+ if (!is_neq_zero_form_p (x2)
+ || !is_neq_zero_form_p (y2))
+ continue;
+
+ if ((pred_expr_equal_p (x2, gimple_assign_rhs1 (def_stmt))
+ && pred_expr_equal_p (y2, gimple_assign_rhs2 (def_stmt)))
+ || (pred_expr_equal_p (x2, gimple_assign_rhs2 (def_stmt))
+ && pred_expr_equal_p (y2, gimple_assign_rhs1 (def_stmt))))
+ {
+ /* Kill a_chain. */
+ a_chain->release ();
+ simplified = true;
+ break;
+ }
+ }
+ }
+ /* Now clean up the chain. */
+ if (simplified)
+ {
+ for (i = 0; i < n; i++)
+ {
+ if ((*preds)[i].is_empty ())
+ continue;
+ s_preds.safe_push ((*preds)[i]);
+ }
+ preds->release ();
+ (*preds) = s_preds;
+ s_preds = vNULL;
}
- return false;
+ return simplified;
}
-/* compares two predicate sets PREDS1 and PREDS2 and returns
- true if the domain defined by PREDS1 is a superset
- of PREDS2's domain. N1 and N2 are array sizes of PREDS1 and
- PREDS2 respectively. The implementation chooses not to build
- generic trees (and relying on the folding capability of the
- compiler), but instead performs brute force comparison of
- individual predicate chains (won't be a compile time problem
- as the chains are pretty short). When the function returns
- false, it does not necessarily mean *PREDS1 is not a superset
- of *PREDS2, but mean it may not be so since the analysis can
- not prove it. In such cases, false warnings may still be
- emitted. */
-static bool
-is_superset_of (vec<use_pred_info_t> *preds1,
- size_t n1,
- vec<use_pred_info_t> *preds2,
- size_t n2)
+/* This function simplifies predicates in PREDS. */
+
+static void
+simplify_preds (pred_chain_union *preds, gimple use_or_def, bool is_use)
{
- size_t i;
- vec<use_pred_info_t> one_pred_chain;
+ size_t i, n;
+ bool changed = false;
- for (i = 0; i < n2; i++)
+ if (dump_file && dump_flags & TDF_DETAILS)
{
- one_pred_chain = preds2[i];
- if (!is_included_in (one_pred_chain, preds1, n1))
- return false;
+ fprintf (dump_file, "[BEFORE SIMPLICATION -- ");
+ dump_predicates (use_or_def, *preds, is_use ? "[USE]:\n" : "[DEF]:\n");
}
- return true;
+ for (i = 0; i < preds->length (); i++)
+ simplify_pred (&(*preds)[i]);
+
+ n = preds->length ();
+ if (n < 2)
+ return;
+
+ do
+ {
+ changed = false;
+ if (simplify_preds_2 (preds))
+ changed = true;
+
+ /* Now iteratively simplify X OR (!X AND Z ..)
+ into X OR (Z ...). */
+ if (simplify_preds_3 (preds))
+ changed = true;
+
+ if (simplify_preds_4 (preds))
+ changed = true;
+
+ } while (changed);
+
+ return;
}
-/* Comparison function used by qsort. It is used to
- sort predicate chains to allow predicate
- simplification. */
+/* This is a helper function which attempts to normalize predicate chains
+ by following UD chains. It basically builds up a big tree of either IOR
+ operations or AND operations, and convert the IOR tree into a
+ pred_chain_union or BIT_AND tree into a pred_chain.
+ Example:
-static int
-pred_chain_length_cmp (const void *p1, const void *p2)
+ _3 = _2 RELOP1 _1;
+ _6 = _5 RELOP2 _4;
+ _9 = _8 RELOP3 _7;
+ _10 = _3 | _6;
+ _12 = _9 | _0;
+ _t = _10 | _12;
+
+ then _t != 0 will be normalized into a pred_chain_union
+
+ (_2 RELOP1 _1) OR (_5 RELOP2 _4) OR (_8 RELOP3 _7) OR (_0 != 0)
+
+ Similarly given,
+
+ _3 = _2 RELOP1 _1;
+ _6 = _5 RELOP2 _4;
+ _9 = _8 RELOP3 _7;
+ _10 = _3 & _6;
+ _12 = _9 & _0;
+
+ then _t != 0 will be normalized into a pred_chain:
+ (_2 RELOP1 _1) AND (_5 RELOP2 _4) AND (_8 RELOP3 _7) AND (_0 != 0)
+
+ */
+
+/* This is a helper function that stores a PRED into NORM_PREDS. */
+
+inline static void
+push_pred (pred_chain_union *norm_preds, pred_info pred)
{
- use_pred_info_t i1, i2;
- vec<use_pred_info_t> const *chain1
- = (vec<use_pred_info_t> const *)p1;
- vec<use_pred_info_t> const *chain2
- = (vec<use_pred_info_t> const *)p2;
+ pred_chain pred_chain = vNULL;
+ pred_chain.safe_push (pred);
+ norm_preds->safe_push (pred_chain);
+}
- if (chain1->length () != chain2->length ())
- return (chain1->length () - chain2->length ());
+/* A helper function that creates a predicate of the form
+ OP != 0 and push it WORK_LIST. */
- i1 = (*chain1)[0];
- i2 = (*chain2)[0];
+inline static void
+push_to_worklist (tree op, vec<pred_info, va_heap, vl_ptr> *work_list)
+{
+ pred_info arg_pred;
+ arg_pred.pred_lhs = op;
+ arg_pred.pred_rhs = integer_zero_node;
+ arg_pred.cond_code = NE_EXPR;
+ arg_pred.invert = false;
+ work_list->safe_push (arg_pred);
+}
- /* Allow predicates with similar prefix come together. */
- if (!i1->invert && i2->invert)
- return -1;
- else if (i1->invert && !i2->invert)
- return 1;
+/* A helper that generates a pred_info from a gimple assignment
+ CMP_ASSIGN with comparison rhs. */
- return gimple_uid (i1->cond) - gimple_uid (i2->cond);
+static pred_info
+get_pred_info_from_cmp (gimple cmp_assign)
+{
+ pred_info n_pred;
+ n_pred.pred_lhs = gimple_assign_rhs1 (cmp_assign);
+ n_pred.pred_rhs = gimple_assign_rhs2 (cmp_assign);
+ n_pred.cond_code = gimple_assign_rhs_code (cmp_assign);
+ n_pred.invert = false;
+ return n_pred;
}
-/* x OR (!x AND y) is equivalent to x OR y.
- This function normalizes x1 OR (!x1 AND x2) OR (!x1 AND !x2 AND x3)
- into x1 OR x2 OR x3. PREDS is the predicate chains, and N is
- the number of chains. Returns true if normalization happens. */
-
-static bool
-normalize_preds (vec<use_pred_info_t> *preds, size_t *n)
-{
- size_t i, j, ll;
- vec<use_pred_info_t> pred_chain;
- vec<use_pred_info_t> x = vNULL;
- use_pred_info_t xj = 0, nxj = 0;
-
- if (*n < 2)
- return false;
-
- /* First sort the chains in ascending order of lengths. */
- qsort (preds, *n, sizeof (void *), pred_chain_length_cmp);
- pred_chain = preds[0];
- ll = pred_chain.length ();
- if (ll != 1)
- {
- if (ll == 2)
- {
- use_pred_info_t xx, yy, xx2, nyy;
- vec<use_pred_info_t> pred_chain2 = preds[1];
- if (pred_chain2.length () != 2)
- return false;
-
- /* See if simplification x AND y OR x AND !y is possible. */
- xx = pred_chain[0];
- yy = pred_chain[1];
- xx2 = pred_chain2[0];
- nyy = pred_chain2[1];
- if (gimple_cond_lhs (xx->cond) != gimple_cond_lhs (xx2->cond)
- || gimple_cond_rhs (xx->cond) != gimple_cond_rhs (xx2->cond)
- || gimple_cond_code (xx->cond) != gimple_cond_code (xx2->cond)
- || (xx->invert != xx2->invert))
- return false;
- if (gimple_cond_lhs (yy->cond) != gimple_cond_lhs (nyy->cond)
- || gimple_cond_rhs (yy->cond) != gimple_cond_rhs (nyy->cond)
- || gimple_cond_code (yy->cond) != gimple_cond_code (nyy->cond)
- || (yy->invert == nyy->invert))
- return false;
-
- /* Now merge the first two chains. */
- free (yy);
- free (nyy);
- free (xx2);
- pred_chain.release ();
- pred_chain2.release ();
- pred_chain.safe_push (xx);
- preds[0] = pred_chain;
- for (i = 1; i < *n - 1; i++)
- preds[i] = preds[i + 1];
-
- preds[*n - 1].create (0);
- *n = *n - 1;
- }
- else
- return false;
- }
-
- x.safe_push (pred_chain[0]);
-
- /* The loop extracts x1, x2, x3, etc from chains
- x1 OR (!x1 AND x2) OR (!x1 AND !x2 AND x3) OR ... */
- for (i = 1; i < *n; i++)
+/* Returns true if the PHI is a degenerated phi with
+ all args with the same value (relop). In that case, *PRED
+ will be updated to that value. */
+
+static bool
+is_degenerated_phi (gimple phi, pred_info *pred_p)
+{
+ int i, n;
+ tree op0;
+ gimple def0;
+ pred_info pred0;
+
+ n = gimple_phi_num_args (phi);
+ op0 = gimple_phi_arg_def (phi, 0);
+
+ if (TREE_CODE (op0) != SSA_NAME)
+ return false;
+
+ def0 = SSA_NAME_DEF_STMT (op0);
+ if (gimple_code (def0) != GIMPLE_ASSIGN)
+ return false;
+ if (TREE_CODE_CLASS (gimple_assign_rhs_code (def0))
+ != tcc_comparison)
+ return false;
+ pred0 = get_pred_info_from_cmp (def0);
+
+ for (i = 1; i < n; ++i)
{
- pred_chain = preds[i];
- if (pred_chain.length () != i + 1)
+ gimple def;
+ pred_info pred;
+ tree op = gimple_phi_arg_def (phi, i);
+
+ if (TREE_CODE (op) != SSA_NAME)
+ return false;
+
+ def = SSA_NAME_DEF_STMT (op);
+ if (gimple_code (def) != GIMPLE_ASSIGN)
return false;
+ if (TREE_CODE_CLASS (gimple_assign_rhs_code (def))
+ != tcc_comparison)
+ return false;
+ pred = get_pred_info_from_cmp (def);
+ if (!pred_equal_p (pred, pred0))
+ return false;
+ }
+
+ *pred_p = pred0;
+ return true;
+}
- for (j = 0; j < i; j++)
+/* Normalize one predicate PRED
+ 1) if PRED can no longer be normlized, put it into NORM_PREDS.
+ 2) otherwise if PRED is of the form x != 0, follow x's definition
+ and put normalized predicates into WORK_LIST. */
+
+static void
+normalize_one_pred_1 (pred_chain_union *norm_preds,
+ pred_chain *norm_chain,
+ pred_info pred,
+ enum tree_code and_or_code,
+ vec<pred_info, va_heap, vl_ptr> *work_list)
+{
+ if (!is_neq_zero_form_p (pred))
+ {
+ if (and_or_code == BIT_IOR_EXPR)
+ push_pred (norm_preds, pred);
+ else
+ norm_chain->safe_push (pred);
+ return;
+ }
+
+ gimple def_stmt = SSA_NAME_DEF_STMT (pred.pred_lhs);
+
+ if (gimple_code (def_stmt) == GIMPLE_PHI
+ && is_degenerated_phi (def_stmt, &pred))
+ work_list->safe_push (pred);
+ else if (gimple_code (def_stmt) == GIMPLE_PHI
+ && and_or_code == BIT_IOR_EXPR)
+ {
+ int i, n;
+ n = gimple_phi_num_args (def_stmt);
+
+ /* If we see non zero constant, we should punt. The predicate
+ * should be one guarding the phi edge. */
+ for (i = 0; i < n; ++i)
{
- xj = x[j];
- nxj = pred_chain[j];
+ tree op = gimple_phi_arg_def (def_stmt, i);
+ if (TREE_CODE (op) == INTEGER_CST && !integer_zerop (op))
+ {
+ push_pred (norm_preds, pred);
+ return;
+ }
+ }
- /* Check if nxj is !xj */
- if (gimple_cond_lhs (xj->cond) != gimple_cond_lhs (nxj->cond)
- || gimple_cond_rhs (xj->cond) != gimple_cond_rhs (nxj->cond)
- || gimple_cond_code (xj->cond) != gimple_cond_code (nxj->cond)
- || (xj->invert == nxj->invert))
- return false;
+ for (i = 0; i < n; ++i)
+ {
+ tree op = gimple_phi_arg_def (def_stmt, i);
+ if (integer_zerop (op))
+ continue;
+
+ push_to_worklist (op, work_list);
}
+ }
+ else if (gimple_code (def_stmt) != GIMPLE_ASSIGN)
+ {
+ if (and_or_code == BIT_IOR_EXPR)
+ push_pred (norm_preds, pred);
+ else
+ norm_chain->safe_push (pred);
+ }
+ else if (gimple_assign_rhs_code (def_stmt) == and_or_code)
+ {
+ push_to_worklist (gimple_assign_rhs1 (def_stmt),
+ work_list);
+ push_to_worklist (gimple_assign_rhs2 (def_stmt),
+ work_list);
+ }
+ else if (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt))
+ == tcc_comparison)
+ {
+ pred_info n_pred = get_pred_info_from_cmp (def_stmt);
+ if (and_or_code == BIT_IOR_EXPR)
+ push_pred (norm_preds, n_pred);
+ else
+ norm_chain->safe_push (n_pred);
+ }
+ else
+ {
+ if (and_or_code == BIT_IOR_EXPR)
+ push_pred (norm_preds, pred);
+ else
+ norm_chain->safe_push (pred);
+ }
+}
- x.safe_push (pred_chain[i]);
- }
+/* Normalize PRED and store the normalized predicates into NORM_PREDS. */
- /* Now normalize the pred chains using the extraced x1, x2, x3 etc. */
- for (j = 0; j < *n; j++)
+static void
+normalize_one_pred (pred_chain_union *norm_preds,
+ pred_info pred)
+{
+ vec<pred_info, va_heap, vl_ptr> work_list = vNULL;
+ enum tree_code and_or_code = ERROR_MARK;
+ pred_chain norm_chain = vNULL;
+
+ if (!is_neq_zero_form_p (pred))
{
- use_pred_info_t t;
- xj = x[j];
+ push_pred (norm_preds, pred);
+ return;
+ }
- t = XNEW (struct use_pred_info);
- *t = *xj;
+ gimple def_stmt = SSA_NAME_DEF_STMT (pred.pred_lhs);
+ if (gimple_code (def_stmt) == GIMPLE_ASSIGN)
+ and_or_code = gimple_assign_rhs_code (def_stmt);
+ if (and_or_code != BIT_IOR_EXPR
+ && and_or_code != BIT_AND_EXPR)
+ {
+ if (TREE_CODE_CLASS (and_or_code)
+ == tcc_comparison)
+ {
+ pred_info n_pred = get_pred_info_from_cmp (def_stmt);
+ push_pred (norm_preds, n_pred);
+ }
+ else
+ push_pred (norm_preds, pred);
+ return;
+ }
- x[j] = t;
+ work_list.safe_push (pred);
+ while (!work_list.is_empty ())
+ {
+ pred_info a_pred = work_list.pop ();
+ normalize_one_pred_1 (norm_preds, &norm_chain, a_pred,
+ and_or_code, &work_list);
}
+ if (and_or_code == BIT_AND_EXPR)
+ norm_preds->safe_push (norm_chain);
+
+ work_list.release ();
+}
- for (i = 0; i < *n; i++)
+static void
+normalize_one_pred_chain (pred_chain_union *norm_preds,
+ pred_chain one_chain)
+{
+ vec<pred_info, va_heap, vl_ptr> work_list = vNULL;
+ pred_chain norm_chain = vNULL;
+ size_t i;
+
+ for (i = 0; i < one_chain.length (); i++)
+ work_list.safe_push (one_chain[i]);
+
+ while (!work_list.is_empty ())
{
- pred_chain = preds[i];
- for (j = 0; j < pred_chain.length (); j++)
- free (pred_chain[j]);
- pred_chain.release ();
- /* A new chain. */
- pred_chain.safe_push (x[i]);
- preds[i] = pred_chain;
+ pred_info a_pred = work_list.pop ();
+ normalize_one_pred_1 (0, &norm_chain, a_pred,
+ BIT_AND_EXPR, &work_list);
}
- return true;
+
+ norm_preds->safe_push (norm_chain);
+ work_list.release ();
}
+/* Normalize predicate chains PREDS and returns the normalized one. */
+
+static pred_chain_union
+normalize_preds (pred_chain_union preds, gimple use_or_def, bool is_use)
+{
+ pred_chain_union norm_preds = vNULL;
+ size_t n = preds.length ();
+ size_t i;
+
+ if (dump_file && dump_flags & TDF_DETAILS)
+ {
+ fprintf (dump_file, "[BEFORE NORMALIZATION --");
+ dump_predicates (use_or_def, preds, is_use ? "[USE]:\n" : "[DEF]:\n");
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ if (preds[i].length () != 1)
+ normalize_one_pred_chain (&norm_preds, preds[i]);
+ else
+ {
+ normalize_one_pred (&norm_preds, preds[i][0]);
+ preds[i].release ();
+ }
+ }
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "[AFTER NORMALIZATION -- ");
+ dump_predicates (use_or_def, norm_preds, is_use ? "[USE]:\n" : "[DEF]:\n");
+ }
+
+ preds.release ();
+ return norm_preds;
+}
/* Computes the predicates that guard the use and checks
@@ -1917,12 +2103,11 @@ is_use_properly_guarded (gimple use_stmt
basic_block use_bb,
gimple phi,
unsigned uninit_opnds,
- struct pointer_set_t *visited_phis)
+ pointer_set_t *visited_phis)
{
basic_block phi_bb;
- vec<use_pred_info_t> *preds = 0;
- vec<use_pred_info_t> *def_preds = 0;
- size_t num_preds = 0, num_def_preds = 0;
+ pred_chain_union preds = vNULL;
+ pred_chain_union def_preds = vNULL;
bool has_valid_preds = false;
bool is_properly_guarded = false;
@@ -1934,49 +2119,44 @@ is_use_properly_guarded (gimple use_stmt
if (is_non_loop_exit_postdominating (use_bb, phi_bb))
return false;
- has_valid_preds = find_predicates (&preds, &num_preds,
- phi_bb, use_bb);
+ has_valid_preds = find_predicates (&preds, phi_bb, use_bb);
if (!has_valid_preds)
{
- destroy_predicate_vecs (num_preds, preds);
+ destroy_predicate_vecs (preds);
return false;
}
- if (dump_file)
- dump_predicates (use_stmt, num_preds, preds,
- "\nUse in stmt ");
-
- has_valid_preds = find_def_preds (&def_preds,
- &num_def_preds, phi);
+ /* Try to prune the dead incoming phi edges. */
+ is_properly_guarded
+ = use_pred_not_overlap_with_undef_path_pred (preds, phi, uninit_opnds,
+ visited_phis);
- if (has_valid_preds)
+ if (is_properly_guarded)
{
- bool normed;
- if (dump_file)
- dump_predicates (phi, num_def_preds, def_preds,
- "Operand defs of phi ");
+ destroy_predicate_vecs (preds);
+ return true;
+ }
- normed = normalize_preds (def_preds, &num_def_preds);
- if (normed && dump_file)
- {
- fprintf (dump_file, "\nNormalized to\n");
- dump_predicates (phi, num_def_preds, def_preds,
- "Operand defs of phi ");
- }
- is_properly_guarded =
- is_superset_of (def_preds, num_def_preds,
- preds, num_preds);
+ has_valid_preds = find_def_preds (&def_preds, phi);
+
+ if (!has_valid_preds)
+ {
+ destroy_predicate_vecs (preds);
+ destroy_predicate_vecs (def_preds);
+ return false;
}
- /* further prune the dead incoming phi edges. */
- if (!is_properly_guarded)
- is_properly_guarded
- = use_pred_not_overlap_with_undef_path_pred (
- num_preds, preds, phi, uninit_opnds, visited_phis);
+ simplify_preds (&preds, use_stmt, true);
+ preds = normalize_preds (preds, use_stmt, true);
+
+ simplify_preds (&def_preds, phi, false);
+ def_preds = normalize_preds (def_preds, phi, false);
+
+ is_properly_guarded = is_superset_of (def_preds, preds);
- destroy_predicate_vecs (num_preds, preds);
- destroy_predicate_vecs (num_def_preds, def_preds);
+ destroy_predicate_vecs (preds);
+ destroy_predicate_vecs (def_preds);
return is_properly_guarded;
}
@@ -1992,7 +2172,7 @@ is_use_properly_guarded (gimple use_stmt
static gimple
find_uninit_use (gimple phi, unsigned uninit_opnds,
vec<gimple> *worklist,
- struct pointer_set_t *added_to_worklist)
+ pointer_set_t *added_to_worklist)
{
tree phi_result;
use_operand_p use_p;
@@ -2003,7 +2183,7 @@ find_uninit_use (gimple phi, unsigned un
FOR_EACH_IMM_USE_FAST (use_p, iter, phi_result)
{
- struct pointer_set_t *visited_phis;
+ pointer_set_t *visited_phis;
basic_block use_bb;
use_stmt = USE_STMT (use_p);
@@ -2018,10 +2198,7 @@ find_uninit_use (gimple phi, unsigned un
else
use_bb = gimple_bb (use_stmt);
- if (is_use_properly_guarded (use_stmt,
- use_bb,
- phi,
- uninit_opnds,
+ if (is_use_properly_guarded (use_stmt, use_bb, phi, uninit_opnds,
visited_phis))
{
pointer_set_destroy (visited_phis);
@@ -2040,8 +2217,7 @@ find_uninit_use (gimple phi, unsigned un
/* Found a phi use that is not guarded,
add the phi to the worklist. */
- if (!pointer_set_insert (added_to_worklist,
- use_stmt))
+ if (!pointer_set_insert (added_to_worklist, use_stmt))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
@@ -2067,7 +2243,7 @@ find_uninit_use (gimple phi, unsigned un
static void
warn_uninitialized_phi (gimple phi, vec<gimple> *worklist,
- struct pointer_set_t *added_to_worklist)
+ pointer_set_t *added_to_worklist)
{
unsigned uninit_opnds;
gimple uninit_use_stmt = 0;
@@ -2115,7 +2291,7 @@ execute_late_warn_uninitialized (void)
basic_block bb;
gimple_stmt_iterator gsi;
vec<gimple> worklist = vNULL;
- struct pointer_set_t *added_to_worklist;
+ pointer_set_t *added_to_worklist;
calculate_dominance_info (CDI_DOMINATORS);
calculate_dominance_info (CDI_POST_DOMINATORS);
@@ -2229,8 +2405,7 @@ execute_early_warn_uninitialized (void)
execute_late_warn_uninitialized only runs with optimization. With
optimization we want to warn about possible uninitialized as late
as possible, thus don't do it here. However, without
- optimization we need to warn here about "may be uninitialized".
- */
+ optimization we need to warn here about "may be uninitialized". */
calculate_dominance_info (CDI_POST_DOMINATORS);
warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize);
@@ -2280,5 +2455,3 @@ make_pass_early_warn_uninitialized (gcc:
{
return new pass_early_warn_uninitialized (ctxt);
}
-
-
===================================================================
@@ -1,3 +1,46 @@
+2013-12-21 Xinliang David Li <davidxl@google.com>
+
+ PR tree-optimization/59303
+ * tree-ssa-uninit.c (is_use_properly_guarded):
+ Main cleanup.
+ (dump_predicates): Better output format.
+ (pred_equal_p): New function.
+ (is_neq_relop_p): Ditto.
+ (is_neq_zero_form_p): Ditto.
+ (pred_expr_equal_p): Ditto.
+ (pred_neg_p): Ditto.
+ (simplify_pred): Ditto.
+ (simplify_preds_2): Ditto.
+ (simplify_preds_3): Ditto.
+ (simplify_preds_4): Ditto.
+ (simplify_preds): Ditto.
+ (push_pred): Ditto.
+ (push_to_worklist): Ditto.
+ (get_pred_info_from_cmp): Ditto.
+ (is_degenerated_phi): Ditto.
+ (normalize_one_pred_1): Ditto.
+ (normalize_one_pred): Ditto.
+ (normalize_one_pred_chain): Ditto.
+ (normalize_preds): Ditto.
+ (normalize_cond_1): Remove function.
+ (normalize_cond): Ditto.
+ (is_gcond_subset_of): Ditto.
+ (is_subset_of_any): Ditto.
+ (is_or_set_subset_of): Ditto.
+ (is_and_set_subset_of): Ditto.
+ (is_norm_cond_subset_of): Ditto.
+ (pred_chain_length_cmp): Ditto.
+ (convert_control_dep_chain_into_preds): Type change.
+ (find_predicates): Ditto.
+ (find_def_preds): Ditto.
+ (destroy_predicates_vecs): Ditto.
+ (find_matching_predicates_in_rest_chains): Ditto.
+ (use_pred_not_overlap_with_undef_path_pred): Ditto.
+ (is_pred_expr_subset): Ditto.
+ (is_pred_chain_subset_of): Ditto.
+ (is_included_in): Ditto.
+ (is_superset_of): Ditto.
+
2013-12-20 Sharad Singhai <singhai@google.com>
* Makefile.in: Add optinfo.texi.