diff options
author | Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz> | 2004-09-16 16:58:01 +0200 |
---|---|---|
committer | Zdenek Dvorak <rakdver@gcc.gnu.org> | 2004-09-16 14:58:01 +0000 |
commit | 2f4675b4822f842055c3f6a5cef01bbed8d264e8 (patch) | |
tree | 83497c6bb39910f542ef7657087dd15d1aac8289 /gcc/fold-const.c | |
parent | 9c763d1957c4c86fb0d299c71c44f70962959a15 (diff) | |
download | gcc-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.c | 60 |
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; +} |