aboutsummaryrefslogtreecommitdiff
path: root/gcc/combine.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@linaro.org>2017-08-30 11:15:46 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2017-08-30 11:15:46 +0000
commitbf62e687b552f87c36bc5579c65a24de0b4f59b9 (patch)
tree2e431339af054633d0375b384554024913d45efc /gcc/combine.c
parente3731c52cf1b60d90f27f81ff0d1e2ad164fed07 (diff)
downloadgcc-bf62e687b552f87c36bc5579c65a24de0b4f59b9.zip
gcc-bf62e687b552f87c36bc5579c65a24de0b4f59b9.tar.gz
gcc-bf62e687b552f87c36bc5579c65a24de0b4f59b9.tar.bz2
[43/77] Use scalar_int_mode in simplify_comparison
The main loop of simplify_comparison starts with: if (GET_MODE_CLASS (mode) != MODE_INT && ! (mode == VOIDmode && (GET_CODE (op0) == COMPARE || COMPARISON_P (op0)))) break; So VOIDmode is only acceptable when comparing a COMPARE, EQ, NE, etc. operand against a constant. After this, the loop calls simplify_compare_const to: (a) bring the constant op1 closer to 0 where possible and (b) use nonzero_bits and num_sign_bit_copies to get a simpler constant. (a) works for both integer and VOID modes, (b) is specific to integer modes. The loop then has a big switch statement that handles further simplifications. This switch statement checks for COMPARISON_P codes but not for COMPARE. This patch uses scalar_int_mode to make the split between (a) and (b) more explicit. It also takes the COMPARISON_P handling out of the switch statement and does it first, so that the rest of the loop can treat the mode as a scalar_int_mode. 2017-08-30 Richard Sandiford <richard.sandiford@linaro.org> Alan Hayward <alan.hayward@arm.com> David Sherwood <david.sherwood@arm.com> gcc/ * combine.c (simplify_compare_const): Check that the mode is a scalar_int_mode (rather than VOIDmode) before testing its precision. (simplify_comparison): Move COMPARISON_P handling out of the loop and restrict the latter part of the loop to scalar_int_modes. Check is_a <scalar_int_mode> before calling HWI_COMPUTABLE_MODE_P and when considering SUBREG_REGs. Use is_int_mode instead of checking GET_MODE_CLASS against MODE_INT. Co-Authored-By: Alan Hayward <alan.hayward@arm.com> Co-Authored-By: David Sherwood <david.sherwood@arm.com> From-SVN: r251495
Diffstat (limited to 'gcc/combine.c')
-rw-r--r--gcc/combine.c179
1 files changed, 97 insertions, 82 deletions
diff --git a/gcc/combine.c b/gcc/combine.c
index 2e0e67b..2fbfed4 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -11640,7 +11640,7 @@ static enum rtx_code
simplify_compare_const (enum rtx_code code, machine_mode mode,
rtx op0, rtx *pop1)
{
- unsigned int mode_width = GET_MODE_PRECISION (mode);
+ scalar_int_mode int_mode;
HOST_WIDE_INT const_op = INTVAL (*pop1);
/* Get the constant we are comparing against and turn off all bits
@@ -11655,10 +11655,11 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
if (const_op
&& (code == EQ || code == NE || code == GE || code == GEU
|| code == LT || code == LTU)
- && mode_width - 1 < HOST_BITS_PER_WIDE_INT
- && pow2p_hwi (const_op & GET_MODE_MASK (mode))
- && (nonzero_bits (op0, mode)
- == (unsigned HOST_WIDE_INT) (const_op & GET_MODE_MASK (mode))))
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && pow2p_hwi (const_op & GET_MODE_MASK (int_mode))
+ && (nonzero_bits (op0, int_mode)
+ == (unsigned HOST_WIDE_INT) (const_op & GET_MODE_MASK (int_mode))))
{
code = (code == EQ || code == GE || code == GEU ? NE : EQ);
const_op = 0;
@@ -11669,7 +11670,8 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
if (const_op == -1
&& (code == EQ || code == NE || code == GT || code == LE
|| code == GEU || code == LTU)
- && num_sign_bit_copies (op0, mode) == mode_width)
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && num_sign_bit_copies (op0, int_mode) == GET_MODE_PRECISION (int_mode))
{
code = (code == EQ || code == LE || code == GEU ? NE : EQ);
const_op = 0;
@@ -11703,9 +11705,10 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
/* 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 - 1 < HOST_BITS_PER_WIDE_INT
- && (nonzero_bits (op0, mode)
- & (HOST_WIDE_INT_1U << (mode_width - 1)))
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (op0, int_mode)
+ & (HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
== 0)
code = EQ;
break;
@@ -11733,9 +11736,10 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
/* 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 - 1 < HOST_BITS_PER_WIDE_INT
- && (nonzero_bits (op0, mode)
- & (HOST_WIDE_INT_1U << (mode_width - 1)))
+ && is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (op0, int_mode)
+ & (HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
== 0)
code = NE;
break;
@@ -11749,9 +11753,10 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
/* ... fall through ... */
}
/* (unsigned) < 0x80000000 is equivalent to >= 0. */
- else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
- && (unsigned HOST_WIDE_INT) const_op
- == HOST_WIDE_INT_1U << (mode_width - 1))
+ else if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && ((unsigned HOST_WIDE_INT) const_op
+ == HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
{
const_op = 0;
code = GE;
@@ -11765,9 +11770,11 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
if (const_op == 0)
code = EQ;
/* (unsigned) <= 0x7fffffff is equivalent to >= 0. */
- else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
- && (unsigned HOST_WIDE_INT) const_op
- == (HOST_WIDE_INT_1U << (mode_width - 1)) - 1)
+ else if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && ((unsigned HOST_WIDE_INT) const_op
+ == ((HOST_WIDE_INT_1U
+ << (GET_MODE_PRECISION (int_mode) - 1)) - 1)))
{
const_op = 0;
code = GE;
@@ -11784,9 +11791,10 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
}
/* (unsigned) >= 0x80000000 is equivalent to < 0. */
- else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
- && (unsigned HOST_WIDE_INT) const_op
- == HOST_WIDE_INT_1U << (mode_width - 1))
+ else if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && ((unsigned HOST_WIDE_INT) const_op
+ == HOST_WIDE_INT_1U << (GET_MODE_PRECISION (int_mode) - 1)))
{
const_op = 0;
code = LT;
@@ -11800,9 +11808,11 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
if (const_op == 0)
code = NE;
/* (unsigned) > 0x7fffffff is equivalent to < 0. */
- else if (mode_width - 1 < HOST_BITS_PER_WIDE_INT
- && (unsigned HOST_WIDE_INT) const_op
- == (HOST_WIDE_INT_1U << (mode_width - 1)) - 1)
+ else if (is_a <scalar_int_mode> (mode, &int_mode)
+ && GET_MODE_PRECISION (int_mode) - 1 < HOST_BITS_PER_WIDE_INT
+ && ((unsigned HOST_WIDE_INT) const_op
+ == (HOST_WIDE_INT_1U
+ << (GET_MODE_PRECISION (int_mode) - 1)) - 1))
{
const_op = 0;
code = LT;
@@ -11987,9 +11997,8 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
while (CONST_INT_P (op1))
{
- machine_mode mode = GET_MODE (op0);
- unsigned int mode_width = GET_MODE_PRECISION (mode);
- unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
+ machine_mode raw_mode = GET_MODE (op0);
+ scalar_int_mode int_mode;
int equality_comparison_p;
int sign_bit_comparison_p;
int unsigned_comparison_p;
@@ -12000,14 +12009,14 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
can handle VOIDmode if OP0 is a COMPARE or a comparison
operation. */
- if (GET_MODE_CLASS (mode) != MODE_INT
- && ! (mode == VOIDmode
+ if (GET_MODE_CLASS (raw_mode) != MODE_INT
+ && ! (raw_mode == VOIDmode
&& (GET_CODE (op0) == COMPARE || COMPARISON_P (op0))))
break;
/* Try to simplify the compare to constant, possibly changing the
comparison op, and/or changing op1 to zero. */
- code = simplify_compare_const (code, mode, op0, &op1);
+ code = simplify_compare_const (code, raw_mode, op0, &op1);
const_op = INTVAL (op1);
/* Compute some predicates to simplify code below. */
@@ -12019,16 +12028,62 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
/* 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 && HWI_COMPUTABLE_MODE_P (mode))
- op0 = force_to_mode (op0, mode,
+ if (sign_bit_comparison_p
+ && is_a <scalar_int_mode> (raw_mode, &int_mode)
+ && HWI_COMPUTABLE_MODE_P (int_mode))
+ op0 = force_to_mode (op0, int_mode,
HOST_WIDE_INT_1U
- << (GET_MODE_PRECISION (mode) - 1),
+ << (GET_MODE_PRECISION (int_mode) - 1),
0);
+ if (COMPARISON_P (op0))
+ {
+ /* We can't do anything if OP0 is a condition code value, rather
+ than an actual data value. */
+ if (const_op != 0
+ || CC0_P (XEXP (op0, 0))
+ || GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
+ break;
+
+ /* Get the two operands being compared. */
+ if (GET_CODE (XEXP (op0, 0)) == COMPARE)
+ tem = XEXP (XEXP (op0, 0), 0), tem1 = XEXP (XEXP (op0, 0), 1);
+ else
+ tem = XEXP (op0, 0), tem1 = XEXP (op0, 1);
+
+ /* Check for the cases where we simply want the result of the
+ earlier test or the opposite of that result. */
+ if (code == NE || code == EQ
+ || (val_signbit_known_set_p (raw_mode, STORE_FLAG_VALUE)
+ && (code == LT || code == GE)))
+ {
+ enum rtx_code new_code;
+ if (code == LT || code == NE)
+ new_code = GET_CODE (op0);
+ else
+ new_code = reversed_comparison_code (op0, NULL);
+
+ if (new_code != UNKNOWN)
+ {
+ code = new_code;
+ op0 = tem;
+ op1 = tem1;
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (raw_mode == VOIDmode)
+ break;
+ scalar_int_mode mode = as_a <scalar_int_mode> (raw_mode);
+
/* 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. */
+ unsigned int mode_width = GET_MODE_PRECISION (mode);
+ unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode);
switch (GET_CODE (op0))
{
case ZERO_EXTRACT:
@@ -12173,8 +12228,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
insn of the given mode, since we'd have to revert it
later on, and then we wouldn't know whether to sign- or
zero-extend. */
- mode = GET_MODE (XEXP (op0, 0));
- if (GET_MODE_CLASS (mode) == MODE_INT
+ if (is_int_mode (GET_MODE (XEXP (op0, 0)), &mode)
&& ! unsigned_comparison_p
&& HWI_COMPUTABLE_MODE_P (mode)
&& trunc_int_for_mode (const_op, mode) == const_op
@@ -12208,11 +12262,12 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
if (mode_width <= HOST_BITS_PER_WIDE_INT
&& subreg_lowpart_p (op0)
- && GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op0))) > mode_width
+ && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (op0)),
+ &inner_mode)
+ && GET_MODE_PRECISION (inner_mode) > mode_width
&& GET_CODE (SUBREG_REG (op0)) == PLUS
&& CONST_INT_P (XEXP (SUBREG_REG (op0), 1)))
{
- machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
rtx a = XEXP (SUBREG_REG (op0), 0);
HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
@@ -12248,19 +12303,19 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
if (paradoxical_subreg_p (op0))
;
else if (subreg_lowpart_p (op0)
- && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+ && GET_MODE_CLASS (mode) == MODE_INT
&& is_int_mode (GET_MODE (SUBREG_REG (op0)), &inner_mode)
&& (code == NE || code == EQ)
&& GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT
&& !paradoxical_subreg_p (op0)
&& (nonzero_bits (SUBREG_REG (op0), inner_mode)
- & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
+ & ~GET_MODE_MASK (mode)) == 0)
{
/* Remove outer subregs that don't do anything. */
tem = gen_lowpart (inner_mode, op1);
if ((nonzero_bits (tem, inner_mode)
- & ~GET_MODE_MASK (GET_MODE (op0))) == 0)
+ & ~GET_MODE_MASK (mode)) == 0)
{
op0 = SUBREG_REG (op0);
op1 = tem;
@@ -12274,8 +12329,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
/* FALLTHROUGH */
case ZERO_EXTEND:
- mode = GET_MODE (XEXP (op0, 0));
- if (GET_MODE_CLASS (mode) == MODE_INT
+ if (is_int_mode (GET_MODE (XEXP (op0, 0)), &mode)
&& (unsigned_comparison_p || equality_comparison_p)
&& HWI_COMPUTABLE_MODE_P (mode)
&& (unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (mode)
@@ -12364,45 +12418,6 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
}
break;
- case EQ: case NE:
- case UNEQ: case LTGT:
- case LT: case LTU: case UNLT: case LE: case LEU: case UNLE:
- case GT: case GTU: case UNGT: case GE: case GEU: case UNGE:
- case UNORDERED: case ORDERED:
- /* We can't do anything if OP0 is a condition code value, rather
- than an actual data value. */
- if (const_op != 0
- || CC0_P (XEXP (op0, 0))
- || GET_MODE_CLASS (GET_MODE (XEXP (op0, 0))) == MODE_CC)
- break;
-
- /* Get the two operands being compared. */
- if (GET_CODE (XEXP (op0, 0)) == COMPARE)
- tem = XEXP (XEXP (op0, 0), 0), tem1 = XEXP (XEXP (op0, 0), 1);
- else
- tem = XEXP (op0, 0), tem1 = XEXP (op0, 1);
-
- /* Check for the cases where we simply want the result of the
- earlier test or the opposite of that result. */
- if (code == NE || code == EQ
- || (val_signbit_known_set_p (GET_MODE (op0), STORE_FLAG_VALUE)
- && (code == LT || code == GE)))
- {
- enum rtx_code new_code;
- if (code == LT || code == NE)
- new_code = GET_CODE (op0);
- else
- new_code = reversed_comparison_code (op0, NULL);
-
- if (new_code != UNKNOWN)
- {
- code = new_code;
- op0 = tem;
- op1 = tem1;
- continue;
- }
- }
- break;
case IOR:
/* The sign bit of (ior (plus X (const_int -1)) X) is nonzero
@@ -12674,7 +12689,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
{
rtx inner = XEXP (XEXP (XEXP (op0, 0), 0), 0);
rtx add_const = XEXP (XEXP (op0, 0), 1);
- rtx new_const = simplify_gen_binary (ASHIFTRT, GET_MODE (op0),
+ rtx new_const = simplify_gen_binary (ASHIFTRT, mode,
add_const, XEXP (op0, 1));
op0 = simplify_gen_binary (PLUS, tmode,