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
This commit is contained in:
parent
ff8ba86f44
commit
b8a003c165
5 changed files with 104 additions and 7 deletions
|
@ -1,4 +1,16 @@
|
|||
2018-12-06 Alexandre Oliva <aoliva@redhat.com>
|
||||
2018-12-07 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
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.
|
||||
|
||||
2018-12-06 Alexandre Oliva <aoliva@redhat.com>
|
||||
|
||||
* cselib.c (cselib_record_sets): Skip strict low part sets
|
||||
with NULL src_elt.
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
2018-12-07 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c/88367
|
||||
* gcc.dg/tree-ssa/pr88367.c: New test.
|
||||
|
||||
PR c++/87506
|
||||
* g++.dg/cpp0x/constexpr-87506.C: New test.
|
||||
|
||||
|
|
31
gcc/testsuite/gcc.dg/tree-ssa/pr88367.c
Normal file
31
gcc/testsuite/gcc.dg/tree-ssa/pr88367.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* PR c/88367 */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-fno-delete-null-pointer-checks -O2 -fdump-tree-optimized -fno-wrapv-pointer" } */
|
||||
/* { dg-final { scan-tree-dump-not "link_error \\(\\);" "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-times "bar \\(\\);" 2 "optimized" } } */
|
||||
|
||||
void bar (void);
|
||||
void link_error (void);
|
||||
|
||||
void
|
||||
foo (char *p)
|
||||
{
|
||||
if (!p)
|
||||
return;
|
||||
p += 3;
|
||||
if (!p)
|
||||
link_error ();
|
||||
p -= 6;
|
||||
if (!p)
|
||||
bar ();
|
||||
}
|
||||
|
||||
void
|
||||
baz (char *p)
|
||||
{
|
||||
if (!p)
|
||||
return;
|
||||
p -= 6;
|
||||
if (!p)
|
||||
bar ();
|
||||
}
|
|
@ -1673,9 +1673,26 @@ extract_range_from_binary_expr (value_range_base *vr,
|
|||
else if (code == POINTER_PLUS_EXPR)
|
||||
{
|
||||
/* For pointer types, we are really only interested in asserting
|
||||
whether the expression evaluates to non-NULL. */
|
||||
if (!range_includes_zero_p (&vr0)
|
||||
|| !range_includes_zero_p (&vr1))
|
||||
whether the expression evaluates to non-NULL.
|
||||
With -fno-delete-null-pointer-checks we need to be more
|
||||
conservative. As some object might reside at address 0,
|
||||
then some offset could be added to it and the same offset
|
||||
subtracted again and the result would be NULL.
|
||||
E.g.
|
||||
static int a[12]; where &a[0] is NULL and
|
||||
ptr = &a[6];
|
||||
ptr -= 6;
|
||||
ptr will be NULL here, even when there is POINTER_PLUS_EXPR
|
||||
where the first range doesn't include zero and the second one
|
||||
doesn't either. As the second operand is sizetype (unsigned),
|
||||
consider all ranges where the MSB could be set as possible
|
||||
subtractions where the result might be NULL. */
|
||||
if ((!range_includes_zero_p (&vr0)
|
||||
|| !range_includes_zero_p (&vr1))
|
||||
&& !TYPE_OVERFLOW_WRAPS (expr_type)
|
||||
&& (flag_delete_null_pointer_checks
|
||||
|| (range_int_cst_p (&vr1)
|
||||
&& !tree_int_cst_sign_bit (vr1.max ()))))
|
||||
vr->set_nonnull (expr_type);
|
||||
else if (range_is_null (&vr0) && range_is_null (&vr1))
|
||||
vr->set_null (expr_type);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue