This patch splits simplify_and_const_int and simplify_shift_const into two functions (each): one that tries to simplify and returns NULL_RTX if it cannot produce anything, and one that has the same calling convention as before. In the meanwhile, I made them produce new RTXen instead of substituting into the preexisting expressions, which is another tiny step towards moving these many valuable transformations into simplify-rtx.c. In particular, I believe that they could help the forward propagation that I'm submitting in stage2.
In the meanwhile I removed the need to have two variables for the shift count (one signed and one unsigned) in simplify_shift_const. This is ok because the count is constrained at the beginning of the function to be between 0 and GET_MODE_BITSIZE (mode) - 1, and care is taken to make it positive again if it goes negative. The places where this is done are easy to find, because they are exactly where the signed_count variable was used. It was very hard to split this in two patches. I am sending a single patch for simplify_and_const_int and simplify_shift_const because the split is very logical. Tell me if it is better to send two separate patches. A previous version of this patch exhibited an infinite loop in simplify_comparison. simplify_and_const_int is called to transform (and REG (ashift 1 N)) to (and (ashiftrt REG N) 1) when it is only being checked for non-zeroness. After this patch, however, the first argument must be NULL because op0 is not equal to (and (ashiftrt REG N) 1). I scanned other invocations of simplify_and_const_int and simplify_shift_const with a non-NULL first parameter, and there seem to be only two cases where this convention is not obeyed: this one in simplify_comparison and one in force_to_mode, whose code is really obscure and can be simplified a good deal. Bootstrapped and regtested i686-pc-linux-gnu (all languages except Java which is broken for me on this box), together with the other combine patches that were approved, but not committed yet. A powerpc-apple-darwin8.3.0 bootstrap will finish overnight, this time including Java. Paolo
2005-12-18 Paolo Bonzini <[EMAIL PROTECTED]> * combine.c (simplify_shift_const): Leave only the fallback case when no simplification is possible. Extract to... (simplify_shift_const_1): ... here. Always create a new RTX instead of substituting. Remove the signed_count variable. Return NULL_RTX if no substitution is possible. (simplify_and_const_int): Leave only the fallback case when no simplification is possible. Extract to... (simplify_and_const_int_1): ... here. Always create a new RTX instead of substituting. Return NULL_RTX if no substitution is possible. (force_to_mode, simplify_comparison): Don't pass a non-NULL first parameter to simplify_and_const_int and simplify_shift_const, unless it is equal to the expected non-simplified result. Index: combine.c =================================================================== --- combine.c (revision 108634) +++ combine.c (working copy) @@ -394,11 +394,14 @@ static int rtx_equal_for_field_assignmen static rtx make_field_assignment (rtx); static rtx apply_distributive_law (rtx); static rtx distribute_and_simplify_rtx (rtx, int); +static rtx simplify_and_const_int_1 (enum machine_mode, rtx, + unsigned HOST_WIDE_INT); static rtx simplify_and_const_int (rtx, enum machine_mode, rtx, unsigned HOST_WIDE_INT); static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code, HOST_WIDE_INT, enum machine_mode, int *); -static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx, +static rtx simplify_shift_const_1 (enum rtx_code, enum machine_mode, rtx, int); +static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx, int); static int recog_for_combine (rtx *, rtx, rtx *); static rtx gen_lowpart_for_combine (enum machine_mode, rtx); @@ -6921,7 +6915,7 @@ force_to_mode (rtx x, enum machine_mode if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0 && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT) { - int i = -1; + int i; /* If the considered data is wider than HOST_WIDE_INT, we can't represent a mask for all its bits in a single scalar. @@ -6948,13 +6942,19 @@ force_to_mode (rtx x, enum machine_mode nonzero >>= INTVAL (XEXP (x, 1)); } - if ((mask & ~nonzero) == 0 - || (i = exact_log2 (mask)) >= 0) + if ((mask & ~nonzero) == 0) + { + x = simplify_shift_const (x, LSHIFTRT, GET_MODE (x), + XEXP (x, 0), INTVAL (XEXP (x, 1))); + if (GET_CODE (x) != ASHIFTRT) + return force_to_mode (x, mode, mask, next_select); + } + + else if ((i = exact_log2 (mask)) >= 0) { x = simplify_shift_const - (x, LSHIFTRT, GET_MODE (x), XEXP (x, 0), - i < 0 ? INTVAL (XEXP (x, 1)) - : GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i); + (NULL_RTX, LSHIFTRT, GET_MODE (x), XEXP (x, 0), + GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i); if (GET_CODE (x) != ASHIFTRT) return force_to_mode (x, mode, mask, next_select); @@ -7841,19 +7835,24 @@ distribute_and_simplify_rtx (rtx x, int return NULL_RTX; } -/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done - in MODE. - - Return an equivalent form, if different from X. Otherwise, return X. If - X is zero, we are to always construct the equivalent form. */ +/* Simplify a logical `and' of VAROP with the constant CONSTOP, to be done + in MODE. Return an equivalent form, if different from X. Otherwise, + return NULL_RTX. */ static rtx -simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop, - unsigned HOST_WIDE_INT constop) +simplify_and_const_int_1 (enum machine_mode mode, rtx varop, + unsigned HOST_WIDE_INT constop) { unsigned HOST_WIDE_INT nonzero; + unsigned HOST_WIDE_INT orig_constop; + rtx orig_varop; int i; + orig_varop = varop; + orig_constop = constop; + if (GET_CODE (varop) == CLOBBER) + return NULL_RTX; + /* Simplify VAROP knowing that we will be only looking at some of the bits in it. @@ -7924,41 +7923,46 @@ simplify_and_const_int (rtx x, enum mach return o0; } - /* Get VAROP in MODE. Try to get a SUBREG if not. Don't make a new SUBREG - if we already had one (just check for the simplest cases). */ - if (x && GET_CODE (XEXP (x, 0)) == SUBREG - && GET_MODE (XEXP (x, 0)) == mode - && SUBREG_REG (XEXP (x, 0)) == varop) - varop = XEXP (x, 0); - else - varop = gen_lowpart (mode, varop); - - /* If we can't make the SUBREG, try to return what we were given. */ - if (GET_CODE (varop) == CLOBBER) - return x ? x : varop; + /* Make a SUBREG if necessary. If we can't make it, fail. */ + varop = gen_lowpart (mode, varop); + if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER) + return NULL_RTX; /* If we are only masking insignificant bits, return VAROP. */ if (constop == nonzero) - x = varop; - else - { - /* Otherwise, return an AND. */ - constop = trunc_int_for_mode (constop, mode); - /* See how much, if any, of X we can use. */ - if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode) - x = simplify_gen_binary (AND, mode, varop, GEN_INT (constop)); + return varop; - else - { - if (GET_CODE (XEXP (x, 1)) != CONST_INT - || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop) - SUBST (XEXP (x, 1), GEN_INT (constop)); + if (varop == orig_varop && constop == orig_constop) + return NULL_RTX; - SUBST (XEXP (x, 0), varop); - } - } + /* Otherwise, return an AND. */ + constop = trunc_int_for_mode (constop, mode); + return simplify_gen_binary (AND, mode, varop, GEN_INT (constop)); +} - return x; + +/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done + in MODE. + + Return an equivalent form, if different from X. Otherwise, return X. If + X is zero, we are to always construct the equivalent form. */ + +static rtx +simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop, + unsigned HOST_WIDE_INT constop) +{ + rtx tem = simplify_and_const_int_1 (mode, varop, constop); + if (tem) + return tem; + else + { + if (!x) + x = simplify_gen_binary (AND, GET_MODE (varop), varop, + GEN_INT (constop)); + if (GET_MODE (x) != mode) + x = gen_lowpart (mode, x); + return x; + } } /* Given a REG, X, compute which bits in X can be nonzero. @@ -8241,21 +8245,20 @@ merge_outer_ops (enum rtx_code *pop0, HO } /* Simplify a shift of VAROP by COUNT bits. CODE says what kind of shift. - The result of the shift is RESULT_MODE. X, if nonzero, is an expression - that we started with. + The result of the shift is RESULT_MODE. Return NULL_RTX if we cannot + simplify it. Otherwise, return a simplified value. The shift is normally computed in the widest mode we find in VAROP, as long as it isn't a different number of words than RESULT_MODE. Exceptions - are ASHIFTRT and ROTATE, which are always done in their original mode, */ + are ASHIFTRT and ROTATE, which are always done in their original mode. */ static rtx -simplify_shift_const (rtx x, enum rtx_code code, - enum machine_mode result_mode, rtx varop, - int orig_count) +simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode, + rtx varop, int orig_count) { enum rtx_code orig_code = code; - unsigned int count; - int signed_count; + rtx orig_varop = varop; + int count; enum machine_mode mode = result_mode; enum machine_mode shift_mode, tmode; unsigned int mode_words @@ -8263,9 +8266,8 @@ simplify_shift_const (rtx x, enum rtx_co /* We form (outer_op (code varop count) (outer_const)). */ enum rtx_code outer_op = UNKNOWN; HOST_WIDE_INT outer_const = 0; - rtx const_rtx; int complement_p = 0; - rtx new; + rtx new, x; /* Make sure and truncate the "natural" shift on the way in. We don't want to do this inside the loop as it makes it more difficult to @@ -8277,12 +8279,7 @@ simplify_shift_const (rtx x, enum rtx_co what was requested. */ if (orig_count < 0 || orig_count >= (int) GET_MODE_BITSIZE (mode)) - { - if (x) - return x; - - return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (orig_count)); - } + return NULL_RTX; count = orig_count; @@ -8291,10 +8288,9 @@ simplify_shift_const (rtx x, enum rtx_co while (count != 0) { - /* If we have an operand of (clobber (const_int 0)), just return that - value. */ + /* If we have an operand of (clobber (const_int 0)), fail. */ if (GET_CODE (varop) == CLOBBER) - return varop; + return NULL_RTX; /* If we discovered we had to complement VAROP, leave. Making a NOT here would cause an infinite loop. */ @@ -8330,7 +8326,7 @@ simplify_shift_const (rtx x, enum rtx_co multiple operations, each of which are defined, we know what the result is supposed to be. */ - if (count > (unsigned int) (GET_MODE_BITSIZE (shift_mode) - 1)) + if (count > (GET_MODE_BITSIZE (shift_mode) - 1)) { if (code == ASHIFTRT) count = GET_MODE_BITSIZE (shift_mode) - 1; @@ -8504,7 +8473,7 @@ simplify_shift_const (rtx x, enum rtx_co interpreted as the sign bit in a narrower mode, so, if the result is narrower, don't discard the shift. */ if (code == LSHIFTRT - && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1) + && count == (GET_MODE_BITSIZE (result_mode) - 1) && (GET_MODE_BITSIZE (result_mode) >= GET_MODE_BITSIZE (GET_MODE (varop)))) { @@ -8538,8 +8507,7 @@ simplify_shift_const (rtx x, enum rtx_co (ashiftrt:M1 (ashift:M1 (and:M1 (subreg:M1 FOO 0 C2) C3) C1). This simplifies certain SIGN_EXTEND operations. */ if (code == ASHIFT && first_code == ASHIFTRT - && count == (unsigned int) - (GET_MODE_BITSIZE (result_mode) + && count == (GET_MODE_BITSIZE (result_mode) - GET_MODE_BITSIZE (GET_MODE (varop)))) { /* C3 has the low-order C1 bits zero. */ @@ -8569,12 +8537,12 @@ simplify_shift_const (rtx x, enum rtx_co > first_count)) { varop = XEXP (varop, 0); - - signed_count = count - first_count; - if (signed_count < 0) - count = -signed_count, code = ASHIFT; - else - count = signed_count; + count -= first_count; + if (count < 0) + { + count = -count; + code = ASHIFT; + } continue; } @@ -8635,25 +8603,22 @@ simplify_shift_const (rtx x, enum rtx_co /* If the shifts are in the same direction, we add the counts. Otherwise, we subtract them. */ - signed_count = count; if ((code == ASHIFTRT || code == LSHIFTRT) == (first_code == ASHIFTRT || first_code == LSHIFTRT)) - signed_count += first_count; + count += first_count; else - signed_count -= first_count; + count -= first_count; /* If COUNT is positive, the new shift is usually CODE, except for the two exceptions below, in which case it is FIRST_CODE. If the count is negative, FIRST_CODE should always be used */ - if (signed_count > 0 + if (count > 0 && ((first_code == ROTATE && code == ASHIFT) || (first_code == ASHIFTRT && code == LSHIFTRT))) - code = first_code, count = signed_count; - else if (signed_count < 0) - code = first_code, count = -signed_count; - else - count = signed_count; + code = first_code; + else if (count < 0) + code = first_code, count = -count; varop = XEXP (varop, 0); continue; @@ -8696,8 +8661,7 @@ simplify_shift_const (rtx x, enum rtx_co && XEXP (XEXP (varop, 0), 1) == constm1_rtx && (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1) && (code == LSHIFTRT || code == ASHIFTRT) - && count == (unsigned int) - (GET_MODE_BITSIZE (GET_MODE (varop)) - 1) + && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1) && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1))) { count = 0; @@ -8764,7 +8728,7 @@ simplify_shift_const (rtx x, enum rtx_co if (code == LSHIFTRT && XEXP (varop, 1) == const0_rtx && GET_MODE (XEXP (varop, 0)) == result_mode - && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1) + && count == (GET_MODE_BITSIZE (result_mode) - 1) && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT && STORE_FLAG_VALUE == -1 && nonzero_bits (XEXP (varop, 0), result_mode) == 1 @@ -8784,7 +8746,7 @@ simplify_shift_const (rtx x, enum rtx_co /* (lshiftrt (neg A) C) where A is either 0 or 1 and C is one less than the number of bits in the mode is equivalent to A. */ if (code == LSHIFTRT - && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1) + && count == (GET_MODE_BITSIZE (result_mode) - 1) && nonzero_bits (XEXP (varop, 0), result_mode) == 1) { varop = XEXP (varop, 0); @@ -8809,7 +8771,7 @@ simplify_shift_const (rtx x, enum rtx_co is one less than the number of bits in the mode is equivalent to (xor A 1). */ if (code == LSHIFTRT - && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1) + && count == (GET_MODE_BITSIZE (result_mode) - 1) && XEXP (varop, 1) == constm1_rtx && nonzero_bits (XEXP (varop, 0), result_mode) == 1 && merge_outer_ops (&outer_op, &outer_const, XOR, @@ -8894,12 +8856,10 @@ simplify_shift_const (rtx x, enum rtx_co if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1) && GET_CODE (XEXP (varop, 0)) == ASHIFTRT - && count == (unsigned int) - (GET_MODE_BITSIZE (GET_MODE (varop)) - 1) + && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1) && (code == LSHIFTRT || code == ASHIFTRT) && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (varop, 0), 1)) - == count + && INTVAL (XEXP (XEXP (varop, 0), 1)) == count && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1))) { count = 0; @@ -8956,44 +8916,31 @@ simplify_shift_const (rtx x, enum rtx_co a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places. If OUTER_OP is non-UNKNOWN, it is an operation that needs to be applied to the result of the shift. OUTER_CONST is the relevant constant, - but we must turn off all bits turned off in the shift. - - If we were passed a value for X, see if we can use any pieces of - it. If not, make new rtx. */ - - if (x && GET_RTX_CLASS (GET_CODE (x)) == RTX_BIN_ARITH - && GET_CODE (XEXP (x, 1)) == CONST_INT - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == count) - const_rtx = XEXP (x, 1); - else - const_rtx = GEN_INT (count); - - if (x && GET_CODE (XEXP (x, 0)) == SUBREG - && GET_MODE (XEXP (x, 0)) == shift_mode - && SUBREG_REG (XEXP (x, 0)) == varop) - varop = XEXP (x, 0); - else if (GET_MODE (varop) != shift_mode) - varop = gen_lowpart (shift_mode, varop); + but we must turn off all bits turned off in the shift. */ - /* If we can't make the SUBREG, try to return what we were given. */ - if (GET_CODE (varop) == CLOBBER) - return x ? x : varop; + if (outer_op == UNKNOWN + && orig_code == code && orig_count == count + && varop == orig_varop + && shift_mode == GET_MODE (varop)) + return NULL_RTX; - new = simplify_binary_operation (code, shift_mode, varop, const_rtx); - if (new != 0) - x = new; - else - x = gen_rtx_fmt_ee (code, shift_mode, varop, const_rtx); + /* Make a SUBREG if necessary. If we can't make it, fail. */ + varop = gen_lowpart (shift_mode, varop); + if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER) + return NULL_RTX; /* If we have an outer operation and we just made a shift, it is possible that we could have simplified the shift were it not for the outer operation. So try to do the simplification recursively. */ - if (outer_op != UNKNOWN && GET_CODE (x) == code - && GET_CODE (XEXP (x, 1)) == CONST_INT) - x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0), - INTVAL (XEXP (x, 1))); + if (outer_op != UNKNOWN) + x = simplify_shift_const_1 (code, shift_mode, varop, count); + else + x = NULL_RTX; + + if (x == NULL_RTX) + x = simplify_gen_binary (code, shift_mode, varop, GEN_INT (count)); /* If we were doing an LSHIFTRT in a wider mode than it was originally, turn off all the bits that the shift would have turned off. */ @@ -9029,6 +8965,25 @@ simplify_shift_const (rtx x, enum rtx_co return x; } + +static rtx +simplify_shift_const (rtx x, enum rtx_code code, enum machine_mode result_mode, + rtx varop, int count) +{ + rtx tem = simplify_shift_const_1 (code, result_mode, varop, count); + if (tem) + return tem; + else + { + if (!x) + x = simplify_gen_binary (code, GET_MODE (varop), varop, + GEN_INT (count)); + if (GET_MODE (x) != result_mode) + x = gen_lowpart (result_mode, x); + return x; + } +} + /* Like recog, but we receive the address of a pointer to a new pattern. We try to match the rtx that the pointer points to. @@ -10033,9 +9988,9 @@ simplify_comparison (enum rtx_code code, && XEXP (XEXP (op0, 0), 0) == const1_rtx) { op0 = simplify_and_const_int - (op0, mode, gen_rtx_LSHIFTRT (mode, - XEXP (op0, 1), - XEXP (XEXP (op0, 0), 1)), + (NULL_RTX, mode, gen_rtx_LSHIFTRT (mode, + XEXP (op0, 1), + XEXP (XEXP (op0, 0), 1)), (HOST_WIDE_INT) 1); continue; }