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:
parent
ffb41aab7a
commit
1af4ebf598
24 changed files with 283 additions and 49 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
79
gcc/match.pd
79
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
|
||||
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue