Index: combine.c =================================================================== --- combine.c (revision 172860) +++ combine.c (working copy) @@ -450,6 +450,7 @@ int); static int recog_for_combine (rtx *, rtx, rtx *); static rtx gen_lowpart_for_combine (enum machine_mode, rtx); +static enum rtx_code simplify_compare_const (enum rtx_code, rtx, rtx *); static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *); static void update_table_tick (rtx); static void record_value_for_reg (rtx, rtx, rtx); @@ -10808,6 +10840,188 @@ return gen_rtx_CLOBBER (omode, const0_rtx); } +/* Try to simplify a comparison between OP0 and a constant OP1, + where CODE is the comparison code that will be tested, into a + (CODE OP0 const0_rtx) form. */ + +static enum rtx_code +simplify_compare_const (enum rtx_code code, rtx op0, rtx *pop1) +{ + enum machine_mode mode = GET_MODE (op0); + unsigned int mode_width = GET_MODE_BITSIZE (mode); + HOST_WIDE_INT const_op = INTVAL (*pop1); + + /* Get the constant we are comparing against and turn off all bits + not on in our mode. */ + if (mode != VOIDmode) + const_op = trunc_int_for_mode (const_op, mode); + + /* If we are comparing against a constant power of two and the value + being compared can only have that single bit nonzero (e.g., it was + `and'ed with that bit), we can replace this with a comparison + with zero. */ + if (const_op + && (code == EQ || code == NE || code == GE || code == GEU + || code == LT || code == LTU) + && mode_width <= HOST_BITS_PER_WIDE_INT + && exact_log2 (const_op) >= 0 + && nonzero_bits (op0, mode) == (unsigned HOST_WIDE_INT) const_op) + { + code = (code == EQ || code == GE || code == GEU ? NE : EQ); + const_op = 0; + } + + /* Similarly, if we are comparing a value known to be either -1 or + 0 with -1, change it to the opposite comparison against zero. */ + if (const_op == -1 + && (code == EQ || code == NE || code == GT || code == LE + || code == GEU || code == LTU) + && num_sign_bit_copies (op0, mode) == mode_width) + { + code = (code == EQ || code == LE || code == GEU ? NE : EQ); + const_op = 0; + } + + /* Do some canonicalizations based on the comparison code. We prefer + comparisons against zero and then prefer equality comparisons. + If we can reduce the size of a constant, we will do that too. */ + switch (code) + { + case LT: + /* < C is equivalent to <= (C - 1) */ + if (const_op > 0) + { + const_op -= 1; + code = LE; + /* ... fall through to LE case below. */ + } + else + break; + + case LE: + /* <= C is equivalent to < (C + 1); we do this for C < 0 */ + if (const_op < 0) + { + const_op += 1; + code = LT; + } + + /* If we are doing a <= 0 comparison on a value known to have + a zero sign bit, we can replace this with == 0. */ + else if (const_op == 0 + && mode_width <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (op0, mode) + & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1))) + == 0) + code = EQ; + break; + + case GE: + /* >= C is equivalent to > (C - 1). */ + if (const_op > 0) + { + const_op -= 1; + code = GT; + /* ... fall through to GT below. */ + } + else + break; + + case GT: + /* > C is equivalent to >= (C + 1); we do this for C < 0. */ + if (const_op < 0) + { + const_op += 1; + code = GE; + } + + /* If we are doing a > 0 comparison on a value known to have + a zero sign bit, we can replace this with != 0. */ + else if (const_op == 0 + && mode_width <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (op0, mode) + & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1))) + == 0) + code = NE; + break; + + case LTU: + /* < C is equivalent to <= (C - 1). */ + if (const_op > 0) + { + const_op -= 1; + code = LEU; + /* ... fall through ... */ + } + /* (unsigned) < 0x80000000 is equivalent to >= 0. */ + else if (mode_width <= HOST_BITS_PER_WIDE_INT + && (unsigned HOST_WIDE_INT) const_op + == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) + { + const_op = 0; + code = GE; + break; + } + else + break; + + case LEU: + /* unsigned <= 0 is equivalent to == 0 */ + if (const_op == 0) + code = EQ; + /* (unsigned) <= 0x7fffffff is equivalent to >= 0. */ + else if (mode_width <= HOST_BITS_PER_WIDE_INT + && (unsigned HOST_WIDE_INT) const_op + == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1) + { + const_op = 0; + code = GE; + } + break; + + case GEU: + /* >= C is equivalent to > (C - 1). */ + if (const_op > 1) + { + const_op -= 1; + code = GTU; + /* ... fall through ... */ + } + + /* (unsigned) >= 0x80000000 is equivalent to < 0. */ + else if (mode_width <= HOST_BITS_PER_WIDE_INT + && (unsigned HOST_WIDE_INT) const_op + == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) + { + const_op = 0; + code = LT; + break; + } + else + break; + + case GTU: + /* unsigned > 0 is equivalent to != 0 */ + if (const_op == 0) + code = NE; + /* (unsigned) > 0x7fffffff is equivalent to < 0. */ + else if (mode_width <= HOST_BITS_PER_WIDE_INT + && (unsigned HOST_WIDE_INT) const_op + == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1) + { + const_op = 0; + code = LT; + } + break; + + default: + break; + } + + *pop1 = GEN_INT (const_op); + return code; +} + /* Simplify a comparison between *POP0 and *POP1 where CODE is the comparison code that will be tested. @@ -10997,186 +11211,11 @@ && (GET_CODE (op0) == COMPARE || COMPARISON_P (op0)))) break; - /* Get the constant we are comparing against and turn off all bits - not on in our mode. */ + /* Try to simplify the compare to constant, possibly changing the + comparison op, and/or changing op1 to zero. */ + code = simplify_compare_const (code, op0, &op1); const_op = INTVAL (op1); - if (mode != VOIDmode) - const_op = trunc_int_for_mode (const_op, mode); - op1 = GEN_INT (const_op); - /* If we are comparing against a constant power of two and the value - being compared can only have that single bit nonzero (e.g., it was - `and'ed with that bit), we can replace this with a comparison - with zero. */ - if (const_op - && (code == EQ || code == NE || code == GE || code == GEU - || code == LT || code == LTU) - && mode_width <= HOST_BITS_PER_WIDE_INT - && exact_log2 (const_op) >= 0 - && nonzero_bits (op0, mode) == (unsigned HOST_WIDE_INT) const_op) - { - code = (code == EQ || code == GE || code == GEU ? NE : EQ); - op1 = const0_rtx, const_op = 0; - } - - /* Similarly, if we are comparing a value known to be either -1 or - 0 with -1, change it to the opposite comparison against zero. */ - - if (const_op == -1 - && (code == EQ || code == NE || code == GT || code == LE - || code == GEU || code == LTU) - && num_sign_bit_copies (op0, mode) == mode_width) - { - code = (code == EQ || code == LE || code == GEU ? NE : EQ); - op1 = const0_rtx, const_op = 0; - } - - /* Do some canonicalizations based on the comparison code. We prefer - comparisons against zero and then prefer equality comparisons. - If we can reduce the size of a constant, we will do that too. */ - - switch (code) - { - case LT: - /* < C is equivalent to <= (C - 1) */ - if (const_op > 0) - { - const_op -= 1; - op1 = GEN_INT (const_op); - code = LE; - /* ... fall through to LE case below. */ - } - else - break; - - case LE: - /* <= C is equivalent to < (C + 1); we do this for C < 0 */ - if (const_op < 0) - { - const_op += 1; - op1 = GEN_INT (const_op); - code = LT; - } - - /* If we are doing a <= 0 comparison on a value known to have - a zero sign bit, we can replace this with == 0. */ - else if (const_op == 0 - && mode_width <= HOST_BITS_PER_WIDE_INT - && (nonzero_bits (op0, mode) - & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1))) - == 0) - code = EQ; - break; - - case GE: - /* >= C is equivalent to > (C - 1). */ - if (const_op > 0) - { - const_op -= 1; - op1 = GEN_INT (const_op); - code = GT; - /* ... fall through to GT below. */ - } - else - break; - - case GT: - /* > C is equivalent to >= (C + 1); we do this for C < 0. */ - if (const_op < 0) - { - const_op += 1; - op1 = GEN_INT (const_op); - code = GE; - } - - /* If we are doing a > 0 comparison on a value known to have - a zero sign bit, we can replace this with != 0. */ - else if (const_op == 0 - && mode_width <= HOST_BITS_PER_WIDE_INT - && (nonzero_bits (op0, mode) - & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1))) - == 0) - code = NE; - break; - - case LTU: - /* < C is equivalent to <= (C - 1). */ - if (const_op > 0) - { - const_op -= 1; - op1 = GEN_INT (const_op); - code = LEU; - /* ... fall through ... */ - } - - /* (unsigned) < 0x80000000 is equivalent to >= 0. */ - else if (mode_width <= HOST_BITS_PER_WIDE_INT - && (unsigned HOST_WIDE_INT) const_op - == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - { - const_op = 0, op1 = const0_rtx; - code = GE; - break; - } - else - break; - - case LEU: - /* unsigned <= 0 is equivalent to == 0 */ - if (const_op == 0) - code = EQ; - - /* (unsigned) <= 0x7fffffff is equivalent to >= 0. */ - else if (mode_width <= HOST_BITS_PER_WIDE_INT - && (unsigned HOST_WIDE_INT) const_op - == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1) - { - const_op = 0, op1 = const0_rtx; - code = GE; - } - break; - - case GEU: - /* >= C is equivalent to > (C - 1). */ - if (const_op > 1) - { - const_op -= 1; - op1 = GEN_INT (const_op); - code = GTU; - /* ... fall through ... */ - } - - /* (unsigned) >= 0x80000000 is equivalent to < 0. */ - else if (mode_width <= HOST_BITS_PER_WIDE_INT - && (unsigned HOST_WIDE_INT) const_op - == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - { - const_op = 0, op1 = const0_rtx; - code = LT; - break; - } - else - break; - - case GTU: - /* unsigned > 0 is equivalent to != 0 */ - if (const_op == 0) - code = NE; - - /* (unsigned) > 0x7fffffff is equivalent to < 0. */ - else if (mode_width <= HOST_BITS_PER_WIDE_INT - && (unsigned HOST_WIDE_INT) const_op - == ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)) - 1) - { - const_op = 0, op1 = const0_rtx; - code = LT; - } - break; - - default: - break; - } - /* Compute some predicates to simplify code below. */ equality_comparison_p = (code == EQ || code == NE);