On Thu, 6 Dec 2018, Jakub Jelinek wrote: > On Thu, Dec 06, 2018 at 10:05:15AM +0100, Richard Biener wrote: > > Note I wonder if with -fwrapv-pointer NULL automatically becomes a > > valid address? Or is only wrapping around half of the address > > space UB? > > Hadn't thought about -fwrapv-pointer, I guess we (especially with > -fno-delete-null-pointer-checks) need to be even more conservative in that > case. > > Furthermore, I've discovered that the ADDR_EXPR of MEM_REF case actually > uses get_base_address and therefore the offset on MEM_REF is just one of the > many possible offsets in the play. > > So, this patch punts for -fwrapv-pointer in some further cases, and > adjusts the vr-values.c ADDR_EXPR handling code so that it sums up all 2 or > 3 offsets together and looks at the resulting sign. If > -fdelete-null-pointer-checks -fno-wrapv-pointer, it does what it did before > in tree-vrp.c and in vr-values.c is even more aggressive than before, as in > even if the base pointer is varying etc., if the sum of all the offsets > is provably non-zero, the result is non-NULL. For > -fno-delete-null-pointer-checks -fno-wrapv-pointer it does this only if the > resulting offset is positive. > > Does this look ok?
Little bit more expensive than before but OK. Thanks, Richard. > 2018-12-06 Jakub Jelinek <ja...@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. > > * gcc.dg/tree-ssa/pr88367.c: New test. > > --- gcc/tree-vrp.c.jj 2018-12-06 11:19:24.170939864 +0100 > +++ gcc/tree-vrp.c 2018-12-06 11:50:12.104711210 +0100 > @@ -1673,9 +1673,26 @@ extract_range_from_binary_expr (value_ra > 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); > --- gcc/vr-values.c.jj 2018-12-06 11:19:23.550950006 +0100 > +++ gcc/vr-values.c 2018-12-06 12:59:28.269999920 +0100 > @@ -297,14 +297,48 @@ vr_values::vrp_stmt_computes_nonzero (gi > && 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; > } > } > --- gcc/testsuite/gcc.dg/tree-ssa/pr88367.c.jj 2018-12-06 > 11:46:51.915985811 +0100 > +++ gcc/testsuite/gcc.dg/tree-ssa/pr88367.c 2018-12-06 13:00:14.692248340 > +0100 > @@ -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 (); > +} > > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)