(simplify_relational_operation): Rewrite and simplify.
Add case when we can simplify A-B for compare of A and B. From-SVN: r6344
This commit is contained in:
parent
abe6e52f23
commit
a432f20d05
346
gcc/cse.c
346
gcc/cse.c
|
@ -4276,7 +4276,12 @@ cse_gen_binary (code, mode, op0, op1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Like simplify_binary_operation except used for relational operators.
|
/* Like simplify_binary_operation except used for relational operators.
|
||||||
MODE is the mode of the operands, not that of the result. */
|
MODE is the mode of the operands, not that of the result. If MODE
|
||||||
|
is VOIDmode, both operands must also be VOIDmode and we compare the
|
||||||
|
operands in "infinite precision".
|
||||||
|
|
||||||
|
If no simplification is possible, this function returns zero. Otherwise,
|
||||||
|
it returns either const_true_rtx or const0_rtx. */
|
||||||
|
|
||||||
rtx
|
rtx
|
||||||
simplify_relational_operation (code, mode, op0, op1)
|
simplify_relational_operation (code, mode, op0, op1)
|
||||||
|
@ -4284,9 +4289,8 @@ simplify_relational_operation (code, mode, op0, op1)
|
||||||
enum machine_mode mode;
|
enum machine_mode mode;
|
||||||
rtx op0, op1;
|
rtx op0, op1;
|
||||||
{
|
{
|
||||||
register HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
|
int equal, op0lt, op0ltu, op1lt, op1ltu;
|
||||||
HOST_WIDE_INT val;
|
rtx tem;
|
||||||
int width = GET_MODE_BITSIZE (mode);
|
|
||||||
|
|
||||||
/* If op0 is a compare, extract the comparison arguments from it. */
|
/* If op0 is a compare, extract the comparison arguments from it. */
|
||||||
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
|
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
|
||||||
|
@ -4297,151 +4301,148 @@ simplify_relational_operation (code, mode, op0, op1)
|
||||||
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
|
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Unlike the arithmetic operations, we can do the comparison whether
|
/* For integer comparisons of A and B maybe we can simplify A - B and can
|
||||||
or not WIDTH is larger than HOST_BITS_PER_WIDE_INT because the
|
then simplify a comparison of that with zero. If A and B are both either
|
||||||
CONST_INTs are to be understood as being infinite precision as
|
a register or a CONST_INT, this can't help; testing for these cases will
|
||||||
is the comparison. So there is no question of overflow. */
|
prevent infinite recursion here and speed things up.
|
||||||
|
|
||||||
if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT || width == 0)
|
If CODE is an unsigned comparison, we can only do this if A - B is a
|
||||||
{
|
constant integer, and then we have to compare that integer with zero as a
|
||||||
/* Even if we can't compute a constant result,
|
signed comparison. Note that this will give the incorrect result from
|
||||||
there are some cases worth simplifying. */
|
comparisons that overflow. Since these are undefined, this is probably
|
||||||
|
OK. If it causes a problem, we can check for A or B being an address
|
||||||
|
(fp + const or SYMBOL_REF) and only do it in that case. */
|
||||||
|
|
||||||
/* For non-IEEE floating-point, if the two operands are equal, we know
|
if (INTEGRAL_MODE_P (mode) && op1 != const0_rtx
|
||||||
the result. */
|
&& ! ((GET_CODE (op0) == REG || GET_CODE (op0) == CONST_INT)
|
||||||
if (rtx_equal_p (op0, op1)
|
&& (GET_CODE (op1) == REG || GET_CODE (op1) == CONST_INT))
|
||||||
&& (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|
&& 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
|
||||||
|| ! FLOAT_MODE_P (GET_MODE (op0)) || flag_fast_math))
|
&& (GET_CODE (tem) == CONST_INT
|
||||||
return (code == EQ || code == GE || code == LE || code == LEU
|
|| (code != GTU && code != GEU &&
|
||||||
|| code == GEU) ? const_true_rtx : const0_rtx;
|
code != LTU && code != LEU)))
|
||||||
|
return simplify_relational_operation (signed_condition (code),
|
||||||
|
mode, tem, const0_rtx);
|
||||||
|
|
||||||
|
/* For non-IEEE floating-point, if the two operands are equal, we know the
|
||||||
|
result. */
|
||||||
|
if (rtx_equal_p (op0, op1)
|
||||||
|
&& (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|
||||||
|
|| ! FLOAT_MODE_P (GET_MODE (op0)) || flag_fast_math))
|
||||||
|
equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
|
||||||
|
|
||||||
|
/* If the operands are floating-point constants, see if we can fold
|
||||||
|
the result. */
|
||||||
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
|
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
|
||||||
else if (GET_CODE (op0) == CONST_DOUBLE
|
else if (GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE
|
||||||
&& GET_CODE (op1) == CONST_DOUBLE
|
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
|
||||||
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
|
{
|
||||||
{
|
REAL_VALUE_TYPE d0, d1;
|
||||||
REAL_VALUE_TYPE d0, d1;
|
jmp_buf handler;
|
||||||
jmp_buf handler;
|
|
||||||
int op0lt, op1lt, equal;
|
|
||||||
|
|
||||||
if (setjmp (handler))
|
if (setjmp (handler))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
set_float_handler (handler);
|
set_float_handler (handler);
|
||||||
REAL_VALUE_FROM_CONST_DOUBLE (d0, op0);
|
REAL_VALUE_FROM_CONST_DOUBLE (d0, op0);
|
||||||
REAL_VALUE_FROM_CONST_DOUBLE (d1, op1);
|
REAL_VALUE_FROM_CONST_DOUBLE (d1, op1);
|
||||||
equal = REAL_VALUES_EQUAL (d0, d1);
|
equal = REAL_VALUES_EQUAL (d0, d1);
|
||||||
op0lt = REAL_VALUES_LESS (d0, d1);
|
op0lt = op0ltu = REAL_VALUES_LESS (d0, d1);
|
||||||
op1lt = REAL_VALUES_LESS (d1, d0);
|
op1lt = op1ltu = REAL_VALUES_LESS (d1, d0);
|
||||||
set_float_handler (NULL_PTR);
|
set_float_handler (NULL_PTR);
|
||||||
|
}
|
||||||
switch (code)
|
|
||||||
{
|
|
||||||
case EQ:
|
|
||||||
return equal ? const_true_rtx : const0_rtx;
|
|
||||||
case NE:
|
|
||||||
return !equal ? const_true_rtx : const0_rtx;
|
|
||||||
case LE:
|
|
||||||
return equal || op0lt ? const_true_rtx : const0_rtx;
|
|
||||||
case LT:
|
|
||||||
return op0lt ? const_true_rtx : const0_rtx;
|
|
||||||
case GE:
|
|
||||||
return equal || op1lt ? const_true_rtx : const0_rtx;
|
|
||||||
case GT:
|
|
||||||
return op1lt ? const_true_rtx : const0_rtx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
|
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
|
||||||
|
|
||||||
else if (GET_MODE_CLASS (mode) == MODE_INT
|
/* Otherwise, see if the operands are both integers. */
|
||||||
&& width > HOST_BITS_PER_WIDE_INT
|
else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
|
||||||
&& (GET_CODE (op0) == CONST_DOUBLE
|
&& (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
|
||||||
|| GET_CODE (op0) == CONST_INT)
|
&& (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
|
||||||
&& (GET_CODE (op1) == CONST_DOUBLE
|
{
|
||||||
|| GET_CODE (op1) == CONST_INT))
|
int width = GET_MODE_BITSIZE (mode);
|
||||||
|
HOST_WIDE_INT l0u, l0s, h0u, h0s, l1u, l1s, h1u, h1s;
|
||||||
|
|
||||||
|
/* Get the two words comprising each integer constant. */
|
||||||
|
if (GET_CODE (op0) == CONST_DOUBLE)
|
||||||
{
|
{
|
||||||
HOST_WIDE_INT h0, l0, h1, l1;
|
l0u = l0s = CONST_DOUBLE_LOW (op0);
|
||||||
unsigned HOST_WIDE_INT uh0, ul0, uh1, ul1;
|
h0u = h0s = CONST_DOUBLE_HIGH (op0);
|
||||||
int op0lt, op0ltu, equal;
|
}
|
||||||
|
else
|
||||||
if (GET_CODE (op0) == CONST_DOUBLE)
|
{
|
||||||
l0 = CONST_DOUBLE_LOW (op0), h0 = CONST_DOUBLE_HIGH (op0);
|
l0u = l0s = INTVAL (op0);
|
||||||
else
|
h0u = 0, h0s = l0s < 0 ? -1 : 0;
|
||||||
l0 = INTVAL (op0), h0 = l0 < 0 ? -1 : 0;
|
|
||||||
|
|
||||||
if (GET_CODE (op1) == CONST_DOUBLE)
|
|
||||||
l1 = CONST_DOUBLE_LOW (op1), h1 = CONST_DOUBLE_HIGH (op1);
|
|
||||||
else
|
|
||||||
l1 = INTVAL (op1), h1 = l1 < 0 ? -1 : 0;
|
|
||||||
|
|
||||||
uh0 = h0, ul0 = l0, uh1 = h1, ul1 = l1;
|
|
||||||
|
|
||||||
equal = (h0 == h1 && l0 == l1);
|
|
||||||
op0lt = (h0 < h1 || (h0 == h1 && l0 < l1));
|
|
||||||
op0ltu = (uh0 < uh1 || (uh0 == uh1 && ul0 < ul1));
|
|
||||||
|
|
||||||
switch (code)
|
|
||||||
{
|
|
||||||
case EQ:
|
|
||||||
return equal ? const_true_rtx : const0_rtx;
|
|
||||||
case NE:
|
|
||||||
return !equal ? const_true_rtx : const0_rtx;
|
|
||||||
case LE:
|
|
||||||
return equal || op0lt ? const_true_rtx : const0_rtx;
|
|
||||||
case LT:
|
|
||||||
return op0lt ? const_true_rtx : const0_rtx;
|
|
||||||
case GE:
|
|
||||||
return !op0lt ? const_true_rtx : const0_rtx;
|
|
||||||
case GT:
|
|
||||||
return !equal && !op0lt ? const_true_rtx : const0_rtx;
|
|
||||||
case LEU:
|
|
||||||
return equal || op0ltu ? const_true_rtx : const0_rtx;
|
|
||||||
case LTU:
|
|
||||||
return op0ltu ? const_true_rtx : const0_rtx;
|
|
||||||
case GEU:
|
|
||||||
return !op0ltu ? const_true_rtx : const0_rtx;
|
|
||||||
case GTU:
|
|
||||||
return !equal && !op0ltu ? const_true_rtx : const0_rtx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GET_CODE (op1) == CONST_DOUBLE)
|
||||||
|
{
|
||||||
|
l1u = l1s = CONST_DOUBLE_LOW (op1);
|
||||||
|
h1u = h1s = CONST_DOUBLE_HIGH (op1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
l1u = l1s = INTVAL (op1);
|
||||||
|
h1u = 0, h1s = l1s < 0 ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
|
||||||
|
we have to sign or zero-extend the values. */
|
||||||
|
if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
|
||||||
|
h0u = h1u = 0, h0s = l0s < 0 ? -1 : 0, h1s = l1s < 0 ? -1 : 0;
|
||||||
|
|
||||||
|
if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
|
||||||
|
{
|
||||||
|
l0u &= ((HOST_WIDE_INT) 1 << width) - 1;
|
||||||
|
l1u &= ((HOST_WIDE_INT) 1 << width) - 1;
|
||||||
|
|
||||||
|
if (l0s & ((HOST_WIDE_INT) 1 << (width - 1)))
|
||||||
|
l0s |= ((HOST_WIDE_INT) (-1) << width);
|
||||||
|
|
||||||
|
if (l1s & ((HOST_WIDE_INT) 1 << (width - 1)))
|
||||||
|
l1s |= ((HOST_WIDE_INT) (-1) << width);
|
||||||
|
}
|
||||||
|
|
||||||
|
equal = (h0u == h1u && l0u == l1u);
|
||||||
|
op0lt = (h0s < h1s || (h0s == h1s && l0s < l1s));
|
||||||
|
op1lt = (h1s < h0s || (h1s == h0s && l1s < l0s));
|
||||||
|
op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u));
|
||||||
|
op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, there are some code-specific tests we can make. */
|
||||||
|
else
|
||||||
|
{
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case EQ:
|
case EQ:
|
||||||
{
|
/* References to the frame plus a constant or labels cannot
|
||||||
#if 0
|
be zero, but a SYMBOL_REF can due to #pragma weak. */
|
||||||
/* We can't make this assumption due to #pragma weak */
|
if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
|
||||||
if (CONSTANT_P (op0) && op1 == const0_rtx)
|
|| GET_CODE (op0) == LABEL_REF)
|
||||||
return const0_rtx;
|
#if FRAME_POINTER_REGNO != ARG_POINTGER_REGNO
|
||||||
|
/* On some machines, the ap reg can be 0 sometimes. */
|
||||||
|
&& op0 != arg_pointer_rtx
|
||||||
#endif
|
#endif
|
||||||
if (NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx
|
)
|
||||||
/* On some machines, the ap reg can be 0 sometimes. */
|
return const0_rtx;
|
||||||
&& op0 != arg_pointer_rtx)
|
break;
|
||||||
return const0_rtx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case NE:
|
case NE:
|
||||||
#if 0
|
if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
|
||||||
/* We can't make this assumption due to #pragma weak */
|
|| GET_CODE (op0) == LABEL_REF)
|
||||||
if (CONSTANT_P (op0) && op1 == const0_rtx)
|
#if FRAME_POINTER_REGNO != ARG_POINTER_REGNO
|
||||||
return const_true_rtx;
|
&& op0 != arg_pointer_rtx
|
||||||
#endif
|
#endif
|
||||||
if (NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx
|
)
|
||||||
/* On some machines, the ap reg can be 0 sometimes. */
|
|
||||||
&& op0 != arg_pointer_rtx)
|
|
||||||
return const_true_rtx;
|
return const_true_rtx;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEU:
|
case GEU:
|
||||||
/* Unsigned values are never negative, but we must be sure we are
|
/* Unsigned values are never negative. */
|
||||||
actually comparing a value, not a CC operand. */
|
if (op1 == const0_rtx)
|
||||||
if (op1 == const0_rtx && INTEGRAL_MODE_P (mode))
|
|
||||||
return const_true_rtx;
|
return const_true_rtx;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LTU:
|
case LTU:
|
||||||
if (op1 == const0_rtx && INTEGRAL_MODE_P (mode))
|
if (op1 == const0_rtx)
|
||||||
return const0_rtx;
|
return const0_rtx;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -4450,8 +4451,8 @@ simplify_relational_operation (code, mode, op0, op1)
|
||||||
unsigned value. */
|
unsigned value. */
|
||||||
if (GET_CODE (op1) == CONST_INT
|
if (GET_CODE (op1) == CONST_INT
|
||||||
&& INTVAL (op1) == GET_MODE_MASK (mode)
|
&& INTVAL (op1) == GET_MODE_MASK (mode)
|
||||||
&& INTEGRAL_MODE_P (mode))
|
&& INTEGRAL_MODE_P (mode))
|
||||||
return const_true_rtx;
|
return const_true_rtx;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GTU:
|
case GTU:
|
||||||
|
@ -4465,92 +4466,33 @@ simplify_relational_operation (code, mode, op0, op1)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the integer argument values in two forms:
|
/* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
|
||||||
zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S. */
|
as appropriate. */
|
||||||
|
|
||||||
arg0 = INTVAL (op0);
|
|
||||||
arg1 = INTVAL (op1);
|
|
||||||
|
|
||||||
if (width < HOST_BITS_PER_WIDE_INT)
|
|
||||||
{
|
|
||||||
arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
|
|
||||||
arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
|
|
||||||
|
|
||||||
arg0s = arg0;
|
|
||||||
if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
|
|
||||||
arg0s |= ((HOST_WIDE_INT) (-1) << width);
|
|
||||||
|
|
||||||
arg1s = arg1;
|
|
||||||
if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
|
|
||||||
arg1s |= ((HOST_WIDE_INT) (-1) << width);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arg0s = arg0;
|
|
||||||
arg1s = arg1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compute the value of the arithmetic. */
|
|
||||||
|
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case NE:
|
|
||||||
val = arg0 != arg1 ? STORE_FLAG_VALUE : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EQ:
|
case EQ:
|
||||||
val = arg0 == arg1 ? STORE_FLAG_VALUE : 0;
|
return equal ? const_true_rtx : const0_rtx;
|
||||||
break;
|
case NE:
|
||||||
|
return ! equal ? const_true_rtx : const0_rtx;
|
||||||
case LE:
|
|
||||||
val = arg0s <= arg1s ? STORE_FLAG_VALUE : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LT:
|
case LT:
|
||||||
val = arg0s < arg1s ? STORE_FLAG_VALUE : 0;
|
return op0lt ? const_true_rtx : const0_rtx;
|
||||||
break;
|
|
||||||
|
|
||||||
case GE:
|
|
||||||
val = arg0s >= arg1s ? STORE_FLAG_VALUE : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GT:
|
case GT:
|
||||||
val = arg0s > arg1s ? STORE_FLAG_VALUE : 0;
|
return op1lt ? const_true_rtx : const0_rtx;
|
||||||
break;
|
|
||||||
|
|
||||||
case LEU:
|
|
||||||
val = (((unsigned HOST_WIDE_INT) arg0)
|
|
||||||
<= ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LTU:
|
case LTU:
|
||||||
val = (((unsigned HOST_WIDE_INT) arg0)
|
return op0ltu ? const_true_rtx : const0_rtx;
|
||||||
< ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GEU:
|
|
||||||
val = (((unsigned HOST_WIDE_INT) arg0)
|
|
||||||
>= ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GTU:
|
case GTU:
|
||||||
val = (((unsigned HOST_WIDE_INT) arg0)
|
return op1ltu ? const_true_rtx : const0_rtx;
|
||||||
> ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
|
case LE:
|
||||||
break;
|
return equal || op0lt ? const_true_rtx : const0_rtx;
|
||||||
|
case GE:
|
||||||
default:
|
return equal || op1lt ? const_true_rtx : const0_rtx;
|
||||||
abort ();
|
case LEU:
|
||||||
|
return equal || op0ltu ? const_true_rtx : const0_rtx;
|
||||||
|
case GEU:
|
||||||
|
return equal || op1ltu ? const_true_rtx : const0_rtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the bits that don't belong in our mode, unless they and our sign
|
abort ();
|
||||||
bit are all one. So we get either a reasonable negative value or a
|
|
||||||
reasonable unsigned value for this mode. */
|
|
||||||
if (width < HOST_BITS_PER_WIDE_INT
|
|
||||||
&& ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
|
|
||||||
!= ((HOST_WIDE_INT) (-1) << (width - 1))))
|
|
||||||
val &= ((HOST_WIDE_INT) 1 << width) - 1;
|
|
||||||
|
|
||||||
return GEN_INT (val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simplify CODE, an operation with result mode MODE and three operands,
|
/* Simplify CODE, an operation with result mode MODE and three operands,
|
||||||
|
|
Loading…
Reference in New Issue