(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:
Richard Kenner 1993-12-31 06:47:13 -05:00
parent abe6e52f23
commit a432f20d05
1 changed files with 144 additions and 202 deletions

346
gcc/cse.c
View File

@ -4276,7 +4276,12 @@ cse_gen_binary (code, mode, op0, op1)
}
/* 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
simplify_relational_operation (code, mode, op0, op1)
@ -4284,9 +4289,8 @@ simplify_relational_operation (code, mode, op0, op1)
enum machine_mode mode;
rtx op0, op1;
{
register HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
HOST_WIDE_INT val;
int width = GET_MODE_BITSIZE (mode);
int equal, op0lt, op0ltu, op1lt, op1ltu;
rtx tem;
/* If op0 is a compare, extract the comparison arguments from it. */
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)
return 0;
/* Unlike the arithmetic operations, we can do the comparison whether
or not WIDTH is larger than HOST_BITS_PER_WIDE_INT because the
CONST_INTs are to be understood as being infinite precision as
is the comparison. So there is no question of overflow. */
/* For integer comparisons of A and B maybe we can simplify A - B and can
then simplify a comparison of that with zero. If A and B are both either
a register or a CONST_INT, this can't help; testing for these cases will
prevent infinite recursion here and speed things up.
if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT || width == 0)
{
/* Even if we can't compute a constant result,
there are some cases worth simplifying. */
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
signed comparison. Note that this will give the incorrect result from
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
the result. */
if (rtx_equal_p (op0, op1)
&& (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| ! FLOAT_MODE_P (GET_MODE (op0)) || flag_fast_math))
return (code == EQ || code == GE || code == LE || code == LEU
|| code == GEU) ? const_true_rtx : const0_rtx;
if (INTEGRAL_MODE_P (mode) && op1 != const0_rtx
&& ! ((GET_CODE (op0) == REG || GET_CODE (op0) == CONST_INT)
&& (GET_CODE (op1) == REG || GET_CODE (op1) == CONST_INT))
&& 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
&& (GET_CODE (tem) == CONST_INT
|| (code != GTU && code != GEU &&
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)
else if (GET_CODE (op0) == CONST_DOUBLE
&& GET_CODE (op1) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
{
REAL_VALUE_TYPE d0, d1;
jmp_buf handler;
int op0lt, op1lt, equal;
else if (GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
{
REAL_VALUE_TYPE d0, d1;
jmp_buf handler;
if (setjmp (handler))
return 0;
if (setjmp (handler))
return 0;
set_float_handler (handler);
REAL_VALUE_FROM_CONST_DOUBLE (d0, op0);
REAL_VALUE_FROM_CONST_DOUBLE (d1, op1);
equal = REAL_VALUES_EQUAL (d0, d1);
op0lt = REAL_VALUES_LESS (d0, d1);
op1lt = REAL_VALUES_LESS (d1, d0);
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;
}
}
set_float_handler (handler);
REAL_VALUE_FROM_CONST_DOUBLE (d0, op0);
REAL_VALUE_FROM_CONST_DOUBLE (d1, op1);
equal = REAL_VALUES_EQUAL (d0, d1);
op0lt = op0ltu = REAL_VALUES_LESS (d0, d1);
op1lt = op1ltu = REAL_VALUES_LESS (d1, d0);
set_float_handler (NULL_PTR);
}
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
else if (GET_MODE_CLASS (mode) == MODE_INT
&& width > HOST_BITS_PER_WIDE_INT
&& (GET_CODE (op0) == CONST_DOUBLE
|| GET_CODE (op0) == CONST_INT)
&& (GET_CODE (op1) == CONST_DOUBLE
|| GET_CODE (op1) == CONST_INT))
/* Otherwise, see if the operands are both integers. */
else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
&& (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == 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;
unsigned HOST_WIDE_INT uh0, ul0, uh1, ul1;
int op0lt, op0ltu, equal;
if (GET_CODE (op0) == CONST_DOUBLE)
l0 = CONST_DOUBLE_LOW (op0), h0 = CONST_DOUBLE_HIGH (op0);
else
l0 = INTVAL (op0), h0 = l0 < 0 ? -1 : 0;
l0u = l0s = CONST_DOUBLE_LOW (op0);
h0u = h0s = CONST_DOUBLE_HIGH (op0);
}
else
{
l0u = l0s = INTVAL (op0);
h0u = 0, h0s = l0s < 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)
{
case EQ:
{
#if 0
/* We can't make this assumption due to #pragma weak */
if (CONSTANT_P (op0) && op1 == const0_rtx)
return const0_rtx;
/* References to the frame plus a constant or labels cannot
be zero, but a SYMBOL_REF can due to #pragma weak. */
if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
|| GET_CODE (op0) == LABEL_REF)
#if FRAME_POINTER_REGNO != ARG_POINTGER_REGNO
/* On some machines, the ap reg can be 0 sometimes. */
&& op0 != arg_pointer_rtx
#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 const0_rtx;
break;
}
)
return const0_rtx;
break;
case NE:
#if 0
/* We can't make this assumption due to #pragma weak */
if (CONSTANT_P (op0) && op1 == const0_rtx)
return const_true_rtx;
if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
|| GET_CODE (op0) == LABEL_REF)
#if FRAME_POINTER_REGNO != ARG_POINTER_REGNO
&& op0 != arg_pointer_rtx
#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;
break;
case GEU:
/* Unsigned values are never negative, but we must be sure we are
actually comparing a value, not a CC operand. */
if (op1 == const0_rtx && INTEGRAL_MODE_P (mode))
/* Unsigned values are never negative. */
if (op1 == const0_rtx)
return const_true_rtx;
break;
case LTU:
if (op1 == const0_rtx && INTEGRAL_MODE_P (mode))
if (op1 == const0_rtx)
return const0_rtx;
break;
@ -4450,8 +4451,8 @@ simplify_relational_operation (code, mode, op0, op1)
unsigned value. */
if (GET_CODE (op1) == CONST_INT
&& INTVAL (op1) == GET_MODE_MASK (mode)
&& INTEGRAL_MODE_P (mode))
return const_true_rtx;
&& INTEGRAL_MODE_P (mode))
return const_true_rtx;
break;
case GTU:
@ -4465,92 +4466,33 @@ simplify_relational_operation (code, mode, op0, op1)
return 0;
}
/* Get the integer argument values in two forms:
zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S. */
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. */
/* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
as appropriate. */
switch (code)
{
case NE:
val = arg0 != arg1 ? STORE_FLAG_VALUE : 0;
break;
case EQ:
val = arg0 == arg1 ? STORE_FLAG_VALUE : 0;
break;
case LE:
val = arg0s <= arg1s ? STORE_FLAG_VALUE : 0;
break;
return equal ? const_true_rtx : const0_rtx;
case NE:
return ! equal ? const_true_rtx : const0_rtx;
case LT:
val = arg0s < arg1s ? STORE_FLAG_VALUE : 0;
break;
case GE:
val = arg0s >= arg1s ? STORE_FLAG_VALUE : 0;
break;
return op0lt ? const_true_rtx : const0_rtx;
case GT:
val = arg0s > arg1s ? STORE_FLAG_VALUE : 0;
break;
case LEU:
val = (((unsigned HOST_WIDE_INT) arg0)
<= ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
break;
return op1lt ? const_true_rtx : const0_rtx;
case LTU:
val = (((unsigned HOST_WIDE_INT) arg0)
< ((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;
return op0ltu ? const_true_rtx : const0_rtx;
case GTU:
val = (((unsigned HOST_WIDE_INT) arg0)
> ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
break;
default:
abort ();
return op1ltu ? const_true_rtx : const0_rtx;
case LE:
return equal || op0lt ? const_true_rtx : const0_rtx;
case GE:
return equal || op1lt ? const_true_rtx : const0_rtx;
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
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);
abort ();
}
/* Simplify CODE, an operation with result mode MODE and three operands,