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
This commit is contained in:
Marc Glisse 2017-11-21 19:23:56 +01:00 committed by Marc Glisse
parent ffb41aab7a
commit 1af4ebf598
24 changed files with 283 additions and 49 deletions

View 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

View 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.

View 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;

View 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

View 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:

View file

@ -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");

View 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:

View 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

View 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;

View 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:

View 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);

View 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. */
/* 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;
op0 = cp_build_binary_op (loc,
MINUS_EXPR,
cp_convert (restype, op0, complain),
cp_convert (restype, op1, complain),
complain);
/* 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

View 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

View 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

View 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.

View 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
@ -1643,6 +1690,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
(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

View 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;

View 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:

View 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:

View 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:

View 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);

View 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)

View 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;

View 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