aboutsummaryrefslogtreecommitdiff
path: root/gcc/cse.c
diff options
context:
space:
mode:
authorJeffrey A Law <law@cygnus.com>1999-11-01 00:18:23 +0000
committerJeff Law <law@gcc.gnu.org>1999-10-31 17:18:23 -0700
commit0cedb36cbd7e0c407a33ecbcfffd08458059bf00 (patch)
tree30a0da0025261198277a799d7e091866f77def9e /gcc/cse.c
parent8fbe10354e67f3e1e6de42a770c3247c6f3b9330 (diff)
downloadgcc-0cedb36cbd7e0c407a33ecbcfffd08458059bf00.zip
gcc-0cedb36cbd7e0c407a33ecbcfffd08458059bf00.tar.gz
gcc-0cedb36cbd7e0c407a33ecbcfffd08458059bf00.tar.bz2
simplify-rtx.c: New file.
* simplify-rtx.c: New file. * Makefile.in (OBJS): Add simplify-rtx.o (simplify-rtx.o): Add dependencies. * rtl.h (simplify_gen_binary, simplify_rtx): Add prototypes. * cse.c: Use simplify_gen_binary intead of cse_gen_binary. (cse_gen_binary, simplify_unary_operation): Delete. (simplify_binary_operation, simplify_plus_minus): Likewise. (check_fold_consts, simplify_relation_operation): Likewise. (simplify_ternary_operation): Likewise. (delete_trivially_dead_insns): Simplify the contents of the REG_EQUAL note before trying to substitute it into the source of the reg-reg copy at the end of a libcall sequence. From-SVN: r30295
Diffstat (limited to 'gcc/cse.c')
-rw-r--r--gcc/cse.c1836
1 files changed, 40 insertions, 1796 deletions
diff --git a/gcc/cse.c b/gcc/cse.c
index bc7bd659..1478556 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -600,7 +600,12 @@ struct cse_basic_block_data {
/* Nonzero if X has the form (PLUS frame-pointer integer). We check for
virtual regs here because the simplify_*_operation routines are called
- by integrate.c, which is called before virtual register instantiation. */
+ by integrate.c, which is called before virtual register instantiation.
+
+ ?!? FIXED_BASE_PLUS_P and NONZERO_BASE_PLUS_P need to move into
+ a header file so that their definitions can be shared with the
+ simplification routines in simplify-rtx.c. Until then, do not
+ change these macros without also changing the copy in simplify-rtx.c. */
#define FIXED_BASE_PLUS_P(X) \
((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \
@@ -679,8 +684,6 @@ static void find_best_addr PROTO((rtx, rtx *));
static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *,
enum machine_mode *,
enum machine_mode *));
-static rtx cse_gen_binary PROTO((enum rtx_code, enum machine_mode,
- rtx, rtx));
static rtx simplify_plus_minus PROTO((enum rtx_code, enum machine_mode,
rtx, rtx));
static rtx fold_rtx PROTO((rtx, rtx));
@@ -3020,7 +3023,8 @@ find_best_addr (insn, loc)
/* This is at worst case an O(n^2) algorithm, so limit our search
to the first 32 elements on the list. This avoids trouble
compiling code with very long basic blocks that can easily
- call cse_gen_binary so many times that we run out of memory. */
+ call simplify_gen_binary so many times that we run out of
+ memory. */
found_better = 0;
for (p = elt->first_same_value, count = 0;
@@ -3030,7 +3034,8 @@ find_best_addr (insn, loc)
&& (GET_CODE (p->exp) == REG
|| exp_equiv_p (p->exp, p->exp, 1, 0)))
{
- rtx new = cse_gen_binary (GET_CODE (*loc), Pmode, p->exp, c);
+ rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
+ p->exp, c);
if ((CSE_ADDRESS_COST (new) < best_addr_cost
|| (CSE_ADDRESS_COST (new) == best_addr_cost
@@ -3221,1792 +3226,6 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
return code;
}
-/* Try to simplify a unary operation CODE whose output mode is to be
- MODE with input operand OP whose mode was originally OP_MODE.
- Return zero if no simplification can be made. */
-
-rtx
-simplify_unary_operation (code, mode, op, op_mode)
- enum rtx_code code;
- enum machine_mode mode;
- rtx op;
- enum machine_mode op_mode;
-{
- register int width = GET_MODE_BITSIZE (mode);
-
- /* The order of these tests is critical so that, for example, we don't
- check the wrong mode (input vs. output) for a conversion operation,
- such as FIX. At some point, this should be simplified. */
-
-#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC)
-
- if (code == FLOAT && GET_MODE (op) == VOIDmode
- && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
- {
- HOST_WIDE_INT hv, lv;
- REAL_VALUE_TYPE d;
-
- if (GET_CODE (op) == CONST_INT)
- lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
- else
- lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
-
-#ifdef REAL_ARITHMETIC
- REAL_VALUE_FROM_INT (d, lv, hv, mode);
-#else
- if (hv < 0)
- {
- d = (double) (~ hv);
- d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
- * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
- d += (double) (unsigned HOST_WIDE_INT) (~ lv);
- d = (- d - 1.0);
- }
- else
- {
- d = (double) hv;
- d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
- * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
- d += (double) (unsigned HOST_WIDE_INT) lv;
- }
-#endif /* REAL_ARITHMETIC */
- d = real_value_truncate (mode, d);
- return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
- }
- else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode
- && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
- {
- HOST_WIDE_INT hv, lv;
- REAL_VALUE_TYPE d;
-
- if (GET_CODE (op) == CONST_INT)
- lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
- else
- lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
-
- if (op_mode == VOIDmode)
- {
- /* We don't know how to interpret negative-looking numbers in
- this case, so don't try to fold those. */
- if (hv < 0)
- return 0;
- }
- else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
- ;
- else
- hv = 0, lv &= GET_MODE_MASK (op_mode);
-
-#ifdef REAL_ARITHMETIC
- REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
-#else
-
- d = (double) (unsigned HOST_WIDE_INT) hv;
- d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
- * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
- d += (double) (unsigned HOST_WIDE_INT) lv;
-#endif /* REAL_ARITHMETIC */
- d = real_value_truncate (mode, d);
- return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
- }
-#endif
-
- if (GET_CODE (op) == CONST_INT
- && width <= HOST_BITS_PER_WIDE_INT && width > 0)
- {
- register HOST_WIDE_INT arg0 = INTVAL (op);
- register HOST_WIDE_INT val;
-
- switch (code)
- {
- case NOT:
- val = ~ arg0;
- break;
-
- case NEG:
- val = - arg0;
- break;
-
- case ABS:
- val = (arg0 >= 0 ? arg0 : - arg0);
- break;
-
- case FFS:
- /* Don't use ffs here. Instead, get low order bit and then its
- number. If arg0 is zero, this will return 0, as desired. */
- arg0 &= GET_MODE_MASK (mode);
- val = exact_log2 (arg0 & (- arg0)) + 1;
- break;
-
- case TRUNCATE:
- val = arg0;
- break;
-
- case ZERO_EXTEND:
- if (op_mode == VOIDmode)
- op_mode = mode;
- if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
- {
- /* If we were really extending the mode,
- we would have to distinguish between zero-extension
- and sign-extension. */
- if (width != GET_MODE_BITSIZE (op_mode))
- abort ();
- val = arg0;
- }
- else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
- val = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
- else
- return 0;
- break;
-
- case SIGN_EXTEND:
- if (op_mode == VOIDmode)
- op_mode = mode;
- if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
- {
- /* If we were really extending the mode,
- we would have to distinguish between zero-extension
- and sign-extension. */
- if (width != GET_MODE_BITSIZE (op_mode))
- abort ();
- val = arg0;
- }
- else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
- {
- val
- = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
- if (val
- & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (op_mode) - 1)))
- val -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
- }
- else
- return 0;
- break;
-
- case SQRT:
- return 0;
-
- default:
- abort ();
- }
-
- val = trunc_int_for_mode (val, mode);
-
- return GEN_INT (val);
- }
-
- /* We can do some operations on integer CONST_DOUBLEs. Also allow
- for a DImode operation on a CONST_INT. */
- else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2
- && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
- {
- HOST_WIDE_INT l1, h1, lv, hv;
-
- if (GET_CODE (op) == CONST_DOUBLE)
- l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op);
- else
- l1 = INTVAL (op), h1 = l1 < 0 ? -1 : 0;
-
- switch (code)
- {
- case NOT:
- lv = ~ l1;
- hv = ~ h1;
- break;
-
- case NEG:
- neg_double (l1, h1, &lv, &hv);
- break;
-
- case ABS:
- if (h1 < 0)
- neg_double (l1, h1, &lv, &hv);
- else
- lv = l1, hv = h1;
- break;
-
- case FFS:
- hv = 0;
- if (l1 == 0)
- lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & (-h1)) + 1;
- else
- lv = exact_log2 (l1 & (-l1)) + 1;
- break;
-
- case TRUNCATE:
- /* This is just a change-of-mode, so do nothing. */
- lv = l1, hv = h1;
- break;
-
- case ZERO_EXTEND:
- if (op_mode == VOIDmode
- || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
- return 0;
-
- hv = 0;
- lv = l1 & GET_MODE_MASK (op_mode);
- break;
-
- case SIGN_EXTEND:
- if (op_mode == VOIDmode
- || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
- return 0;
- else
- {
- lv = l1 & GET_MODE_MASK (op_mode);
- if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
- && (lv & ((HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (op_mode) - 1))) != 0)
- lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
-
- hv = (lv < 0) ? ~ (HOST_WIDE_INT) 0 : 0;
- }
- break;
-
- case SQRT:
- return 0;
-
- default:
- return 0;
- }
-
- return immed_double_const (lv, hv, mode);
- }
-
-#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
- else if (GET_CODE (op) == CONST_DOUBLE
- && GET_MODE_CLASS (mode) == MODE_FLOAT)
- {
- REAL_VALUE_TYPE d;
- jmp_buf handler;
- rtx x;
-
- if (setjmp (handler))
- /* There used to be a warning here, but that is inadvisable.
- People may want to cause traps, and the natural way
- to do it should not get a warning. */
- return 0;
-
- set_float_handler (handler);
-
- REAL_VALUE_FROM_CONST_DOUBLE (d, op);
-
- switch (code)
- {
- case NEG:
- d = REAL_VALUE_NEGATE (d);
- break;
-
- case ABS:
- if (REAL_VALUE_NEGATIVE (d))
- d = REAL_VALUE_NEGATE (d);
- break;
-
- case FLOAT_TRUNCATE:
- d = real_value_truncate (mode, d);
- break;
-
- case FLOAT_EXTEND:
- /* All this does is change the mode. */
- break;
-
- case FIX:
- d = REAL_VALUE_RNDZINT (d);
- break;
-
- case UNSIGNED_FIX:
- d = REAL_VALUE_UNSIGNED_RNDZINT (d);
- break;
-
- case SQRT:
- return 0;
-
- default:
- abort ();
- }
-
- x = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
- set_float_handler (NULL_PTR);
- return x;
- }
-
- else if (GET_CODE (op) == CONST_DOUBLE
- && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
- && GET_MODE_CLASS (mode) == MODE_INT
- && width <= HOST_BITS_PER_WIDE_INT && width > 0)
- {
- REAL_VALUE_TYPE d;
- jmp_buf handler;
- HOST_WIDE_INT val;
-
- if (setjmp (handler))
- return 0;
-
- set_float_handler (handler);
-
- REAL_VALUE_FROM_CONST_DOUBLE (d, op);
-
- switch (code)
- {
- case FIX:
- val = REAL_VALUE_FIX (d);
- break;
-
- case UNSIGNED_FIX:
- val = REAL_VALUE_UNSIGNED_FIX (d);
- break;
-
- default:
- abort ();
- }
-
- set_float_handler (NULL_PTR);
-
- val = trunc_int_for_mode (val, mode);
-
- return GEN_INT (val);
- }
-#endif
- /* This was formerly used only for non-IEEE float.
- eggert@twinsun.com says it is safe for IEEE also. */
- else
- {
- /* There are some simplifications we can do even if the operands
- aren't constant. */
- switch (code)
- {
- case NEG:
- case NOT:
- /* (not (not X)) == X, similarly for NEG. */
- if (GET_CODE (op) == code)
- return XEXP (op, 0);
- break;
-
- case SIGN_EXTEND:
- /* (sign_extend (truncate (minus (label_ref L1) (label_ref L2))))
- becomes just the MINUS if its mode is MODE. This allows
- folding switch statements on machines using casesi (such as
- the Vax). */
- if (GET_CODE (op) == TRUNCATE
- && GET_MODE (XEXP (op, 0)) == mode
- && GET_CODE (XEXP (op, 0)) == MINUS
- && GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF
- && GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
- return XEXP (op, 0);
-
-#ifdef POINTERS_EXTEND_UNSIGNED
- if (! POINTERS_EXTEND_UNSIGNED
- && mode == Pmode && GET_MODE (op) == ptr_mode
- && CONSTANT_P (op))
- return convert_memory_address (Pmode, op);
-#endif
- break;
-
-#ifdef POINTERS_EXTEND_UNSIGNED
- case ZERO_EXTEND:
- if (POINTERS_EXTEND_UNSIGNED
- && mode == Pmode && GET_MODE (op) == ptr_mode
- && CONSTANT_P (op))
- return convert_memory_address (Pmode, op);
- break;
-#endif
-
- default:
- break;
- }
-
- return 0;
- }
-}
-
-/* Simplify a binary operation CODE with result mode MODE, operating on OP0
- and OP1. Return 0 if no simplification is possible.
-
- Don't use this for relational operations such as EQ or LT.
- Use simplify_relational_operation instead. */
-
-rtx
-simplify_binary_operation (code, mode, op0, op1)
- enum rtx_code code;
- 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);
- rtx tem;
-
- /* Relational operations don't work here. We must know the mode
- of the operands in order to do the comparison correctly.
- Assuming a full word can give incorrect results.
- Consider comparing 128 with -128 in QImode. */
-
- if (GET_RTX_CLASS (code) == '<')
- abort ();
-
-#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
- if (GET_MODE_CLASS (mode) == MODE_FLOAT
- && GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE
- && mode == GET_MODE (op0) && mode == GET_MODE (op1))
- {
- REAL_VALUE_TYPE f0, f1, value;
- jmp_buf handler;
-
- if (setjmp (handler))
- return 0;
-
- set_float_handler (handler);
-
- REAL_VALUE_FROM_CONST_DOUBLE (f0, op0);
- REAL_VALUE_FROM_CONST_DOUBLE (f1, op1);
- f0 = real_value_truncate (mode, f0);
- f1 = real_value_truncate (mode, f1);
-
-#ifdef REAL_ARITHMETIC
-#ifndef REAL_INFINITY
- if (code == DIV && REAL_VALUES_EQUAL (f1, dconst0))
- return 0;
-#endif
- REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
-#else
- switch (code)
- {
- case PLUS:
- value = f0 + f1;
- break;
- case MINUS:
- value = f0 - f1;
- break;
- case MULT:
- value = f0 * f1;
- break;
- case DIV:
-#ifndef REAL_INFINITY
- if (f1 == 0)
- return 0;
-#endif
- value = f0 / f1;
- break;
- case SMIN:
- value = MIN (f0, f1);
- break;
- case SMAX:
- value = MAX (f0, f1);
- break;
- default:
- abort ();
- }
-#endif
-
- value = real_value_truncate (mode, value);
- set_float_handler (NULL_PTR);
- return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
- }
-#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
-
- /* We can fold some multi-word operations. */
- if (GET_MODE_CLASS (mode) == MODE_INT
- && width == HOST_BITS_PER_WIDE_INT * 2
- && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
- && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
- {
- HOST_WIDE_INT l1, l2, h1, h2, lv, hv;
-
- if (GET_CODE (op0) == CONST_DOUBLE)
- l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0);
- else
- l1 = INTVAL (op0), h1 = l1 < 0 ? -1 : 0;
-
- if (GET_CODE (op1) == CONST_DOUBLE)
- l2 = CONST_DOUBLE_LOW (op1), h2 = CONST_DOUBLE_HIGH (op1);
- else
- l2 = INTVAL (op1), h2 = l2 < 0 ? -1 : 0;
-
- switch (code)
- {
- case MINUS:
- /* A - B == A + (-B). */
- neg_double (l2, h2, &lv, &hv);
- l2 = lv, h2 = hv;
-
- /* .. fall through ... */
-
- case PLUS:
- add_double (l1, h1, l2, h2, &lv, &hv);
- break;
-
- case MULT:
- mul_double (l1, h1, l2, h2, &lv, &hv);
- break;
-
- case DIV: case MOD: case UDIV: case UMOD:
- /* We'd need to include tree.h to do this and it doesn't seem worth
- it. */
- return 0;
-
- case AND:
- lv = l1 & l2, hv = h1 & h2;
- break;
-
- case IOR:
- lv = l1 | l2, hv = h1 | h2;
- break;
-
- case XOR:
- lv = l1 ^ l2, hv = h1 ^ h2;
- break;
-
- case SMIN:
- if (h1 < h2
- || (h1 == h2
- && ((unsigned HOST_WIDE_INT) l1
- < (unsigned HOST_WIDE_INT) l2)))
- lv = l1, hv = h1;
- else
- lv = l2, hv = h2;
- break;
-
- case SMAX:
- if (h1 > h2
- || (h1 == h2
- && ((unsigned HOST_WIDE_INT) l1
- > (unsigned HOST_WIDE_INT) l2)))
- lv = l1, hv = h1;
- else
- lv = l2, hv = h2;
- break;
-
- case UMIN:
- if ((unsigned HOST_WIDE_INT) h1 < (unsigned HOST_WIDE_INT) h2
- || (h1 == h2
- && ((unsigned HOST_WIDE_INT) l1
- < (unsigned HOST_WIDE_INT) l2)))
- lv = l1, hv = h1;
- else
- lv = l2, hv = h2;
- break;
-
- case UMAX:
- if ((unsigned HOST_WIDE_INT) h1 > (unsigned HOST_WIDE_INT) h2
- || (h1 == h2
- && ((unsigned HOST_WIDE_INT) l1
- > (unsigned HOST_WIDE_INT) l2)))
- lv = l1, hv = h1;
- else
- lv = l2, hv = h2;
- break;
-
- case LSHIFTRT: case ASHIFTRT:
- case ASHIFT:
- case ROTATE: case ROTATERT:
-#ifdef SHIFT_COUNT_TRUNCATED
- if (SHIFT_COUNT_TRUNCATED)
- l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
-#endif
-
- if (h2 != 0 || l2 < 0 || l2 >= GET_MODE_BITSIZE (mode))
- return 0;
-
- if (code == LSHIFTRT || code == ASHIFTRT)
- rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
- code == ASHIFTRT);
- else if (code == ASHIFT)
- lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
- else if (code == ROTATE)
- lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
- else /* code == ROTATERT */
- rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
- break;
-
- default:
- return 0;
- }
-
- return immed_double_const (lv, hv, mode);
- }
-
- if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT
- || width > HOST_BITS_PER_WIDE_INT || width == 0)
- {
- /* Even if we can't compute a constant result,
- there are some cases worth simplifying. */
-
- switch (code)
- {
- case PLUS:
- /* In IEEE floating point, x+0 is not the same as x. Similarly
- for the other optimizations below. */
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- && FLOAT_MODE_P (mode) && ! flag_fast_math)
- break;
-
- if (op1 == CONST0_RTX (mode))
- return op0;
-
- /* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */
- if (GET_CODE (op0) == NEG)
- return cse_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
- else if (GET_CODE (op1) == NEG)
- return cse_gen_binary (MINUS, mode, op0, XEXP (op1, 0));
-
- /* Handle both-operands-constant cases. We can only add
- CONST_INTs to constants since the sum of relocatable symbols
- can't be handled by most assemblers. Don't add CONST_INT
- to CONST_INT since overflow won't be computed properly if wider
- than HOST_BITS_PER_WIDE_INT. */
-
- if (CONSTANT_P (op0) && GET_MODE (op0) != VOIDmode
- && GET_CODE (op1) == CONST_INT)
- return plus_constant (op0, INTVAL (op1));
- else if (CONSTANT_P (op1) && GET_MODE (op1) != VOIDmode
- && GET_CODE (op0) == CONST_INT)
- return plus_constant (op1, INTVAL (op0));
-
- /* See if this is something like X * C - X or vice versa or
- if the multiplication is written as a shift. If so, we can
- distribute and make a new multiply, shift, or maybe just
- have X (if C is 2 in the example above). But don't make
- real multiply if we didn't have one before. */
-
- if (! FLOAT_MODE_P (mode))
- {
- HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
- rtx lhs = op0, rhs = op1;
- int had_mult = 0;
-
- if (GET_CODE (lhs) == NEG)
- coeff0 = -1, lhs = XEXP (lhs, 0);
- else if (GET_CODE (lhs) == MULT
- && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
- {
- coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
- had_mult = 1;
- }
- else if (GET_CODE (lhs) == ASHIFT
- && GET_CODE (XEXP (lhs, 1)) == CONST_INT
- && INTVAL (XEXP (lhs, 1)) >= 0
- && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
- {
- coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
- lhs = XEXP (lhs, 0);
- }
-
- if (GET_CODE (rhs) == NEG)
- coeff1 = -1, rhs = XEXP (rhs, 0);
- else if (GET_CODE (rhs) == MULT
- && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
- {
- coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
- had_mult = 1;
- }
- else if (GET_CODE (rhs) == ASHIFT
- && GET_CODE (XEXP (rhs, 1)) == CONST_INT
- && INTVAL (XEXP (rhs, 1)) >= 0
- && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
- {
- coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
- rhs = XEXP (rhs, 0);
- }
-
- if (rtx_equal_p (lhs, rhs))
- {
- tem = cse_gen_binary (MULT, mode, lhs,
- GEN_INT (coeff0 + coeff1));
- return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
- }
- }
-
- /* If one of the operands is a PLUS or a MINUS, see if we can
- simplify this by the associative law.
- Don't use the associative law for floating point.
- The inaccuracy makes it nonassociative,
- and subtle programs can break if operations are associated. */
-
- if (INTEGRAL_MODE_P (mode)
- && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
- || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS)
- && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
- return tem;
- break;
-
- case COMPARE:
-#ifdef HAVE_cc0
- /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
- using cc0, in which case we want to leave it as a COMPARE
- so we can distinguish it from a register-register-copy.
-
- In IEEE floating point, x-0 is not the same as x. */
-
- if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_MODE_P (mode) || flag_fast_math)
- && op1 == CONST0_RTX (mode))
- return op0;
-#else
- /* Do nothing here. */
-#endif
- break;
-
- case MINUS:
- /* None of these optimizations can be done for IEEE
- floating point. */
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- && FLOAT_MODE_P (mode) && ! flag_fast_math)
- break;
-
- /* We can't assume x-x is 0 even with non-IEEE floating point,
- but since it is zero except in very strange circumstances, we
- will treat it as zero with -ffast-math. */
- if (rtx_equal_p (op0, op1)
- && ! side_effects_p (op0)
- && (! FLOAT_MODE_P (mode) || flag_fast_math))
- return CONST0_RTX (mode);
-
- /* Change subtraction from zero into negation. */
- if (op0 == CONST0_RTX (mode))
- return gen_rtx_NEG (mode, op1);
-
- /* (-1 - a) is ~a. */
- if (op0 == constm1_rtx)
- return gen_rtx_NOT (mode, op1);
-
- /* Subtracting 0 has no effect. */
- if (op1 == CONST0_RTX (mode))
- return op0;
-
- /* See if this is something like X * C - X or vice versa or
- if the multiplication is written as a shift. If so, we can
- distribute and make a new multiply, shift, or maybe just
- have X (if C is 2 in the example above). But don't make
- real multiply if we didn't have one before. */
-
- if (! FLOAT_MODE_P (mode))
- {
- HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
- rtx lhs = op0, rhs = op1;
- int had_mult = 0;
-
- if (GET_CODE (lhs) == NEG)
- coeff0 = -1, lhs = XEXP (lhs, 0);
- else if (GET_CODE (lhs) == MULT
- && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
- {
- coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
- had_mult = 1;
- }
- else if (GET_CODE (lhs) == ASHIFT
- && GET_CODE (XEXP (lhs, 1)) == CONST_INT
- && INTVAL (XEXP (lhs, 1)) >= 0
- && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
- {
- coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
- lhs = XEXP (lhs, 0);
- }
-
- if (GET_CODE (rhs) == NEG)
- coeff1 = - 1, rhs = XEXP (rhs, 0);
- else if (GET_CODE (rhs) == MULT
- && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
- {
- coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
- had_mult = 1;
- }
- else if (GET_CODE (rhs) == ASHIFT
- && GET_CODE (XEXP (rhs, 1)) == CONST_INT
- && INTVAL (XEXP (rhs, 1)) >= 0
- && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
- {
- coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
- rhs = XEXP (rhs, 0);
- }
-
- if (rtx_equal_p (lhs, rhs))
- {
- tem = cse_gen_binary (MULT, mode, lhs,
- GEN_INT (coeff0 - coeff1));
- return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
- }
- }
-
- /* (a - (-b)) -> (a + b). */
- if (GET_CODE (op1) == NEG)
- return cse_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
-
- /* If one of the operands is a PLUS or a MINUS, see if we can
- simplify this by the associative law.
- Don't use the associative law for floating point.
- The inaccuracy makes it nonassociative,
- and subtle programs can break if operations are associated. */
-
- if (INTEGRAL_MODE_P (mode)
- && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
- || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS)
- && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
- return tem;
-
- /* Don't let a relocatable value get a negative coeff. */
- if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode)
- return plus_constant (op0, - INTVAL (op1));
-
- /* (x - (x & y)) -> (x & ~y) */
- if (GET_CODE (op1) == AND)
- {
- if (rtx_equal_p (op0, XEXP (op1, 0)))
- return cse_gen_binary (AND, mode, op0,
- gen_rtx_NOT (mode, XEXP (op1, 1)));
- if (rtx_equal_p (op0, XEXP (op1, 1)))
- return cse_gen_binary (AND, mode, op0,
- gen_rtx_NOT (mode, XEXP (op1, 0)));
- }
- break;
-
- case MULT:
- if (op1 == constm1_rtx)
- {
- tem = simplify_unary_operation (NEG, mode, op0, mode);
-
- return tem ? tem : gen_rtx_NEG (mode, op0);
- }
-
- /* In IEEE floating point, x*0 is not always 0. */
- if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_MODE_P (mode) || flag_fast_math)
- && op1 == CONST0_RTX (mode)
- && ! side_effects_p (op0))
- return op1;
-
- /* In IEEE floating point, x*1 is not equivalent to x for nans.
- However, ANSI says we can drop signals,
- so we can do this anyway. */
- if (op1 == CONST1_RTX (mode))
- return op0;
-
- /* Convert multiply by constant power of two into shift unless
- we are still generating RTL. This test is a kludge. */
- if (GET_CODE (op1) == CONST_INT
- && (val = exact_log2 (INTVAL (op1))) >= 0
- /* If the mode is larger than the host word size, and the
- uppermost bit is set, then this isn't a power of two due
- to implicit sign extension. */
- && (width <= HOST_BITS_PER_WIDE_INT
- || val != HOST_BITS_PER_WIDE_INT - 1)
- && ! rtx_equal_function_value_matters)
- return gen_rtx_ASHIFT (mode, op0, GEN_INT (val));
-
- if (GET_CODE (op1) == CONST_DOUBLE
- && GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT)
- {
- REAL_VALUE_TYPE d;
- jmp_buf handler;
- int op1is2, op1ism1;
-
- if (setjmp (handler))
- return 0;
-
- set_float_handler (handler);
- REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
- op1is2 = REAL_VALUES_EQUAL (d, dconst2);
- op1ism1 = REAL_VALUES_EQUAL (d, dconstm1);
- set_float_handler (NULL_PTR);
-
- /* x*2 is x+x and x*(-1) is -x */
- if (op1is2 && GET_MODE (op0) == mode)
- return gen_rtx_PLUS (mode, op0, copy_rtx (op0));
-
- else if (op1ism1 && GET_MODE (op0) == mode)
- return gen_rtx_NEG (mode, op0);
- }
- break;
-
- case IOR:
- if (op1 == const0_rtx)
- return op0;
- if (GET_CODE (op1) == CONST_INT
- && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
- return op1;
- if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
- return op0;
- /* A | (~A) -> -1 */
- if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
- || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
- && ! side_effects_p (op0)
- && GET_MODE_CLASS (mode) != MODE_CC)
- return constm1_rtx;
- break;
-
- case XOR:
- if (op1 == const0_rtx)
- return op0;
- if (GET_CODE (op1) == CONST_INT
- && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
- return gen_rtx_NOT (mode, op0);
- if (op0 == op1 && ! side_effects_p (op0)
- && GET_MODE_CLASS (mode) != MODE_CC)
- return const0_rtx;
- break;
-
- case AND:
- if (op1 == const0_rtx && ! side_effects_p (op0))
- return const0_rtx;
- if (GET_CODE (op1) == CONST_INT
- && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
- return op0;
- if (op0 == op1 && ! side_effects_p (op0)
- && GET_MODE_CLASS (mode) != MODE_CC)
- return op0;
- /* A & (~A) -> 0 */
- if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
- || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
- && ! side_effects_p (op0)
- && GET_MODE_CLASS (mode) != MODE_CC)
- return const0_rtx;
- break;
-
- case UDIV:
- /* Convert divide by power of two into shift (divide by 1 handled
- below). */
- if (GET_CODE (op1) == CONST_INT
- && (arg1 = exact_log2 (INTVAL (op1))) > 0)
- return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1));
-
- /* ... fall through ... */
-
- case DIV:
- if (op1 == CONST1_RTX (mode))
- return op0;
-
- /* In IEEE floating point, 0/x is not always 0. */
- if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_MODE_P (mode) || flag_fast_math)
- && op0 == CONST0_RTX (mode)
- && ! side_effects_p (op1))
- return op0;
-
-#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
- /* Change division by a constant into multiplication. Only do
- this with -ffast-math until an expert says it is safe in
- general. */
- else if (GET_CODE (op1) == CONST_DOUBLE
- && GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT
- && op1 != CONST0_RTX (mode)
- && flag_fast_math)
- {
- REAL_VALUE_TYPE d;
- REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
-
- if (! REAL_VALUES_EQUAL (d, dconst0))
- {
-#if defined (REAL_ARITHMETIC)
- REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
- return gen_rtx_MULT (mode, op0,
- CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
-#else
- return
- gen_rtx_MULT (mode, op0,
- CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
-#endif
- }
- }
-#endif
- break;
-
- case UMOD:
- /* Handle modulus by power of two (mod with 1 handled below). */
- if (GET_CODE (op1) == CONST_INT
- && exact_log2 (INTVAL (op1)) > 0)
- return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1));
-
- /* ... fall through ... */
-
- case MOD:
- if ((op0 == const0_rtx || op1 == const1_rtx)
- && ! side_effects_p (op0) && ! side_effects_p (op1))
- return const0_rtx;
- break;
-
- case ROTATERT:
- case ROTATE:
- /* Rotating ~0 always results in ~0. */
- if (GET_CODE (op0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
- && (unsigned HOST_WIDE_INT) INTVAL (op0) == GET_MODE_MASK (mode)
- && ! side_effects_p (op1))
- return op0;
-
- /* ... fall through ... */
-
- case ASHIFT:
- case ASHIFTRT:
- case LSHIFTRT:
- if (op1 == const0_rtx)
- return op0;
- if (op0 == const0_rtx && ! side_effects_p (op1))
- return op0;
- break;
-
- case SMIN:
- if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
- && INTVAL (op1) == (HOST_WIDE_INT) 1 << (width -1)
- && ! side_effects_p (op0))
- return op1;
- else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
- return op0;
- break;
-
- case SMAX:
- if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
- && ((unsigned HOST_WIDE_INT) INTVAL (op1)
- == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
- && ! side_effects_p (op0))
- return op1;
- else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
- return op0;
- break;
-
- case UMIN:
- if (op1 == const0_rtx && ! side_effects_p (op0))
- return op1;
- else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
- return op0;
- break;
-
- case UMAX:
- if (op1 == constm1_rtx && ! side_effects_p (op0))
- return op1;
- else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
- return op0;
- break;
-
- default:
- abort ();
- }
-
- 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. */
-
- switch (code)
- {
- case PLUS:
- val = arg0s + arg1s;
- break;
-
- case MINUS:
- val = arg0s - arg1s;
- break;
-
- case MULT:
- val = arg0s * arg1s;
- break;
-
- case DIV:
- if (arg1s == 0)
- return 0;
- val = arg0s / arg1s;
- break;
-
- case MOD:
- if (arg1s == 0)
- return 0;
- val = arg0s % arg1s;
- break;
-
- case UDIV:
- if (arg1 == 0)
- return 0;
- val = (unsigned HOST_WIDE_INT) arg0 / arg1;
- break;
-
- case UMOD:
- if (arg1 == 0)
- return 0;
- val = (unsigned HOST_WIDE_INT) arg0 % arg1;
- break;
-
- case AND:
- val = arg0 & arg1;
- break;
-
- case IOR:
- val = arg0 | arg1;
- break;
-
- case XOR:
- val = arg0 ^ arg1;
- break;
-
- case LSHIFTRT:
- /* If shift count is undefined, don't fold it; let the machine do
- what it wants. But truncate it if the machine will do that. */
- if (arg1 < 0)
- return 0;
-
-#ifdef SHIFT_COUNT_TRUNCATED
- if (SHIFT_COUNT_TRUNCATED)
- arg1 %= width;
-#endif
-
- val = ((unsigned HOST_WIDE_INT) arg0) >> arg1;
- break;
-
- case ASHIFT:
- if (arg1 < 0)
- return 0;
-
-#ifdef SHIFT_COUNT_TRUNCATED
- if (SHIFT_COUNT_TRUNCATED)
- arg1 %= width;
-#endif
-
- val = ((unsigned HOST_WIDE_INT) arg0) << arg1;
- break;
-
- case ASHIFTRT:
- if (arg1 < 0)
- return 0;
-
-#ifdef SHIFT_COUNT_TRUNCATED
- if (SHIFT_COUNT_TRUNCATED)
- arg1 %= width;
-#endif
-
- val = arg0s >> arg1;
-
- /* Bootstrap compiler may not have sign extended the right shift.
- Manually extend the sign to insure bootstrap cc matches gcc. */
- if (arg0s < 0 && arg1 > 0)
- val |= ((HOST_WIDE_INT) -1) << (HOST_BITS_PER_WIDE_INT - arg1);
-
- break;
-
- case ROTATERT:
- if (arg1 < 0)
- return 0;
-
- arg1 %= width;
- val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
- | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
- break;
-
- case ROTATE:
- if (arg1 < 0)
- return 0;
-
- arg1 %= width;
- val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
- | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
- break;
-
- case COMPARE:
- /* Do nothing here. */
- return 0;
-
- case SMIN:
- val = arg0s <= arg1s ? arg0s : arg1s;
- break;
-
- case UMIN:
- val = ((unsigned HOST_WIDE_INT) arg0
- <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
- break;
-
- case SMAX:
- val = arg0s > arg1s ? arg0s : arg1s;
- break;
-
- case UMAX:
- val = ((unsigned HOST_WIDE_INT) arg0
- > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
- break;
-
- default:
- abort ();
- }
-
- val = trunc_int_for_mode (val, mode);
-
- return GEN_INT (val);
-}
-
-/* Simplify a PLUS or MINUS, at least one of whose operands may be another
- PLUS or MINUS.
-
- Rather than test for specific case, we do this by a brute-force method
- and do all possible simplifications until no more changes occur. Then
- we rebuild the operation. */
-
-static rtx
-simplify_plus_minus (code, mode, op0, op1)
- enum rtx_code code;
- enum machine_mode mode;
- rtx op0, op1;
-{
- rtx ops[8];
- int negs[8];
- rtx result, tem;
- int n_ops = 2, input_ops = 2, input_consts = 0, n_consts = 0;
- int first = 1, negate = 0, changed;
- int i, j;
-
- bzero ((char *) ops, sizeof ops);
-
- /* Set up the two operands and then expand them until nothing has been
- changed. If we run out of room in our array, give up; this should
- almost never happen. */
-
- ops[0] = op0, ops[1] = op1, negs[0] = 0, negs[1] = (code == MINUS);
-
- changed = 1;
- while (changed)
- {
- changed = 0;
-
- for (i = 0; i < n_ops; i++)
- switch (GET_CODE (ops[i]))
- {
- case PLUS:
- case MINUS:
- if (n_ops == 7)
- return 0;
-
- ops[n_ops] = XEXP (ops[i], 1);
- negs[n_ops++] = GET_CODE (ops[i]) == MINUS ? !negs[i] : negs[i];
- ops[i] = XEXP (ops[i], 0);
- input_ops++;
- changed = 1;
- break;
-
- case NEG:
- ops[i] = XEXP (ops[i], 0);
- negs[i] = ! negs[i];
- changed = 1;
- break;
-
- case CONST:
- ops[i] = XEXP (ops[i], 0);
- input_consts++;
- changed = 1;
- break;
-
- case NOT:
- /* ~a -> (-a - 1) */
- if (n_ops != 7)
- {
- ops[n_ops] = constm1_rtx;
- negs[n_ops++] = negs[i];
- ops[i] = XEXP (ops[i], 0);
- negs[i] = ! negs[i];
- changed = 1;
- }
- break;
-
- case CONST_INT:
- if (negs[i])
- ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0, changed = 1;
- break;
-
- default:
- break;
- }
- }
-
- /* If we only have two operands, we can't do anything. */
- if (n_ops <= 2)
- return 0;
-
- /* Now simplify each pair of operands until nothing changes. The first
- time through just simplify constants against each other. */
-
- changed = 1;
- while (changed)
- {
- changed = first;
-
- for (i = 0; i < n_ops - 1; i++)
- for (j = i + 1; j < n_ops; j++)
- if (ops[i] != 0 && ops[j] != 0
- && (! first || (CONSTANT_P (ops[i]) && CONSTANT_P (ops[j]))))
- {
- rtx lhs = ops[i], rhs = ops[j];
- enum rtx_code ncode = PLUS;
-
- if (negs[i] && ! negs[j])
- lhs = ops[j], rhs = ops[i], ncode = MINUS;
- else if (! negs[i] && negs[j])
- ncode = MINUS;
-
- tem = simplify_binary_operation (ncode, mode, lhs, rhs);
- if (tem)
- {
- ops[i] = tem, ops[j] = 0;
- negs[i] = negs[i] && negs[j];
- if (GET_CODE (tem) == NEG)
- ops[i] = XEXP (tem, 0), negs[i] = ! negs[i];
-
- if (GET_CODE (ops[i]) == CONST_INT && negs[i])
- ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0;
- changed = 1;
- }
- }
-
- first = 0;
- }
-
- /* Pack all the operands to the lower-numbered entries and give up if
- we didn't reduce the number of operands we had. Make sure we
- count a CONST as two operands. If we have the same number of
- operands, but have made more CONSTs than we had, this is also
- an improvement, so accept it. */
-
- for (i = 0, j = 0; j < n_ops; j++)
- if (ops[j] != 0)
- {
- ops[i] = ops[j], negs[i++] = negs[j];
- if (GET_CODE (ops[j]) == CONST)
- n_consts++;
- }
-
- if (i + n_consts > input_ops
- || (i + n_consts == input_ops && n_consts <= input_consts))
- return 0;
-
- n_ops = i;
-
- /* If we have a CONST_INT, put it last. */
- for (i = 0; i < n_ops - 1; i++)
- if (GET_CODE (ops[i]) == CONST_INT)
- {
- tem = ops[n_ops - 1], ops[n_ops - 1] = ops[i] , ops[i] = tem;
- j = negs[n_ops - 1], negs[n_ops - 1] = negs[i], negs[i] = j;
- }
-
- /* Put a non-negated operand first. If there aren't any, make all
- operands positive and negate the whole thing later. */
- for (i = 0; i < n_ops && negs[i]; i++)
- ;
-
- if (i == n_ops)
- {
- for (i = 0; i < n_ops; i++)
- negs[i] = 0;
- negate = 1;
- }
- else if (i != 0)
- {
- tem = ops[0], ops[0] = ops[i], ops[i] = tem;
- j = negs[0], negs[0] = negs[i], negs[i] = j;
- }
-
- /* Now make the result by performing the requested operations. */
- result = ops[0];
- for (i = 1; i < n_ops; i++)
- result = cse_gen_binary (negs[i] ? MINUS : PLUS, mode, result, ops[i]);
-
- return negate ? gen_rtx_NEG (mode, result) : result;
-}
-
-/* Make a binary operation by properly ordering the operands and
- seeing if the expression folds. */
-
-static rtx
-cse_gen_binary (code, mode, op0, op1)
- enum rtx_code code;
- enum machine_mode mode;
- rtx op0, op1;
-{
- rtx tem;
-
- /* Put complex operands first and constants second if commutative. */
- if (GET_RTX_CLASS (code) == 'c'
- && ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
- || (GET_RTX_CLASS (GET_CODE (op0)) == 'o'
- && GET_RTX_CLASS (GET_CODE (op1)) != 'o')
- || (GET_CODE (op0) == SUBREG
- && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o'
- && GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
- tem = op0, op0 = op1, op1 = tem;
-
- /* If this simplifies, do it. */
- tem = simplify_binary_operation (code, mode, op0, op1);
-
- if (tem)
- return tem;
-
- /* Handle addition and subtraction of CONST_INT specially. Otherwise,
- just form the operation. */
-
- if (code == PLUS && GET_CODE (op1) == CONST_INT
- && GET_MODE (op0) != VOIDmode)
- return plus_constant (op0, INTVAL (op1));
- else if (code == MINUS && GET_CODE (op1) == CONST_INT
- && GET_MODE (op0) != VOIDmode)
- return plus_constant (op0, - INTVAL (op1));
- else
- return gen_rtx_fmt_ee (code, mode, op0, op1);
-}
-
-struct cfc_args
-{
- /* Input */
- rtx op0, op1;
- /* Output */
- int equal, op0lt, op1lt;
-};
-
-static void
-check_fold_consts (data)
- PTR data;
-{
- struct cfc_args * args = (struct cfc_args *) data;
- REAL_VALUE_TYPE d0, d1;
-
- REAL_VALUE_FROM_CONST_DOUBLE (d0, args->op0);
- REAL_VALUE_FROM_CONST_DOUBLE (d1, args->op1);
- args->equal = REAL_VALUES_EQUAL (d0, d1);
- args->op0lt = REAL_VALUES_LESS (d0, d1);
- args->op1lt = REAL_VALUES_LESS (d1, d0);
-}
-
-/* Like simplify_binary_operation except used for relational operators.
- 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)
- enum rtx_code code;
- enum machine_mode mode;
- rtx op0, op1;
-{
- 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)
- op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
-
- /* We can't simplify MODE_CC values since we don't know what the
- actual comparison is. */
- if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC
-#ifdef HAVE_cc0
- || op0 == cc0_rtx
-#endif
- )
- return 0;
-
- /* 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 CODE is an unsigned comparison, then we can never do this optimization,
- because it gives an incorrect result if the subtraction wraps around zero.
- ANSI C defines unsigned operations such that they never overflow, and
- thus such cases can not be ignored. */
-
- 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))
- && 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)
- {
- struct cfc_args args;
-
- /* Setup input for check_fold_consts() */
- args.op0 = op0;
- args.op1 = op1;
-
- if (do_float_handler(check_fold_consts, (PTR) &args) == 0)
- /* We got an exception from check_fold_consts() */
- return 0;
-
- /* Receive output from check_fold_consts() */
- equal = args.equal;
- op0lt = op0ltu = args.op0lt;
- op1lt = op1ltu = args.op1lt;
- }
-#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
-
- /* 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 l0s, h0s, l1s, h1s;
- unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
-
- /* Get the two words comprising each integer constant. */
- if (GET_CODE (op0) == CONST_DOUBLE)
- {
- l0u = l0s = CONST_DOUBLE_LOW (op0);
- h0u = h0s = CONST_DOUBLE_HIGH (op0);
- }
- else
- {
- l0u = l0s = INTVAL (op0);
- h0u = h0s = l0s < 0 ? -1 : 0;
- }
-
- if (GET_CODE (op1) == CONST_DOUBLE)
- {
- l1u = l1s = CONST_DOUBLE_LOW (op1);
- h1u = h1s = CONST_DOUBLE_HIGH (op1);
- }
- else
- {
- l1u = l1s = INTVAL (op1);
- h1u = 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:
- /* 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_REGNUM != ARG_POINTER_REGNUM
- /* On some machines, the ap reg can be 0 sometimes. */
- && op0 != arg_pointer_rtx
-#endif
- )
- return const0_rtx;
- break;
-
- case NE:
- if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
- || GET_CODE (op0) == LABEL_REF)
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
- && op0 != arg_pointer_rtx
-#endif
- )
- return const_true_rtx;
- break;
-
- case GEU:
- /* Unsigned values are never negative. */
- if (op1 == const0_rtx)
- return const_true_rtx;
- break;
-
- case LTU:
- if (op1 == const0_rtx)
- return const0_rtx;
- break;
-
- case LEU:
- /* Unsigned values are never greater than the largest
- unsigned value. */
- if (GET_CODE (op1) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
- && INTEGRAL_MODE_P (mode))
- return const_true_rtx;
- break;
-
- case GTU:
- if (GET_CODE (op1) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
- && INTEGRAL_MODE_P (mode))
- return const0_rtx;
- break;
-
- default:
- break;
- }
-
- return 0;
- }
-
- /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
- as appropriate. */
- switch (code)
- {
- case EQ:
- return equal ? const_true_rtx : const0_rtx;
- case NE:
- return ! equal ? const_true_rtx : const0_rtx;
- case LT:
- return op0lt ? const_true_rtx : const0_rtx;
- case GT:
- return op1lt ? const_true_rtx : const0_rtx;
- case LTU:
- return op0ltu ? const_true_rtx : const0_rtx;
- case GTU:
- 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;
- default:
- abort ();
- }
-}
-
-/* Simplify CODE, an operation with result mode MODE and three operands,
- OP0, OP1, and OP2. OP0_MODE was the mode of OP0 before it became
- a constant. Return 0 if no simplifications is possible. */
-
-rtx
-simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
- enum rtx_code code;
- enum machine_mode mode, op0_mode;
- rtx op0, op1, op2;
-{
- int width = GET_MODE_BITSIZE (mode);
-
- /* VOIDmode means "infinite" precision. */
- if (width == 0)
- width = HOST_BITS_PER_WIDE_INT;
-
- switch (code)
- {
- case SIGN_EXTRACT:
- case ZERO_EXTRACT:
- if (GET_CODE (op0) == CONST_INT
- && GET_CODE (op1) == CONST_INT
- && GET_CODE (op2) == CONST_INT
- && INTVAL (op1) + INTVAL (op2) <= GET_MODE_BITSIZE (op0_mode)
- && width <= HOST_BITS_PER_WIDE_INT)
- {
- /* Extracting a bit-field from a constant */
- HOST_WIDE_INT val = INTVAL (op0);
-
- if (BITS_BIG_ENDIAN)
- val >>= (GET_MODE_BITSIZE (op0_mode)
- - INTVAL (op2) - INTVAL (op1));
- else
- val >>= INTVAL (op2);
-
- if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
- {
- /* First zero-extend. */
- val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
- /* If desired, propagate sign bit. */
- if (code == SIGN_EXTRACT
- && (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1))))
- val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
- }
-
- /* 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);
- }
- break;
-
- case IF_THEN_ELSE:
- if (GET_CODE (op0) == CONST_INT)
- return op0 != const0_rtx ? op1 : op2;
-
- /* Convert a == b ? b : a to "a". */
- if (GET_CODE (op0) == NE && ! side_effects_p (op0)
- && rtx_equal_p (XEXP (op0, 0), op1)
- && rtx_equal_p (XEXP (op0, 1), op2))
- return op1;
- else if (GET_CODE (op0) == EQ && ! side_effects_p (op0)
- && rtx_equal_p (XEXP (op0, 1), op1)
- && rtx_equal_p (XEXP (op0, 0), op2))
- return op2;
- else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0))
- {
- rtx temp;
- temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
- XEXP (op0, 0), XEXP (op0, 1));
- /* See if any simplifications were possible. */
- if (temp == const0_rtx)
- return op2;
- else if (temp == const1_rtx)
- return op1;
- }
- break;
-
- default:
- abort ();
- }
-
- return 0;
-}
-
/* If X is a nontrivial arithmetic operation on an argument
for which a constant value can be determined, return
the result of operating on that value, as a constant.
@@ -5850,8 +4069,8 @@ fold_rtx (x, insn)
if (p)
for (p = p->first_same_value; p; p = p->next_same_value)
if (GET_CODE (p->exp) == REG)
- return cse_gen_binary (MINUS, mode, folded_arg0,
- canon_reg (p->exp, NULL_RTX));
+ return simplify_gen_binary (MINUS, mode, folded_arg0,
+ canon_reg (p->exp, NULL_RTX));
}
goto from_plus;
@@ -5958,7 +4177,7 @@ fold_rtx (x, insn)
if (! reg_mentioned_p (folded_arg0, y))
y = fold_rtx (y, insn);
- return cse_gen_binary (code, mode, y, new_const);
+ return simplify_gen_binary (code, mode, y, new_const);
}
break;
@@ -7298,11 +5517,32 @@ cse_insn (insn, libcall_insn)
&& GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
&& GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
{
+ rtx simplified_src_const;
tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
/* Make sure that the rtx is not shared with any other insn. */
src_const = copy_rtx (src_const);
+ /* Try to simplify SRC_CONST.
+
+ The primary purpose behind simplifying the note is to allow
+ for easier removal of library call sequences later. Consider
+ a udiv libcall where we can determine the second argument is
+ a constant. SRC_CONST would look like:
+
+ (udiv (reg) (const_int 2**n))
+
+ That RTL expression will simplify into:
+
+ (lshiftrt (reg) (const_int n))
+
+ A target using library calls for division is more likely to
+ have a lshiftrt insn. Thus, it is more likely that the libcall
+ can be deleted in delete_trivially_dead_insns if we simplify
+ the note. */
+ simplified_src_const = simplify_rtx (src_const);
+ src_const = simplified_src_const ? simplified_src_const : src_const;
+
/* Record the actual constant value in a REG_EQUAL note, making
a new one if one does not already exist. */
if (tem)
@@ -9181,8 +7421,12 @@ delete_trivially_dead_insns (insns, nreg)
if (note)
{
rtx set = single_set (insn);
- if (set
- && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0))
+ rtx new = simplify_rtx (XEXP (note, 0));
+
+ if (!new)
+ new = XEXP (note, 0);
+
+ if (set && validate_change (insn, &SET_SRC (set), new, 0))
{
remove_note (insn,
find_reg_note (insn, REG_RETVAL, NULL_RTX));