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:
Jeff Law 2016-11-11 09:00:47 -07:00 committed by Jeff Law
parent be2789903f
commit 606f928d38
5 changed files with 173 additions and 48 deletions

View File

@ -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

View File

@ -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 location_t loc = gimple_location (use_stmt)
= infer_nonnull_range_by_dereference (use_stmt, lhs); ? gimple_location (use_stmt)
: gimple_phi_arg_location (phi, i);
if (by_dereference if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc))
|| infer_nonnull_range_by_attribute (use_stmt, lhs))
{ {
location_t loc = gimple_location (use_stmt)
? gimple_location (use_stmt)
: gimple_phi_arg_location (phi, i);
if (by_dereference)
{
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));

View File

@ -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

View File

@ -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"} } */

View File

@ -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"} } */