aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-uninit.c
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2021-01-03 21:40:04 +0100
committerThomas Koenig <tkoenig@gcc.gnu.org>2021-01-03 21:40:04 +0100
commitafae4a55ccaa0de95ea11e5f634084db6ab2f444 (patch)
treed632cc867d10410ba9fb750523be790b86846ac4 /gcc/tree-ssa-uninit.c
parent9d9a82ec8478ff52c7a9d61f58cd2a7b6295b5f9 (diff)
parentd2eb616a0f7bea78164912aa438c29fe1ef5774a (diff)
downloadgcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.zip
gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.gz
gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.bz2
Merge branch 'master' into devel/coarray_native
Diffstat (limited to 'gcc/tree-ssa-uninit.c')
-rw-r--r--gcc/tree-ssa-uninit.c211
1 files changed, 141 insertions, 70 deletions
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index 7ed1686..516a7bd 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -404,10 +404,7 @@ maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs,
tree rhstype = TREE_TYPE (rhs);
if (POINTER_TYPE_P (rhstype))
rhstype = TREE_TYPE (rhstype);
- if (TYPE_EMPTY_P (rhstype)
- || (RECORD_OR_UNION_TYPE_P (rhstype)
- && (!first_field (rhstype)
- || default_is_empty_record (rhstype))))
+ if (is_empty_type (rhstype))
return NULL_TREE;
bool warned = false;
@@ -443,7 +440,7 @@ maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs,
access implying read access to those objects. */
static void
-maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
+maybe_warn_pass_by_reference (gcall *stmt, wlimits &wlims)
{
if (!wlims.wmaybe_uninit)
return;
@@ -457,6 +454,10 @@ maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
if (!fntype)
return;
+ /* Const function do not read their arguments. */
+ if (gimple_call_flags (stmt) & ECF_CONST)
+ return;
+
const built_in_function fncode
= (fndecl && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
? DECL_FUNCTION_CODE (fndecl) : (built_in_function)BUILT_IN_LAST);
@@ -523,6 +524,10 @@ maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
(but not definitive) read access. */
wlims.always_executed = false;
+ /* Ignore args we are not going to read from. */
+ if (gimple_call_arg_flags (stmt, argno - 1) & EAF_UNUSED)
+ continue;
+
tree arg = gimple_call_arg (stmt, argno - 1);
ao_ref ref;
@@ -639,8 +644,8 @@ warn_uninitialized_vars (bool wmaybe_uninit)
if (gimple_vdef (stmt))
wlims.vdef_cnt++;
- if (is_gimple_call (stmt))
- maybe_warn_pass_by_reference (stmt, wlims);
+ if (gcall *call = dyn_cast <gcall *> (stmt))
+ maybe_warn_pass_by_reference (call, wlims);
else if (gimple_assign_load_p (stmt)
&& gimple_has_location (stmt))
{
@@ -1345,21 +1350,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 +1532,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 +1732,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);