From 606f928d3805614e8d2307961198706ed9958a76 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Fri, 11 Nov 2016 09:00:47 -0700 Subject: [PATCH] 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 --- gcc/ChangeLog | 11 ++ gcc/gimple-ssa-isolate-paths.c | 171 ++++++++++++++++------ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.dg/tree-ssa/isolate-6.c | 19 +++ gcc/testsuite/gcc.dg/tree-ssa/isolate-7.c | 15 ++ 5 files changed, 173 insertions(+), 48 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/isolate-6.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/isolate-7.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5c0f8976aaf..65afc8a0947 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2016-11-11 Jeff Law + + * 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 PR tree-optimization/71575 diff --git a/gcc/gimple-ssa-isolate-paths.c b/gcc/gimple-ssa-isolate-paths.c index 9d2fc8a30c0..84048d3daf9 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 53f27b93ed6..6da1cd87cc9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-11-11 Jeff Law + + * gcc.dg/tree-ssa/isolate-6.c: New test. + * gcc.dg/tree-ssa/isolate-7.c: New test. + 2016-11-11 Bin Cheng 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 00000000000..ec7c57ac56c --- /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 00000000000..e63d5a032c1 --- /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"} } */ +