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>
|
||||
|
||||
PR tree-optimization/71575
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
19
gcc/testsuite/gcc.dg/tree-ssa/isolate-6.c
Normal file
19
gcc/testsuite/gcc.dg/tree-ssa/isolate-6.c
Normal 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"} } */
|
||||
|
15
gcc/testsuite/gcc.dg/tree-ssa/isolate-7.c
Normal file
15
gcc/testsuite/gcc.dg/tree-ssa/isolate-7.c
Normal 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"} } */
|
||||
|
Loading…
Reference in New Issue
Block a user