aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
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 /gcc/fold-const.c
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
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c62
1 files changed, 43 insertions, 19 deletions
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.