From: Richard Kenner Date: Tue, 3 Aug 1993 21:31:46 +0000 (-0400) Subject: (force_to_mode): Now pass actual AND mask instead of number off; X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6139ff201982260460464bb59bf9022b0dfce18e;p=gcc.git (force_to_mode): Now pass actual AND mask instead of number off; generalize appropriately. Move most cases from simplify_and_const_int in. (simplify_and_const_int): Remove most code from here; call force_to_mode instead. (subst, make_extraction, make_compound_operation): Change calls to force_to_mode. (make_field_assignment): Likewise. (simplify_comparison): Add call to force_to_mode when doing a sign bit comparison. From-SVN: r5060 --- diff --git a/gcc/combine.c b/gcc/combine.c index 501d5e2cc95..1362dbc1b70 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -382,7 +382,8 @@ static rtx make_extraction PROTO((enum machine_mode, rtx, int, rtx, int, int, int, int)); static rtx make_compound_operation PROTO((rtx, enum rtx_code)); static int get_pos_from_mask PROTO((unsigned HOST_WIDE_INT, int *)); -static rtx force_to_mode PROTO((rtx, enum machine_mode, int, rtx)); +static rtx force_to_mode PROTO((rtx, enum machine_mode, + unsigned HOST_WIDE_INT, rtx)); static rtx known_cond PROTO((rtx, enum rtx_code, rtx, rtx)); static rtx make_field_assignment PROTO((rtx)); static rtx apply_distributive_law PROTO((rtx)); @@ -3134,7 +3135,7 @@ subst (x, from, to, in_dest, unique_copy) if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) && subreg_lowpart_p (x)) - return force_to_mode (SUBREG_REG (x), mode, GET_MODE_BITSIZE (mode), + return force_to_mode (SUBREG_REG (x), mode, GET_MODE_MASK (mode), NULL_RTX); break; @@ -4624,7 +4625,9 @@ subst (x, from, to, in_dest, unique_copy) else if (GET_CODE (XEXP (x, 1)) != REG) SUBST (XEXP (x, 1), force_to_mode (XEXP (x, 1), GET_MODE (x), - exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))), + ((HOST_WIDE_INT) 1 + << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x)))) + - 1, NULL_RTX)); #endif @@ -4914,6 +4917,7 @@ make_extraction (mode, inner, pos, pos_rtx, len, int spans_byte = 0; rtx new = 0; rtx orig_pos_rtx = pos_rtx; + int orig_pos; /* Get some information about INNER and get the innermost object. */ if (GET_CODE (inner) == USE) @@ -5000,7 +5004,11 @@ make_extraction (mode, inner, pos, pos_rtx, len, / UNITS_PER_WORD) : 0)); else - new = force_to_mode (inner, tmode, len, NULL_RTX); + new = force_to_mode (inner, tmode, + len >= HOST_BITS_PER_WIDE_INT + ? GET_MODE_MASK (tmode) + : ((HOST_WIDE_INT) 1 << len) - 1, + NULL_RTX); /* If this extraction is going into the destination of a SET, make a STRICT_LOW_PART unless we made a MEM. */ @@ -5073,6 +5081,8 @@ make_extraction (mode, inner, pos, pos_rtx, len, || MEM_VOLATILE_P (inner)))) wanted_mem_mode = extraction_mode; + orig_pos = pos; + #if BITS_BIG_ENDIAN /* If position is constant, compute new position. Otherwise, build subtraction. */ @@ -5139,8 +5149,9 @@ make_extraction (mode, inner, pos, pos_rtx, len, /* If INNER is not memory, we can always get it into the proper mode. */ else if (GET_CODE (inner) != MEM) inner = force_to_mode (inner, extraction_mode, - (pos < 0 ? GET_MODE_BITSIZE (extraction_mode) - : len + pos), + pos_rtx || len + orig_pos >= HOST_BITS_PER_WIDE_INT + ? GET_MODE_MASK (extraction_mode) + : (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos, NULL_RTX); /* Adjust mode of POS_RTX, if needed. If we want a wider mode, we @@ -5425,7 +5436,7 @@ make_compound_operation (x, in_code) && subreg_lowpart_p (x)) { rtx newer = force_to_mode (tem, mode, - GET_MODE_BITSIZE (mode), NULL_RTX); + GET_MODE_MASK (mode), NULL_RTX); /* If we have something other than a SUBREG, we might have done an expansion, so rerun outselves. */ @@ -5482,39 +5493,87 @@ get_pos_from_mask (m, plen) return pos; } -/* Rewrite X so that it is an expression in MODE. We only care about the - low-order BITS bits so we can ignore AND operations that just clear - higher-order bits. +/* See if X can be simplified knowing that we will only refer to it in + MODE and will only refer to those bits that are nonzero in MASK. + If other bits are being computed or if masking operations are done + that select a superset of the bits in MASK, they can sometimes be + ignored. + + Return a possibly simplified expression, but always convert X to + MODE. If X is a CONST_INT, AND the CONST_INT with MASK. Also, if REG is non-zero and X is a register equal in value to REG, replace X with REG. */ static rtx -force_to_mode (x, mode, bits, reg) +force_to_mode (x, mode, mask, reg) rtx x; enum machine_mode mode; - int bits; + unsigned HOST_WIDE_INT mask; rtx reg; { enum rtx_code code = GET_CODE (x); - enum machine_mode op_mode = mode; + unsigned HOST_WIDE_INT nonzero = nonzero_bits (x, mode); + rtx op0, op1, temp; + + /* We want to perform the operation is its present mode unless we know + that the operation is valid in MODE, in which case we do the operation + in MODE. */ + enum machine_mode op_mode + = ((code_to_optab[(int) code] != 0 + && (code_to_optab[(int) code]->handlers[(int) mode].insn_code + != CODE_FOR_nothing)) + ? mode : GET_MODE (x)); + + /* When we have an arithmetic operation, or a shift whose count we + do not know, we need to assume that all bit the up to the highest-order + bit in MASK will be needed. This is how we form such a mask. */ + unsigned HOST_WIDE_INT fuller_mask + = (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT + ? GET_MODE_MASK (op_mode) + : ((HOST_WIDE_INT) 1 << (floor_log2 (mask) + 1)) - 1); + + /* If none of the bits in X are needed, return a zero. */ + if ((nonzero & mask) == 0) + return const0_rtx; - /* If X is narrower than MODE or if BITS is larger than the size of MODE, - just get X in the proper mode. */ + /* If X is a CONST_INT, return a new one. Do this here since the + test below will fail. */ + if (GET_CODE (x) == CONST_INT) + return GEN_INT (INTVAL (x) & mask); - if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode) - || bits > GET_MODE_BITSIZE (mode)) + /* If X is narrower than MODE, just get X in the proper mode. */ + if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode)) return gen_lowpart_for_combine (mode, x); + /* If we aren't changing the mode and all zero bits in MASK are already + known to be zero in X, we need not do anything. */ + if (GET_MODE (x) == mode && (~ mask & nonzero) == 0) + return x; + switch (code) { + case CLOBBER: + /* If X is a (clobber (const_int)), return it since we know we are + generating something that won't match. */ + return x; + +#if ! BITS_BIG_ENDIAN + case USE: + /* X is a (use (mem ..)) that was made from a bit-field extraction that + spanned the boundary of the MEM. If we are now masking so it is + within that boundary, we don't need the USE any more. */ + if ((mask & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0) + return force_to_mode (XEXP (x, 0), mode, mask, reg); +#endif + case SIGN_EXTEND: case ZERO_EXTEND: case ZERO_EXTRACT: case SIGN_EXTRACT: x = expand_compound_operation (x); if (GET_CODE (x) != code) - return force_to_mode (x, mode, bits, reg); + return force_to_mode (x, mode, mask, reg); break; case REG: @@ -5523,90 +5582,106 @@ force_to_mode (x, mode, bits, reg) x = reg; break; - case CONST_INT: - if (bits < HOST_BITS_PER_WIDE_INT) - x = GEN_INT (INTVAL (x) & (((HOST_WIDE_INT) 1 << bits) - 1)); - return x; - case SUBREG: - /* Ignore low-order SUBREGs. */ - if (subreg_lowpart_p (x)) - return force_to_mode (SUBREG_REG (x), mode, bits, reg); + if (subreg_lowpart_p (x) + /* We can ignore the effect this SUBREG if it narrows the mode or, + on machines where byte operations extend, if the constant masks + to zero all the bits the mode doesn't have. */ + && ((GET_MODE_SIZE (GET_MODE (x)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) +#ifdef BYTE_LOADS_EXTEND + || (0 == (mask + & GET_MODE_MASK (GET_MODE (x)) + & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))))) +#endif + )) + return force_to_mode (SUBREG_REG (x), mode, mask, reg); break; case AND: - /* If this is an AND with a constant. Otherwise, we fall through to - do the general binary case. */ + /* If this is an AND with a constant, convert it into an AND + whose constant is the AND of that constant with MASK. If it + remains an AND of MASK, delete it since it is redundant. */ - if (GET_CODE (XEXP (x, 1)) == CONST_INT) + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT) { - HOST_WIDE_INT mask = INTVAL (XEXP (x, 1)); - int len = exact_log2 (mask + 1); - rtx op = XEXP (x, 0); - - /* If this is masking some low-order bits, we may be able to - impose a stricter constraint on what bits of the operand are - required. */ - - op = force_to_mode (op, mode, len > 0 ? MIN (len, bits) : bits, - reg); - - if (bits < HOST_BITS_PER_WIDE_INT) - mask &= ((HOST_WIDE_INT) 1 << bits) - 1; - - /* If we have no AND in MODE, use the original mode for the - operation. */ - - if (and_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) - op_mode = GET_MODE (x); - - x = simplify_and_const_int (x, op_mode, op, mask); + x = simplify_and_const_int (x, op_mode, XEXP (x, 0), + mask & INTVAL (XEXP (x, 1))); /* If X is still an AND, see if it is an AND with a mask that is just some low-order bits. If so, and it is BITS wide (it can't be wider), we don't need it. */ if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT - && bits < HOST_BITS_PER_WIDE_INT - && INTVAL (XEXP (x, 1)) == ((HOST_WIDE_INT) 1 << bits) - 1) + && INTVAL (XEXP (x, 1)) == mask) x = XEXP (x, 0); break; } - /* ... fall through ... */ + goto binop; case PLUS: + /* In (and (plus FOO C1) M), if M is a mask that just turns off + low-order bits (as in an alignment operation) and FOO is already + aligned to that boundary, mask C1 to that boundary as well. + This may eliminate that PLUS and, later, the AND. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && exact_log2 (- mask) >= 0 + && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0 + && (INTVAL (XEXP (x, 1)) & ~ mask) != 0) + return force_to_mode (plus_constant (XEXP (x, 0), + INTVAL (XEXP (x, 1)) & mask), + mode, mask, reg); + + /* ... fall through ... */ + case MINUS: case MULT: + /* For PLUS, MINUS and MULT, we need any bits less significant than the + most significant bit in MASK since carries from those bits will + affect the bits we are interested in. */ + mask = fuller_mask; + goto binop; + case IOR: case XOR: + /* If X is (ior (lshiftrt FOO C1) C2), try to commute the IOR and + LSHIFTRT so we end up with an (and (lshiftrt (ior ...) ...) ...) + operation which may be a bitfield extraction. Ensure that the + constant we form is not wider than the mode of X. */ + + if (GET_CODE (XEXP (x, 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT + && GET_CODE (XEXP (x, 1)) == CONST_INT + && ((INTVAL (XEXP (XEXP (x, 0), 1)) + + floor_log2 (INTVAL (XEXP (x, 1)))) + < GET_MODE_BITSIZE (GET_MODE (x))) + && (INTVAL (XEXP (x, 1)) + & ~ nonzero_bits (XEXP (x, 0), GET_MODE (x)) == 0)) + { + temp = GEN_INT ((INTVAL (XEXP (x, 1)) & mask) + << INTVAL (XEXP (XEXP (x, 0), 1))); + temp = gen_binary (GET_CODE (x), GET_MODE (x), + XEXP (XEXP (x, 0), 0), temp); + x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (x, 1)); + return force_to_mode (x, mode, mask, reg); + } + + binop: /* For most binary operations, just propagate into the operation and - change the mode if we have an operation of that mode. */ - - if ((code == PLUS - && add_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) - || (code == MINUS - && sub_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) - || (code == MULT && (smul_optab->handlers[(int) mode].insn_code - == CODE_FOR_nothing)) - || (code == AND - && and_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) - || (code == IOR - && ior_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) - || (code == XOR && (xor_optab->handlers[(int) mode].insn_code - == CODE_FOR_nothing))) - op_mode = GET_MODE (x); - - x = gen_binary (code, op_mode, - gen_lowpart_for_combine (op_mode, - force_to_mode (XEXP (x, 0), - mode, bits, - reg)), - gen_lowpart_for_combine (op_mode, - force_to_mode (XEXP (x, 1), - mode, bits, - reg))); + change the mode if we have an operation of that mode. */ + + op0 = gen_lowpart_for_combine (op_mode, force_to_mode (XEXP (x, 0), + mode, mask, reg)); + op1 = gen_lowpart_for_combine (op_mode, force_to_mode (XEXP (x, 1), + mode, mask, reg)); + + if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1)) + x = gen_binary (code, op_mode, op0, op1); break; case ASHIFT: @@ -5615,81 +5690,191 @@ force_to_mode (x, mode, bits, reg) However, we cannot do anything with shifts where we cannot guarantee that the counts are smaller than the size of the mode because such a count will have a different meaning in a - wider mode. - - If we can narrow the shift and know the count, we need even fewer - bits of the first operand. */ + wider mode. */ if (! (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0 && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode)) && ! (GET_MODE (XEXP (x, 1)) != VOIDmode && (nonzero_bits (XEXP (x, 1), GET_MODE (XEXP (x, 1))) < (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode)))) break; - if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) < bits) - bits -= INTVAL (XEXP (x, 1)); - - if ((code == ASHIFT - && ashl_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) - || (code == LSHIFT && (lshl_optab->handlers[(int) mode].insn_code - == CODE_FOR_nothing))) - op_mode = GET_MODE (x); - - x = gen_binary (code, op_mode, - gen_lowpart_for_combine (op_mode, - force_to_mode (XEXP (x, 0), - mode, bits, - reg)), - XEXP (x, 1)); + /* If the shift count is a constant and we can do arithmetic in + the mode of the shift, refine which bits we need. Otherwise, use the + conservative form of the mask. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0 + && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (op_mode) + && GET_MODE_BITSIZE (op_mode) <= HOST_BITS_PER_WIDE_INT) + mask >>= INTVAL (XEXP (x, 1)); + else + mask = fuller_mask; + + op0 = gen_lowpart_for_combine (op_mode, + force_to_mode (XEXP (x, 0), op_mode, + mask, reg)); + + if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0)) + x = gen_binary (code, op_mode, op0, XEXP (x, 1)); break; case LSHIFTRT: /* Here we can only do something if the shift count is a constant and - the count plus BITS is no larger than the width of MODE. In that - case, we can do the shift in MODE. */ + we can do arithmetic in OP_MODE. */ if (GET_CODE (XEXP (x, 1)) == CONST_INT - && INTVAL (XEXP (x, 1)) + bits <= GET_MODE_BITSIZE (mode)) + && GET_MODE_BITSIZE (op_mode) <= HOST_BITS_PER_WIDE_INT) { - rtx inner = force_to_mode (XEXP (x, 0), mode, - bits + INTVAL (XEXP (x, 1)), reg); + rtx inner = XEXP (x, 0); + + /* Select the mask of the bits we need for the shift operand. */ + mask <<= INTVAL (XEXP (x, 1)); - if (lshr_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) + /* We can only change the mode of the shift if we can do arithmetic + in the mode of the shift and MASK is no wider than the width of + OP_MODE. */ + if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT + || (mask & ~ GET_MODE_MASK (op_mode)) != 0) op_mode = GET_MODE (x); - x = gen_binary (LSHIFTRT, op_mode, - gen_lowpart_for_combine (op_mode, inner), - XEXP (x, 1)); + inner = force_to_mode (inner, op_mode, mask, reg); + + if (GET_MODE (x) != op_mode || inner != XEXP (x, 0)) + x = gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1)); } + + /* If we have (and (lshiftrt FOO C1) C2) where the combination of the + shift and AND produces only copies of the sign bit (C2 is one less + than a power of two), we can do this with just a shift. */ + + if (GET_CODE (x) == LSHIFTRT + && GET_CODE (XEXP (x, 1)) == CONST_INT + && ((INTVAL (XEXP (x, 1)) + + num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))) + >= GET_MODE_BITSIZE (GET_MODE (x))) + && exact_log2 (mask + 1) >= 0 + && (num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0))) + >= exact_log2 (mask + 1))) + x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0), + GEN_INT (GET_MODE_BITSIZE (GET_MODE (x)) + - exact_log2 (mask + 1))); break; case ASHIFTRT: + /* If we are just looking for the sign bit, we don't need this shift at + all, even if it has a variable count. */ + if (mask == ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))) + return force_to_mode (XEXP (x, 0), mode, mask, reg); + + /* If this is a shift by a constant, get a mask that contains those bits + that are not copies of the sign bit. We then have two cases: If + MASK only includes those bits, this can be a logical shift, which may + allow simplifications. If MASK is a single-bit field not within + those bits, we are requesting a copy of the sign bit and hence can + shift the sign bit to the appropriate location. */ + + 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; + + nonzero = GET_MODE_MASK (GET_MODE (x)); + nonzero >>= INTVAL (XEXP (x, 1)); + + if ((mask & ~ nonzero) == 0 + || (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); + + if (GET_CODE (x) != ASHIFTRT) + return force_to_mode (x, mode, mask, reg); + } + } + + /* If MASK is 1, convert this to a LSHIFTRT. This can be done + even if the shift count isn't a constant. */ + if (mask == 1) + x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)); + /* If this is a sign-extension operation that just affects bits we don't care about, remove it. */ if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0 - && INTVAL (XEXP (x, 1)) <= GET_MODE_BITSIZE (GET_MODE (x)) - bits + && (INTVAL (XEXP (x, 1)) + <= GET_MODE_BITSIZE (GET_MODE (x)) - (floor_log2 (mask) + 1)) && GET_CODE (XEXP (x, 0)) == ASHIFT && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT && INTVAL (XEXP (XEXP (x, 0), 1)) == INTVAL (XEXP (x, 1))) - return force_to_mode (XEXP (XEXP (x, 0), 0), mode, bits, reg); + return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask, reg); + break; + case ROTATE: + case ROTATERT: + /* If the shift count is constant and we can do computations + in the mode of X, compute where the bits we care about are. + Otherwise, we can't do anything. Don't change the mode of + the shift or propagate MODE into the shift, though. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0) + { + temp = simplify_binary_operation (code == ROTATE ? ROTATERT : ROTATE, + GET_MODE (x), GEN_INT (mask), + XEXP (x, 1)); + if (temp) + SUBST (XEXP (x, 0), + force_to_mode (XEXP (x, 0), GET_MODE (x), + INTVAL (temp), reg)); + } + break; + case NEG: + /* We need any bits less significant than the most significant bit in + MASK since carries from those bits will affect the bits we are + interested in. */ + mask = fuller_mask; + goto unop; + case NOT: - if ((code == NEG - && neg_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) - || (code == NOT && (one_cmpl_optab->handlers[(int) mode].insn_code - == CODE_FOR_nothing))) - op_mode = GET_MODE (x); - - /* Handle these similarly to the way we handle most binary operations. */ - x = gen_unary (code, op_mode, - gen_lowpart_for_combine (op_mode, - force_to_mode (XEXP (x, 0), mode, - bits, reg))); + /* (not FOO) is (xor FOO CONST), so if FOO is an LSHIFTRT, we can do the + same as the XOR case above. Ensure that the constant we form is not + wider than the mode of X. */ + + if (GET_CODE (XEXP (x, 0)) == LSHIFTRT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 0), 1)) >= 0 + && (INTVAL (XEXP (XEXP (x, 0), 1)) + floor_log2 (mask) + < GET_MODE_BITSIZE (GET_MODE (x))) + && INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT) + { + temp = GEN_INT (mask << INTVAL (XEXP (XEXP (x, 0), 1))); + temp = gen_binary (XOR, GET_MODE (x), XEXP (XEXP (x, 0), 0), temp); + x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (XEXP (x, 0), 1)); + + return force_to_mode (x, mode, mask, reg); + } + + unop: + op0 = gen_lowpart_for_combine (op_mode, force_to_mode (XEXP (x, 0), mode, + mask, reg)); + if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0)) + x = gen_unary (code, op_mode, op0); + break; + + case NE: + /* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is included + in STORE_FLAG_VALUE and FOO has no bits that might be nonzero not + in CONST. */ + if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 0) == const0_rtx + && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0) + return force_to_mode (XEXP (x, 0), mode, mask, reg); + break; case IF_THEN_ELSE: @@ -5699,11 +5884,11 @@ force_to_mode (x, mode, bits, reg) SUBST (XEXP (x, 1), gen_lowpart_for_combine (GET_MODE (x), force_to_mode (XEXP (x, 1), mode, - bits, reg))); + mask, reg))); SUBST (XEXP (x, 2), gen_lowpart_for_combine (GET_MODE (x), force_to_mode (XEXP (x, 2), mode, - bits, reg))); + mask, reg))); break; } @@ -5907,7 +6092,11 @@ make_field_assignment (x) src = force_to_mode (simplify_shift_const (NULL_RTX, LSHIFTRT, GET_MODE (src), other, pos), - mode, len, dest); + mode, + GET_MODE_BITSIZE (mode) >= HOST_BITS_PER_WIDE_INT + ? GET_MODE_MASK (mode) + : ((HOST_WIDE_INT) 1 << len) - 1, + dest); return gen_rtx_combine (SET, VOIDmode, assign, src); } @@ -6053,276 +6242,14 @@ simplify_and_const_int (x, mode, varop, constop) register rtx temp; unsigned HOST_WIDE_INT nonzero; - /* There is a large class of optimizations based on the principle that - some operations produce results where certain bits are known to be zero, - and hence are not significant to the AND. For example, if we have just - done a left shift of one bit, the low-order bit is known to be zero and - hence an AND with a mask of ~1 would not do anything. - - At the end of the following loop, we set: - - VAROP to be the item to be AND'ed with; - CONSTOP to the constant value to AND it with. */ + /* Simplify VAROP knowing that we will be only looking at some of the + bits in it. */ + varop = force_to_mode (varop, mode, constop, NULL_RTX); - while (1) - { - /* If we ever encounter a mode wider than the host machine's widest - integer size, we can't compute the masks accurately, so give up. */ - if (GET_MODE_BITSIZE (GET_MODE (varop)) > HOST_BITS_PER_WIDE_INT) - break; - - /* Unless one of the cases below does a `continue', - a `break' will be executed to exit the loop. */ - - switch (GET_CODE (varop)) - { - case CLOBBER: - /* If VAROP is a (clobber (const_int)), return it since we know - we are generating something that won't match. */ - return varop; - -#if ! BITS_BIG_ENDIAN - case USE: - /* VAROP is a (use (mem ..)) that was made from a bit-field - extraction that spanned the boundary of the MEM. If we are - now masking so it is within that boundary, we don't need the - USE any more. */ - if ((constop & ~ GET_MODE_MASK (GET_MODE (XEXP (varop, 0)))) == 0) - { - varop = XEXP (varop, 0); - continue; - } - break; -#endif - - case SUBREG: - if (subreg_lowpart_p (varop) - /* We can ignore the effect this SUBREG if it narrows the mode - or, on machines where byte operations extend, if the - constant masks to zero all the bits the mode doesn't have. */ - && ((GET_MODE_SIZE (GET_MODE (varop)) - < GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop)))) -#ifdef BYTE_LOADS_EXTEND - || (0 == (constop - & GET_MODE_MASK (GET_MODE (varop)) - & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (varop))))) -#endif - )) - { - varop = SUBREG_REG (varop); - continue; - } - break; - - case ZERO_EXTRACT: - case SIGN_EXTRACT: - case ZERO_EXTEND: - case SIGN_EXTEND: - /* Try to expand these into a series of shifts and then work - with that result. If we can't, for example, if the extract - isn't at a fixed position, give up. */ - temp = expand_compound_operation (varop); - if (temp != varop) - { - varop = temp; - continue; - } - break; - - case AND: - if (GET_CODE (XEXP (varop, 1)) == CONST_INT) - { - constop &= INTVAL (XEXP (varop, 1)); - varop = XEXP (varop, 0); - continue; - } - break; - - case IOR: - case XOR: - /* If VAROP is (ior (lshiftrt FOO C1) C2), try to commute the IOR and - LSHIFT so we end up with an (and (lshiftrt (ior ...) ...) ...) - operation which may be a bitfield extraction. Ensure - that the constant we form is not wider than the mode of - VAROP. */ - - if (GET_CODE (XEXP (varop, 0)) == LSHIFTRT - && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT - && INTVAL (XEXP (XEXP (varop, 0), 1)) >= 0 - && INTVAL (XEXP (XEXP (varop, 0), 1)) < HOST_BITS_PER_WIDE_INT - && GET_CODE (XEXP (varop, 1)) == CONST_INT - && ((INTVAL (XEXP (XEXP (varop, 0), 1)) - + floor_log2 (INTVAL (XEXP (varop, 1)))) - < GET_MODE_BITSIZE (GET_MODE (varop))) - && (INTVAL (XEXP (varop, 1)) - & ~ nonzero_bits (XEXP (varop, 0), GET_MODE (varop)) == 0)) - { - temp = GEN_INT ((INTVAL (XEXP (varop, 1)) & constop) - << INTVAL (XEXP (XEXP (varop, 0), 1))); - temp = gen_binary (GET_CODE (varop), GET_MODE (varop), - XEXP (XEXP (varop, 0), 0), temp); - varop = gen_rtx_combine (LSHIFTRT, GET_MODE (varop), - temp, XEXP (varop, 1)); - continue; - } - - /* Apply the AND to both branches of the IOR or XOR, then try to - apply the distributive law. This may eliminate operations - if either branch can be simplified because of the AND. - It may also make some cases more complex, but those cases - probably won't match a pattern either with or without this. */ - return - gen_lowpart_for_combine - (mode, apply_distributive_law - (gen_rtx_combine - (GET_CODE (varop), GET_MODE (varop), - simplify_and_const_int (NULL_RTX, GET_MODE (varop), - XEXP (varop, 0), constop), - simplify_and_const_int (NULL_RTX, GET_MODE (varop), - XEXP (varop, 1), constop)))); - - case NOT: - /* (and (not FOO)) is (and (xor FOO CONST)), so if FOO is an - LSHIFTRT, we can do the same as above. Ensure that the constant - we form is not wider than the mode of VAROP. */ - - if (GET_CODE (XEXP (varop, 0)) == LSHIFTRT - && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT - && INTVAL (XEXP (XEXP (varop, 0), 1)) >= 0 - && (INTVAL (XEXP (XEXP (varop, 0), 1)) + floor_log2 (constop) - < GET_MODE_BITSIZE (GET_MODE (varop))) - && INTVAL (XEXP (XEXP (varop, 0), 1)) < HOST_BITS_PER_WIDE_INT) - { - temp = GEN_INT (constop << INTVAL (XEXP (XEXP (varop, 0), 1))); - temp = gen_binary (XOR, GET_MODE (varop), - XEXP (XEXP (varop, 0), 0), temp); - varop = gen_rtx_combine (LSHIFTRT, GET_MODE (varop), - temp, XEXP (XEXP (varop, 0), 1)); - continue; - } - break; - - case ASHIFTRT: - /* If we are just looking for the sign bit, we don't need this - shift at all, even if it has a variable count. */ - if (constop == ((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (GET_MODE (varop)) - 1))) - { - varop = XEXP (varop, 0); - continue; - } - - /* If this is a shift by a constant, get a mask that contains - those bits that are not copies of the sign bit. We then have - two cases: If CONSTOP only includes those bits, this can be - a logical shift, which may allow simplifications. If CONSTOP - is a single-bit field not within those bits, we are requesting - a copy of the sign bit and hence can shift the sign bit to - the appropriate location. */ - if (GET_CODE (XEXP (varop, 1)) == CONST_INT - && INTVAL (XEXP (varop, 1)) >= 0 - && INTVAL (XEXP (varop, 1)) < HOST_BITS_PER_WIDE_INT) - { - int i = -1; - - nonzero = GET_MODE_MASK (GET_MODE (varop)); - nonzero >>= INTVAL (XEXP (varop, 1)); - - if ((constop & ~ nonzero) == 0 - || (i = exact_log2 (constop)) >= 0) - { - varop = simplify_shift_const - (varop, LSHIFTRT, GET_MODE (varop), XEXP (varop, 0), - i < 0 ? INTVAL (XEXP (varop, 1)) - : GET_MODE_BITSIZE (GET_MODE (varop)) - 1 - i); - if (GET_CODE (varop) != ASHIFTRT) - continue; - } - } - - /* If our mask is 1, convert this to a LSHIFTRT. This can be done - even if the shift count isn't a constant. */ - if (constop == 1) - varop = gen_rtx_combine (LSHIFTRT, GET_MODE (varop), - XEXP (varop, 0), XEXP (varop, 1)); - break; - - case LSHIFTRT: - /* If we have (and (lshiftrt FOO C1) C2) where the combination of the - shift and AND produces only copies of the sign bit (C2 is one less - than a power of two), we can do this with just a shift. */ - - if (GET_CODE (XEXP (varop, 1)) == CONST_INT - && ((INTVAL (XEXP (varop, 1)) - + num_sign_bit_copies (XEXP (varop, 0), - GET_MODE (XEXP (varop, 0)))) - >= GET_MODE_BITSIZE (GET_MODE (varop))) - && exact_log2 (constop + 1) >= 0 - && (num_sign_bit_copies (XEXP (varop, 0), - GET_MODE (XEXP (varop, 0))) - >= exact_log2 (constop + 1))) - varop - = gen_rtx_combine (LSHIFTRT, GET_MODE (varop), XEXP (varop, 0), - GEN_INT (GET_MODE_BITSIZE (GET_MODE (varop)) - - exact_log2 (constop + 1))); - break; - - case NE: - /* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is - included in STORE_FLAG_VALUE and FOO has no bits that might be - nonzero not in CONST. */ - if ((constop & ~ STORE_FLAG_VALUE) == 0 - && XEXP (varop, 0) == const0_rtx - && (nonzero_bits (XEXP (varop, 0), mode) & ~ constop) == 0) - { - varop = XEXP (varop, 0); - continue; - } - break; - - case PLUS: - /* In (and (plus FOO C1) M), if M is a mask that just turns off - low-order bits (as in an alignment operation) and FOO is already - aligned to that boundary, we can convert remove this AND - and possibly the PLUS if it is now adding zero. */ - if (GET_CODE (XEXP (varop, 1)) == CONST_INT - && exact_log2 (-constop) >= 0 - && (nonzero_bits (XEXP (varop, 0), mode) & ~ constop) == 0) - { - varop = plus_constant (XEXP (varop, 0), - INTVAL (XEXP (varop, 1)) & constop); - constop = ~0; - break; - } - - /* ... fall through ... */ - - case MINUS: - /* In (and (plus (and FOO M1) BAR) M2), if M1 and M2 are one - less than powers of two and M2 is narrower than M1, we can - eliminate the inner AND. This occurs when incrementing - bit fields. */ - - if (GET_CODE (XEXP (varop, 0)) == ZERO_EXTRACT - || GET_CODE (XEXP (varop, 0)) == ZERO_EXTEND) - SUBST (XEXP (varop, 0), - expand_compound_operation (XEXP (varop, 0))); - - if (GET_CODE (XEXP (varop, 0)) == AND - && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT - && exact_log2 (constop + 1) >= 0 - && exact_log2 (INTVAL (XEXP (XEXP (varop, 0), 1)) + 1) >= 0 - && (~ INTVAL (XEXP (XEXP (varop, 0), 1)) & constop) == 0) - SUBST (XEXP (varop, 0), XEXP (XEXP (varop, 0), 0)); - break; - } - - break; - } - - /* If we have reached a constant, this whole thing is constant. */ - if (GET_CODE (varop) == CONST_INT) - return GEN_INT (constop & INTVAL (varop)); + /* If VAROP is a CLOBBER, we will fail so return it; if it is a + CONST_INT, we are done. */ + if (GET_CODE (varop) == CLOBBER || GET_CODE (varop) == CONST_INT) + return varop; /* See what bits may be nonzero in VAROP. Unlike the general case of a call to nonzero_bits, here we don't care about bits outside @@ -6340,6 +6267,23 @@ simplify_and_const_int (x, mode, varop, constop) if (constop == 0) return const0_rtx; + /* If VAROP is an IOR or XOR, apply the AND to both branches of the IOR + or XOR, then try to apply the distributive law. This may eliminate + operations if either branch can be simplified because of the AND. + It may also make some cases more complex, but those cases probably + won't match a pattern either with or without this. */ + + if (GET_CODE (varop) == IOR || GET_CODE (varop) == XOR) + return + gen_lowpart_for_combine + (mode, + apply_distributive_law + (gen_binary (GET_CODE (varop), GET_MODE (varop), + simplify_and_const_int (NULL_RTX, GET_MODE (varop), + XEXP (varop, 0), constop), + simplify_and_const_int (NULL_RTX, GET_MODE (varop), + XEXP (varop, 1), constop)))); + /* 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 @@ -6359,7 +6303,7 @@ simplify_and_const_int (x, mode, varop, constop) /* Otherwise, return an AND. See how much, if any, of X we can use. */ else if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode) - x = gen_rtx_combine (AND, mode, varop, GEN_INT (constop)); + x = gen_binary (AND, mode, varop, GEN_INT (constop)); else { @@ -8459,6 +8403,15 @@ simplify_comparison (code, pop0, pop1) unsigned_comparison_p = (code == LTU || code == LEU || code == GTU || code == LEU); + /* If this is a sign bit comparison and we can do arithmetic in + MODE, say that we will only be needing the sign bit of OP0. */ + if (sign_bit_comparison_p + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + op0 = force_to_mode (op0, mode, + ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (mode) - 1)), + NULL_RTX); + /* Now try cases based on the opcode of OP0. If none of the cases does a "continue", we exit this loop immediately after the switch. */