diff options
author | kenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-11-27 13:50:13 +0000 |
---|---|---|
committer | kenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-11-27 13:50:13 +0000 |
commit | 23ec2d5e273f9f93bfa360cb99fc57619fbd1be2 (patch) | |
tree | 368881c3a9ecac0c1c9c28d7d35bd0a9485737fe /gcc/fold-const.c | |
parent | a0e65537b70e4ed56311f4a7543927a8b4a9c1a9 (diff) | |
download | gcc-23ec2d5e273f9f93bfa360cb99fc57619fbd1be2.tar.gz |
* fold-const.c (negate_expr, associate_trees, extract_muldiv): New.
(split_tree): Completely rework to make more general.
(make_range, fold): Call negate_expr.
(fold, case NEGATE_EXPR): Simplify -(a-b) is -ffast-math.
(fold, associate): Call new split_tree and associate_trees.
(fold, case MULT_EXPR, case *_{DIV,MOD}_EXPR): Call extract_muldiv.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@30673 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 815 |
1 files changed, 443 insertions, 372 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index b93f49e400e..e48f0e243b7 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -61,8 +61,10 @@ int div_and_round_double PROTO((enum tree_code, int, HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT *, HOST_WIDE_INT *, HOST_WIDE_INT *, HOST_WIDE_INT *)); -static int split_tree PROTO((tree, enum tree_code, tree *, - tree *, int *)); +static tree negate_expr PROTO((tree)); +static tree split_tree PROTO((tree, enum tree_code, tree *, tree *, + int)); +static tree associate_trees PROTO((tree, tree, enum tree_code, tree)); 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)); @@ -93,6 +95,7 @@ static tree fold_range_test PROTO((tree)); static tree unextend PROTO((tree, int, int, tree)); static tree fold_truthop PROTO((enum tree_code, tree, tree, tree)); static tree optimize_minmax_comparison PROTO((tree)); +static tree extract_muldiv PROTO((tree, tree, enum tree_code, tree)); static tree strip_compound_expr PROTO((tree, tree)); static int multiple_of_p PROTO((tree, tree, tree)); static tree constant_boolean_node PROTO((int, tree)); @@ -1199,93 +1202,181 @@ real_hex_to_f (s, mode) #endif /* no REAL_ARITHMETIC */ -/* Split a tree IN into a constant and a variable part - that could be combined with CODE to make IN. - CODE must be a commutative arithmetic operation. - Store the constant part into *CONP and the variable in &VARP. - Return 1 if this was done; zero means the tree IN did not decompose - this way. - - If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR. - Therefore, we must tell the caller whether the variable part - was subtracted. We do this by storing 1 or -1 into *VARSIGNP. - The value stored is the coefficient for the variable term. - The constant term we return should always be added; - we negate it if necessary. */ +/* Given T, an expression, return the negation of T. Allow for T to be + null, in which case return null. */ -static int -split_tree (in, code, varp, conp, varsignp) +static tree +negate_expr (t) + tree t; +{ + tree type; + tree tem; + + if (t == 0) + return 0; + + type = TREE_TYPE (t); + STRIP_SIGN_NOPS (t); + + switch (TREE_CODE (t)) + { + case INTEGER_CST: + case REAL_CST: + if (! TREE_UNSIGNED (type) + && 0 != (tem = fold (build1 (NEGATE_EXPR, type, t))) + && ! TREE_OVERFLOW (tem)) + return tem; + break; + + case NEGATE_EXPR: + return convert (type, TREE_OPERAND (t, 0)); + + case MINUS_EXPR: + /* - (A - B) -> B - A */ + if (! FLOAT_TYPE_P (type) || flag_fast_math) + return convert (type, + fold (build (MINUS_EXPR, TREE_TYPE (t), + TREE_OPERAND (t, 1), + TREE_OPERAND (t, 0)))); + break; + + default: + break; + } + + return convert (type, build1 (NEGATE_EXPR, TREE_TYPE (t), t)); +} + +/* Split a tree IN into a constant, literal and variable parts that could be + combined with CODE to make IN. "constant" means an expression with + TREE_CONSTANT but that isn't an actual constant. CODE must be a + commutative arithmetic operation. Store the constant part into *CONP, + the literal in &LITP and return the variable part. If a part isn't + present, set it to null. If the tree does not decompose in this way, + return the entire tree as the variable part and the other parts as null. + + If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR. In that + case, we negate an operand that was subtracted. If NEGATE_P is true, we + are negating all of IN. + + If IN is itself a literal or constant, return it as appropriate. + + Note that we do not guarantee that any of the three values will be the + same type as IN, but they will have the same signedness and mode. */ + +static tree +split_tree (in, code, conp, litp, negate_p) tree in; enum tree_code code; - tree *varp, *conp; - int *varsignp; + tree *conp, *litp; + int negate_p; { - register tree outtype = TREE_TYPE (in); - *varp = 0; + tree orig_in = in; + tree type = TREE_TYPE (in); + tree var = 0; + *conp = 0; + *litp = 0; + + /* Strip any conversions that don't change the machine mode or signedness. */ + STRIP_SIGN_NOPS (in); + + if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST) + *litp = in; + else if (TREE_CONSTANT (in)) + *conp = in; + + else if (TREE_CODE (in) == code + || (! FLOAT_TYPE_P (TREE_TYPE (in)) + /* We can associate addition and subtraction together (even + though the C standard doesn't say so) for integers because + the value is not affected. For reals, the value might be + affected, so we can't. */ + && ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR) + || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR)))) + { + tree op0 = TREE_OPERAND (in, 0); + tree op1 = TREE_OPERAND (in, 1); + int neg1_p = TREE_CODE (in) == MINUS_EXPR; + int neg_litp_p = 0, neg_conp_p = 0, neg_var_p = 0; + + /* First see if either of the operands is a literal, then a constant. */ + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST) + *litp = op0, op0 = 0; + else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST) + *litp = op1, neg_litp_p = neg1_p, op1 = 0; + + if (op0 != 0 && TREE_CONSTANT (op0)) + *conp = op0, op0 = 0; + else if (op1 != 0 && TREE_CONSTANT (op1)) + *conp = op1, neg_conp_p = neg1_p, op1 = 0; + + /* If we haven't dealt with either operand, this is not a case we can + decompose. Otherwise, VAR is either of the ones remaining, if any. */ + if (op0 != 0 && op1 != 0) + var = in; + else if (op0 != 0) + var = op0; + else + var = op1, neg_var_p = neg1_p; - /* Strip any conversions that don't change the machine mode. */ - while ((TREE_CODE (in) == NOP_EXPR - || TREE_CODE (in) == CONVERT_EXPR) - && (TYPE_MODE (TREE_TYPE (in)) - == TYPE_MODE (TREE_TYPE (TREE_OPERAND (in, 0))))) - in = TREE_OPERAND (in, 0); - - if (TREE_CODE (in) == code - || (! FLOAT_TYPE_P (TREE_TYPE (in)) - /* We can associate addition and subtraction together - (even though the C standard doesn't say so) - for integers because the value is not affected. - For reals, the value might be affected, so we can't. */ - && ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR) - || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR)))) + /* Now do any needed negations. */ + if (neg_litp_p) *litp = negate_expr (*litp); + if (neg_conp_p) *conp = negate_expr (*conp); + if (neg_var_p) var = negate_expr (var); + } + else + var = in; + + if (negate_p) { - enum tree_code code = TREE_CODE (TREE_OPERAND (in, 0)); - if (code == INTEGER_CST) - { - *conp = TREE_OPERAND (in, 0); - *varp = TREE_OPERAND (in, 1); - if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype) - && TREE_TYPE (*varp) != outtype) - *varp = convert (outtype, *varp); - *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1; - return 1; - } - if (TREE_CONSTANT (TREE_OPERAND (in, 1))) - { - *conp = TREE_OPERAND (in, 1); - *varp = TREE_OPERAND (in, 0); - *varsignp = 1; - if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype) - && TREE_TYPE (*varp) != outtype) - *varp = convert (outtype, *varp); - if (TREE_CODE (in) == MINUS_EXPR) - { - /* If operation is subtraction and constant is second, - must negate it to get an additive constant. - And this cannot be done unless it is a manifest constant. - It could also be the address of a static variable. - We cannot negate that, so give up. */ - if (TREE_CODE (*conp) == INTEGER_CST) - /* Subtracting from integer_zero_node loses for long long. */ - *conp = fold (build1 (NEGATE_EXPR, TREE_TYPE (*conp), *conp)); - else - return 0; - } - return 1; - } - if (TREE_CONSTANT (TREE_OPERAND (in, 0))) - { - *conp = TREE_OPERAND (in, 0); - *varp = TREE_OPERAND (in, 1); - if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype) - && TREE_TYPE (*varp) != outtype) - *varp = convert (outtype, *varp); - *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1; - return 1; - } + var = negate_expr (var); + *conp = negate_expr (*conp); + *litp = negate_expr (*litp); } - return 0; + + return var; +} + +/* Re-associate trees split by the above function. T1 and T2 are either + expressions to associate or null. Return the new expression, if any. If + we build an operation, do it in TYPE and with CODE, except if CODE is a + MINUS_EXPR, in which case we use PLUS_EXPR since split_tree will already + have taken care of the negations. */ + +static tree +associate_trees (t1, t2, code, type) + tree t1, t2; + enum tree_code code; + tree type; +{ + tree tem; + + if (t1 == 0) + return t2; + else if (t2 == 0) + return t1; + + if (code == MINUS_EXPR) + code = PLUS_EXPR; + + /* If either input is CODE, a PLUS_EXPR, or a MINUS_EXPR, don't + try to fold this since we will have infinite recursion. But do + deal with any NEGATE_EXPRs. */ + if (TREE_CODE (t1) == code || TREE_CODE (t2) == code + || TREE_CODE (t1) == MINUS_EXPR || TREE_CODE (t2) == MINUS_EXPR) + { + if (TREE_CODE (t1) == NEGATE_EXPR) + return build (MINUS_EXPR, type, convert (type, t2), + convert (type, TREE_OPERAND (t1, 0))); + else if (TREE_CODE (t2) == NEGATE_EXPR) + return build (MINUS_EXPR, type, convert (type, t1), + convert (type, TREE_OPERAND (t2, 0))); + else + return build (code, type, convert (type, t1), convert (type, t2)); + } + + return fold (build (code, type, convert (type, t1), convert (type, t2))); } /* Combine two integer constants ARG1 and ARG2 under operation CODE @@ -3249,7 +3340,7 @@ make_range (exp, pin_p, plow, phigh) case BIT_NOT_EXPR: /* ~ X -> -X - 1 */ - exp = build (MINUS_EXPR, type, build1 (NEGATE_EXPR, type, arg0), + exp = build (MINUS_EXPR, type, negate_expr (arg0), convert (type, integer_one_node)); continue; @@ -4154,6 +4245,213 @@ optimize_minmax_comparison (t) } } +/* T is an integer expression that is being multiplied, divided, or taken a + modulus (CODE says which and what kind of divide or modulus) by a + constant C. See if we can eliminate that operation by folding it with + other operations already in T. WIDE_TYPE, if non-null, is a type that + should be used for the computation if wider than our type. + + For example, if we are dividing (X * 8) + (Y + 16) by 4, we can return + (X * 2) + (Y + 4). We also canonicalize (X + 7) * 4 into X * 4 + 28 + in the hope that either the machine has a multiply-accumulate insn + or that this is part of an addressing calculation. + + If we return a non-null expression, it is an equivalent form of the + original computation, but need not be in the original type. */ + +static tree +extract_muldiv (t, c, code, wide_type) + tree t; + tree c; + enum tree_code code; + tree wide_type; +{ + tree type = TREE_TYPE (t); + enum tree_code tcode = TREE_CODE (t); + tree ctype = (wide_type != 0 && (GET_MODE_SIZE (TYPE_MODE (wide_type)) + > GET_MODE_SIZE (TYPE_MODE (type))) + ? wide_type : type); + tree t1, t2; + int same_p = tcode == code; + int cancel_p + = (code == MULT_EXPR && tcode == EXACT_DIV_EXPR) || tcode == MULT_EXPR; + tree op0, op1; + + /* Don't deal with constants of zero here; they confuse the code below. */ + if (integer_zerop (c)) + return 0; + + if (TREE_CODE_CLASS (tcode) == '1') + op0 = TREE_OPERAND (t, 0); + + if (TREE_CODE_CLASS (tcode) == '2') + op0 = TREE_OPERAND (t, 0), op1 = TREE_OPERAND (t, 1); + + /* Note that we need not handle conditional operations here since fold + already handles those cases. So just do arithmetic here. */ + switch (tcode) + { + case INTEGER_CST: + /* For a constant, we can always simplify if we are a multiply + or (for divide and modulus) if it is a multiple of our constant. */ + if (code == MULT_EXPR + || integer_zerop (const_binop (TRUNC_MOD_EXPR, t, c, 0))) + return const_binop (code, convert (ctype, t), convert (ctype, c), 0); + break; + + case CONVERT_EXPR: case NON_LVALUE_EXPR: case NOP_EXPR: + + /* Pass the constant down and see if we can make a simplification. If + we can, replace this expression with a conversion of that result to + our type. */ + if (0 != (t1 = extract_muldiv (op0, convert (TREE_TYPE (op0), c), code, + code == MULT_EXPR ? ctype : NULL_TREE))) + return t1; + break; + + case NEGATE_EXPR: case ABS_EXPR: + if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0) + return fold (build1 (tcode, ctype, convert (ctype, t1))); + break; + + case MIN_EXPR: case MAX_EXPR: + /* MIN (a, b) / 5 -> MIN (a / 5, b / 5) */ + if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0 + && (t2 = extract_muldiv (op1, c, code, wide_type)) != 0) + return fold (build (tcode, ctype, convert (ctype, t1), + convert (ctype, t2))); + break; + + case WITH_RECORD_EXPR: + if ((t1 = extract_muldiv (TREE_OPERAND (t, 0), c, code, wide_type)) != 0) + return build (WITH_RECORD_EXPR, TREE_TYPE (t1), t1, + TREE_OPERAND (t, 1)); + break; + + case SAVE_EXPR: + /* If this has not been evaluated, we can see if we can do + something inside it and make a new one. */ + if (SAVE_EXPR_RTL (t) == 0 + && 0 != (t1 = extract_muldiv (TREE_OPERAND (t, 0), c, code, + wide_type))) + return save_expr (t1); + break; + + case LSHIFT_EXPR: case RSHIFT_EXPR: + /* If the second operand is constant, this is a multiplication + or floor division, by a power of two, so we can treat it that + way unless the multiplier or divisor overflows. */ + if (TREE_CODE (op1) == INTEGER_CST + && 0 != (t1 = convert (ctype, + const_binop (LSHIFT_EXPR, size_one_node, + op1, 0))) + && ! TREE_OVERFLOW (t1)) + return extract_muldiv (build (tcode == LSHIFT_EXPR + ? MULT_EXPR : FLOOR_DIV_EXPR, + ctype, convert (ctype, op0), t1), + c, code, wide_type); + break; + + case PLUS_EXPR: case MINUS_EXPR: + /* See if we can eliminate the operation on both sides. If we can, we + can return a new PLUS or MINUS. If we can't, the only remaining + cases where we can do anything are if the second operand is a + constant. */ + t1 = extract_muldiv (op0, c, code, wide_type); + t2 = extract_muldiv (op1, c, code, wide_type); + if (t1 != 0 && t2 != 0) + return fold (build (tcode, ctype, convert (ctype, t1), + convert (ctype, t2))); + else if (TREE_CODE (op1) != INTEGER_CST) + break; + + /* If we were able to eliminate our operation from the first side, + apply our operation to the second side and reform the PLUS or + MINUS. */ + if (t1 != 0 && (TREE_CODE (t1) != code || code == MULT_EXPR) + && 0 != (t2 = const_binop (code, convert (ctype, op1), + convert (ctype, c), 0)) + && ! TREE_OVERFLOW (t2)) + return fold (build (tcode, ctype, convert (ctype, t1), t2)); + + /* The last case is if we are a multiply. In that case, we can + apply the distributive law to commute the multiply and addition + if the multiplication of the constants doesn't overflow. */ + if (code == MULT_EXPR + && 0 != (t1 = const_binop (code, convert (ctype, op1), + convert (ctype, c), 0)) + && ! TREE_OVERFLOW (t1)) + return fold (build (tcode, ctype, fold (build (code, ctype, + convert (ctype, op0), + convert (ctype, c))), + t1)); + + break; + + case MULT_EXPR: + /* We have a special case here if we are doing something like + (C * 8) % 4 since we know that's zero. */ + if ((code == TRUNC_MOD_EXPR || code == CEIL_MOD_EXPR + || code == FLOOR_MOD_EXPR || code == ROUND_MOD_EXPR) + && TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST + && integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0))) + return omit_one_operand (type, integer_zero_node, op0); + + /* ... fall through ... */ + + case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: case EXACT_DIV_EXPR: + /* If we can extract our operation from the LHS, do so and return a + new operation. Likewise for the RHS from a MULT_EXPR. Otherwise, + do something only if the second operand is a constant. */ + if (same_p + && (t1 = extract_muldiv (op0, c, code, wide_type)) != 0) + return fold (build (tcode, ctype, convert (ctype, t1), + convert (ctype, op1))); + else if (tcode == MULT_EXPR && code == MULT_EXPR + && (t1 = extract_muldiv (op1, c, code, wide_type)) != 0) + return fold (build (tcode, ctype, convert (ctype, op0), + convert (ctype, t1))); + else if (TREE_CODE (op1) != INTEGER_CST) + return 0; + + /* If these are the same operation types, we can associate them + assuming no overflow. */ + if (tcode == code + && 0 != (t1 = const_binop (MULT_EXPR, convert (ctype, op1), + convert (ctype, c), 0)) + && ! TREE_OVERFLOW (t1)) + return fold (build (tcode, ctype, convert (ctype, op0), t1)); + + /* If these operations "cancel" each other, we have the main + optimizations of this pass, which occur when either constant is a + multiple of the other, in which case we replace this with either an + operation or CODE or TCODE. */ + if ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR) + || (tcode == MULT_EXPR + && code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR + && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR)) + { + if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0))) + return fold (build (tcode, ctype, convert (ctype, op0), + convert (ctype, + const_binop (TRUNC_DIV_EXPR, + op1, c, 0)))); + else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1, 0))) + return fold (build (code, ctype, convert (ctype, op0), + convert (ctype, + const_binop (TRUNC_DIV_EXPR, + c, op1, 0)))); + } + break; + + default: + break; + } + + return 0; +} + /* If T contains a COMPOUND_EXPR which was inserted merely to evaluate S, a SAVE_EXPR, return the expression actually being evaluated. Note that we may sometimes modify the tree. */ @@ -4772,7 +5070,8 @@ fold (expr) return TREE_OPERAND (arg0, 0); /* Convert - (a - b) to (b - a) for non-floating-point. */ - else if (TREE_CODE (arg0) == MINUS_EXPR && ! FLOAT_TYPE_P (type)) + else if (TREE_CODE (arg0) == MINUS_EXPR + && (! FLOAT_TYPE_P (type) || flag_fast_math)) return build (MINUS_EXPR, type, TREE_OPERAND (arg0, 1), TREE_OPERAND (arg0, 0)); @@ -4816,14 +5115,10 @@ fold (expr) else if (TREE_CODE (arg0) == COMPLEX_EXPR) return build (COMPLEX_EXPR, TREE_TYPE (arg0), TREE_OPERAND (arg0, 0), - fold (build1 (NEGATE_EXPR, - TREE_TYPE (TREE_TYPE (arg0)), - TREE_OPERAND (arg0, 1)))); + negate_expr (TREE_OPERAND (arg0, 1))); else if (TREE_CODE (arg0) == COMPLEX_CST) return build_complex (type, TREE_OPERAND (arg0, 0), - fold (build1 (NEGATE_EXPR, - TREE_TYPE (TREE_TYPE (arg0)), - TREE_OPERAND (arg0, 1)))); + negate_expr (TREE_OPERAND (arg0, 1))); else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR) return fold (build (TREE_CODE (arg0), type, fold (build1 (CONJ_EXPR, type, @@ -5047,109 +5342,41 @@ fold (expr) } } + associate: - /* In most languages, can't associate operations on floats - through parentheses. Rather than remember where the parentheses - were, we don't associate floats at all. It shouldn't matter much. - However, associating multiplications is only very slightly - inaccurate, so do that if -ffast-math is specified. */ - if (FLOAT_TYPE_P (type) - && ! (flag_fast_math && code == MULT_EXPR)) - goto binary; - - /* The varsign == -1 cases happen only for addition and subtraction. - It says that the arg that was split was really CON minus VAR. - The rest of the code applies to all associative operations. */ - if (!wins) + /* In most languages, can't associate operations on floats through + parentheses. Rather than remember where the parentheses were, we + don't associate floats at all. It shouldn't matter much. However, + associating multiplications is only very slightly inaccurate, so do + that if -ffast-math is specified. */ + + if (! wins + && (! FLOAT_TYPE_P (type) + || (flag_fast_math && code != MULT_EXPR))) { - tree var, con; - int varsign; - - if (split_tree (arg0, code, &var, &con, &varsign)) - { - if (varsign == -1) - { - /* EXPR is (CON-VAR) +- ARG1. */ - /* If it is + and VAR==ARG1, return just CONST. */ - if (code == PLUS_EXPR && operand_equal_p (var, arg1, 0)) - return convert (TREE_TYPE (t), con); - - /* If ARG0 is a constant, don't change things around; - instead keep all the constant computations together. */ - - if (TREE_CONSTANT (arg0)) - return t; - - /* Otherwise return (CON +- ARG1) - VAR. */ - t = build (MINUS_EXPR, type, - fold (build (code, type, con, arg1)), var); - } - else - { - /* EXPR is (VAR+CON) +- ARG1. */ - /* If it is - and VAR==ARG1, return just CONST. */ - if (code == MINUS_EXPR && operand_equal_p (var, arg1, 0)) - return convert (TREE_TYPE (t), con); - - /* If ARG0 is a constant, don't change things around; - instead keep all the constant computations together. */ - - if (TREE_CONSTANT (arg0)) - return t; - - /* Otherwise return VAR +- (ARG1 +- CON). */ - tem = fold (build (code, type, arg1, con)); - t = build (code, type, var, tem); - - if (integer_zerop (tem) - && (code == PLUS_EXPR || code == MINUS_EXPR)) - return convert (type, var); - /* If we have x +/- (c - d) [c an explicit integer] - change it to x -/+ (d - c) since if d is relocatable - then the latter can be a single immediate insn - and the former cannot. */ - if (TREE_CODE (tem) == MINUS_EXPR - && TREE_CODE (TREE_OPERAND (tem, 0)) == INTEGER_CST) - { - tree tem1 = TREE_OPERAND (tem, 1); - TREE_OPERAND (tem, 1) = TREE_OPERAND (tem, 0); - TREE_OPERAND (tem, 0) = tem1; - TREE_SET_CODE (t, - (code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR)); - } - } - return t; - } - - if (split_tree (arg1, code, &var, &con, &varsign)) + tree var0, con0, lit0, var1, con1, lit1; + + /* Split both trees into variables, constants, and literals. Then + associate each group together, the constants with literals, + then the result with variables. This increases the chances of + literals being recombined later and of generating relocatable + expressions for the sum of a constant and literal. */ + var0 = split_tree (arg0, code, &con0, &lit0, 0); + var1 = split_tree (arg1, code, &con1, &lit1, code == MINUS_EXPR); + + /* Only do something if we found more than two objects. Otherwise, + nothing has changed and we risk infinite recursion. */ + if (2 < ((var0 != 0) + (var1 != 0) + (con0 != 0) + (con1 != 0) + + (lit0 != 0) + (lit1 != 0))) { - if (TREE_CONSTANT (arg1)) - return t; - - if (varsign == -1) - TREE_SET_CODE (t, - (code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR)); - - /* EXPR is ARG0 +- (CON +- VAR). */ - if (TREE_CODE (t) == MINUS_EXPR - && operand_equal_p (var, arg0, 0)) - { - /* If VAR and ARG0 cancel, return just CON or -CON. */ - if (code == PLUS_EXPR) - return convert (TREE_TYPE (t), con); - return fold (build1 (NEGATE_EXPR, TREE_TYPE (t), - convert (TREE_TYPE (t), con))); - } - - t = build (TREE_CODE (t), type, - fold (build (code, TREE_TYPE (t), arg0, con)), var); - - if (integer_zerop (TREE_OPERAND (t, 0)) - && TREE_CODE (t) == PLUS_EXPR) - return convert (TREE_TYPE (t), var); - return t; + var0 = associate_trees (var0, var1, code, type); + con0 = associate_trees (con0, con1, code, type); + lit0 = associate_trees (lit0, lit1, code, type); + con0 = associate_trees (con0, lit0, code, type); + return convert (type, associate_trees (var0, con0, code, type)); } } + binary: #if defined (REAL_IS_NOT_DOUBLE) && ! defined (REAL_ARITHMETIC) if (TREE_CODE (arg1) == REAL_CST) @@ -5183,7 +5410,7 @@ fold (expr) if (! FLOAT_TYPE_P (type)) { if (! wins && integer_zerop (arg0)) - return build1 (NEGATE_EXPR, type, arg1); + return negate_expr (arg1); if (integer_zerop (arg1)) return non_lvalue (convert (type, arg0)); @@ -5206,7 +5433,7 @@ fold (expr) { /* Except with IEEE floating point, 0-x equals -x. */ if (! wins && real_zerop (arg0)) - return build1 (NEGATE_EXPR, type, arg1); + return negate_expr (arg1); /* Except with IEEE floating point, x-0 equals x. */ if (real_zerop (arg1)) return non_lvalue (convert (type, arg0)); @@ -5237,14 +5464,6 @@ fold (expr) if (integer_onep (arg1)) return non_lvalue (convert (type, arg0)); - /* ((A / C) * C) is A if the division is an - EXACT_DIV_EXPR. Since C is normally a constant, - just check for one of the four possibilities. */ - - if (TREE_CODE (arg0) == EXACT_DIV_EXPR - && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) - return TREE_OPERAND (arg0, 0); - /* (a * (1 << b)) is (a << b) */ if (TREE_CODE (arg1) == LSHIFT_EXPR && integer_onep (TREE_OPERAND (arg1, 0))) @@ -5254,6 +5473,12 @@ fold (expr) && integer_onep (TREE_OPERAND (arg0, 0))) return fold (build (LSHIFT_EXPR, type, arg1, TREE_OPERAND (arg0, 1))); + + if (TREE_CODE (arg1) == INTEGER_CST + && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1, + code, NULL_TREE))) + return convert (type, tem); + } else { @@ -5455,129 +5680,10 @@ fold (expr) && multiple_of_p (type, arg0, arg1)) return fold (build (EXACT_DIV_EXPR, type, arg0, arg1)); - /* If we have ((a / C1) / C2) where both division are the same type, try - to simplify. First see if C1 * C2 overflows or not. */ - if (TREE_CODE (arg0) == code && TREE_CODE (arg1) == INTEGER_CST - && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) - { - tree new_divisor; - - new_divisor = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 1), arg1, 0); - tem = const_binop (FLOOR_DIV_EXPR, new_divisor, arg1, 0); - - if (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) == TREE_INT_CST_LOW (tem) - && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == TREE_INT_CST_HIGH (tem)) - { - /* If no overflow, divide by C1*C2. */ - return fold (build (code, type, TREE_OPERAND (arg0, 0), new_divisor)); - } - } - - /* Look for ((a * C1) / C3) or (((a * C1) + C2) / C3), - where C1 % C3 == 0 or C3 % C1 == 0. We can simplify these - expressions, which often appear in the offsets or sizes of - objects with a varying size. Only deal with positive divisors - and multiplicands. If C2 is negative, we must have C2 % C3 == 0. - - Look for NOPs and SAVE_EXPRs inside. */ - - if (TREE_CODE (arg1) == INTEGER_CST - && tree_int_cst_sgn (arg1) >= 0) - { - int have_save_expr = 0; - tree c2 = integer_zero_node; - tree xarg0 = arg0; - - if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0) - have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0); - - STRIP_NOPS (xarg0); - - /* Look inside the dividend and simplify using EXACT_DIV_EXPR - if possible. */ - if (TREE_CODE (xarg0) == MULT_EXPR - && multiple_of_p (type, TREE_OPERAND (xarg0, 0), arg1)) - { - tree t; - - t = fold (build (MULT_EXPR, type, - fold (build (EXACT_DIV_EXPR, type, - TREE_OPERAND (xarg0, 0), arg1)), - TREE_OPERAND (xarg0, 1))); - if (have_save_expr) - t = save_expr (t); - return t; - - } - - if (TREE_CODE (xarg0) == MULT_EXPR - && multiple_of_p (type, TREE_OPERAND (xarg0, 1), arg1)) - { - tree t; - - t = fold (build (MULT_EXPR, type, - fold (build (EXACT_DIV_EXPR, type, - TREE_OPERAND (xarg0, 1), arg1)), - TREE_OPERAND (xarg0, 0))); - if (have_save_expr) - t = save_expr (t); - return t; - } - - if (TREE_CODE (xarg0) == PLUS_EXPR - && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST) - c2 = TREE_OPERAND (xarg0, 1), xarg0 = TREE_OPERAND (xarg0, 0); - else if (TREE_CODE (xarg0) == MINUS_EXPR - && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST - /* If we are doing this computation unsigned, the negate - is incorrect. */ - && ! TREE_UNSIGNED (type)) - { - c2 = fold (build1 (NEGATE_EXPR, type, TREE_OPERAND (xarg0, 1))); - xarg0 = TREE_OPERAND (xarg0, 0); - } - - if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0) - have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0); - - STRIP_NOPS (xarg0); - - if (TREE_CODE (xarg0) == MULT_EXPR - && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST - && tree_int_cst_sgn (TREE_OPERAND (xarg0, 1)) >= 0 - && (integer_zerop (const_binop (TRUNC_MOD_EXPR, - TREE_OPERAND (xarg0, 1), arg1, 1)) - || integer_zerop (const_binop (TRUNC_MOD_EXPR, arg1, - TREE_OPERAND (xarg0, 1), 1))) - && (tree_int_cst_sgn (c2) >= 0 - || integer_zerop (const_binop (TRUNC_MOD_EXPR, c2, - arg1, 1)))) - { - tree outer_div = integer_one_node; - tree c1 = TREE_OPERAND (xarg0, 1); - tree c3 = arg1; - - /* If C3 > C1, set them equal and do a divide by - C3/C1 at the end of the operation. */ - if (tree_int_cst_lt (c1, c3)) - outer_div = const_binop (code, c3, c1, 0), c3 = c1; - - /* The result is A * (C1/C3) + (C2/C3). */ - t = fold (build (PLUS_EXPR, type, - fold (build (MULT_EXPR, type, - TREE_OPERAND (xarg0, 0), - const_binop (code, c1, c3, 1))), - const_binop (code, c2, c3, 1))); - - if (! integer_onep (outer_div)) - t = fold (build (code, type, t, convert (type, outer_div))); - - if (have_save_expr) - t = save_expr (t); - - return t; - } - } + if (TREE_CODE (arg1) == INTEGER_CST + && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1, + code, NULL_TREE))) + return convert (type, tem); goto binary; @@ -5590,39 +5696,10 @@ fold (expr) if (integer_zerop (arg1)) return t; - /* Look for ((a * C1) % C3) or (((a * C1) + C2) % C3), - where C1 % C3 == 0. Handle similarly to the division case, - but don't bother with SAVE_EXPRs. */ - if (TREE_CODE (arg1) == INTEGER_CST - && ! integer_zerop (arg1)) - { - tree c2 = integer_zero_node; - tree xarg0 = arg0; - - if (TREE_CODE (xarg0) == PLUS_EXPR - && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST) - c2 = TREE_OPERAND (xarg0, 1), xarg0 = TREE_OPERAND (xarg0, 0); - else if (TREE_CODE (xarg0) == MINUS_EXPR - && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST - && ! TREE_UNSIGNED (type)) - { - c2 = fold (build1 (NEGATE_EXPR, type, TREE_OPERAND (xarg0, 1))); - xarg0 = TREE_OPERAND (xarg0, 0); - } - - STRIP_NOPS (xarg0); - - if (TREE_CODE (xarg0) == MULT_EXPR - && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST - && integer_zerop (const_binop (TRUNC_MOD_EXPR, - TREE_OPERAND (xarg0, 1), - arg1, 1)) - && tree_int_cst_sgn (c2) >= 0) - /* The result is (C2%C3). */ - return omit_one_operand (type, const_binop (code, c2, arg1, 1), - TREE_OPERAND (xarg0, 0)); - } + && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1, + code, NULL_TREE))) + return convert (type, tem); goto binary; @@ -6046,8 +6123,7 @@ fold (expr) else if ((code == EQ_EXPR || code == NE_EXPR) && TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == INTEGER_CST - && 0 != (tem = fold (build1 (NEGATE_EXPR, TREE_TYPE (arg1), - arg1))) + && 0 != (tem = negate_expr (arg1)) && TREE_CODE (tem) == INTEGER_CST && ! TREE_CONSTANT_OVERFLOW (tem)) return fold (build (code, type, TREE_OPERAND (arg0, 0), tem)); @@ -6086,17 +6162,14 @@ fold (expr) and a comparison, and is probably faster. */ else if (code == LE_EXPR && TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == ABS_EXPR - && ! TREE_SIDE_EFFECTS (arg0)) - { - tree inner = TREE_OPERAND (arg0, 0); - - tem = fold (build1 (NEGATE_EXPR, TREE_TYPE (arg1), arg1)); - if (TREE_CODE (tem) == INTEGER_CST - && ! TREE_CONSTANT_OVERFLOW (tem)) - return fold (build (TRUTH_ANDIF_EXPR, type, - build (GE_EXPR, type, inner, tem), - build (LE_EXPR, type, inner, arg1))); - } + && ! TREE_SIDE_EFFECTS (arg0) + && (0 != (tem = negate_expr (arg1))) + && TREE_CODE (tem) == INTEGER_CST + && ! TREE_CONSTANT_OVERFLOW (tem)) + return fold (build (TRUTH_ANDIF_EXPR, type, + build (GE_EXPR, type, TREE_OPERAND (arg0, 0), tem), + build (LE_EXPR, type, + TREE_OPERAND (arg0, 0), arg1))); /* If this is an EQ or NE comparison with zero and ARG0 is (1 << foo) & bar, convert it to (bar >> foo) & 1. Both require @@ -6635,8 +6708,7 @@ fold (expr) switch (comp_code) { case EQ_EXPR: - return pedantic_non_lvalue - (fold (build1 (NEGATE_EXPR, type, arg1))); + return pedantic_non_lvalue (negate_expr (arg1)); case NE_EXPR: return pedantic_non_lvalue (convert (type, arg1)); case GE_EXPR: @@ -6651,11 +6723,10 @@ fold (expr) if (TREE_UNSIGNED (TREE_TYPE (arg1))) arg1 = convert (signed_type (TREE_TYPE (arg1)), arg1); return pedantic_non_lvalue - (fold (build1 (NEGATE_EXPR, type, - convert (type, - fold (build1 (ABS_EXPR, - TREE_TYPE (arg1), - arg1)))))); + (negate_expr (convert (type, + fold (build1 (ABS_EXPR, + TREE_TYPE (arg1), + arg1))))); default: abort (); } |