+/* 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.
+
+ The result is a possibly different comparison code to use.
+ *POP1 may be updated. */
+
+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_PRECISION (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;
+}
+\f