From 7987a8d29a78eb373b5e054d539e332d75e92e92 Mon Sep 17 00:00:00 2001 From: Bin Cheng Date: Fri, 6 Nov 2020 16:19:40 -0500 Subject: [PATCH] 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. --- gcc/tree-ssa-uninit.c | 192 ++++++++++++++++++++++++++++-------------- 1 file changed, 129 insertions(+), 63 deletions(-) diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index 7ed16866afa..f23514395e0 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 *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 (flag_def), boundary_cst, cmp_code, visited_phis, &visited_flag_phis); -- 2.30.2