From 0cedb36cbd7e0c407a33ecbcfffd08458059bf00 Mon Sep 17 00:00:00 2001 From: Jeffrey A Law Date: Mon, 1 Nov 1999 00:18:23 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 13 + gcc/Makefile.in | 5 +- gcc/cse.c | 1836 +---------------------------------------- gcc/rtl.h | 3 + gcc/simplify-rtx.c | 1953 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 2013 insertions(+), 1797 deletions(-) create mode 100644 gcc/simplify-rtx.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cc4971b173b..1df4e23fd9d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -7,6 +7,19 @@ Sun Oct 31 13:32:15 CET 1999 Marc Lehmann Sun Oct 31 01:53:30 1999 Jeffrey A Law (law@cygnus.com) + * 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. + * combine.c (combine_simplify_rtx): Renamed from simplify_rtx. All references/callers changed. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index fd9847e5653..3773f9b53a0 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -667,7 +667,7 @@ OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \ insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \ profile.o insn-attrtab.o $(out_object_file) $(EXTRA_OBJS) convert.o \ mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o \ - lists.o ggc-common.o $(GGC) + lists.o ggc-common.o $(GGC) simplify-rtx.o # GEN files are listed separately, so they can be built before doing parallel # makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load @@ -1532,6 +1532,9 @@ jump.o : jump.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h $(REGS_H) \ stupid.o : stupid.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h \ $(BASIC_BLOCK_H) insn-config.h reload.h flags.h function.h toplev.h +simplify-rtx.o : simplify-rtx.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) \ + hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ + output.h function.h cse.o : cse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \ real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h function.h \ $(srcdir)/../include/hashtab.h ggc.h diff --git a/gcc/cse.c b/gcc/cse.c index bc7bd659ba0..1478556aa38 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)); diff --git a/gcc/rtl.h b/gcc/rtl.h index e1e1b66f0b2..b96ab3839b2 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1069,6 +1069,9 @@ extern rtx simplify_unary_operation PROTO((enum rtx_code, enum machine_mode, rtx extern rtx simplify_binary_operation PROTO((enum rtx_code, enum machine_mode, rtx, rtx)); extern rtx simplify_ternary_operation PROTO((enum rtx_code, enum machine_mode, enum machine_mode, rtx, rtx, rtx)); extern rtx simplify_relational_operation PROTO((enum rtx_code, enum machine_mode, rtx, rtx)); +extern rtx simplify_gen_binary PROTO((enum rtx_code, enum machine_mode, + rtx, rtx)); +extern rtx simplify_rtx PROTO((rtx)); extern rtx gen_move_insn PROTO((rtx, rtx)); extern rtx gen_jump PROTO((rtx)); extern rtx gen_beq PROTO((rtx)); diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c new file mode 100644 index 00000000000..60c80c09d21 --- /dev/null +++ b/gcc/simplify-rtx.c @@ -0,0 +1,1953 @@ +/* Common subexpression elimination for GNU compiler. + Copyright (C) 1987, 88, 89, 92-7, 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +/* stdio.h must precede rtl.h for FFS. */ +#include "system.h" +#include + +#include "rtl.h" +#include "tm_p.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "flags.h" +#include "real.h" +#include "insn-config.h" +#include "recog.h" +#include "function.h" +#include "expr.h" +#include "toplev.h" +#include "output.h" + +/* Simplification and canonicalization of RTL. */ + +/* 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. + + ?!? 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 \ + || ((X) == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])\ + || (X) == virtual_stack_vars_rtx \ + || (X) == virtual_incoming_args_rtx \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (XEXP (X, 0) == frame_pointer_rtx \ + || XEXP (X, 0) == hard_frame_pointer_rtx \ + || ((X) == arg_pointer_rtx \ + && fixed_regs[ARG_POINTER_REGNUM]) \ + || XEXP (X, 0) == virtual_stack_vars_rtx \ + || XEXP (X, 0) == virtual_incoming_args_rtx)) \ + || GET_CODE (X) == ADDRESSOF) + +/* Similar, but also allows reference to the stack pointer. + + This used to include FIXED_BASE_PLUS_P, however, we can't assume that + arg_pointer_rtx by itself is nonzero, because on at least one machine, + the i960, the arg pointer is zero when it is unused. */ + +#define NONZERO_BASE_PLUS_P(X) \ + ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \ + || (X) == virtual_stack_vars_rtx \ + || (X) == virtual_incoming_args_rtx \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (XEXP (X, 0) == frame_pointer_rtx \ + || XEXP (X, 0) == hard_frame_pointer_rtx \ + || ((X) == arg_pointer_rtx \ + && fixed_regs[ARG_POINTER_REGNUM]) \ + || XEXP (X, 0) == virtual_stack_vars_rtx \ + || XEXP (X, 0) == virtual_incoming_args_rtx)) \ + || (X) == stack_pointer_rtx \ + || (X) == virtual_stack_dynamic_rtx \ + || (X) == virtual_outgoing_args_rtx \ + || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (XEXP (X, 0) == stack_pointer_rtx \ + || XEXP (X, 0) == virtual_stack_dynamic_rtx \ + || XEXP (X, 0) == virtual_outgoing_args_rtx)) \ + || GET_CODE (X) == ADDRESSOF) + + +static rtx simplify_plus_minus PROTO((enum rtx_code, enum machine_mode, + rtx, rtx)); +static void check_fold_consts PROTO((PTR)); + +/* Make a binary operation by properly ordering the operands and + seeing if the expression folds. */ + +rtx +simplify_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); +} + +/* 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 simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0)); + else if (GET_CODE (op1) == NEG) + return simplify_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 = simplify_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 = simplify_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 simplify_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 simplify_gen_binary (AND, mode, op0, + gen_rtx_NOT (mode, XEXP (op1, 1))); + if (rtx_equal_p (op0, XEXP (op1, 1))) + return simplify_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 = simplify_gen_binary (negs[i] ? MINUS : PLUS, mode, result, ops[i]); + + return negate ? gen_rtx_NEG (mode, result) : result; +} + +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; +} + +/* Simplify X, an rtx expression. + + Return the simplified expression or NULL if no simplifications + were possible. + + This is the preferred entry point into the simplification routines; + however, we still allow passes to call the more specific routines. + + Right now GCC has three (yes, three) major bodies of RTL simplficiation + code that need to be unified. + + 1. fold_rtx in cse.c. This code uses various CSE specific + information to aid in RTL simplification. + + 2. simplify_rtx in combine.c. Similar to fold_rtx, except that + it uses combine specific information to aid in RTL + simplification. + + 3. The routines in this file. + + + Long term we want to only have one body of simplification code; to + get to that state I recommend the following steps: + + 1. Pour over fold_rtx & simplify_rtx and move any simplifications + which are not pass dependent state into these routines. + + 2. As code is moved by #1, change fold_rtx & simplify_rtx to + use this routine whenever possible. + + 3. Allow for pass dependent state to be provided to these + routines and add simplifications based on the pass dependent + state. Remove code from cse.c & combine.c that becomes + redundant/dead. + + It will take time, but ultimately the compiler will be easier to + maintain and improve. It's totally silly that when we add a + simplification that it needs to be added to 4 places (3 for RTL + simplification and 1 for tree simplification. */ + +rtx +simplify_rtx (x) + rtx x; +{ + enum rtx_code code; + enum machine_mode mode; + rtx new; + + mode = GET_MODE (x); + code = GET_CODE (x); + + switch (GET_RTX_CLASS (code)) + { + case '1': + return simplify_unary_operation (code, mode, + XEXP (x, 0), GET_MODE (XEXP (x, 0))); + case '2': + case 'c': + return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1)); + + case '3': + case 'b': + return simplify_ternary_operation (code, mode, GET_MODE (XEXP (x, 0)), + XEXP (x, 0), XEXP (x, 1), XEXP (x, 2)); + + case '<': + return simplify_relational_operation (code, GET_MODE (XEXP (x, 0)), + XEXP (x, 0), XEXP (x, 1)); + default: + return NULL; + } +}