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>
PR tree-optimization/71575

View File

@ -206,6 +206,124 @@ isolate_path (basic_block bb, basic_block 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
the value of the PHI node implies the statement is erroneous.
@ -243,11 +361,6 @@ find_implicit_erroneous_behavior (void)
gphi *phi = si.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
arguments are NULL.
@ -315,29 +428,12 @@ find_implicit_erroneous_behavior (void)
if (gimple_bb (use_stmt) != bb)
continue;
bool by_dereference
= infer_nonnull_range_by_dereference (use_stmt, lhs);
location_t loc = gimple_location (use_stmt)
? gimple_location (use_stmt)
: gimple_phi_arg_location (phi, i);
if (by_dereference
|| infer_nonnull_range_by_attribute (use_stmt, lhs))
if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc))
{
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,
use_stmt, lhs, false);
@ -383,29 +479,8 @@ find_explicit_erroneous_behavior (void)
{
gimple *stmt = gsi_stmt (si);
/* 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 (stmt_uses_0_or_null_in_undefined_way (stmt))
{
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);
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>
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"} } */