gimple-ssa-isolate-paths.c (is_divmod_with_given_divisor): New function.
* gimple-ssa-isolate-paths.c (is_divmod_with_given_divisor): New function. (stmt_uses_name_in_undefined_way): New function, extracted from find_implicit_erroneous_behavior and extended for div/mod case. (stmt_uses_0_or_null_in_undefined_way): New function, extracted from find_explicit_erroneous_behavior and extended for div/mod case. (find_implicit_erroneous_behavior): Use new helper function. (find_explicit_erroneous_behavior): Use new helper function. * gcc.dg/tree-ssa/isolate-6.c: New test. * gcc.dg/tree-ssa/isolate-7.c: New test. From-SVN: r242075
This commit is contained in:
parent
be2789903f
commit
606f928d38
|
@ -1,3 +1,14 @@
|
||||||
|
2016-11-11 Jeff Law <law@redhat.com>
|
||||||
|
|
||||||
|
* gimple-ssa-isolate-paths.c (is_divmod_with_given_divisor): New
|
||||||
|
function.
|
||||||
|
(stmt_uses_name_in_undefined_way): New function, extracted from
|
||||||
|
find_implicit_erroneous_behavior and extended for div/mod case.
|
||||||
|
(stmt_uses_0_or_null_in_undefined_way): New function, extracted from
|
||||||
|
find_explicit_erroneous_behavior and extended for div/mod case.
|
||||||
|
(find_implicit_erroneous_behavior): Use new helper function.
|
||||||
|
(find_explicit_erroneous_behavior): Use new helper function.
|
||||||
|
|
||||||
2016-11-11 Richard Biener <rguenther@suse.de>
|
2016-11-11 Richard Biener <rguenther@suse.de>
|
||||||
|
|
||||||
PR tree-optimization/71575
|
PR tree-optimization/71575
|
||||||
|
|
|
@ -206,6 +206,124 @@ isolate_path (basic_block bb, basic_block duplicate,
|
||||||
return duplicate;
|
return duplicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return TRUE if STMT is a div/mod operation using DIVISOR as the divisor.
|
||||||
|
FALSE otherwise. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_divmod_with_given_divisor (gimple *stmt, tree divisor)
|
||||||
|
{
|
||||||
|
/* Only assignments matter. */
|
||||||
|
if (!is_gimple_assign (stmt))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check for every DIV/MOD expression. */
|
||||||
|
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
|
||||||
|
if (rhs_code == TRUNC_DIV_EXPR
|
||||||
|
|| rhs_code == FLOOR_DIV_EXPR
|
||||||
|
|| rhs_code == CEIL_DIV_EXPR
|
||||||
|
|| rhs_code == EXACT_DIV_EXPR
|
||||||
|
|| rhs_code == ROUND_DIV_EXPR
|
||||||
|
|| rhs_code == TRUNC_MOD_EXPR
|
||||||
|
|| rhs_code == FLOOR_MOD_EXPR
|
||||||
|
|| rhs_code == CEIL_MOD_EXPR
|
||||||
|
|| rhs_code == ROUND_MOD_EXPR)
|
||||||
|
{
|
||||||
|
/* Pointer equality is fine when DIVISOR is an SSA_NAME, but
|
||||||
|
not sufficient for constants which may have different types. */
|
||||||
|
if (operand_equal_p (gimple_assign_rhs2 (stmt), divisor, 0))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NAME is an SSA_NAME that we have already determined has the value 0 or NULL.
|
||||||
|
|
||||||
|
Return TRUE if USE_STMT uses NAME in a way where a 0 or NULL value results
|
||||||
|
in undefined behavior, FALSE otherwise
|
||||||
|
|
||||||
|
LOC is used for issuing diagnostics. This case represents potential
|
||||||
|
undefined behavior exposed by path splitting and that's reflected in
|
||||||
|
the diagnostic. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
stmt_uses_name_in_undefined_way (gimple *use_stmt, tree name, location_t loc)
|
||||||
|
{
|
||||||
|
/* If we are working with a non pointer type, then see
|
||||||
|
if this use is a DIV/MOD operation using NAME as the
|
||||||
|
divisor. */
|
||||||
|
if (!POINTER_TYPE_P (TREE_TYPE (name)))
|
||||||
|
{
|
||||||
|
if (!flag_non_call_exceptions)
|
||||||
|
return is_divmod_with_given_divisor (use_stmt, name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NAME is a pointer, so see if it's used in a context where it must
|
||||||
|
be non-NULL. */
|
||||||
|
bool by_dereference
|
||||||
|
= infer_nonnull_range_by_dereference (use_stmt, name);
|
||||||
|
|
||||||
|
if (by_dereference
|
||||||
|
|| infer_nonnull_range_by_attribute (use_stmt, name))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (by_dereference)
|
||||||
|
{
|
||||||
|
warning_at (loc, OPT_Wnull_dereference,
|
||||||
|
"potential null pointer dereference");
|
||||||
|
if (!flag_isolate_erroneous_paths_dereference)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!flag_isolate_erroneous_paths_attribute)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return TRUE if USE_STMT uses 0 or NULL in a context which results in
|
||||||
|
undefined behavior, FALSE otherwise.
|
||||||
|
|
||||||
|
These cases are explicit in the IL. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
stmt_uses_0_or_null_in_undefined_way (gimple *stmt)
|
||||||
|
{
|
||||||
|
if (!flag_non_call_exceptions
|
||||||
|
&& is_divmod_with_given_divisor (stmt, integer_zero_node))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* By passing null_pointer_node, we can use the
|
||||||
|
infer_nonnull_range functions to detect explicit NULL
|
||||||
|
pointer dereferences and other uses where a non-NULL
|
||||||
|
value is required. */
|
||||||
|
|
||||||
|
bool by_dereference
|
||||||
|
= infer_nonnull_range_by_dereference (stmt, null_pointer_node);
|
||||||
|
if (by_dereference
|
||||||
|
|| infer_nonnull_range_by_attribute (stmt, null_pointer_node))
|
||||||
|
{
|
||||||
|
if (by_dereference)
|
||||||
|
{
|
||||||
|
location_t loc = gimple_location (stmt);
|
||||||
|
warning_at (loc, OPT_Wnull_dereference,
|
||||||
|
"null pointer dereference");
|
||||||
|
if (!flag_isolate_erroneous_paths_dereference)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!flag_isolate_erroneous_paths_attribute)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Look for PHI nodes which feed statements in the same block where
|
/* Look for PHI nodes which feed statements in the same block where
|
||||||
the value of the PHI node implies the statement is erroneous.
|
the value of the PHI node implies the statement is erroneous.
|
||||||
|
|
||||||
|
@ -243,11 +361,6 @@ find_implicit_erroneous_behavior (void)
|
||||||
gphi *phi = si.phi ();
|
gphi *phi = si.phi ();
|
||||||
tree lhs = gimple_phi_result (phi);
|
tree lhs = gimple_phi_result (phi);
|
||||||
|
|
||||||
/* If the result is not a pointer, then there is no need to
|
|
||||||
examine the arguments. */
|
|
||||||
if (!POINTER_TYPE_P (TREE_TYPE (lhs)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* PHI produces a pointer result. See if any of the PHI's
|
/* PHI produces a pointer result. See if any of the PHI's
|
||||||
arguments are NULL.
|
arguments are NULL.
|
||||||
|
|
||||||
|
@ -315,29 +428,12 @@ find_implicit_erroneous_behavior (void)
|
||||||
if (gimple_bb (use_stmt) != bb)
|
if (gimple_bb (use_stmt) != bb)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool by_dereference
|
|
||||||
= infer_nonnull_range_by_dereference (use_stmt, lhs);
|
|
||||||
|
|
||||||
if (by_dereference
|
|
||||||
|| infer_nonnull_range_by_attribute (use_stmt, lhs))
|
|
||||||
{
|
|
||||||
location_t loc = gimple_location (use_stmt)
|
location_t loc = gimple_location (use_stmt)
|
||||||
? gimple_location (use_stmt)
|
? gimple_location (use_stmt)
|
||||||
: gimple_phi_arg_location (phi, i);
|
: gimple_phi_arg_location (phi, i);
|
||||||
|
|
||||||
if (by_dereference)
|
if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc))
|
||||||
{
|
{
|
||||||
warning_at (loc, OPT_Wnull_dereference,
|
|
||||||
"potential null pointer dereference");
|
|
||||||
if (!flag_isolate_erroneous_paths_dereference)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!flag_isolate_erroneous_paths_attribute)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
duplicate = isolate_path (bb, duplicate, e,
|
duplicate = isolate_path (bb, duplicate, e,
|
||||||
use_stmt, lhs, false);
|
use_stmt, lhs, false);
|
||||||
|
|
||||||
|
@ -383,29 +479,8 @@ find_explicit_erroneous_behavior (void)
|
||||||
{
|
{
|
||||||
gimple *stmt = gsi_stmt (si);
|
gimple *stmt = gsi_stmt (si);
|
||||||
|
|
||||||
/* By passing null_pointer_node, we can use the
|
if (stmt_uses_0_or_null_in_undefined_way (stmt))
|
||||||
infer_nonnull_range functions to detect explicit NULL
|
|
||||||
pointer dereferences and other uses where a non-NULL
|
|
||||||
value is required. */
|
|
||||||
|
|
||||||
bool by_dereference
|
|
||||||
= infer_nonnull_range_by_dereference (stmt, null_pointer_node);
|
|
||||||
if (by_dereference
|
|
||||||
|| infer_nonnull_range_by_attribute (stmt, null_pointer_node))
|
|
||||||
{
|
{
|
||||||
if (by_dereference)
|
|
||||||
{
|
|
||||||
warning_at (gimple_location (stmt), OPT_Wnull_dereference,
|
|
||||||
"null pointer dereference");
|
|
||||||
if (!flag_isolate_erroneous_paths_dereference)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!flag_isolate_erroneous_paths_attribute)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
insert_trap (&si, null_pointer_node);
|
insert_trap (&si, null_pointer_node);
|
||||||
bb = gimple_bb (gsi_stmt (si));
|
bb = gimple_bb (gsi_stmt (si));
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2016-11-11 Jeff Law <law@redhat.com>
|
||||||
|
|
||||||
|
* gcc.dg/tree-ssa/isolate-6.c: New test.
|
||||||
|
* gcc.dg/tree-ssa/isolate-7.c: New test.
|
||||||
|
|
||||||
2016-11-11 Bin Cheng <bin.cheng@arm.com>
|
2016-11-11 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
PR testsuite/78292
|
PR testsuite/78292
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
|
||||||
|
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
z ()
|
||||||
|
{
|
||||||
|
return x ? y : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lower_for (int j)
|
||||||
|
{
|
||||||
|
return j % z ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O2 -fdump-tree-isolate-paths" } */
|
||||||
|
|
||||||
|
extern int oof ();
|
||||||
|
extern int x;
|
||||||
|
_Bool
|
||||||
|
gcd_of_steps_may_divide_p ()
|
||||||
|
{
|
||||||
|
long cd = 0, val;
|
||||||
|
if (x)
|
||||||
|
cd = oof ();
|
||||||
|
return val % cd == 0;
|
||||||
|
}
|
||||||
|
/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "isolate-paths"} } */
|
||||||
|
|
Loading…
Reference in New Issue