aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJeff Law <law@redhat.com>2016-11-11 09:00:47 -0700
committerJeff Law <law@gcc.gnu.org>2016-11-11 09:00:47 -0700
commit606f928d3805614e8d2307961198706ed9958a76 (patch)
tree4536e26f7282becf16c143a8e48ebf01f2a07b83 /gcc
parentbe2789903f67338ffa89ad26b056aae7571c850b (diff)
downloadgcc-606f928d3805614e8d2307961198706ed9958a76.zip
gcc-606f928d3805614e8d2307961198706ed9958a76.tar.gz
gcc-606f928d3805614e8d2307961198706ed9958a76.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/gimple-ssa-isolate-paths.c171
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/isolate-6.c19
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/isolate-7.c15
5 files changed, 173 insertions, 48 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5c0f897..65afc8a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/gimple-ssa-isolate-paths.c b/gcc/gimple-ssa-isolate-paths.c
index 9d2fc8a..84048d3 100644
--- a/gcc/gimple-ssa-isolate-paths.c
+++ b/gcc/gimple-ssa-isolate-paths.c
@@ -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));
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 53f27b9..6da1cd8 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-6.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-6.c
new file mode 100644
index 0000000..ec7c57a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/isolate-6.c
@@ -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"} } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-7.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-7.c
new file mode 100644
index 0000000..e63d5a0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/isolate-7.c
@@ -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"} } */
+