aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple.c
diff options
context:
space:
mode:
authorJeff Law <law@redhat.com>2013-11-05 12:47:44 -0700
committerJeff Law <law@gcc.gnu.org>2013-11-05 12:47:44 -0700
commit8fdc414d439bc7148e079d27220e597b3b602a47 (patch)
treefaf2cabbd865647a82ca5248eea0cae3bb79f870 /gcc/gimple.c
parent50fae5a679990a4bba7dc30de21e6d4132d778fb (diff)
downloadgcc-8fdc414d439bc7148e079d27220e597b3b602a47.zip
gcc-8fdc414d439bc7148e079d27220e597b3b602a47.tar.gz
gcc-8fdc414d439bc7148e079d27220e597b3b602a47.tar.bz2
Makefile.in (OBJS): Add gimple-ssa-isolate-paths.o
* Makefile.in (OBJS): Add gimple-ssa-isolate-paths.o * common.opt (-fisolate-erroneous-paths): Add option and documentation. * gimple-ssa-isolate-paths.c: New file. * gimple.c (check_loadstore): New function. (infer_nonnull_range): Moved into gimple.c from tree-vrp.c Verify OP is in the argument list and the argument corresponding to OP is a pointer type. Use operand_equal_p rather than pointer equality when testing if OP is on the nonnull list. Use check_loadstore rather than count_ptr_derefs. Handle GIMPLE_RETURN statements. * tree-vrp.c (infer_nonnull_range): Remove. * gimple.h (infer_nonnull_range): Declare. * opts.c (default_options_table): Add * OPT_fisolate_erroneous_paths. * passes.def: Add pass_isolate_erroneous_paths. * timevar.def (TV_ISOLATE_ERRONEOUS_PATHS): New timevar. * tree-pass.h (make_pass_isolate_erroneous_paths): Declare. * tree-ssa.c (struct count_ptr_d): Remove. (count_ptr_derefs, count_uses_and_derefs): Remove. * tree-ssa.h (count_uses_and_derefs): Remove. * gcc.dg/pr38984.c: Add -fno-isolate-erroneous-paths. * gcc.dg/tree-ssa/isolate-1.c: New test. * gcc.dg/tree-ssa/isolate-2.c: New test. * gcc.dg/tree-ssa/isolate-3.c: New test. * gcc.dg/tree-ssa/isolate-4.c: New test. From-SVN: r204414
Diffstat (limited to 'gcc/gimple.c')
-rw-r--r--gcc/gimple.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 4839f3e..55dd091 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -3347,3 +3347,84 @@ nonfreeing_call_p (gimple call)
return false;
}
+
+/* Callback for walk_stmt_load_store_ops.
+
+ Return TRUE if OP will dereference the tree stored in DATA, FALSE
+ otherwise.
+
+ This routine only makes a superficial check for a dereference. Thus
+ it must only be used if it is safe to return a false negative. */
+static bool
+check_loadstore (gimple stmt ATTRIBUTE_UNUSED, tree op, void *data)
+{
+ if ((TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF)
+ && operand_equal_p (TREE_OPERAND (op, 0), (tree)data, 0))
+ return true;
+ return false;
+}
+
+/* If OP can be inferred to be non-zero after STMT executes, return true. */
+
+bool
+infer_nonnull_range (gimple stmt, tree op)
+{
+ /* We can only assume that a pointer dereference will yield
+ non-NULL if -fdelete-null-pointer-checks is enabled. */
+ if (!flag_delete_null_pointer_checks
+ || !POINTER_TYPE_P (TREE_TYPE (op))
+ || gimple_code (stmt) == GIMPLE_ASM)
+ return false;
+
+ if (walk_stmt_load_store_ops (stmt, (void *)op,
+ check_loadstore, check_loadstore))
+ return true;
+
+ if (is_gimple_call (stmt) && !gimple_call_internal_p (stmt))
+ {
+ tree fntype = gimple_call_fntype (stmt);
+ tree attrs = TYPE_ATTRIBUTES (fntype);
+ for (; attrs; attrs = TREE_CHAIN (attrs))
+ {
+ attrs = lookup_attribute ("nonnull", attrs);
+
+ /* If "nonnull" wasn't specified, we know nothing about
+ the argument. */
+ if (attrs == NULL_TREE)
+ return false;
+
+ /* If "nonnull" applies to all the arguments, then ARG
+ is non-null if it's in the argument list. */
+ if (TREE_VALUE (attrs) == NULL_TREE)
+ {
+ for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++)
+ {
+ if (operand_equal_p (op, gimple_call_arg (stmt, i), 0)
+ && POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (stmt, i))))
+ return true;
+ }
+ return false;
+ }
+
+ /* Now see if op appears in the nonnull list. */
+ for (tree t = TREE_VALUE (attrs); t; t = TREE_CHAIN (t))
+ {
+ int idx = TREE_INT_CST_LOW (TREE_VALUE (t)) - 1;
+ tree arg = gimple_call_arg (stmt, idx);
+ if (operand_equal_p (op, arg, 0))
+ return true;
+ }
+ }
+ }
+
+ /* If this function is marked as returning non-null, then we can
+ infer OP is non-null if it is used in the return statement. */
+ if (gimple_code (stmt) == GIMPLE_RETURN
+ && gimple_return_retval (stmt)
+ && operand_equal_p (gimple_return_retval (stmt), op, 0)
+ && lookup_attribute ("returns_nonnull",
+ TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
+ return true;
+
+ return false;
+}