aboutsummaryrefslogtreecommitdiff
path: root/gcc/vr-values.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@gcc.gnu.org>2018-12-07 00:28:04 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2018-12-07 00:28:04 +0100
commitb8a003c16567ccecffce256a2b35c9210db933a4 (patch)
treecd2b1d9b89ff3acda5dd2a6f6fa1e668e192e7fe /gcc/vr-values.c
parentff8ba86f447546c57e26bfab2a3437f14d6f2595 (diff)
downloadgcc-b8a003c16567ccecffce256a2b35c9210db933a4.zip
gcc-b8a003c16567ccecffce256a2b35c9210db933a4.tar.gz
gcc-b8a003c16567ccecffce256a2b35c9210db933a4.tar.bz2
re PR tree-optimization/88367 (-fno-delete-null-pointer-checks doesn't work properly)
PR c/88367 * tree-vrp.c (extract_range_from_binary_expr): For POINTER_PLUS_EXPR with -fno-delete-null-pointer-checks, set_nonnull only if the pointer is non-NULL and offset is known to have most significant bit clear. * vr-values.c (vr_values::vrp_stmt_computes_nonzero): For ADDR_EXPR of MEM_EXPR, return true if the MEM_EXPR has non-zero offset with most significant bit clear. If offset does have most significant bit set and -fno-delete-null-pointer-checks, don't return true even if the base pointer is non-NULL. * gcc.dg/tree-ssa/pr88367.c: New test. From-SVN: r266878
Diffstat (limited to 'gcc/vr-values.c')
-rw-r--r--gcc/vr-values.c40
1 files changed, 37 insertions, 3 deletions
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index a0027c0..075ea84 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -297,14 +297,48 @@ vr_values::vrp_stmt_computes_nonzero (gimple *stmt)
&& gimple_assign_rhs_code (stmt) == ADDR_EXPR)
{
tree expr = gimple_assign_rhs1 (stmt);
- tree base = get_base_address (TREE_OPERAND (expr, 0));
+ poly_int64 bitsize, bitpos;
+ tree offset;
+ machine_mode mode;
+ int unsignedp, reversep, volatilep;
+ tree base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize,
+ &bitpos, &offset, &mode, &unsignedp,
+ &reversep, &volatilep);
if (base != NULL_TREE
&& TREE_CODE (base) == MEM_REF
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{
- value_range *vr = get_value_range (TREE_OPERAND (base, 0));
- if (!range_includes_zero_p (vr))
+ poly_offset_int off = 0;
+ bool off_cst = false;
+ if (offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST)
+ {
+ off = mem_ref_offset (base);
+ if (offset)
+ off += poly_offset_int::from (wi::to_poly_wide (offset),
+ SIGNED);
+ off <<= LOG2_BITS_PER_UNIT;
+ off += bitpos;
+ off_cst = true;
+ }
+ /* If &X->a is equal to X and X is ~[0, 0], the result is too.
+ For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't
+ allow going from non-NULL pointer to NULL. */
+ if ((off_cst && known_eq (off, 0))
+ || (flag_delete_null_pointer_checks
+ && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))))
+ {
+ value_range *vr = get_value_range (TREE_OPERAND (base, 0));
+ if (!range_includes_zero_p (vr))
+ return true;
+ }
+ /* If MEM_REF has a "positive" offset, consider it non-NULL
+ always, for -fdelete-null-pointer-checks also "negative"
+ ones. Punt for unknown offsets (e.g. variable ones). */
+ if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))
+ && off_cst
+ && known_ne (off, 0)
+ && (flag_delete_null_pointer_checks || known_gt (off, 0)))
return true;
}
}