gimple-ssa-isolate-paths.c (is_divmod_with_given_divisor): New function.
authorJeff Law <law@redhat.com>
Fri, 11 Nov 2016 16:00:47 +0000 (09:00 -0700)
committerJeff Law <law@gcc.gnu.org>
Fri, 11 Nov 2016 16:00:47 +0000 (09:00 -0700)
* 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

gcc/ChangeLog
gcc/gimple-ssa-isolate-paths.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/isolate-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/isolate-7.c [new file with mode: 0644]

index 5c0f8976aaf417cac1916ede9640c759cf9c480b..65afc8a0947753a7a396ba336926662a2c65b41f 100644 (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
index 9d2fc8a30c0de4759da7bf990262fc7f9a553cac..84048d3daf9ec382fd335f671045a19b22b2cb9b 100644 (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));
 
index 53f27b93ed6c080ce7dda51e8a983fb7aca1c255..6da1cd87cc91b24a22a4fc27559b992510c2f5f1 100644 (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
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 (file)
index 0000000..ec7c57a
--- /dev/null
@@ -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 (file)
index 0000000..e63d5a0
--- /dev/null
@@ -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"} } */
+