On Fri, Nov 17, 2017 at 7:56 AM, Richard Biener <richard.guent...@gmail.com> wrote: > On Sat, Nov 11, 2017 at 12:44 AM, Marc Glisse <marc.gli...@inria.fr> wrote: >> Adding some random cc: to people who might be affected. Hopefully I am not >> breaking any of your stuff... >> >> Ulrich Weigand (address space) >> Ilya Enkovich (pointer bound check) >> DJ Delorie (target with 24-bit partial mode pointer) >> >> If you want to give it a try, or just take a quick look to check that you >> are obviously not affected, that would be nice, but don't feel forced. >> >> Here is an updated version of the patch, with just a few more >> transformations in match.pd, to match some MINUS_EXPR optimizations I missed >> the first time: -(A-B), X-Z<Y-Z, (X-Z)-(Y-Z), Z-X<Z-Y, (Z-X)-(Z-Y), >> (A-B)+(C-A) >> >> The exact undefined-behavior status should probably be clarified more. >> First, I'd like to say that POINTER_DIFF_EXPR may only take 2 pointers into >> the same "object" (like in C/C++), so they differ by at most half the size >> of the address space, and a-b is not allowed to be the minimum negative >> value (so I can safely use b-a), and if we compute a-b and b-c, then a and c >> are in the same object so I can safely compute a-c, etc. Second, we probably >> need modes without undefined behavior, wrapping with either -fwrapv or a new >> -fwrapp, or sanitized. For the sanitized version, we could keep using >> POINTER_DIFF_EXPR and check TYPE_OVERFLOW_SANITIZED on the pointer type as >> we currently do for integers. For wrapping, either we say that >> POINTER_DIFF_EXPR has wrapping semantics when that option is in effect, or >> we do not use POINTER_DIFF_EXPR and instead cast to unsigned before applying >> a MINUS_EXPR (my preference). > > CCing C/C++ FE folks as well. > > + /* It is better if the caller provides the return type. */ > + if (code == POINTER_DIFF_EXPR) > + { > + offset_int res = wi::sub (wi::to_offset (arg1), > + wi::to_offset (arg2)); > + return force_fit_type (signed_type_for (TREE_TYPE (arg1)), res, 1, > + TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)); > + } > + > > there's an overload that provides the type... (we should probably go > over all callers > and use that). There is already a folding that is only done when the type is > available. So I'd simply remove the above from the non-type overload > handling. > What breaks then? > > With the patch it's of course somewhat ugly in that we need to deal with both > MINUS_EXPR on pointers and POINTER_DIFF_EXPR - at least that's what > > + case POINTER_DIFF_EXPR: > case MINUS_EXPR: > + /* Fold &a[i] - &a[j] to i-j. */ > + if (TREE_CODE (arg0) == ADDR_EXPR > + && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF > + && TREE_CODE (arg1) == ADDR_EXPR > + && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF) > + { > + tree tem = fold_addr_of_array_ref_difference (loc, type, > + TREE_OPERAND (arg0, > 0), > + TREE_OPERAND (arg1, > 0), > + code > + == POINTER_DIFF_EXPR); > > suggests. But is that really so? The FEs today should never build > a MINUS_EXPR with pointer operands and your patch also doesn't. > I suppose we only arrive above because STRIP_NOPS strips the > pointer to integer conversion? > > + case POINTER_DIFF_EXPR: > + if (!POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 0))) > + || !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 1)))) > + { > + error ("invalid operand to pointer diff, operand is not a pointer"); > + return t; > + } > + CHECK_OP (0, "invalid operand to pointer diff"); > + CHECK_OP (1, "invalid operand to pointer diff"); > + break; > > can you add > || TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE > || TYPE_UNSIGNED (TREE_TYPE (t)) > > ? Note that if the precision of the pointer type arguments are not equal to > the > precision of the return value then foldings like > > (simplify > + (plus:c (pointer_diff @0 @1) (pointer_diff @2 @0)) > + (if (TYPE_OVERFLOW_UNDEFINED (type) > + && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0))) > + (pointer_diff @2 @1))) > > might not be correct as we drop a possible truncation here. Shall we > require (and document) that the result of the pointer difference in > a POINTER_DIFF_EXPR has to be representable in the type of the > expression, otherwise > the behavior is undefined? Shall we allow an unsigned return type for > differences known to be representable? Probably not... Does the behavior > depend on TYPE_OVERFLOW_UNDEFINED? It would be nice to amend > the generic.texi docs somewhat here. > > Ah, the gimple checking adds some more bits here that clarify things: > > + case POINTER_DIFF_EXPR: > + { > + if (!POINTER_TYPE_P (rhs1_type) > + || !POINTER_TYPE_P (rhs2_type) > + || !types_compatible_p (rhs1_type, rhs2_type) > + || TREE_CODE (lhs_type) != INTEGER_TYPE > + || TYPE_UNSIGNED (lhs_type) > + || TYPE_PRECISION (lhs_type) != TYPE_PRECISION (rhs1_type)) > + { > + error ("type mismatch in pointer diff expression"); > + debug_generic_stmt (lhs_type); > + debug_generic_stmt (rhs1_type); > + debug_generic_stmt (rhs2_type); > + return true; > + } > > > I think the patch is ok for trunk, the FE bits should get approval > from their maintainers. > Joseph may have an idea about the address-space issue. > > With this in place we should be able to fix some of the issues Jakub ran into > with pointer sanitizing? > > Also with this in place it would be nice to do the corresponding adjustment to > POINTER_PLUS_EXPR, that is, require a _signed_ offset type that matches > the precision of the other argument. > > Richard. > >> >> >> On Sat, 28 Oct 2017, Marc Glisse wrote: >> >>> Hello, >>> >>> first, if you are doing anything unusual with pointers (address spaces, >>> pointer/sizetype with weird sizes, instrumentation, etc), it would be great >>> if you could give this patch a try. It was bootstrapped and regtested on >>> powerpc64le-unknown-linux-gnu (gcc112), and a slightly older version on >>> x86_64-pc-linux-gnu (skylake laptop). I also built bare cross-compilers (no >>> sysroot or anything) for avr, m32c, alpha64-vms, s390-linux, and visium to >>> check that on trivial examples it behaves as expected (by the way, m32c >>> seems broken for unrelated reasons at the moment), but I wouldn't count that >>> as complete testing. >>> >>> This was previously discussed in the thread "Fix pointer diff (was: >>> -fsanitize=pointer-overflow support (PR sanitizer/80998))" ( >>> https://gcc.gnu.org/ml/gcc-patches/2017-10/msg02128.html for the latest >>> message). >>> >>> Front-ends other than C/C++ can be changed later (I took a quick look at >>> fortran and ada, but they are way too unfamiliar to me), I did not remove >>> any handling for the other representations. >>> >>> 2017-10-28 Marc Glisse <marc.gli...@inria.fr> >>> >>> gcc/cp/ >>> * constexpr.c (cxx_eval_constant_expression, >>> potential_constant_expression_1): Handle POINTER_DIFF_EXPR. >>> * cp-gimplify.c (cp_fold): Likewise. >>> * error.c (dump_expr): Likewise. >>> * typeck.c (cp_build_binary_op): Likewise.
It's not clear to me that cp_build_binary_op needs to handle POINTER_DIFF_EXPR, it should get MINUS_EXPR and produce POINTER_DIFF_EXPR. >>> * tree.def: New tree code POINTER_DIFF_EXPR. The comment might mention that the value is the same for all pointer types, not divided by the size of the pointed-to type. Jason