aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Glisse <marc.glisse@inria.fr>2017-11-21 19:23:56 +0100
committerMarc Glisse <glisse@gcc.gnu.org>2017-11-21 18:23:56 +0000
commit1af4ebf5985ef2aaac13862654044d84a3cd7ae4 (patch)
tree6136f270e536b46d7d9de96d28e38794684035dd
parentffb41aab7a9b8475e773b75fdebd194f4491c9db (diff)
downloadgcc-1af4ebf5985ef2aaac13862654044d84a3cd7ae4.zip
gcc-1af4ebf5985ef2aaac13862654044d84a3cd7ae4.tar.gz
gcc-1af4ebf5985ef2aaac13862654044d84a3cd7ae4.tar.bz2
New POINTER_DIFF_EXPR
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
-rw-r--r--gcc/ChangeLog22
-rw-r--r--gcc/c-family/ChangeLog5
-rw-r--r--gcc/c-family/c-pretty-print.c2
-rw-r--r--gcc/c/ChangeLog5
-rw-r--r--gcc/c/c-fold.c1
-rw-r--r--gcc/c/c-typeck.c25
-rw-r--r--gcc/cfgexpand.c1
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/constexpr.c2
-rw-r--r--gcc/cp/cp-gimplify.c1
-rw-r--r--gcc/cp/error.c4
-rw-r--r--gcc/cp/typeck.c41
-rw-r--r--gcc/doc/generic.texi13
-rw-r--r--gcc/expr.c1
-rw-r--r--gcc/fold-const.c62
-rw-r--r--gcc/match.pd79
-rw-r--r--gcc/optabs-tree.c1
-rw-r--r--gcc/tree-cfg.c38
-rw-r--r--gcc/tree-inline.c1
-rw-r--r--gcc/tree-pretty-print.c3
-rw-r--r--gcc/tree-vect-stmts.c6
-rw-r--r--gcc/tree.def8
-rw-r--r--gcc/varasm.c1
-rw-r--r--gcc/vr-values.c4
24 files changed, 284 insertions, 50 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e4c1a77..a34c125 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 308a617..08d8cec 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -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.
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index 0f48b9e..15e13ea 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -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;
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 95b7718..a2773b0 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -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
diff --git a/gcc/c/c-fold.c b/gcc/c/c-fold.c
index 6a6c716..8895462 100644
--- a/gcc/c/c-fold.c
+++ b/gcc/c/c-fold.c
@@ -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:
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 8a09ea2..7f85c6b 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3778,7 +3778,7 @@ parser_build_binary_op (location_t location, enum tree_code code,
}
/* 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");
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index ca5d8db..a63b414 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -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:
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index db94034..8a6328a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 5eac64b..34a9c6b 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -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;
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 201a595..d597ed9 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -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:
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 2537713..7125b88 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -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);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index cb93cc3..8ba6a12 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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);
}
/* Construct and perhaps optimize a tree representation
diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index a51cfd6..b03970f 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -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
diff --git a/gcc/expr.c b/gcc/expr.c
index c93d9f6..3341e94 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index e9cd968..9fe3462 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -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.
diff --git a/gcc/match.pd b/gcc/match.pd
index 0e21a0d..0949a9b 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -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
diff --git a/gcc/optabs-tree.c b/gcc/optabs-tree.c
index c183b14..47a2aef 100644
--- a/gcc/optabs-tree.c
+++ b/gcc/optabs-tree.c
@@ -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;
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index bdcb04f..b06c3f3 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -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:
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 2da1745..b51f13c 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -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:
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 169f972..373332d 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -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:
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 61a4cbd..0b9f4e6 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -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);
diff --git a/gcc/tree.def b/gcc/tree.def
index 3d2bd95..5655858 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -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)
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 1b35a99..923399d 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -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;
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index 2d11861..7b9c5ad 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -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