diff options
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 158 |
1 files changed, 143 insertions, 15 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index b8ccfa1d207..0d2e4076926 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -1267,7 +1267,15 @@ associate_trees (tree t1, tree t2, enum tree_code code, tree type) else if (TREE_CODE (t2) == NEGATE_EXPR) return build2 (MINUS_EXPR, type, fold_convert (type, t1), fold_convert (type, TREE_OPERAND (t2, 0))); + else if (integer_zerop (t2)) + return fold_convert (type, t1); } + else if (code == MINUS_EXPR) + { + if (integer_zerop (t2)) + return fold_convert (type, t1); + } + return build2 (code, type, fold_convert (type, t1), fold_convert (type, t2)); } @@ -5972,6 +5980,127 @@ tree_swap_operands_p (tree arg0, tree arg1, bool reorder) return 0; } +/* Fold comparison ARG0 CODE ARG1 (with result in TYPE), where + ARG0 is extended to a wider type. */ + +static tree +fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1) +{ + tree arg0_unw = get_unwidened (arg0, NULL_TREE); + tree arg1_unw; + tree shorter_type, outer_type; + tree min, max; + bool above, below; + + if (arg0_unw == arg0) + return NULL_TREE; + shorter_type = TREE_TYPE (arg0_unw); + + arg1_unw = get_unwidened (arg1, shorter_type); + if (!arg1_unw) + return NULL_TREE; + + /* If possible, express the comparison in the shorter mode. */ + if ((code == EQ_EXPR || code == NE_EXPR + || TYPE_UNSIGNED (TREE_TYPE (arg0)) == TYPE_UNSIGNED (shorter_type)) + && (TREE_TYPE (arg1_unw) == shorter_type + || (TREE_CODE (arg1_unw) == INTEGER_CST + && int_fits_type_p (arg1_unw, shorter_type)))) + return fold (build (code, type, arg0_unw, + fold_convert (shorter_type, arg1_unw))); + + if (TREE_CODE (arg1_unw) != INTEGER_CST) + return NULL_TREE; + + /* If we are comparing with the integer that does not fit into the range + of the shorter type, the result is known. */ + outer_type = TREE_TYPE (arg1_unw); + min = lower_bound_in_type (outer_type, shorter_type); + max = upper_bound_in_type (outer_type, shorter_type); + + above = integer_nonzerop (fold_relational_const (LT_EXPR, type, + max, arg1_unw)); + below = integer_nonzerop (fold_relational_const (LT_EXPR, type, + arg1_unw, min)); + + switch (code) + { + case EQ_EXPR: + if (above || below) + return constant_boolean_node (false, type); + break; + + case NE_EXPR: + if (above || below) + return constant_boolean_node (true, type); + break; + + case LT_EXPR: + case LE_EXPR: + if (above) + return constant_boolean_node (true, type); + else if (below) + return constant_boolean_node (false, type);; + + case GT_EXPR: + case GE_EXPR: + if (above) + return constant_boolean_node (false, type); + else if (below) + return constant_boolean_node (true, type);; + + default: + break; + } + + return NULL_TREE; +} + +/* Fold comparison ARG0 CODE ARG1 (with result in TYPE), where for + ARG0 just the signedness is changed. */ + +static tree +fold_sign_changed_comparison (enum tree_code code, tree type, + tree arg0, tree arg1) +{ + tree arg0_inner, tmp; + tree inner_type, outer_type; + + if (TREE_CODE (arg0) != NOP_EXPR) + return NULL_TREE; + + outer_type = TREE_TYPE (arg0); + arg0_inner = TREE_OPERAND (arg0, 0); + inner_type = TREE_TYPE (arg0_inner); + + if (TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type)) + return NULL_TREE; + + if (TREE_CODE (arg1) != INTEGER_CST + && !(TREE_CODE (arg1) == NOP_EXPR + && TREE_TYPE (TREE_OPERAND (arg1, 0)) == inner_type)) + return NULL_TREE; + + if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type) + && code != NE_EXPR + && code != EQ_EXPR) + return NULL_TREE; + + if (TREE_CODE (arg1) == INTEGER_CST) + { + tmp = build_int_cst_wide (inner_type, + TREE_INT_CST_LOW (arg1), + TREE_INT_CST_HIGH (arg1)); + arg1 = force_fit_type (tmp, 0, + TREE_OVERFLOW (arg1), + TREE_CONSTANT_OVERFLOW (arg1)); + } + else + arg1 = fold_convert (inner_type, arg1); + + return fold (build (code, type, arg0_inner, arg1)); +} + /* 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 @@ -8392,22 +8521,21 @@ fold (tree expr) return fold (build2 (code, type, TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1))); - /* If we are widening one operand of an integer comparison, - see if the other operand is similarly being widened. Perhaps we - can do the comparison in the narrower type. */ else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE - && TREE_CODE (arg0) == NOP_EXPR - && (tem = get_unwidened (arg0, NULL_TREE)) != arg0 - && (code == EQ_EXPR || code == NE_EXPR - || TYPE_UNSIGNED (TREE_TYPE (arg0)) - == TYPE_UNSIGNED (TREE_TYPE (tem))) - && (t1 = get_unwidened (arg1, TREE_TYPE (tem))) != 0 - && (TREE_TYPE (t1) == TREE_TYPE (tem) - || (TREE_CODE (t1) == INTEGER_CST - && TREE_CODE (TREE_TYPE (tem)) == INTEGER_TYPE - && int_fits_type_p (t1, TREE_TYPE (tem))))) - return fold (build2 (code, type, tem, - fold_convert (TREE_TYPE (tem), t1))); + && TREE_CODE (arg0) == NOP_EXPR) + { + /* If we are widening one operand of an integer comparison, + see if the other operand is similarly being widened. Perhaps we + can do the comparison in the narrower type. */ + tem = fold_widened_comparison (code, type, arg0, arg1); + if (tem) + return tem; + + /* Or if we are changing signedness. */ + tem = fold_sign_changed_comparison (code, type, arg0, arg1); + if (tem) + return tem; + } /* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a constant, we can simplify it. */ |