diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index cc785bd..930dd49 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -1250,6 +1250,113 @@ 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. Note the predicate is of flag_var cmp boundary_cst form. PHI is the + phi node whose incoming (undefined) paths need to be examined, + PRED_USING_VRINFO_P is true if we should take advantage of value range info + in choosing the predicate. 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, bool pred_using_vrinfo_p) +{ + size_t num_preds = preds.length (); + + gcc_assert (num_preds > 0); + + pred_chain the_pred_chain = preds[0]; + for (unsigned i = 0; i < the_pred_chain.length (); i++) + { + enum tree_code code; + pred_info the_pred = the_pred_chain[i]; + tree 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)) + { + if (pred_using_vrinfo_p) + continue; + } + else if (TREE_CODE (cond_rhs) == SSA_NAME + && is_gimple_constant (cond_lhs)) + { + if (pred_using_vrinfo_p) + continue; + std::swap (cond_lhs, cond_rhs); + if ((code = get_cmp_code (code, true, false)) == ERROR_MARK) + continue; + } + else if (TREE_CODE (cond_lhs) == SSA_NAME + && TREE_CODE (cond_rhs) == SSA_NAME) + { + if (!pred_using_vrinfo_p) + continue; + 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 (max != wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)) + && code == LE_EXPR) + { + code = LT_EXPR; + max = max + 1; + } + if (min != wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)) + && code == GE_EXPR) + { + 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; + } + 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, + num_preds)) + { + *boundary_cst = cond_rhs; + return code; + } + } + return ERROR_MARK; +} + /* 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: @@ -1327,75 +1434,23 @@ 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, false); + if (cmp_code == ERROR_MARK) + cmp_code = find_var_cmp_const (preds, phi, &flag_def, &boundary_cst, true); + 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);