+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
+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.
{
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);
case POINTER_PLUS_EXPR:
case PLUS_EXPR:
+ case POINTER_DIFF_EXPR:
case MINUS_EXPR:
pp_c_additive_expression (this, e);
break;
+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
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:
}
\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)
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)))
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");
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:
+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
break;
case POINTER_PLUS_EXPR:
+ case POINTER_DIFF_EXPR:
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
return true;
}
+ case POINTER_DIFF_EXPR:
case MINUS_EXPR:
want_rval = true;
goto binary;
/* FALLTHRU */
case POINTER_PLUS_EXPR:
case PLUS_EXPR:
+ case POINTER_DIFF_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
case TRUNC_DIV_EXPR:
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);
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);
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))))
/* 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
@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
@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
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
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:
{
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);
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));
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))
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.
(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)
&& !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
&& (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)
&& (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)
&& ((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;
(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
(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))
&& 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)
&& 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)
&& 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(). */
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
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;
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))))
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:
case PLUS_EXPR:
case POINTER_PLUS_EXPR:
+ case POINTER_DIFF_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
case MULT_HIGHPART_EXPR:
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:
case WIDEN_SUM_EXPR:
case PLUS_EXPR:
case POINTER_PLUS_EXPR:
+ case POINTER_DIFF_EXPR:
case MINUS_EXPR:
return 12;
case NEGATE_EXPR:
case MINUS_EXPR:
+ case POINTER_DIFF_EXPR:
return "-";
case BIT_NOT_EXPR:
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);
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)
}
return ret;
+ case POINTER_DIFF_EXPR:
case MINUS_EXPR:
if (TREE_CODE (endtype) == REAL_TYPE)
return NULL_TREE;
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
|| (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