aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBin Cheng <bin.cheng@linux.alibaba.com>2020-11-06 16:19:40 -0500
committerJeff Law <law@torsion.usersys.redhat.com>2020-11-06 16:21:11 -0500
commit7987a8d29a78eb373b5e054d539e332d75e92e92 (patch)
treeb4197947306fbb473293ef3b951a8b0c5b31cad6
parent887515acd27e49c176395ab76d5826959d89cb9b (diff)
downloadgcc-7987a8d29a78eb373b5e054d539e332d75e92e92.zip
gcc-7987a8d29a78eb373b5e054d539e332d75e92e92.tar.gz
gcc-7987a8d29a78eb373b5e054d539e332d75e92e92.tar.bz2
Improve uninitialized warning with value range info
Function use_pred_not_overlap_with_undef_path_pred of pass_late_warn_uninitialized checks if predicate of variable use overlaps with predicate of undefined control flow path. For now, it only checks ssa_var comparing against constant, this can be improved where ssa_var compares against another ssa_var with value range info, as described in comment: + /* Check value range info of rhs, do following transforms: + flag_var < [min, max] -> flag_var < max + flag_var > [min, max] -> flag_var > min + + We can also transform LE_EXPR/GE_EXPR to LT_EXPR/GT_EXPR: + flag_var <= [min, max] -> flag_var < [min, max+1] + flag_var >= [min, max] -> flag_var > [min-1, max] + if no overflow/wrap. */ gcc/ * tree-ssa-uninit.c (find_var_cmp_const): New function. (use_pred_not_overlap_with_undef_path_pred): Call above.
-rw-r--r--gcc/tree-ssa-uninit.c192
1 files changed, 129 insertions, 63 deletions
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index 7ed1686..f235143 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -1345,21 +1345,18 @@ value_sat_pred_p (tree val, tree boundary, enum tree_code cmpc,
}
/* Returns true if PRED is common among all the predicate
- chains (PREDS) (and therefore can be factored out).
- NUM_PRED_CHAIN is the size of array PREDS. */
+ chains (PREDS) (and therefore can be factored out). */
static bool
-find_matching_predicate_in_rest_chains (pred_info pred,
- pred_chain_union preds,
- size_t num_pred_chains)
+find_matching_predicate_in_rest_chains (pred_info pred, pred_chain_union preds)
{
size_t i, j, n;
/* Trival case. */
- if (num_pred_chains == 1)
+ if (preds.length () == 1)
return true;
- for (i = 1; i < num_pred_chains; i++)
+ for (i = 1; i < preds.length (); i++)
{
bool found = false;
pred_chain one_chain = preds[i];
@@ -1530,6 +1527,129 @@ prune_uninit_phi_opnds (gphi *phi, unsigned uninit_opnds, gphi *flag_def,
return true;
}
+/* A helper function finds predicate which will be examined against uninit
+ paths. If there is no "flag_var cmp const" form predicate, the function
+ tries to find predicate of form like "flag_var cmp flag_var" with value
+ range info. PHI is the phi node whose incoming (undefined) paths need to
+ be examined. On success, the function returns the comparsion code, sets
+ defintion gimple of the flag_var to FLAG_DEF, sets boundary_cst to
+ BOUNDARY_CST. On fail, the function returns ERROR_MARK. */
+
+static enum tree_code
+find_var_cmp_const (pred_chain_union preds, gphi *phi, gimple **flag_def,
+ tree *boundary_cst)
+{
+ enum tree_code vrinfo_code = ERROR_MARK, code;
+ gimple *vrinfo_def = NULL;
+ tree vrinfo_cst = NULL, cond_lhs, cond_rhs;
+
+ gcc_assert (preds.length () > 0);
+ pred_chain the_pred_chain = preds[0];
+ for (unsigned i = 0; i < the_pred_chain.length (); i++)
+ {
+ bool use_vrinfo_p = false;
+ pred_info the_pred = the_pred_chain[i];
+ cond_lhs = the_pred.pred_lhs;
+ cond_rhs = the_pred.pred_rhs;
+ if (cond_lhs == NULL_TREE || cond_rhs == NULL_TREE)
+ continue;
+
+ code = get_cmp_code (the_pred.cond_code, false, the_pred.invert);
+ if (code == ERROR_MARK)
+ continue;
+
+ if (TREE_CODE (cond_lhs) == SSA_NAME && is_gimple_constant (cond_rhs))
+ ;
+ else if (TREE_CODE (cond_rhs) == SSA_NAME
+ && is_gimple_constant (cond_lhs))
+ {
+ std::swap (cond_lhs, cond_rhs);
+ if ((code = get_cmp_code (code, true, false)) == ERROR_MARK)
+ continue;
+ }
+ /* Check if we can take advantage of "flag_var comp flag_var" predicate
+ with value range info. Note only first of such case is handled. */
+ else if (vrinfo_code == ERROR_MARK
+ && TREE_CODE (cond_lhs) == SSA_NAME
+ && TREE_CODE (cond_rhs) == SSA_NAME)
+ {
+ gimple* lhs_def = SSA_NAME_DEF_STMT (cond_lhs);
+ if (!lhs_def || gimple_code (lhs_def) != GIMPLE_PHI
+ || gimple_bb (lhs_def) != gimple_bb (phi))
+ {
+ std::swap (cond_lhs, cond_rhs);
+ if ((code = get_cmp_code (code, true, false)) == ERROR_MARK)
+ continue;
+ }
+
+ /* Check value range info of rhs, do following transforms:
+ flag_var < [min, max] -> flag_var < max
+ flag_var > [min, max] -> flag_var > min
+
+ We can also transform LE_EXPR/GE_EXPR to LT_EXPR/GT_EXPR:
+ flag_var <= [min, max] -> flag_var < [min, max+1]
+ flag_var >= [min, max] -> flag_var > [min-1, max]
+ if no overflow/wrap. */
+ wide_int min, max;
+ tree type = TREE_TYPE (cond_lhs);
+ if (!INTEGRAL_TYPE_P (type)
+ || get_range_info (cond_rhs, &min, &max) != VR_RANGE)
+ continue;
+ if (code == LE_EXPR
+ && max != wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)))
+ {
+ code = LT_EXPR;
+ max = max + 1;
+ }
+ if (code == GE_EXPR
+ && min != wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)))
+ {
+ code = GT_EXPR;
+ min = min - 1;
+ }
+ if (code == LT_EXPR)
+ cond_rhs = wide_int_to_tree (type, max);
+ else if (code == GT_EXPR)
+ cond_rhs = wide_int_to_tree (type, min);
+ else
+ continue;
+
+ use_vrinfo_p = true;
+ }
+ else
+ continue;
+
+ if ((*flag_def = SSA_NAME_DEF_STMT (cond_lhs)) == NULL)
+ continue;
+
+ if (gimple_code (*flag_def) != GIMPLE_PHI
+ || gimple_bb (*flag_def) != gimple_bb (phi)
+ || !find_matching_predicate_in_rest_chains (the_pred, preds))
+ continue;
+
+ /* Return if any "flag_var comp const" predicate is found. */
+ if (!use_vrinfo_p)
+ {
+ *boundary_cst = cond_rhs;
+ return code;
+ }
+ /* Record if any "flag_var comp flag_var[vinfo]" predicate is found. */
+ else if (vrinfo_code == ERROR_MARK)
+ {
+ vrinfo_code = code;
+ vrinfo_def = *flag_def;
+ vrinfo_cst = cond_rhs;
+ }
+ }
+ /* Return the "flag_var cmp flag_var[vinfo]" predicate we found. */
+ if (vrinfo_code != ERROR_MARK)
+ {
+ *flag_def = vrinfo_def;
+ *boundary_cst = vrinfo_cst;
+ }
+ return vrinfo_code;
+}
+
/* A helper function that determines if the predicate set
of the use is not overlapping with that of the uninit paths.
The most common senario of guarded use is in Example 1:
@@ -1607,75 +1727,21 @@ use_pred_not_overlap_with_undef_path_pred (pred_chain_union preds,
gphi *phi, unsigned uninit_opnds,
hash_set<gphi *> *visited_phis)
{
- unsigned int i, n;
gimple *flag_def = 0;
tree boundary_cst = 0;
enum tree_code cmp_code;
- bool swap_cond = false;
- bool invert = false;
- 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
a predicate that is a comparison of a flag variable against
a constant. */
- the_pred_chain = preds[0];
- n = the_pred_chain.length ();
- for (i = 0; i < n; i++)
- {
- tree cond_lhs, cond_rhs, flag = 0;
-
- pred_info the_pred = the_pred_chain[i];
-
- 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))
- {
- boundary_cst = cond_rhs;
- flag = cond_lhs;
- }
- else if (cond_rhs != NULL_TREE && TREE_CODE (cond_rhs) == SSA_NAME
- && cond_lhs != NULL_TREE && is_gimple_constant (cond_lhs))
- {
- boundary_cst = cond_lhs;
- flag = cond_rhs;
- swap_cond = true;
- }
-
- if (!flag)
- continue;
-
- flag_def = SSA_NAME_DEF_STMT (flag);
-
- if (!flag_def)
- continue;
-
- 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))
- break;
-
- flag_def = 0;
- }
-
- if (!flag_def)
+ cmp_code = find_var_cmp_const (preds, phi, &flag_def, &boundary_cst);
+ if (cmp_code == ERROR_MARK)
return false;
/* Now check all the uninit incoming edge has a constant flag value
that is in conflict with the use guard/predicate. */
- cmp_code = get_cmp_code (cmp_code, swap_cond, invert);
-
- if (cmp_code == ERROR_MARK)
- return false;
-
all_pruned = prune_uninit_phi_opnds
(phi, uninit_opnds, as_a<gphi *> (flag_def), boundary_cst, cmp_code,
visited_phis, &visited_flag_phis);