diff options
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 78 |
1 files changed, 46 insertions, 32 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 896a9838e14..a7dcfc3ff90 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -58,6 +58,7 @@ along with GCC; see the file COPYING3. If not see #include "rtl.h" #include "expr.h" #include "tm_p.h" +#include "target.h" #include "toplev.h" #include "intl.h" #include "ggc.h" @@ -8483,11 +8484,12 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) HOST_WIDE_INT bitsize, bitpos0 = 0, bitpos1 = 0; enum machine_mode mode; int volatilep, unsignedp; - bool indirect_base0 = false; + bool indirect_base0 = false, indirect_base1 = false; /* Get base and offset for the access. Strip ADDR_EXPR for get_inner_reference, but put it back by stripping INDIRECT_REF - off the base object if possible. */ + off the base object if possible. indirect_baseN will be true + if baseN is not an address but refers to the object itself. */ base0 = arg0; if (TREE_CODE (arg0) == ADDR_EXPR) { @@ -8511,24 +8513,19 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) base1 = get_inner_reference (TREE_OPERAND (arg1, 0), &bitsize, &bitpos1, &offset1, &mode, &unsignedp, &volatilep, false); - /* We have to make sure to have an indirect/non-indirect base1 - just the same as we did for base0. */ - if (TREE_CODE (base1) == INDIRECT_REF - && !indirect_base0) + if (TREE_CODE (base1) == INDIRECT_REF) base1 = TREE_OPERAND (base1, 0); - else if (!indirect_base0) - base1 = NULL_TREE; + else + indirect_base1 = true; } else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR) { base1 = TREE_OPERAND (arg1, 0); offset1 = TREE_OPERAND (arg1, 1); } - else if (indirect_base0) - base1 = NULL_TREE; /* If we have equivalent bases we might be able to simplify. */ - if (base0 && base1 + if (indirect_base0 == indirect_base1 && operand_equal_p (base0, base1, 0)) { /* We can fold this expression to a constant if the non-constant @@ -8583,6 +8580,44 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) return fold_build2 (code, type, offset0, offset1); } } + /* For non-equal bases we can simplify if they are addresses + of local binding decls or constants. */ + else if (indirect_base0 && indirect_base1 + /* We know that !operand_equal_p (base0, base1, 0) + because the if condition was false. */ + && TREE_CODE (arg0) == ADDR_EXPR + && TREE_CODE (arg1) == ADDR_EXPR + && ((DECL_P (base0) + && (targetm.binds_local_p (base0) + || CONSTANT_CLASS_P (base1))) + || CONSTANT_CLASS_P (base0)) + && ((DECL_P (base1) + && (targetm.binds_local_p (base1) + || CONSTANT_CLASS_P (base0))) + || CONSTANT_CLASS_P (base1))) + { + if (code == EQ_EXPR) + return omit_two_operands (type, boolean_false_node, arg0, arg1); + else if (code == NE_EXPR) + return omit_two_operands (type, boolean_true_node, arg0, arg1); + } + /* For equal offsets we can simplify to a comparison of the + base addresses. */ + else if (bitpos0 == bitpos1 + && (indirect_base0 + ? base0 != TREE_OPERAND (arg0, 0) : base0 != arg0) + && (indirect_base1 + ? base1 != TREE_OPERAND (arg1, 0) : base1 != arg1) + && ((offset0 == offset1) + || (offset0 && offset1 + && operand_equal_p (offset0, offset1, 0)))) + { + if (indirect_base0) + base0 = fold_addr_expr (base0); + if (indirect_base1) + base1 = fold_addr_expr (base1); + return fold_build2 (code, type, base0, base1); + } } /* Transform comparisons of the form X +- C1 CMP Y +- C2 to @@ -8929,27 +8964,6 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) } } - /* Fold a comparison of the address of COMPONENT_REFs with the same - type and component to a comparison of the address of the base - object. In short, &x->a OP &y->a to x OP y and - &x->a OP &y.a to x OP &y */ - if (TREE_CODE (arg0) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (arg0, 0)) == COMPONENT_REF - && TREE_CODE (arg1) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (arg1, 0)) == COMPONENT_REF) - { - tree cref0 = TREE_OPERAND (arg0, 0); - tree cref1 = TREE_OPERAND (arg1, 0); - if (TREE_OPERAND (cref0, 1) == TREE_OPERAND (cref1, 1)) - { - tree op0 = TREE_OPERAND (cref0, 0); - tree op1 = TREE_OPERAND (cref1, 0); - return fold_build2 (code, type, - fold_addr_expr (op0), - fold_addr_expr (op1)); - } - } - /* We can fold X/C1 op C2 where C1 and C2 are integer constants into a single range test. */ if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR |