New POINTER_DIFF_EXPR
authorMarc Glisse <marc.glisse@inria.fr>
Tue, 21 Nov 2017 18:23:56 +0000 (19:23 +0100)
committerMarc Glisse <glisse@gcc.gnu.org>
Tue, 21 Nov 2017 18:23:56 +0000 (18:23 +0000)
2017-11-21  Marc Glisse  <marc.glisse@inria.fr>

gcc/c/
* c-fold.c (c_fully_fold_internal): Handle POINTER_DIFF_EXPR.
* c-typeck.c (pointer_diff): Use POINTER_DIFF_EXPR.

gcc/c-family/
* c-pretty-print.c (pp_c_additive_expression,
c_pretty_printer::expression): Handle POINTER_DIFF_EXPR.

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 (pointer_diff): Use POINTER_DIFF_EXPR.

gcc/
* doc/generic.texi: Document POINTER_DIFF_EXPR, update
POINTER_PLUS_EXPR.
* cfgexpand.c (expand_debug_expr): Handle POINTER_DIFF_EXPR.
* expr.c (expand_expr_real_2): Likewise.
* fold-const.c (const_binop, fold_addr_of_array_ref_difference,
fold_binary_loc): Likewise.
* match.pd (X-X, P+(Q-P), &D-P, (P+N)-P, P-(P+N), (P+M)-(P+N),
P-Q==0, -(A-B), X-Z<Y-Z, (X-Z)-(Y-Z), Z-X<Z-Y, (Z-X)-(Z-Y),
(A-B)+(C-A)): New transformations for POINTER_DIFF_EXPR, based on
MINUS_EXPR transformations.
* optabs-tree.c (optab_for_tree_code): Handle POINTER_DIFF_EXPR.
* tree-cfg.c (verify_expr, verify_gimple_assign_binary): Likewise.
* tree-inline.c (estimate_operator_cost): Likewise.
* tree-pretty-print.c (dump_generic_node, op_code_prio,
op_symbol_code): Likewise.
* tree-vect-stmts.c (vectorizable_operation): Likewise.
* vr-values.c (extract_range_from_binary_expr): Likewise.
* varasm.c (initializer_constant_valid_p_1): Likewise.
* tree.def: New tree code POINTER_DIFF_EXPR.

From-SVN: r255021

24 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-pretty-print.c
gcc/c/ChangeLog
gcc/c/c-fold.c
gcc/c/c-typeck.c
gcc/cfgexpand.c
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-gimplify.c
gcc/cp/error.c
gcc/cp/typeck.c
gcc/doc/generic.texi
gcc/expr.c
gcc/fold-const.c
gcc/match.pd
gcc/optabs-tree.c
gcc/tree-cfg.c
gcc/tree-inline.c
gcc/tree-pretty-print.c
gcc/tree-vect-stmts.c
gcc/tree.def
gcc/varasm.c
gcc/vr-values.c

index e4c1a77..a34c125 100644 (file)
@@ -1,3 +1,25 @@
+2017-11-21  Marc Glisse  <marc.glisse@inria.fr>
+
+       * doc/generic.texi: Document POINTER_DIFF_EXPR, update
+       POINTER_PLUS_EXPR.
+       * cfgexpand.c (expand_debug_expr): Handle POINTER_DIFF_EXPR.
+       * expr.c (expand_expr_real_2): Likewise.
+       * fold-const.c (const_binop, fold_addr_of_array_ref_difference,
+       fold_binary_loc): Likewise.
+       * match.pd (X-X, P+(Q-P), &D-P, (P+N)-P, P-(P+N), (P+M)-(P+N),
+       P-Q==0, -(A-B), X-Z<Y-Z, (X-Z)-(Y-Z), Z-X<Z-Y, (Z-X)-(Z-Y),
+       (A-B)+(C-A)): New transformations for POINTER_DIFF_EXPR, based on
+       MINUS_EXPR transformations.
+       * optabs-tree.c (optab_for_tree_code): Handle POINTER_DIFF_EXPR.
+       * tree-cfg.c (verify_expr, verify_gimple_assign_binary): Likewise.
+       * tree-inline.c (estimate_operator_cost): Likewise.
+       * tree-pretty-print.c (dump_generic_node, op_code_prio,
+       op_symbol_code): Likewise.
+       * tree-vect-stmts.c (vectorizable_operation): Likewise.
+       * vr-values.c (extract_range_from_binary_expr): Likewise.
+       * varasm.c (initializer_constant_valid_p_1): Likewise.
+       * tree.def: New tree code POINTER_DIFF_EXPR.
+
 2017-11-21  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/i386/i386.md (*bswap<mode>2_movbe): Add
index 308a617..08d8cec 100644 (file)
@@ -1,3 +1,8 @@
+2017-11-21  Marc Glisse  <marc.glisse@inria.fr>
+
+       * c-pretty-print.c (pp_c_additive_expression,
+       c_pretty_printer::expression): Handle POINTER_DIFF_EXPR.
+
 2017-11-21  Jakub Jelinek  <jakub@redhat.com>
 
        * c-common.c (get_nonnull_operand): Use tree_to_uhwi.
index 0f48b9e..15e13ea 100644 (file)
@@ -1876,6 +1876,7 @@ pp_c_additive_expression (c_pretty_printer *pp, tree e)
     {
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       pp_c_additive_expression (pp, TREE_OPERAND (e, 0));
       pp_c_whitespace (pp);
@@ -2292,6 +2293,7 @@ c_pretty_printer::expression (tree e)
 
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       pp_c_additive_expression (this, e);
       break;
index 95b7718..a2773b0 100644 (file)
@@ -1,3 +1,8 @@
+2017-11-21  Marc Glisse  <marc.glisse@inria.fr>
+
+       * c-fold.c (c_fully_fold_internal): Handle POINTER_DIFF_EXPR.
+       * c-typeck.c (pointer_diff): Use POINTER_DIFF_EXPR.
+
 2017-11-20  David Malcolm  <dmalcolm@redhat.com>
 
        PR c/81404
index 6a6c716..8895462 100644 (file)
@@ -306,6 +306,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
     case MINUS_EXPR:
     case MULT_EXPR:
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case TRUNC_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case FLOOR_DIV_EXPR:
index 8a09ea2..7f85c6b 100644 (file)
@@ -3778,7 +3778,7 @@ parser_build_binary_op (location_t location, enum tree_code code,
 }
 \f
 /* Return a tree for the difference of pointers OP0 and OP1.
-   The resulting tree has type int.  */
+   The resulting tree has type ptrdiff_t.  */
 
 static tree
 pointer_diff (location_t loc, tree op0, tree op1)
@@ -3810,7 +3810,7 @@ pointer_diff (location_t loc, tree op0, tree op1)
       op1 = convert (common_type, op1);
     }
 
-  /* Determine integer type to perform computations in.  This will usually
+  /* Determine integer type result of the subtraction.  This will usually
      be the same as the result type (ptrdiff_t), but may need to be a wider
      type if pointers for the address space are wider than ptrdiff_t.  */
   if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0)))
@@ -3825,14 +3825,21 @@ pointer_diff (location_t loc, tree op0, tree op1)
     pedwarn (loc, OPT_Wpointer_arith,
             "pointer to a function used in subtraction");
 
-  /* First do the subtraction as integers;
-     then drop through to build the divide operator.
-     Do not do default conversions on the minus operator
-     in case restype is a short type.  */
+  /* First do the subtraction, then build the divide operator
+     and only convert at the very end.
+     Do not do default conversions in case restype is a short type.  */
+
+  /* POINTER_DIFF_EXPR requires a signed integer type of the same size as
+     pointers.  If some platform cannot provide that, or has a larger
+     ptrdiff_type to support differences larger than half the address
+     space, cast the pointers to some larger integer type and do the
+     computations in that type.  */
+  if (TYPE_PRECISION (inttype) > TYPE_PRECISION (TREE_TYPE (op0)))
+       op0 = build_binary_op (loc, MINUS_EXPR, convert (inttype, op0),
+                             convert (inttype, op1), false);
+  else
+    op0 = build2_loc (loc, POINTER_DIFF_EXPR, inttype, op0, op1);
 
-  op0 = build_binary_op (loc,
-                        MINUS_EXPR, convert (inttype, op0),
-                        convert (inttype, op1), false);
   /* This generates an error if op1 is pointer to incomplete type.  */
   if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
     error_at (loc, "arithmetic on pointer to an incomplete type");
index ca5d8db..a63b414 100644 (file)
@@ -4623,6 +4623,7 @@ expand_debug_expr (tree exp)
       return simplify_gen_binary (PLUS, mode, op0, op1);
 
     case MINUS_EXPR:
+    case POINTER_DIFF_EXPR:
       return simplify_gen_binary (MINUS, mode, op0, op1);
 
     case MULT_EXPR:
index db94034..8a6328a 100644 (file)
@@ -1,3 +1,11 @@
+2017-11-21  Marc Glisse  <marc.glisse@inria.fr>
+
+       * 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 (pointer_diff): Use POINTER_DIFF_EXPR.
+
 2017-11-21  Jakub Jelinek  <jakub@redhat.com>
 
        P0428R2 - familiar template syntax for generic lambdas
index 5eac64b..34a9c6b 100644 (file)
@@ -4336,6 +4336,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
 
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case PLUS_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
@@ -5590,6 +5591,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
         return true;
       }
 
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       want_rval = true;
       goto binary;
index 201a595..d597ed9 100644 (file)
@@ -2227,6 +2227,7 @@ cp_fold (tree x)
       /* FALLTHRU */
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
     case TRUNC_DIV_EXPR:
index 2537713..7125b88 100644 (file)
@@ -2227,6 +2227,10 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
       dump_binary_op (pp, "+", t, flags);
       break;
 
+    case POINTER_DIFF_EXPR:
+      dump_binary_op (pp, "-", t, flags);
+      break;
+
     case INIT_EXPR:
     case MODIFY_EXPR:
       dump_binary_op (pp, OVL_OP_INFO (true, NOP_EXPR)->name, t, flags);
index cb93cc3..8ba6a12 100644 (file)
@@ -5396,7 +5396,7 @@ static tree
 pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype,
              tsubst_flags_t complain)
 {
-  tree result;
+  tree result, inttype;
   tree restype = ptrdiff_type_node;
   tree target_type = TREE_TYPE (ptrtype);
 
@@ -5428,14 +5428,31 @@ pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype,
        return error_mark_node;
     }
 
-  /* First do the subtraction as integers;
-     then drop through to build the divide operator.  */
-
-  op0 = cp_build_binary_op (loc,
-                           MINUS_EXPR,
-                           cp_convert (restype, op0, complain),
-                           cp_convert (restype, op1, complain),
-                           complain);
+  /* Determine integer type result of the subtraction.  This will usually
+     be the same as the result type (ptrdiff_t), but may need to be a wider
+     type if pointers for the address space are wider than ptrdiff_t.  */
+  if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0)))
+    inttype = c_common_type_for_size (TYPE_PRECISION (TREE_TYPE (op0)), 0);
+  else
+    inttype = restype;
+
+  /* First do the subtraction, then build the divide operator
+     and only convert at the very end.
+     Do not do default conversions in case restype is a short type.  */
+
+  /* POINTER_DIFF_EXPR requires a signed integer type of the same size as
+     pointers.  If some platform cannot provide that, or has a larger
+     ptrdiff_type to support differences larger than half the address
+     space, cast the pointers to some larger integer type and do the
+     computations in that type.  */
+  if (TYPE_PRECISION (inttype) > TYPE_PRECISION (TREE_TYPE (op0)))
+    op0 = cp_build_binary_op (loc,
+                             MINUS_EXPR,
+                             cp_convert (inttype, op0, complain),
+                             cp_convert (inttype, op1, complain),
+                             complain);
+  else
+    op0 = build2_loc (loc, POINTER_DIFF_EXPR, inttype, op0, op1);
 
   /* This generates an error if op1 is a pointer to an incomplete type.  */
   if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
@@ -5461,9 +5478,9 @@ pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype,
 
   /* Do the division.  */
 
-  result = build2_loc (loc, EXACT_DIV_EXPR, restype, op0,
-                      cp_convert (restype, op1, complain));
-  return result;
+  result = build2_loc (loc, EXACT_DIV_EXPR, inttype, op0,
+                      cp_convert (inttype, op1, complain));
+  return cp_convert (restype, result, complain);
 }
 \f
 /* Construct and perhaps optimize a tree representation
index a51cfd6..b03970f 100644 (file)
@@ -1224,6 +1224,7 @@ the byte offset of the field, but should not be used directly; call
 @tindex TRUTH_OR_EXPR
 @tindex TRUTH_XOR_EXPR
 @tindex POINTER_PLUS_EXPR
+@tindex POINTER_DIFF_EXPR
 @tindex PLUS_EXPR
 @tindex MINUS_EXPR
 @tindex MULT_EXPR
@@ -1413,8 +1414,16 @@ always of @code{BOOLEAN_TYPE} or @code{INTEGER_TYPE}.
 @item POINTER_PLUS_EXPR
 This node represents pointer arithmetic.  The first operand is always
 a pointer/reference type.  The second operand is always an unsigned
-integer type compatible with sizetype.  This is the only binary
-arithmetic operand that can operate on pointer types.
+integer type compatible with sizetype.  This and POINTER_DIFF_EXPR are
+the only binary arithmetic operators that can operate on pointer types.
+
+@item POINTER_DIFF_EXPR
+This node represents pointer subtraction.  The two operands always
+have pointer/reference type.  It returns a signed integer of the same
+precision as the pointers.  The behavior is undefined if the difference
+of the two pointers, seen as infinite precision non-negative integers,
+does not fit in the result type.  The result does not depend on the
+pointer type, it is not divided by the size of the pointed-to type.
 
 @item PLUS_EXPR
 @itemx MINUS_EXPR
index c93d9f6..3341e94 100644 (file)
@@ -8555,6 +8555,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
       return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
 
     case MINUS_EXPR:
+    case POINTER_DIFF_EXPR:
     do_minus:
       /* For initializers, we are allowed to return a MINUS of two
         symbolic constants.  Here we handle all cases when both operands
index e9cd968..9fe3462 100644 (file)
@@ -1483,6 +1483,16 @@ const_binop (enum tree_code code, tree type, tree arg1, tree arg2)
        return build_complex (type, arg1, arg2);
       return NULL_TREE;
 
+    case POINTER_DIFF_EXPR:
+      if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST)
+       {
+         offset_int res = wi::sub (wi::to_offset (arg1),
+                                   wi::to_offset (arg2));
+         return force_fit_type (type, res, 1,
+                                TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2));
+       }
+      return NULL_TREE;
+
     case VEC_PACK_TRUNC_EXPR:
     case VEC_PACK_FIX_TRUNC_EXPR:
       {
@@ -8801,7 +8811,8 @@ fold_vec_perm (tree type, tree arg0, tree arg1, vec_perm_indices sel)
 
 static tree
 fold_addr_of_array_ref_difference (location_t loc, tree type,
-                                  tree aref0, tree aref1)
+                                  tree aref0, tree aref1,
+                                  bool use_pointer_diff)
 {
   tree base0 = TREE_OPERAND (aref0, 0);
   tree base1 = TREE_OPERAND (aref1, 0);
@@ -8813,14 +8824,20 @@ fold_addr_of_array_ref_difference (location_t loc, tree type,
   if ((TREE_CODE (base0) == ARRAY_REF
        && TREE_CODE (base1) == ARRAY_REF
        && (base_offset
-          = fold_addr_of_array_ref_difference (loc, type, base0, base1)))
+          = fold_addr_of_array_ref_difference (loc, type, base0, base1,
+                                               use_pointer_diff)))
       || (INDIRECT_REF_P (base0)
          && INDIRECT_REF_P (base1)
          && (base_offset
-               = fold_binary_loc (loc, MINUS_EXPR, type,
-                                  fold_convert (type, TREE_OPERAND (base0, 0)),
-                                  fold_convert (type,
-                                                TREE_OPERAND (base1, 0)))))
+               = use_pointer_diff
+                 ? fold_binary_loc (loc, POINTER_DIFF_EXPR, type,
+                                    TREE_OPERAND (base0, 0),
+                                    TREE_OPERAND (base1, 0))
+                 : fold_binary_loc (loc, MINUS_EXPR, type,
+                                    fold_convert (type,
+                                                  TREE_OPERAND (base0, 0)),
+                                    fold_convert (type,
+                                                  TREE_OPERAND (base1, 0)))))
       || operand_equal_p (base0, base1, OEP_ADDRESS_OF))
     {
       tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1));
@@ -9694,7 +9711,27 @@ fold_binary_loc (location_t loc,
 
       return NULL_TREE;
 
+    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);
+         if (tem)
+           return tem;
+       }
+
+      /* Further transformations are not for pointers.  */
+      if (code == POINTER_DIFF_EXPR)
+       return NULL_TREE;
+
       /* (-A) - B -> (-B) - A  where B is easily negated and we can swap.  */
       if (TREE_CODE (arg0) == NEGATE_EXPR
          && negate_expr_p (op1))
@@ -9752,19 +9789,6 @@ fold_binary_loc (location_t loc,
                                fold_convert_loc (loc, type, arg0),
                                negate_expr (op1));
 
-      /* 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));
-         if (tem)
-           return tem;
-       }
-
       /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the same or
         one.  Make sure the type is not saturating and has the signedness of
         the stripped operands, as fold_plusminus_mult_expr will re-associate.
index 0e21a0d..0949a9b 100644 (file)
@@ -124,6 +124,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (minus @0 @0)
  (if (!FLOAT_TYPE_P (type) || !HONOR_NANS (type))
   { build_zero_cst (type); }))
+(simplify
+ (pointer_diff @@0 @0)
+ { build_zero_cst (type); })
 
 (simplify
  (mult @0 integer_zerop@1)
@@ -1040,6 +1043,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
          && !HONOR_SIGN_DEPENDENT_ROUNDING (type)
          && !HONOR_SIGNED_ZEROS (type)))
   (minus @1 @0)))
+(simplify
+ (negate (pointer_diff @0 @1))
+ (if (TYPE_OVERFLOW_UNDEFINED (type))
+  (pointer_diff @1 @0)))
 
 /* A - B -> A + (-B) if B is easily negatable.  */
 (simplify
@@ -1342,6 +1349,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
           || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
    (op @0 @1))))
+/* And for pointers...  */
+(for op (simple_comparison)
+ (simplify
+  (op (pointer_diff@3 @0 @2) (pointer_diff @1 @2))
+  (if (!TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2)))
+   (op @0 @1))))
+(simplify
+ (minus (pointer_diff@3 @0 @2) (pointer_diff @1 @2))
+ (if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@3))
+      && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2)))
+  (pointer_diff @0 @1)))
 
 /* Z - X < Z - Y is the same as Y < X when there is no overflow.  */
 (for op (lt le ge gt)
@@ -1358,6 +1376,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
           || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
    (op @1 @0))))
+/* And for pointers...  */
+(for op (simple_comparison)
+ (simplify
+  (op (pointer_diff@3 @2 @0) (pointer_diff @2 @1))
+  (if (!TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2)))
+   (op @1 @0))))
+(simplify
+ (minus (pointer_diff@3 @2 @0) (pointer_diff @2 @1))
+ (if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@3))
+      && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@2)))
+  (pointer_diff @1 @0)))
 
 /* X + Y < Y is the same as X < 0 when there is no overflow.  */
 (for op (lt le gt ge)
@@ -1506,6 +1535,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && ((GIMPLE && useless_type_conversion_p (type, TREE_TYPE (@1)))
            || (GENERIC && type == TREE_TYPE (@1))))
    @1))
+(simplify
+  (pointer_plus @0 (convert?@2 (pointer_diff@3 @1 @@0)))
+  (if (TYPE_PRECISION (TREE_TYPE (@2)) >= TYPE_PRECISION (TREE_TYPE (@3)))
+   (convert @1)))
 
 /* Pattern match
      tem = (sizetype) ptr;
@@ -1532,6 +1565,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (with { HOST_WIDE_INT diff; }
    (if (ptr_difference_const (@0, @1, &diff))
     { build_int_cst_type (type, diff); }))))
+(simplify
+ (pointer_diff (convert?@2 ADDR_EXPR@0) (convert?@3 @1))
+ (if (tree_nop_conversion_p (TREE_TYPE(@2), TREE_TYPE (@0))
+      && tree_nop_conversion_p (TREE_TYPE(@3), TREE_TYPE (@1)))
+  (with { HOST_WIDE_INT diff; }
+   (if (ptr_difference_const (@0, @1, &diff))
+    { build_int_cst_type (type, diff); }))))
+(simplify
+ (pointer_diff (convert?@2 @0) (convert?@3 ADDR_EXPR@1))
+ (if (tree_nop_conversion_p (TREE_TYPE(@2), TREE_TYPE (@0))
+      && tree_nop_conversion_p (TREE_TYPE(@3), TREE_TYPE (@1)))
+  (with { HOST_WIDE_INT diff; }
+   (if (ptr_difference_const (@0, @1, &diff))
+    { build_int_cst_type (type, diff); }))))
 
 /* If arg0 is derived from the address of an object or function, we may
    be able to fold this expression using the object or function's
@@ -1644,6 +1691,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (plus:c (minus @0 @1) (minus @2 @0))
    (minus @2 @1))
   (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)))
+  (simplify
    (minus (plus:c @0 @1) (minus @0 @2))
    (plus @1 @2))
 
@@ -1748,6 +1800,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
             && TREE_CODE (@1) == INTEGER_CST
             && tree_int_cst_sign_bit (@1) == 0))
      (convert @1))))
+   (simplify
+    (pointer_diff (pointer_plus @@0 @1) @0)
+    /* The second argument of pointer_plus must be interpreted as signed, and
+       thus sign-extended if necessary.  */
+    (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
+     (convert (convert:stype @1))))
 
   /* (T)P - (T)(P + A) -> -(T) A */
   (for add (plus pointer_plus)
@@ -1772,6 +1830,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
             && TREE_CODE (@1) == INTEGER_CST
             && tree_int_cst_sign_bit (@1) == 0))
      (negate (convert @1)))))
+   (simplify
+    (pointer_diff @0 (pointer_plus @@0 @1))
+    /* The second argument of pointer_plus must be interpreted as signed, and
+       thus sign-extended if necessary.  */
+    (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
+     (negate (convert (convert:stype @1)))))
 
   /* (T)(P + A) - (T)(P + B) -> (T)A - (T)B */
   (for add (plus pointer_plus)
@@ -1798,6 +1862,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
             && TREE_CODE (@2) == INTEGER_CST
             && tree_int_cst_sign_bit (@2) == 0))
      (minus (convert @1) (convert @2)))))))
+   (simplify
+    (pointer_diff (pointer_plus @@0 @1) (pointer_plus @0 @2))
+    /* The second argument of pointer_plus must be interpreted as signed, and
+       thus sign-extended if necessary.  */
+    (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
+     (minus (convert (convert:stype @1)) (convert (convert:stype @2)))))
 
 
 /* Simplifications of MIN_EXPR, MAX_EXPR, fmin() and fmax().  */
@@ -2797,10 +2867,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    with the transformation in fold_cond_expr_with_comparison which
    attempts to synthetize ABS_EXPR.  */
 (for cmp (eq ne)
- (simplify
-  (cmp (minus@2 @0 @1) integer_zerop)
-  (if (single_use (@2))
-   (cmp @0 @1))))
+ (for sub (minus pointer_diff)
+  (simplify
+   (cmp (sub@2 @0 @1) integer_zerop)
+   (if (single_use (@2))
+    (cmp @0 @1)))))
 
 /* Transform comparisons of the form X * C1 CMP 0 to X CMP 0 in the
    signed arithmetic case.  That form is created by the compiler
index c183b14..47a2aef 100644 (file)
@@ -223,6 +223,7 @@ optab_for_tree_code (enum tree_code code, const_tree type,
        return TYPE_UNSIGNED (type) ? usadd_optab : ssadd_optab;
       return trapv ? addv_optab : add_optab;
 
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       if (TYPE_SATURATING (type))
        return TYPE_UNSIGNED (type) ? ussub_optab : sssub_optab;
index bdcb04f..b06c3f3 100644 (file)
@@ -3142,6 +3142,25 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       CHECK_OP (1, "invalid operand to binary operator");
       break;
 
+    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;
+       }
+      if (TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE
+         || TYPE_UNSIGNED (TREE_TYPE (t))
+         || (TYPE_PRECISION (TREE_TYPE (t))
+             != TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (t, 0)))))
+       {
+         error ("invalid type for pointer diff");
+         return t;
+       }
+      CHECK_OP (0, "invalid operand to pointer diff");
+      CHECK_OP (1, "invalid operand to pointer diff");
+      break;
+
     case POINTER_PLUS_EXPR:
       /* Check to make sure the first operand is a pointer or reference type. */
       if (!POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 0))))
@@ -3977,6 +3996,25 @@ verify_gimple_assign_binary (gassign *stmt)
        return false;
       }
 
+    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;
+         }
+
+       return false;
+      }
+
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
     case TRUTH_AND_EXPR:
index 2da1745..b51f13c 100644 (file)
@@ -3819,6 +3819,7 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights,
 
     case PLUS_EXPR:
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
     case MULT_HIGHPART_EXPR:
index 169f972..373332d 100644 (file)
@@ -2308,6 +2308,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
     case MULT_HIGHPART_EXPR:
     case PLUS_EXPR:
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
     case TRUNC_DIV_EXPR:
     case CEIL_DIV_EXPR:
@@ -3553,6 +3554,7 @@ op_code_prio (enum tree_code code)
     case WIDEN_SUM_EXPR:
     case PLUS_EXPR:
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       return 12;
 
@@ -3739,6 +3741,7 @@ op_symbol_code (enum tree_code code)
 
     case NEGATE_EXPR:
     case MINUS_EXPR:
+    case POINTER_DIFF_EXPR:
       return "-";
 
     case BIT_NOT_EXPR:
index 61a4cbd..0b9f4e6 100644 (file)
@@ -5265,10 +5265,12 @@ vectorizable_operation (gimple *stmt, gimple_stmt_iterator *gsi,
 
   code = gimple_assign_rhs_code (stmt);
 
-  /* For pointer addition, we should use the normal plus for
-     the vector addition.  */
+  /* For pointer addition and subtraction, we should use the normal
+     plus and minus for the vector operation.  */
   if (code == POINTER_PLUS_EXPR)
     code = PLUS_EXPR;
+  if (code == POINTER_DIFF_EXPR)
+    code = MINUS_EXPR;
 
   /* Support only unary or binary operations.  */
   op_type = TREE_CODE_LENGTH (code);
index 3d2bd95..5655858 100644 (file)
@@ -676,6 +676,14 @@ DEFTREECODE (MULT_EXPR, "mult_expr", tcc_binary, 2)
    second operand is an integer of type sizetype.  */
 DEFTREECODE (POINTER_PLUS_EXPR, "pointer_plus_expr", tcc_binary, 2)
 
+/* Pointer subtraction.  The two arguments are pointers, and the result
+   is a signed integer of the same precision.  Pointers are interpreted
+   as unsigned, the difference is computed as if in infinite signed
+   precision.  Behavior is undefined if the difference does not fit in
+   the result type.  The result does not depend on the pointer type,
+   it is not divided by the size of the pointed-to type.  */
+DEFTREECODE (POINTER_DIFF_EXPR, "pointer_diff_expr", tcc_binary, 2)
+
 /* Highpart multiplication.  For an integral type with precision B,
    returns bits [2B-1, B] of the full 2*B product.  */
 DEFTREECODE (MULT_HIGHPART_EXPR, "mult_highpart_expr", tcc_binary, 2)
index 1b35a99..923399d 100644 (file)
@@ -4615,6 +4615,7 @@ initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache)
        }
       return ret;
 
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       if (TREE_CODE (endtype) == REAL_TYPE)
        return NULL_TREE;
index 2d11861..7b9c5ad 100644 (file)
@@ -850,7 +850,7 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
      can derive a non-null range.  This happens often for
      pointer subtraction.  */
   if (vr->type == VR_VARYING
-      && code == MINUS_EXPR
+      && (code == MINUS_EXPR || code == POINTER_DIFF_EXPR)
       && TREE_CODE (op0) == SSA_NAME
       && ((vr0.type == VR_ANTI_RANGE
           && vr0.min == op1
@@ -858,7 +858,7 @@ vr_values::extract_range_from_binary_expr (value_range *vr,
          || (vr1.type == VR_ANTI_RANGE
              && vr1.min == op0
              && vr1.min == vr1.max)))
-      set_value_range_to_nonnull (vr, TREE_TYPE (op0));
+      set_value_range_to_nonnull (vr, expr_type);
 }
 
 /* Extract range information from a unary expression CODE OP0 based on