diff options
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 1dba1fb..00892f4 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -5967,6 +5967,84 @@ tree_swap_operands_p (tree arg0, tree arg1, bool reorder) return 0; } +/* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is + step of the array. TYPE is the type of the expression. ADDR is the address. + MULT is the multiplicative expression. If the function succeeds, the new + address expression is returned. Otherwise NULL_TREE is returned. */ + +static tree +try_move_mult_to_index (tree type, enum tree_code code, tree addr, tree mult) +{ + tree s, delta, step; + tree arg0 = TREE_OPERAND (mult, 0), arg1 = TREE_OPERAND (mult, 1); + tree ref = TREE_OPERAND (addr, 0), pref; + tree ret, pos; + tree itype; + + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + + if (TREE_CODE (arg0) == INTEGER_CST) + { + s = arg0; + delta = arg1; + } + else if (TREE_CODE (arg1) == INTEGER_CST) + { + s = arg1; + delta = arg0; + } + else + return NULL_TREE; + + for (;; ref = TREE_OPERAND (ref, 0)) + { + if (TREE_CODE (ref) == ARRAY_REF) + { + step = array_ref_element_size (ref); + + if (TREE_CODE (step) != INTEGER_CST) + continue; + + itype = TREE_TYPE (step); + + /* If the type sizes do not match, we might run into problems + when one of them would overflow. */ + if (TYPE_PRECISION (itype) != TYPE_PRECISION (type)) + continue; + + if (!operand_equal_p (step, fold_convert (itype, s), 0)) + continue; + + delta = fold_convert (itype, delta); + break; + } + + if (!handled_component_p (ref)) + return NULL_TREE; + } + + /* We found the suitable array reference. So copy everything up to it, + and replace the index. */ + + pref = TREE_OPERAND (addr, 0); + ret = copy_node (pref); + pos = ret; + + while (pref != ref) + { + pref = TREE_OPERAND (pref, 0); + TREE_OPERAND (pos, 0) = copy_node (pref); + pos = TREE_OPERAND (pos, 0); + } + + TREE_OPERAND (pos, 1) = fold (build2 (code, itype, + TREE_OPERAND (pos, 1), + delta)); + + return build1 (ADDR_EXPR, type, ret); +} + /* Perform constant folding and related simplification of EXPR. The related simplifications include x*1 => x, x*0 => 0, etc., and application of the associative law. @@ -6602,6 +6680,24 @@ fold (tree expr) alt0, alt1)), same)); } + + /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step + of the array. Loop optimizer sometimes produce this type of + expressions. */ + if (TREE_CODE (arg0) == ADDR_EXPR + && TREE_CODE (arg1) == MULT_EXPR) + { + tem = try_move_mult_to_index (type, PLUS_EXPR, arg0, arg1); + if (tem) + return fold (tem); + } + else if (TREE_CODE (arg1) == ADDR_EXPR + && TREE_CODE (arg0) == MULT_EXPR) + { + tem = try_move_mult_to_index (type, PLUS_EXPR, arg1, arg0); + if (tem) + return fold (tem); + } } else { @@ -6974,6 +7070,17 @@ fold (tree expr) &diff)) return build_int_cst_type (type, diff); } + + /* Try replacing &a[i1] - c * i2 with &a[i1 - i2], if c is step + of the array. Loop optimizer sometimes produce this type of + expressions. */ + if (TREE_CODE (arg0) == ADDR_EXPR + && TREE_CODE (arg1) == MULT_EXPR) + { + tem = try_move_mult_to_index (type, MINUS_EXPR, arg0, arg1); + if (tem) + return fold (tem); + } if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR |