summaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorZdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>2004-09-16 16:58:01 +0200
committerZdenek Dvorak <rakdver@gcc.gnu.org>2004-09-16 14:58:01 +0000
commit2f4675b4822f842055c3f6a5cef01bbed8d264e8 (patch)
tree83497c6bb39910f542ef7657087dd15d1aac8289 /gcc/fold-const.c
parent9c763d1957c4c86fb0d299c71c44f70962959a15 (diff)
downloadgcc-2f4675b4822f842055c3f6a5cef01bbed8d264e8.tar.gz
fold-const.c (fold): Fold difference of addresses.
* fold-const.c (fold): Fold difference of addresses. (ptr_difference_const): Moved from tree-ssa-loop-ivopts, based on get_inner_reference. * tree-ssa-loop-ivopts.c (peel_address): Removed. (ptr_difference_const): Moved to fold-const.c. (split_address_cost): Use get_inner_reference instead of peel_address. (ptr_difference_cost): Change type of diff to HOST_WIDE_INT. * tree.h (ptr_difference_const): Export. * tree-ssa-loop-ivopts.c (dump_iv, dump_use, dump_cand): Add induction variable type to the dump. Fix indentation. (idx_find_step): Handle nonconstant array_ref_element_size and array_ref_low_bound. (idx_record_use): Handle array_ref_element_size and array_ref_low_bound. (find_interesting_uses_stmt): Handle memory = nontrivial_expression statements correctly. (get_computation_at, iv_value): Do not unshare expressions here. (rewrite_use_outer): Unshare the expression before it is emitted to code. * tree-ssa-loop-niter.c (unsigned_type_for, signed_type_for): Moved to tree.c. * tree.c (unsigned_type_for, signed_type_for): Moved from tree-ssa-loop-niter.c. Use langhooks. * tree.h (signed_type_for): Export. From-SVN: r87601
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 378578d000f..7d8fff9d9ee 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -6966,6 +6966,18 @@ fold (tree expr)
|| (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
+ /* Try folding difference of addresses. */
+ {
+ HOST_WIDE_INT diff;
+
+ if (TREE_CODE (arg0) == ADDR_EXPR
+ && TREE_CODE (arg1) == ADDR_EXPR
+ && ptr_difference_const (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg1, 0),
+ &diff))
+ return build_int_cst_type (type, diff);
+ }
+
if (TREE_CODE (arg0) == MULT_EXPR
&& TREE_CODE (arg1) == MULT_EXPR
&& (INTEGRAL_TYPE_P (type) || flag_unsafe_math_optimizations))
@@ -10668,3 +10680,51 @@ round_down (tree value, int divisor)
return value;
}
+
+/* Returns true if addresses of E1 and E2 differ by a constant, false
+ otherwise. If they do, &E1 - &E2 is stored in *DIFF. */
+
+bool
+ptr_difference_const (tree e1, tree e2, HOST_WIDE_INT *diff)
+{
+ tree core1, core2;
+ HOST_WIDE_INT bitsize1, bitsize2;
+ HOST_WIDE_INT bitpos1, bitpos2;
+ tree toffset1, toffset2, tdiff, type;
+ enum machine_mode mode1, mode2;
+ int unsignedp1, unsignedp2, volatilep1, volatilep2;
+
+ core1 = get_inner_reference (e1, &bitsize1, &bitpos1, &toffset1, &mode1,
+ &unsignedp1, &volatilep1);
+ core2 = get_inner_reference (e2, &bitsize2, &bitpos2, &toffset2, &mode2,
+ &unsignedp2, &volatilep2);
+
+ if (bitpos1 % BITS_PER_UNIT != 0
+ || bitpos2 % BITS_PER_UNIT != 0
+ || !operand_equal_p (core1, core2, 0))
+ return false;
+
+ if (toffset1 && toffset2)
+ {
+ type = TREE_TYPE (toffset1);
+ if (type != TREE_TYPE (toffset2))
+ toffset2 = fold_convert (type, toffset2);
+
+ tdiff = fold (build2 (MINUS_EXPR, type, toffset1, toffset2));
+ if (!host_integerp (tdiff, 0))
+ return false;
+
+ *diff = tree_low_cst (tdiff, 0);
+ }
+ else if (toffset1 || toffset2)
+ {
+ /* If only one of the offsets is non-constant, the difference cannot
+ be a constant. */
+ return false;
+ }
+ else
+ *diff = 0;
+
+ *diff += (bitpos1 - bitpos2) / BITS_PER_UNIT;
+ return true;
+}