diff options
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 440 |
1 files changed, 265 insertions, 175 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index da18997..3ce114b 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -42,9 +42,9 @@ Boston, MA 02111-1307, USA. */ force_fit_type takes a constant and prior overflow indicator, and forces the value to fit the type. It returns an overflow indicator. */ +#include "config.h" #include <stdio.h> #include <setjmp.h> -#include "config.h" #include "flags.h" #include "tree.h" @@ -62,6 +62,7 @@ int div_and_round_double PROTO((enum tree_code, int, HOST_WIDE_INT, HOST_WIDE_INT *)); static int split_tree PROTO((tree, enum tree_code, tree *, tree *, int *)); +static tree int_const_binop PROTO((enum tree_code, tree, tree, int, int)); static tree const_binop PROTO((enum tree_code, tree, tree, int)); static tree fold_convert PROTO((tree, tree)); static enum tree_code invert_tree_comparison PROTO((enum tree_code)); @@ -1051,192 +1052,215 @@ split_tree (in, code, varp, conp, varsignp) return 0; } -/* Combine two constants ARG1 and ARG2 under operation CODE +/* Combine two integer constants ARG1 and ARG2 under operation CODE to produce a new constant. - We assume ARG1 and ARG2 have the same data type, - or at least are the same kind of constant and the same machine mode. - If NOTRUNC is nonzero, do not truncate the result to fit the data type. */ + If NOTRUNC is nonzero, do not truncate the result to fit the data type. + If FORSIZE is nonzero, compute overflow for unsigned types. */ static tree -const_binop (code, arg1, arg2, notrunc) +int_const_binop (code, arg1, arg2, notrunc, forsize) enum tree_code code; register tree arg1, arg2; - int notrunc; + int notrunc, forsize; { - STRIP_NOPS (arg1); STRIP_NOPS (arg2); + HOST_WIDE_INT int1l, int1h, int2l, int2h; + HOST_WIDE_INT low, hi; + HOST_WIDE_INT garbagel, garbageh; + register tree t; + int uns = TREE_UNSIGNED (TREE_TYPE (arg1)); + int overflow = 0; + int no_overflow = 0; - if (TREE_CODE (arg1) == INTEGER_CST) + int1l = TREE_INT_CST_LOW (arg1); + int1h = TREE_INT_CST_HIGH (arg1); + int2l = TREE_INT_CST_LOW (arg2); + int2h = TREE_INT_CST_HIGH (arg2); + + switch (code) { - register HOST_WIDE_INT int1l = TREE_INT_CST_LOW (arg1); - register HOST_WIDE_INT int1h = TREE_INT_CST_HIGH (arg1); - HOST_WIDE_INT int2l = TREE_INT_CST_LOW (arg2); - HOST_WIDE_INT int2h = TREE_INT_CST_HIGH (arg2); - HOST_WIDE_INT low, hi; - HOST_WIDE_INT garbagel, garbageh; - register tree t; - int uns = TREE_UNSIGNED (TREE_TYPE (arg1)); - int overflow = 0; - int no_overflow = 0; + case BIT_IOR_EXPR: + low = int1l | int2l, hi = int1h | int2h; + break; - switch (code) - { - case BIT_IOR_EXPR: - low = int1l | int2l, hi = int1h | int2h; - break; + case BIT_XOR_EXPR: + low = int1l ^ int2l, hi = int1h ^ int2h; + break; - case BIT_XOR_EXPR: - low = int1l ^ int2l, hi = int1h ^ int2h; - break; + case BIT_AND_EXPR: + low = int1l & int2l, hi = int1h & int2h; + break; - case BIT_AND_EXPR: - low = int1l & int2l, hi = int1h & int2h; - break; + case BIT_ANDTC_EXPR: + low = int1l & ~int2l, hi = int1h & ~int2h; + break; - case BIT_ANDTC_EXPR: - low = int1l & ~int2l, hi = int1h & ~int2h; - break; + case RSHIFT_EXPR: + int2l = - int2l; + case LSHIFT_EXPR: + /* It's unclear from the C standard whether shifts can overflow. + The following code ignores overflow; perhaps a C standard + interpretation ruling is needed. */ + lshift_double (int1l, int1h, int2l, + TYPE_PRECISION (TREE_TYPE (arg1)), + &low, &hi, + !uns); + no_overflow = 1; + break; - case RSHIFT_EXPR: - int2l = - int2l; - case LSHIFT_EXPR: - /* It's unclear from the C standard whether shifts can overflow. - The following code ignores overflow; perhaps a C standard - interpretation ruling is needed. */ - lshift_double (int1l, int1h, int2l, - TYPE_PRECISION (TREE_TYPE (arg1)), - &low, &hi, - !uns); - no_overflow = 1; - break; + case RROTATE_EXPR: + int2l = - int2l; + case LROTATE_EXPR: + lrotate_double (int1l, int1h, int2l, + TYPE_PRECISION (TREE_TYPE (arg1)), + &low, &hi); + break; - case RROTATE_EXPR: - int2l = - int2l; - case LROTATE_EXPR: - lrotate_double (int1l, int1h, int2l, - TYPE_PRECISION (TREE_TYPE (arg1)), - &low, &hi); - break; + case PLUS_EXPR: + overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi); + break; - case PLUS_EXPR: - overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi); - break; + case MINUS_EXPR: + neg_double (int2l, int2h, &low, &hi); + add_double (int1l, int1h, low, hi, &low, &hi); + overflow = overflow_sum_sign (hi, int2h, int1h); + break; - case MINUS_EXPR: - neg_double (int2l, int2h, &low, &hi); - add_double (int1l, int1h, low, hi, &low, &hi); - overflow = overflow_sum_sign (hi, int2h, int1h); - break; + case MULT_EXPR: + overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi); + break; - case MULT_EXPR: - overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi); + case TRUNC_DIV_EXPR: + case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + /* This is a shortcut for a common special case. */ + if (int2h == 0 && int2l > 0 + && ! TREE_CONSTANT_OVERFLOW (arg1) + && ! TREE_CONSTANT_OVERFLOW (arg2) + && int1h == 0 && int1l >= 0) + { + if (code == CEIL_DIV_EXPR) + int1l += int2l - 1; + low = int1l / int2l, hi = 0; break; + } - case TRUNC_DIV_EXPR: - case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: - case EXACT_DIV_EXPR: - /* This is a shortcut for a common special case. */ - if (int2h == 0 && int2l > 0 - && ! TREE_CONSTANT_OVERFLOW (arg1) - && ! TREE_CONSTANT_OVERFLOW (arg2) - && int1h == 0 && int1l >= 0) - { - if (code == CEIL_DIV_EXPR) - int1l += int2l - 1; - low = int1l / int2l, hi = 0; - break; - } - - /* ... fall through ... */ + /* ... fall through ... */ - case ROUND_DIV_EXPR: - if (int2h == 0 && int2l == 1) - { - low = int1l, hi = int1h; - break; - } - if (int1l == int2l && int1h == int2h - && ! (int1l == 0 && int1h == 0)) - { - low = 1, hi = 0; - break; - } - overflow = div_and_round_double (code, uns, - int1l, int1h, int2l, int2h, - &low, &hi, &garbagel, &garbageh); + case ROUND_DIV_EXPR: + if (int2h == 0 && int2l == 1) + { + low = int1l, hi = int1h; break; - - case TRUNC_MOD_EXPR: - case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR: - /* This is a shortcut for a common special case. */ - if (int2h == 0 && int2l > 0 - && ! TREE_CONSTANT_OVERFLOW (arg1) - && ! TREE_CONSTANT_OVERFLOW (arg2) - && int1h == 0 && int1l >= 0) - { - if (code == CEIL_MOD_EXPR) - int1l += int2l - 1; - low = int1l % int2l, hi = 0; - break; - } - - /* ... fall through ... */ - - case ROUND_MOD_EXPR: - overflow = div_and_round_double (code, uns, - int1l, int1h, int2l, int2h, - &garbagel, &garbageh, &low, &hi); + } + if (int1l == int2l && int1h == int2h + && ! (int1l == 0 && int1h == 0)) + { + low = 1, hi = 0; break; + } + overflow = div_and_round_double (code, uns, + int1l, int1h, int2l, int2h, + &low, &hi, &garbagel, &garbageh); + break; - case MIN_EXPR: - case MAX_EXPR: - if (uns) - { - low = (((unsigned HOST_WIDE_INT) int1h - < (unsigned HOST_WIDE_INT) int2h) - || (((unsigned HOST_WIDE_INT) int1h - == (unsigned HOST_WIDE_INT) int2h) - && ((unsigned HOST_WIDE_INT) int1l - < (unsigned HOST_WIDE_INT) int2l))); - } - else - { - low = ((int1h < int2h) - || ((int1h == int2h) - && ((unsigned HOST_WIDE_INT) int1l - < (unsigned HOST_WIDE_INT) int2l))); - } - if (low == (code == MIN_EXPR)) - low = int1l, hi = int1h; - else - low = int2l, hi = int2h; + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR: + /* This is a shortcut for a common special case. */ + if (int2h == 0 && int2l > 0 + && ! TREE_CONSTANT_OVERFLOW (arg1) + && ! TREE_CONSTANT_OVERFLOW (arg2) + && int1h == 0 && int1l >= 0) + { + if (code == CEIL_MOD_EXPR) + int1l += int2l - 1; + low = int1l % int2l, hi = 0; break; + } - default: - abort (); + /* ... fall through ... */ + + case ROUND_MOD_EXPR: + overflow = div_and_round_double (code, uns, + int1l, int1h, int2l, int2h, + &garbagel, &garbageh, &low, &hi); + break; + + case MIN_EXPR: + case MAX_EXPR: + if (uns) + { + low = (((unsigned HOST_WIDE_INT) int1h + < (unsigned HOST_WIDE_INT) int2h) + || (((unsigned HOST_WIDE_INT) int1h + == (unsigned HOST_WIDE_INT) int2h) + && ((unsigned HOST_WIDE_INT) int1l + < (unsigned HOST_WIDE_INT) int2l))); } - got_it: - if (TREE_TYPE (arg1) == sizetype && hi == 0 - && low >= 0 && low <= TREE_INT_CST_LOW (TYPE_MAX_VALUE (sizetype)) - && ! overflow - && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2)) - t = size_int (low); else { - t = build_int_2 (low, hi); - TREE_TYPE (t) = TREE_TYPE (arg1); + low = ((int1h < int2h) + || ((int1h == int2h) + && ((unsigned HOST_WIDE_INT) int1l + < (unsigned HOST_WIDE_INT) int2l))); } + if (low == (code == MIN_EXPR)) + low = int1l, hi = int1h; + else + low = int2l, hi = int2h; + break; - TREE_OVERFLOW (t) - = ((notrunc ? !uns && overflow - : force_fit_type (t, overflow && !uns) && ! no_overflow) - | TREE_OVERFLOW (arg1) - | TREE_OVERFLOW (arg2)); - TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t) - | TREE_CONSTANT_OVERFLOW (arg1) - | TREE_CONSTANT_OVERFLOW (arg2)); - return t; + default: + abort (); } + + if (TREE_TYPE (arg1) == sizetype && hi == 0 + && low >= 0 && low <= TREE_INT_CST_LOW (TYPE_MAX_VALUE (sizetype)) + && ! overflow + && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2)) + t = size_int (low); + else + { + t = build_int_2 (low, hi); + TREE_TYPE (t) = TREE_TYPE (arg1); + } + + TREE_OVERFLOW (t) + = ((notrunc ? (!uns || forsize) && overflow + : force_fit_type (t, (!uns || forsize) && overflow) && ! no_overflow) + | TREE_OVERFLOW (arg1) + | TREE_OVERFLOW (arg2)); + /* If we're doing a size calculation, unsigned arithmetic does overflow. + So check if force_fit_type truncated the value. */ + if (forsize + && ! TREE_OVERFLOW (t) + && (TREE_INT_CST_HIGH (t) != hi + || TREE_INT_CST_LOW (t) != low)) + TREE_OVERFLOW (t) = 1; + TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t) + | TREE_CONSTANT_OVERFLOW (arg1) + | TREE_CONSTANT_OVERFLOW (arg2)); + return t; +} + +/* Combine two constants ARG1 and ARG2 under operation CODE + to produce a new constant. + We assume ARG1 and ARG2 have the same data type, + or at least are the same kind of constant and the same machine mode. + + If NOTRUNC is nonzero, do not truncate the result to fit the data type. */ + +static tree +const_binop (code, arg1, arg2, notrunc) + enum tree_code code; + register tree arg1, arg2; + int notrunc; +{ + STRIP_NOPS (arg1); STRIP_NOPS (arg2); + + if (TREE_CODE (arg1) == INTEGER_CST) + return int_const_binop (code, arg1, arg2, notrunc, 0); + #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) if (TREE_CODE (arg1) == REAL_CST) { @@ -1450,7 +1474,7 @@ size_binop (code, arg0, arg1) return arg1; /* Handle general case of two integer constants. */ - return const_binop (code, arg0, arg1, 0); + return int_const_binop (code, arg0, arg1, 0, 1); } if (arg0 == error_mark_node || arg1 == error_mark_node) @@ -1790,6 +1814,8 @@ operand_equal_p (arg0, arg1, only_const) case ADDR_EXPR: return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0); + default: + break; } if (only_const) @@ -1847,11 +1873,13 @@ operand_equal_p (arg0, arg1, only_const) TREE_OPERAND (arg1, 1), 0) && operand_equal_p (TREE_OPERAND (arg0, 2), TREE_OPERAND (arg1, 2), 0)); + default: + return 0; } - break; + + default: + return 0; } - - return 0; } /* Similar to operand_equal_p, but see if ARG0 might have been made by @@ -2002,9 +2030,10 @@ twoval_comparison_p (arg, cval1, cval2, save_p) return 0; return 1; - } - return 0; + default: + return 0; + } } /* ARG is a tree that is known to contain just arithmetic operations and @@ -2059,7 +2088,10 @@ eval_subst (arg, old0, new0, old1, new1) old0, new0, old1, new1), eval_subst (TREE_OPERAND (arg, 2), old0, new0, old1, new1))); + default: + break; } + /* fall through (???) */ case '<': { @@ -2082,9 +2114,10 @@ eval_subst (arg, old0, new0, old1, new1) return fold (build (code, type, arg0, arg1)); } - } - return arg; + default: + return arg; + } } /* Return a tree for the case when the result of an expression is RESULT @@ -2222,6 +2255,9 @@ invert_truthvalue (arg) case CLEANUP_POINT_EXPR: return build1 (CLEANUP_POINT_EXPR, type, invert_truthvalue (TREE_OPERAND (arg, 0))); + + default: + break; } if (TREE_CODE (TREE_TYPE (arg)) != BOOLEAN_TYPE) abort (); @@ -2704,6 +2740,8 @@ range_binop (code, type, arg0, upper0_p, arg1, upper1_p) case GT_EXPR: case GE_EXPR: result = sgn0 > sgn1; break; + default: + abort (); } return convert (type, result ? integer_one_node : integer_zero_node); @@ -2780,6 +2818,8 @@ make_range (exp, pin_p, plow, phigh) case LE_EXPR: /* + [-, c] */ in_p = ! in_p, low = 0, high = arg1; break; + default: + abort (); } exp = arg0; @@ -5114,13 +5154,16 @@ fold (expr) arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0); t = build (code, type, TREE_OPERAND (t, 0), arg1); break; + + default: + break; } } /* If this is an EQ or NE comparison with zero and ARG0 is (1 << foo) & bar, convert it to (bar >> foo) & 1. Both require two operations, but the latter can be done in one less insn - one machine that have only two-operand insns or on which a + on machines that have only two-operand insns or on which a constant cannot be the first operand. */ if (integer_zerop (arg1) && (code == EQ_EXPR || code == NE_EXPR) && TREE_CODE (arg0) == BIT_AND_EXPR) @@ -5246,6 +5289,8 @@ fold (expr) t = build_int_2 (0, 0); TREE_TYPE (t) = type; return t; + default: + abort (); } } @@ -5273,9 +5318,41 @@ fold (expr) return omit_one_operand (type, convert (type, integer_zero_node), arg0); + default: + break; } } + /* An unsigned <= 0x7fffffff can be simplified. */ + { + int width = TYPE_PRECISION (TREE_TYPE (arg1)); + if (TREE_CODE (arg1) == INTEGER_CST + && ! TREE_CONSTANT_OVERFLOW (arg1) + && width <= HOST_BITS_PER_WIDE_INT + && TREE_INT_CST_LOW (arg1) == ((HOST_WIDE_INT) 1 << (width - 1)) - 1 + && TREE_INT_CST_HIGH (arg1) == 0 + && (INTEGRAL_TYPE_P (TREE_TYPE (arg1)) + || TREE_CODE (TREE_TYPE (arg1)) == POINTER_TYPE) + && TREE_UNSIGNED (TREE_TYPE (arg1))) + { + switch (TREE_CODE (t)) + { + case LE_EXPR: + return fold (build (GE_EXPR, type, + convert (signed_type (TREE_TYPE (arg0)), + arg0), + convert (signed_type (TREE_TYPE (arg1)), + integer_zero_node))); + case GT_EXPR: + return fold (build (LT_EXPR, type, + convert (signed_type (TREE_TYPE (arg0)), + arg0), + convert (signed_type (TREE_TYPE (arg1)), + integer_zero_node))); + } + } + } + /* If we are comparing an expression that just has comparisons of two integer values, arithmetic expressions of those comparisons, and constants, we can simplify it. There are only three cases @@ -5577,6 +5654,8 @@ fold (expr) fold (build1 (ABS_EXPR, TREE_TYPE (arg1), arg1)))))); + default: + abort (); } /* If this is A != 0 ? A : 0, this is simply A. For ==, it is @@ -5608,21 +5687,28 @@ fold (expr) return pedantic_non_lvalue (convert (type, arg1)); case LE_EXPR: case LT_EXPR: - /* In C++ a ?: expression can be an lvalue, so we can't - do this; we would lose the distinction between - LT and LE. */ - if (pedantic_lvalues) - return pedantic_non_lvalue - (convert (type, (fold (build (MIN_EXPR, comp_type, - comp_op0, comp_op1))))); + /* In C++ a ?: expression can be an lvalue, so put the + operand which will be used if they are equal first + so that we can convert this back to the + corresponding COND_EXPR. */ + return pedantic_non_lvalue + (convert (type, (fold (build (MIN_EXPR, comp_type, + (comp_code == LE_EXPR + ? comp_op0 : comp_op1), + (comp_code == LE_EXPR + ? comp_op1 : comp_op0)))))); break; case GE_EXPR: case GT_EXPR: - if (pedantic_lvalues) - return pedantic_non_lvalue - (convert (type, fold (build (MAX_EXPR, comp_type, - comp_op0, comp_op1)))); + return pedantic_non_lvalue + (convert (type, fold (build (MAX_EXPR, comp_type, + (comp_code == GE_EXPR + ? comp_op0 : comp_op1), + (comp_code == GE_EXPR + ? comp_op1 : comp_op0))))); break; + default: + abort (); } } @@ -5683,6 +5769,10 @@ fold (expr) return pedantic_non_lvalue (fold (build (MAX_EXPR, type, arg1, arg2))); break; + case NE_EXPR: + break; + default: + abort (); } } |