X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fsimplify-rtx.c;h=15e4c2a3424fe1ce295556d741dbbcade19fa64f;hb=66b0f9ffac16d1882bf1992330ae10f8392533e5;hp=f5f36aae6da8082b5da04d29807c802788fd7d86;hpb=46c0d79571e0ef5ff226c0a1f8625a7ce7add85a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index f5f36aae6da..15e4c2a3424 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -1,12 +1,13 @@ /* RTL simplification functions for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. This file is part of GCC. GCC 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 +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,9 +16,8 @@ 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 GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" @@ -49,11 +49,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #define HWI_SIGN_EXTEND(low) \ ((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0)) -static rtx neg_const_int (enum machine_mode, rtx); -static bool plus_minus_operand_p (rtx); -static int simplify_plus_minus_op_data_cmp (const void *, const void *); -static rtx simplify_plus_minus (enum rtx_code, enum machine_mode, rtx, - rtx, int); +static rtx neg_const_int (enum machine_mode, const_rtx); +static bool plus_minus_operand_p (const_rtx); +static bool simplify_plus_minus_op_data_cmp (rtx, rtx); +static rtx simplify_plus_minus (enum rtx_code, enum machine_mode, rtx, rtx); static rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode, unsigned int); static rtx simplify_associative_operation (enum rtx_code, enum machine_mode, @@ -67,7 +66,7 @@ static rtx simplify_binary_operation_1 (enum rtx_code, enum machine_mode, /* Negate a CONST_INT rtx, truncating (because a conversion from a maximally negative number can overflow). */ static rtx -neg_const_int (enum machine_mode mode, rtx i) +neg_const_int (enum machine_mode mode, const_rtx i) { return gen_int_mode (- INTVAL (i), mode); } @@ -76,7 +75,7 @@ neg_const_int (enum machine_mode mode, rtx i) the most significant bit of machine mode MODE. */ bool -mode_signbit_p (enum machine_mode mode, rtx x) +mode_signbit_p (enum machine_mode mode, const_rtx x) { unsigned HOST_WIDE_INT val; unsigned int width; @@ -115,25 +114,15 @@ simplify_gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0, { rtx tem; - /* Put complex operands first and constants second if commutative. */ - if (GET_RTX_CLASS (code) == RTX_COMM_ARITH - && swap_commutative_operands_p (op0, op1)) - 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 specially. Otherwise, just form - the operation. */ - - if (code == PLUS || code == MINUS) - { - tem = simplify_plus_minus (code, mode, op0, op1, 1); - if (tem) - return tem; - } + /* Put complex operands first and constants second if commutative. */ + if (GET_RTX_CLASS (code) == RTX_COMM_ARITH + && swap_commutative_operands_p (op0, op1)) + tem = op0, op0 = op1, op1 = tem; return gen_rtx_fmt_ee (code, mode, op0, op1); } @@ -145,6 +134,7 @@ avoid_constant_pool_reference (rtx x) { rtx c, tmp, addr; enum machine_mode cmode; + HOST_WIDE_INT offset = 0; switch (GET_CODE (x)) { @@ -168,31 +158,48 @@ avoid_constant_pool_reference (rtx x) return x; } + if (GET_MODE (x) == BLKmode) + return x; + addr = XEXP (x, 0); /* Call target hook to avoid the effects of -fpic etc.... */ addr = targetm.delegitimize_address (addr); + /* Split the address into a base and integer offset. */ + if (GET_CODE (addr) == CONST + && GET_CODE (XEXP (addr, 0)) == PLUS + && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT) + { + offset = INTVAL (XEXP (XEXP (addr, 0), 1)); + addr = XEXP (XEXP (addr, 0), 0); + } + if (GET_CODE (addr) == LO_SUM) addr = XEXP (addr, 1); - if (GET_CODE (addr) != SYMBOL_REF - || ! CONSTANT_POOL_ADDRESS_P (addr)) - return x; - - c = get_pool_constant (addr); - cmode = get_pool_mode (addr); - - /* If we're accessing the constant in a different mode than it was - originally stored, attempt to fix that up via subreg simplifications. - If that fails we have no choice but to return the original memory. */ - if (cmode != GET_MODE (x)) + /* If this is a constant pool reference, we can turn it into its + constant and hope that simplifications happen. */ + if (GET_CODE (addr) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (addr)) { - c = simplify_subreg (GET_MODE (x), c, cmode, 0); - return c ? c : x; + c = get_pool_constant (addr); + cmode = get_pool_mode (addr); + + /* If we're accessing the constant in a different mode than it was + originally stored, attempt to fix that up via subreg simplifications. + If that fails we have no choice but to return the original memory. */ + if (offset != 0 || cmode != GET_MODE (x)) + { + rtx tem = simplify_subreg (GET_MODE (x), c, cmode, offset); + if (tem && CONSTANT_P (tem)) + return tem; + } + else + return c; } - return c; + return x; } /* Make a unary operation by first seeing if it folds and otherwise making @@ -247,7 +254,7 @@ simplify_gen_relational (enum rtx_code code, enum machine_mode mode, resulting RTX. Return a new RTX which is as simplified as possible. */ rtx -simplify_replace_rtx (rtx x, rtx old_rtx, rtx new_rtx) +simplify_replace_rtx (rtx x, const_rtx old_rtx, rtx new_rtx) { enum rtx_code code = GET_CODE (x); enum machine_mode mode = GET_MODE (x); @@ -387,7 +394,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) if (GET_CODE (op) == NOT) return XEXP (op, 0); - /* (not (eq X Y)) == (ne X Y), etc. */ + /* (not (eq X Y)) == (ne X Y), etc. if BImode or the result of the + comparison is all ones. */ if (COMPARISON_P (op) && (mode == BImode || STORE_FLAG_VALUE == -1) && ((reversed = reversed_comparison_code (op, NULL_RTX)) != UNKNOWN)) @@ -431,18 +439,10 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) return simplify_gen_binary (ROTATE, mode, temp, XEXP (op, 1)); } - /* If STORE_FLAG_VALUE is -1, (not (comparison X Y)) can be done - by reversing the comparison code if valid. */ - if (STORE_FLAG_VALUE == -1 - && COMPARISON_P (op) - && (reversed = reversed_comparison_code (op, NULL_RTX)) != UNKNOWN) - return simplify_gen_relational (reversed, mode, VOIDmode, - XEXP (op, 0), XEXP (op, 1)); - /* (not (ashiftrt foo C)) where C is the number of bits in FOO minus 1 is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can perform the above simplification. */ - + if (STORE_FLAG_VALUE == -1 && GET_CODE (op) == ASHIFTRT && GET_CODE (XEXP (op, 1)) == CONST_INT @@ -450,6 +450,51 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) return simplify_gen_relational (GE, mode, VOIDmode, XEXP (op, 0), const0_rtx); + + if (GET_CODE (op) == SUBREG + && subreg_lowpart_p (op) + && (GET_MODE_SIZE (GET_MODE (op)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op)))) + && GET_CODE (SUBREG_REG (op)) == ASHIFT + && XEXP (SUBREG_REG (op), 0) == const1_rtx) + { + enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op)); + rtx x; + + x = gen_rtx_ROTATE (inner_mode, + simplify_gen_unary (NOT, inner_mode, const1_rtx, + inner_mode), + XEXP (SUBREG_REG (op), 1)); + return rtl_hooks.gen_lowpart_no_emit (mode, x); + } + + /* Apply De Morgan's laws to reduce number of patterns for machines + with negating logical insns (and-not, nand, etc.). If result has + only one NOT, put it first, since that is how the patterns are + coded. */ + + if (GET_CODE (op) == IOR || GET_CODE (op) == AND) + { + rtx in1 = XEXP (op, 0), in2 = XEXP (op, 1); + enum machine_mode op_mode; + + op_mode = GET_MODE (in1); + in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode); + + op_mode = GET_MODE (in2); + if (op_mode == VOIDmode) + op_mode = mode; + in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode); + + if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT) + { + rtx tem = in2; + in2 = in1; in1 = tem; + } + + return gen_rtx_fmt_ee (GET_CODE (op) == IOR ? AND : IOR, + mode, in1, in2); + } break; case NEG: @@ -529,6 +574,271 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) return simplify_gen_binary (ASHIFTRT, mode, XEXP (op, 0), XEXP (op, 1)); + /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */ + if (GET_CODE (op) == XOR + && XEXP (op, 1) == const1_rtx + && nonzero_bits (XEXP (op, 0), mode) == 1) + return plus_constant (XEXP (op, 0), -1); + + /* (neg (lt x 0)) is (ashiftrt X C) if STORE_FLAG_VALUE is 1. */ + /* (neg (lt x 0)) is (lshiftrt X C) if STORE_FLAG_VALUE is -1. */ + if (GET_CODE (op) == LT + && XEXP (op, 1) == const0_rtx + && SCALAR_INT_MODE_P (GET_MODE (XEXP (op, 0)))) + { + enum machine_mode inner = GET_MODE (XEXP (op, 0)); + int isize = GET_MODE_BITSIZE (inner); + if (STORE_FLAG_VALUE == 1) + { + temp = simplify_gen_binary (ASHIFTRT, inner, XEXP (op, 0), + GEN_INT (isize - 1)); + if (mode == inner) + return temp; + if (GET_MODE_BITSIZE (mode) > isize) + return simplify_gen_unary (SIGN_EXTEND, mode, temp, inner); + return simplify_gen_unary (TRUNCATE, mode, temp, inner); + } + else if (STORE_FLAG_VALUE == -1) + { + temp = simplify_gen_binary (LSHIFTRT, inner, XEXP (op, 0), + GEN_INT (isize - 1)); + if (mode == inner) + return temp; + if (GET_MODE_BITSIZE (mode) > isize) + return simplify_gen_unary (ZERO_EXTEND, mode, temp, inner); + return simplify_gen_unary (TRUNCATE, mode, temp, inner); + } + } + break; + + case TRUNCATE: + /* We can't handle truncation to a partial integer mode here + because we don't know the real bitsize of the partial + integer mode. */ + if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) + break; + + /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI. */ + if ((GET_CODE (op) == SIGN_EXTEND + || GET_CODE (op) == ZERO_EXTEND) + && GET_MODE (XEXP (op, 0)) == mode) + return XEXP (op, 0); + + /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is + (OP:SI foo:SI) if OP is NEG or ABS. */ + if ((GET_CODE (op) == ABS + || GET_CODE (op) == NEG) + && (GET_CODE (XEXP (op, 0)) == SIGN_EXTEND + || GET_CODE (XEXP (op, 0)) == ZERO_EXTEND) + && GET_MODE (XEXP (XEXP (op, 0), 0)) == mode) + return simplify_gen_unary (GET_CODE (op), mode, + XEXP (XEXP (op, 0), 0), mode); + + /* (truncate:A (subreg:B (truncate:C X) 0)) is + (truncate:A X). */ + if (GET_CODE (op) == SUBREG + && GET_CODE (SUBREG_REG (op)) == TRUNCATE + && subreg_lowpart_p (op)) + return simplify_gen_unary (TRUNCATE, mode, XEXP (SUBREG_REG (op), 0), + GET_MODE (XEXP (SUBREG_REG (op), 0))); + + /* If we know that the value is already truncated, we can + replace the TRUNCATE with a SUBREG. Note that this is also + valid if TRULY_NOOP_TRUNCATION is false for the corresponding + modes we just have to apply a different definition for + truncation. But don't do this for an (LSHIFTRT (MULT ...)) + since this will cause problems with the umulXi3_highpart + patterns. */ + if ((TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), + GET_MODE_BITSIZE (GET_MODE (op))) + ? (num_sign_bit_copies (op, GET_MODE (op)) + > (unsigned int) (GET_MODE_BITSIZE (GET_MODE (op)) + - GET_MODE_BITSIZE (mode))) + : truncated_to_mode (mode, op)) + && ! (GET_CODE (op) == LSHIFTRT + && GET_CODE (XEXP (op, 0)) == MULT)) + return rtl_hooks.gen_lowpart_no_emit (mode, op); + + /* A truncate of a comparison can be replaced with a subreg if + STORE_FLAG_VALUE permits. This is like the previous test, + but it works even if the comparison is done in a mode larger + than HOST_BITS_PER_WIDE_INT. */ + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && COMPARISON_P (op) + && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0) + return rtl_hooks.gen_lowpart_no_emit (mode, op); + break; + + case FLOAT_TRUNCATE: + if (DECIMAL_FLOAT_MODE_P (mode)) + break; + + /* (float_truncate:SF (float_extend:DF foo:SF)) = foo:SF. */ + if (GET_CODE (op) == FLOAT_EXTEND + && GET_MODE (XEXP (op, 0)) == mode) + return XEXP (op, 0); + + /* (float_truncate:SF (float_truncate:DF foo:XF)) + = (float_truncate:SF foo:XF). + This may eliminate double rounding, so it is unsafe. + + (float_truncate:SF (float_extend:XF foo:DF)) + = (float_truncate:SF foo:DF). + + (float_truncate:DF (float_extend:XF foo:SF)) + = (float_extend:SF foo:DF). */ + if ((GET_CODE (op) == FLOAT_TRUNCATE + && flag_unsafe_math_optimizations) + || GET_CODE (op) == FLOAT_EXTEND) + return simplify_gen_unary (GET_MODE_SIZE (GET_MODE (XEXP (op, + 0))) + > GET_MODE_SIZE (mode) + ? FLOAT_TRUNCATE : FLOAT_EXTEND, + mode, + XEXP (op, 0), mode); + + /* (float_truncate (float x)) is (float x) */ + if (GET_CODE (op) == FLOAT + && (flag_unsafe_math_optimizations + || (SCALAR_FLOAT_MODE_P (GET_MODE (op)) + && ((unsigned)significand_size (GET_MODE (op)) + >= (GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0))) + - num_sign_bit_copies (XEXP (op, 0), + GET_MODE (XEXP (op, 0)))))))) + return simplify_gen_unary (FLOAT, mode, + XEXP (op, 0), + GET_MODE (XEXP (op, 0))); + + /* (float_truncate:SF (OP:DF (float_extend:DF foo:sf))) is + (OP:SF foo:SF) if OP is NEG or ABS. */ + if ((GET_CODE (op) == ABS + || GET_CODE (op) == NEG) + && GET_CODE (XEXP (op, 0)) == FLOAT_EXTEND + && GET_MODE (XEXP (XEXP (op, 0), 0)) == mode) + return simplify_gen_unary (GET_CODE (op), mode, + XEXP (XEXP (op, 0), 0), mode); + + /* (float_truncate:SF (subreg:DF (float_truncate:SF X) 0)) + is (float_truncate:SF x). */ + if (GET_CODE (op) == SUBREG + && subreg_lowpart_p (op) + && GET_CODE (SUBREG_REG (op)) == FLOAT_TRUNCATE) + return SUBREG_REG (op); + break; + + case FLOAT_EXTEND: + if (DECIMAL_FLOAT_MODE_P (mode)) + break; + + /* (float_extend (float_extend x)) is (float_extend x) + + (float_extend (float x)) is (float x) assuming that double + rounding can't happen. + */ + if (GET_CODE (op) == FLOAT_EXTEND + || (GET_CODE (op) == FLOAT + && SCALAR_FLOAT_MODE_P (GET_MODE (op)) + && ((unsigned)significand_size (GET_MODE (op)) + >= (GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0))) + - num_sign_bit_copies (XEXP (op, 0), + GET_MODE (XEXP (op, 0))))))) + return simplify_gen_unary (GET_CODE (op), mode, + XEXP (op, 0), + GET_MODE (XEXP (op, 0))); + + break; + + case ABS: + /* (abs (neg )) -> (abs ) */ + if (GET_CODE (op) == NEG) + return simplify_gen_unary (ABS, mode, XEXP (op, 0), + GET_MODE (XEXP (op, 0))); + + /* If the mode of the operand is VOIDmode (i.e. if it is ASM_OPERANDS), + do nothing. */ + if (GET_MODE (op) == VOIDmode) + break; + + /* If operand is something known to be positive, ignore the ABS. */ + if (GET_CODE (op) == FFS || GET_CODE (op) == ABS + || ((GET_MODE_BITSIZE (GET_MODE (op)) + <= HOST_BITS_PER_WIDE_INT) + && ((nonzero_bits (op, GET_MODE (op)) + & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (op)) - 1))) + == 0))) + return op; + + /* If operand is known to be only -1 or 0, convert ABS to NEG. */ + if (num_sign_bit_copies (op, mode) == GET_MODE_BITSIZE (mode)) + return gen_rtx_NEG (mode, op); + + break; + + case FFS: + /* (ffs (*_extend )) = (ffs ) */ + if (GET_CODE (op) == SIGN_EXTEND + || GET_CODE (op) == ZERO_EXTEND) + return simplify_gen_unary (FFS, mode, XEXP (op, 0), + GET_MODE (XEXP (op, 0))); + break; + + case POPCOUNT: + switch (GET_CODE (op)) + { + case BSWAP: + case ZERO_EXTEND: + /* (popcount (zero_extend )) = (popcount ) */ + return simplify_gen_unary (POPCOUNT, mode, XEXP (op, 0), + GET_MODE (XEXP (op, 0))); + + case ROTATE: + case ROTATERT: + /* Rotations don't affect popcount. */ + if (!side_effects_p (XEXP (op, 1))) + return simplify_gen_unary (POPCOUNT, mode, XEXP (op, 0), + GET_MODE (XEXP (op, 0))); + break; + + default: + break; + } + break; + + case PARITY: + switch (GET_CODE (op)) + { + case NOT: + case BSWAP: + case ZERO_EXTEND: + case SIGN_EXTEND: + return simplify_gen_unary (PARITY, mode, XEXP (op, 0), + GET_MODE (XEXP (op, 0))); + + case ROTATE: + case ROTATERT: + /* Rotations don't affect parity. */ + if (!side_effects_p (XEXP (op, 1))) + return simplify_gen_unary (PARITY, mode, XEXP (op, 0), + GET_MODE (XEXP (op, 0))); + break; + + default: + break; + } + break; + + case BSWAP: + /* (bswap (bswap x)) -> x. */ + if (GET_CODE (op) == BSWAP) + return XEXP (op, 0); + break; + + case FLOAT: + /* (float (sign_extend )) = (float ). */ + if (GET_CODE (op) == SIGN_EXTEND) + return simplify_gen_unary (FLOAT, mode, XEXP (op, 0), + GET_MODE (XEXP (op, 0))); break; case SIGN_EXTEND: @@ -549,8 +859,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) if (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op) && ! SUBREG_PROMOTED_UNSIGNED_P (op) - && GET_MODE (XEXP (op, 0)) == mode) - return XEXP (op, 0); + && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0)))) + return rtl_hooks.gen_lowpart_no_emit (mode, op); #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) if (! POINTERS_EXTEND_UNSIGNED @@ -571,8 +881,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) if (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op) && SUBREG_PROMOTED_UNSIGNED_P (op) > 0 - && GET_MODE (XEXP (op, 0)) == mode) - return XEXP (op, 0); + && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0)))) + return rtl_hooks.gen_lowpart_no_emit (mode, op); #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) if (POINTERS_EXTEND_UNSIGNED > 0 @@ -773,6 +1083,21 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode, val &= 1; break; + case BSWAP: + { + unsigned int s; + + val = 0; + for (s = 0; s < width; s += 8) + { + unsigned int d = width - s - 8; + unsigned HOST_WIDE_INT byte; + byte = (arg0 >> s) & 0xff; + val |= byte << d; + } + } + break; + case TRUNCATE: val = arg0; break; @@ -823,6 +1148,8 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode, case FLOAT_TRUNCATE: case SS_TRUNCATE: case US_TRUNCATE: + case SS_NEG: + case US_NEG: return 0; default: @@ -918,6 +1245,30 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode, lv &= 1; break; + case BSWAP: + { + unsigned int s; + + hv = 0; + lv = 0; + for (s = 0; s < width; s += 8) + { + unsigned int d = width - s - 8; + unsigned HOST_WIDE_INT byte; + + if (s < HOST_BITS_PER_WIDE_INT) + byte = (l1 >> s) & 0xff; + else + byte = (h1 >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff; + + if (d < HOST_BITS_PER_WIDE_INT) + lv |= byte << d; + else + hv |= byte << (d - HOST_BITS_PER_WIDE_INT); + } + } + break; + case TRUNCATE: /* This is just a change-of-mode, so do nothing. */ lv = l1, hv = h1; @@ -960,7 +1311,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode, } else if (GET_CODE (op) == CONST_DOUBLE - && GET_MODE_CLASS (mode) == MODE_FLOAT) + && SCALAR_FLOAT_MODE_P (mode)) { REAL_VALUE_TYPE d, t; REAL_VALUE_FROM_CONST_DOUBLE (d, op); @@ -1006,7 +1357,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode, } else if (GET_CODE (op) == CONST_DOUBLE - && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT + && SCALAR_FLOAT_MODE_P (GET_MODE (op)) && GET_MODE_CLASS (mode) == MODE_INT && width <= 2*HOST_BITS_PER_WIDE_INT && width > 0) { @@ -1149,16 +1500,12 @@ simplify_associative_operation (enum rtx_code code, enum machine_mode mode, } /* Attempt to simplify "(a op b) op c" as "a op (b op c)". */ - tem = swap_commutative_operands_p (XEXP (op0, 1), op1) - ? simplify_binary_operation (code, mode, op1, XEXP (op0, 1)) - : simplify_binary_operation (code, mode, XEXP (op0, 1), op1); + tem = simplify_binary_operation (code, mode, XEXP (op0, 1), op1); if (tem != 0) return simplify_gen_binary (code, mode, XEXP (op0, 0), tem); /* Attempt to simplify "(a op b) op c" as "(a op c) op b". */ - tem = swap_commutative_operands_p (XEXP (op0, 0), op1) - ? simplify_binary_operation (code, mode, op1, XEXP (op0, 0)) - : simplify_binary_operation (code, mode, XEXP (op0, 0), op1); + tem = simplify_binary_operation (code, mode, XEXP (op0, 0), op1); if (tem != 0) return simplify_gen_binary (code, mode, tem, XEXP (op0, 1)); } @@ -1202,11 +1549,16 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode, return simplify_binary_operation_1 (code, mode, op0, op1, trueop0, trueop1); } +/* Subroutine of simplify_binary_operation. Simplify a binary operation + CODE with result mode MODE, operating on OP0 and OP1. If OP0 and/or + OP1 are constant pool references, TRUEOP0 and TRUEOP1 represent the + actual constants. */ + static rtx simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1, rtx trueop0, rtx trueop1) { - rtx tem; + rtx tem, reversed, opleft, opright; HOST_WIDE_INT val; unsigned int width = GET_MODE_BITSIZE (mode); @@ -1334,6 +1686,30 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, simplify_gen_binary (XOR, mode, op1, XEXP (op0, 1))); + /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)). */ + if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode) + && GET_CODE (op0) == MULT + && GET_CODE (XEXP (op0, 0)) == NEG) + { + rtx in1, in2; + + in1 = XEXP (XEXP (op0, 0), 0); + in2 = XEXP (op0, 1); + return simplify_gen_binary (MINUS, mode, op1, + simplify_gen_binary (MULT, mode, + in1, in2)); + } + + /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if + C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE + is 1. */ + if (COMPARISON_P (op0) + && ((STORE_FLAG_VALUE == -1 && trueop1 == const1_rtx) + || (STORE_FLAG_VALUE == 1 && trueop1 == constm1_rtx)) + && (reversed = reversed_comparison (op0, mode))) + return + simplify_gen_unary (NEG, mode, reversed, mode); + /* 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. @@ -1343,13 +1719,13 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, if (INTEGRAL_MODE_P (mode) && (plus_minus_operand_p (op0) || plus_minus_operand_p (op1)) - && (tem = simplify_plus_minus (code, mode, op0, op1, 0)) != 0) + && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0) return tem; /* Reassociate floating point addition only when the user - specifies unsafe math optimizations. */ + specifies associative math operations. */ if (FLOAT_MODE_P (mode) - && flag_unsafe_math_optimizations) + && flag_associative_math) { tem = simplify_associative_operation (code, mode, op0, op1); if (tem) @@ -1395,10 +1771,10 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, case MINUS: /* 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 -funsafe-math-optimizations. */ + will treat it as zero with -ffinite-math-only. */ if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0) - && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)) + && (!FLOAT_MODE_P (mode) || !HONOR_NANS (mode))) return CONST0_RTX (mode); /* Change subtraction from zero into negation. (0 - x) is the @@ -1508,18 +1884,6 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, return simplify_gen_binary (MINUS, mode, tem, XEXP (op0, 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) - && (plus_minus_operand_p (op0) - || plus_minus_operand_p (op1)) - && (tem = simplify_plus_minus (code, mode, op0, op1, 0)) != 0) - return tem; - /* Don't let a relocatable value get a negative coeff. */ if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode) return simplify_gen_binary (PLUS, mode, @@ -1542,6 +1906,58 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, return simplify_gen_binary (AND, mode, op0, tem); } } + + /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done + by reversing the comparison code if valid. */ + if (STORE_FLAG_VALUE == 1 + && trueop0 == const1_rtx + && COMPARISON_P (op1) + && (reversed = reversed_comparison (op1, mode))) + return reversed; + + /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A). */ + if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode) + && GET_CODE (op1) == MULT + && GET_CODE (XEXP (op1, 0)) == NEG) + { + rtx in1, in2; + + in1 = XEXP (XEXP (op1, 0), 0); + in2 = XEXP (op1, 1); + return simplify_gen_binary (PLUS, mode, + simplify_gen_binary (MULT, mode, + in1, in2), + op0); + } + + /* Canonicalize (minus (neg A) (mult B C)) to + (minus (mult (neg B) C) A). */ + if (!HONOR_SIGN_DEPENDENT_ROUNDING (mode) + && GET_CODE (op1) == MULT + && GET_CODE (op0) == NEG) + { + rtx in1, in2; + + in1 = simplify_gen_unary (NEG, mode, XEXP (op1, 0), mode); + in2 = XEXP (op1, 1); + return simplify_gen_binary (MINUS, mode, + simplify_gen_binary (MULT, mode, + in1, in2), + XEXP (op0, 0)); + } + + /* If one of the operands is a PLUS or a MINUS, see if we can + simplify this by the associative law. This will, for example, + canonicalize (minus A (plus B C)) to (minus (minus A B) C). + 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) + && (plus_minus_operand_p (op0) + || plus_minus_operand_p (op1)) + && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0) + return tem; break; case MULT: @@ -1576,18 +1992,18 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val)); /* Likewise for multipliers wider than a word. */ - else if (GET_CODE (trueop1) == CONST_DOUBLE - && (GET_MODE (trueop1) == VOIDmode - || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT) - && GET_MODE (op0) == mode - && CONST_DOUBLE_LOW (trueop1) == 0 - && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0) + if (GET_CODE (trueop1) == CONST_DOUBLE + && (GET_MODE (trueop1) == VOIDmode + || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT) + && GET_MODE (op0) == mode + && CONST_DOUBLE_LOW (trueop1) == 0 + && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0) return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val + HOST_BITS_PER_WIDE_INT)); /* x*2 is x+x and x*(-1) is -x */ if (GET_CODE (trueop1) == CONST_DOUBLE - && GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_FLOAT + && SCALAR_FLOAT_MODE_P (GET_MODE (trueop1)) && GET_MODE (op0) == mode) { REAL_VALUE_TYPE d; @@ -1596,10 +2012,27 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, if (REAL_VALUES_EQUAL (d, dconst2)) return simplify_gen_binary (PLUS, mode, op0, copy_rtx (op0)); - if (REAL_VALUES_EQUAL (d, dconstm1)) + if (!HONOR_SNANS (mode) + && REAL_VALUES_EQUAL (d, dconstm1)) return simplify_gen_unary (NEG, mode, op0, mode); } + /* Optimize -x * -x as x * x. */ + if (FLOAT_MODE_P (mode) + && GET_CODE (op0) == NEG + && GET_CODE (op1) == NEG + && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0)) + && !side_effects_p (XEXP (op0, 0))) + return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0)); + + /* Likewise, optimize abs(x) * abs(x) as x * x. */ + if (SCALAR_FLOAT_MODE_P (mode) + && GET_CODE (op0) == ABS + && GET_CODE (op1) == ABS + && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0)) + && !side_effects_p (XEXP (op0, 0))) + return simplify_gen_binary (MULT, mode, XEXP (op0, 0), XEXP (op1, 0)); + /* Reassociate multiplication, but for floating point MULTs only when the user specifies unsafe math optimizations. */ if (! FLOAT_MODE_P (mode) @@ -1624,8 +2057,130 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, 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) + && SCALAR_INT_MODE_P (mode)) return constm1_rtx; + + /* (ior A C) is C if all bits of A that might be nonzero are on in C. */ + if (GET_CODE (op1) == CONST_INT + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0) + return op1; + + /* Canonicalize (X & C1) | C2. */ + if (GET_CODE (op0) == AND + && GET_CODE (trueop1) == CONST_INT + && GET_CODE (XEXP (op0, 1)) == CONST_INT) + { + HOST_WIDE_INT mask = GET_MODE_MASK (mode); + HOST_WIDE_INT c1 = INTVAL (XEXP (op0, 1)); + HOST_WIDE_INT c2 = INTVAL (trueop1); + + /* If (C1&C2) == C1, then (X&C1)|C2 becomes X. */ + if ((c1 & c2) == c1 + && !side_effects_p (XEXP (op0, 0))) + return trueop1; + + /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */ + if (((c1|c2) & mask) == mask) + return simplify_gen_binary (IOR, mode, XEXP (op0, 0), op1); + + /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2. */ + if (((c1 & ~c2) & mask) != (c1 & mask)) + { + tem = simplify_gen_binary (AND, mode, XEXP (op0, 0), + gen_int_mode (c1 & ~c2, mode)); + return simplify_gen_binary (IOR, mode, tem, op1); + } + } + + /* Convert (A & B) | A to A. */ + if (GET_CODE (op0) == AND + && (rtx_equal_p (XEXP (op0, 0), op1) + || rtx_equal_p (XEXP (op0, 1), op1)) + && ! side_effects_p (XEXP (op0, 0)) + && ! side_effects_p (XEXP (op0, 1))) + return op1; + + /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the + mode size to (rotate A CX). */ + + if (GET_CODE (op1) == ASHIFT + || GET_CODE (op1) == SUBREG) + { + opleft = op1; + opright = op0; + } + else + { + opright = op1; + opleft = op0; + } + + if (GET_CODE (opleft) == ASHIFT && GET_CODE (opright) == LSHIFTRT + && rtx_equal_p (XEXP (opleft, 0), XEXP (opright, 0)) + && GET_CODE (XEXP (opleft, 1)) == CONST_INT + && GET_CODE (XEXP (opright, 1)) == CONST_INT + && (INTVAL (XEXP (opleft, 1)) + INTVAL (XEXP (opright, 1)) + == GET_MODE_BITSIZE (mode))) + return gen_rtx_ROTATE (mode, XEXP (opright, 0), XEXP (opleft, 1)); + + /* Same, but for ashift that has been "simplified" to a wider mode + by simplify_shift_const. */ + + if (GET_CODE (opleft) == SUBREG + && GET_CODE (SUBREG_REG (opleft)) == ASHIFT + && GET_CODE (opright) == LSHIFTRT + && GET_CODE (XEXP (opright, 0)) == SUBREG + && GET_MODE (opleft) == GET_MODE (XEXP (opright, 0)) + && SUBREG_BYTE (opleft) == SUBREG_BYTE (XEXP (opright, 0)) + && (GET_MODE_SIZE (GET_MODE (opleft)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (opleft)))) + && rtx_equal_p (XEXP (SUBREG_REG (opleft), 0), + SUBREG_REG (XEXP (opright, 0))) + && GET_CODE (XEXP (SUBREG_REG (opleft), 1)) == CONST_INT + && GET_CODE (XEXP (opright, 1)) == CONST_INT + && (INTVAL (XEXP (SUBREG_REG (opleft), 1)) + INTVAL (XEXP (opright, 1)) + == GET_MODE_BITSIZE (mode))) + return gen_rtx_ROTATE (mode, XEXP (opright, 0), + XEXP (SUBREG_REG (opleft), 1)); + + /* If we have (ior (and (X C1) C2)), simplify this by making + C1 as small as possible if C1 actually changes. */ + if (GET_CODE (op1) == CONST_INT + && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + || INTVAL (op1) > 0) + && GET_CODE (op0) == AND + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && GET_CODE (op1) == CONST_INT + && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0) + return simplify_gen_binary (IOR, mode, + simplify_gen_binary + (AND, mode, XEXP (op0, 0), + GEN_INT (INTVAL (XEXP (op0, 1)) + & ~INTVAL (op1))), + op1); + + /* If OP0 is (ashiftrt (plus ...) C), it might actually be + a (sign_extend (plus ...)). Then check if OP1 is a CONST_INT and + the PLUS does not affect any of the bits in OP1: then we can do + the IOR as a PLUS and we can associate. This is valid if OP1 + can be safely shifted left C bits. */ + if (GET_CODE (trueop1) == CONST_INT && GET_CODE (op0) == ASHIFTRT + && GET_CODE (XEXP (op0, 0)) == PLUS + && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT) + { + int count = INTVAL (XEXP (op0, 1)); + HOST_WIDE_INT mask = INTVAL (trueop1) << count; + + if (mask >> count == INTVAL (trueop1) + && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0) + return simplify_gen_binary (ASHIFTRT, mode, + plus_constant (XEXP (op0, 0), mask), + XEXP (op0, 1)); + } + tem = simplify_associative_operation (code, mode, op0, op1); if (tem) return tem; @@ -1638,7 +2193,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, && ((INTVAL (trueop1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))) return simplify_gen_unary (NOT, mode, op0, mode); - if (trueop0 == trueop1 + if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0) && GET_MODE_CLASS (mode) != MODE_CC) return CONST0_RTX (mode); @@ -1658,22 +2213,99 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, return simplify_gen_binary (XOR, mode, XEXP (op0, 0), simplify_gen_binary (XOR, mode, op1, XEXP (op0, 1))); - + + /* If we are XORing two things that have no bits in common, + convert them into an IOR. This helps to detect rotation encoded + using those methods and possibly other simplifications. */ + + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && (nonzero_bits (op0, mode) + & nonzero_bits (op1, mode)) == 0) + return (simplify_gen_binary (IOR, mode, op0, op1)); + + /* Convert (XOR (NOT x) (NOT y)) to (XOR x y). + Also convert (XOR (NOT x) y) to (NOT (XOR x y)), similarly for + (NOT y). */ + { + int num_negated = 0; + + if (GET_CODE (op0) == NOT) + num_negated++, op0 = XEXP (op0, 0); + if (GET_CODE (op1) == NOT) + num_negated++, op1 = XEXP (op1, 0); + + if (num_negated == 2) + return simplify_gen_binary (XOR, mode, op0, op1); + else if (num_negated == 1) + return simplify_gen_unary (NOT, mode, + simplify_gen_binary (XOR, mode, op0, op1), + mode); + } + + /* Convert (xor (and A B) B) to (and (not A) B). The latter may + correspond to a machine insn or result in further simplifications + if B is a constant. */ + + if (GET_CODE (op0) == AND + && rtx_equal_p (XEXP (op0, 1), op1) + && ! side_effects_p (op1)) + return simplify_gen_binary (AND, mode, + simplify_gen_unary (NOT, mode, + XEXP (op0, 0), mode), + op1); + + else if (GET_CODE (op0) == AND + && rtx_equal_p (XEXP (op0, 0), op1) + && ! side_effects_p (op1)) + return simplify_gen_binary (AND, mode, + simplify_gen_unary (NOT, mode, + XEXP (op0, 1), mode), + op1); + + /* (xor (comparison foo bar) (const_int 1)) can become the reversed + comparison if STORE_FLAG_VALUE is 1. */ + if (STORE_FLAG_VALUE == 1 + && trueop1 == const1_rtx + && COMPARISON_P (op0) + && (reversed = reversed_comparison (op0, mode))) + return reversed; + + /* (lshiftrt foo C) where C is the number of bits in FOO minus 1 + is (lt foo (const_int 0)), so we can perform the above + simplification if STORE_FLAG_VALUE is 1. */ + + if (STORE_FLAG_VALUE == 1 + && trueop1 == const1_rtx + && GET_CODE (op0) == LSHIFTRT + && GET_CODE (XEXP (op0, 1)) == CONST_INT + && INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1) + return gen_rtx_GE (mode, XEXP (op0, 0), const0_rtx); + + /* (xor (comparison foo bar) (const_int sign-bit)) + when STORE_FLAG_VALUE is the sign bit. */ + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode)) + == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)) + && trueop1 == const_true_rtx + && COMPARISON_P (op0) + && (reversed = reversed_comparison (op0, mode))) + return reversed; + tem = simplify_associative_operation (code, mode, op0, op1); if (tem) return tem; break; case AND: - if (trueop1 == const0_rtx && ! side_effects_p (op0)) - return const0_rtx; + if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0)) + return trueop1; /* If we are turning off bits already known off in OP0, we need not do an AND. */ if (GET_CODE (trueop1) == CONST_INT && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT && (nonzero_bits (trueop0, mode) & ~INTVAL (trueop1)) == 0) return op0; - if (trueop0 == trueop1 && ! side_effects_p (op0) + if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0) && GET_MODE_CLASS (mode) != MODE_CC) return op0; /* A & (~A) -> 0 */ @@ -1681,7 +2313,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0))) && ! side_effects_p (op0) && GET_MODE_CLASS (mode) != MODE_CC) - return const0_rtx; + return CONST0_RTX (mode); /* Transform (and (extend X) C) into (zero_extend (and X C)) if there are no nonzero bits of C outside of X's mode. */ @@ -1699,6 +2331,57 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, return simplify_gen_unary (ZERO_EXTEND, mode, tem, imode); } + /* Canonicalize (A | C1) & C2 as (A & C2) | (C1 & C2). */ + if (GET_CODE (op0) == IOR + && GET_CODE (trueop1) == CONST_INT + && GET_CODE (XEXP (op0, 1)) == CONST_INT) + { + HOST_WIDE_INT tmp = INTVAL (trueop1) & INTVAL (XEXP (op0, 1)); + return simplify_gen_binary (IOR, mode, + simplify_gen_binary (AND, mode, + XEXP (op0, 0), op1), + gen_int_mode (tmp, mode)); + } + + /* Convert (A ^ B) & A to A & (~B) since the latter is often a single + insn (and may simplify more). */ + if (GET_CODE (op0) == XOR + && rtx_equal_p (XEXP (op0, 0), op1) + && ! side_effects_p (op1)) + return simplify_gen_binary (AND, mode, + simplify_gen_unary (NOT, mode, + XEXP (op0, 1), mode), + op1); + + if (GET_CODE (op0) == XOR + && rtx_equal_p (XEXP (op0, 1), op1) + && ! side_effects_p (op1)) + return simplify_gen_binary (AND, mode, + simplify_gen_unary (NOT, mode, + XEXP (op0, 0), mode), + op1); + + /* Similarly for (~(A ^ B)) & A. */ + if (GET_CODE (op0) == NOT + && GET_CODE (XEXP (op0, 0)) == XOR + && rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1) + && ! side_effects_p (op1)) + return simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1); + + if (GET_CODE (op0) == NOT + && GET_CODE (XEXP (op0, 0)) == XOR + && rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1) + && ! side_effects_p (op1)) + return simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1); + + /* Convert (A | B) & A to A. */ + if (GET_CODE (op0) == IOR + && (rtx_equal_p (XEXP (op0, 0), op1) + || rtx_equal_p (XEXP (op0, 1), op1)) + && ! side_effects_p (XEXP (op0, 0)) + && ! side_effects_p (XEXP (op0, 1))) + return op1; + /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M, ((A & N) + B) & M -> (A + B) & M Similarly if (N & M) == 0, @@ -1745,6 +2428,19 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, return simplify_gen_binary (code, mode, tem, op1); } } + + /* (and X (ior (not X) Y) -> (and X Y) */ + if (GET_CODE (op1) == IOR + && GET_CODE (XEXP (op1, 0)) == NOT + && op0 == XEXP (XEXP (op1, 0), 0)) + return simplify_gen_binary (AND, mode, op0, XEXP (op1, 1)); + + /* (and (ior (not X) Y) X) -> (and X Y) */ + if (GET_CODE (op0) == IOR + && GET_CODE (XEXP (op0, 0)) == NOT + && op1 == XEXP (XEXP (op0, 0), 0)) + return simplify_gen_binary (AND, mode, op1, XEXP (op0, 1)); + tem = simplify_associative_operation (code, mode, op0, op1); if (tem) return tem; @@ -1752,22 +2448,24 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, case UDIV: /* 0/x is 0 (or x&0 if x has side-effects). */ - if (trueop0 == const0_rtx) - return side_effects_p (op1) - ? simplify_gen_binary (AND, mode, op1, const0_rtx) - : const0_rtx; - /* x/1 is x. */ - if (trueop1 == const1_rtx) - return rtl_hooks.gen_lowpart_no_emit (mode, op0); - /* Convert divide by power of two into shift. */ - if (GET_CODE (trueop1) == CONST_INT - && (val = exact_log2 (INTVAL (trueop1))) > 0) - return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (val)); - break; + if (trueop0 == CONST0_RTX (mode)) + { + if (side_effects_p (op1)) + return simplify_gen_binary (AND, mode, op1, trueop0); + return trueop0; + } + /* x/1 is x. */ + if (trueop1 == CONST1_RTX (mode)) + return rtl_hooks.gen_lowpart_no_emit (mode, op0); + /* Convert divide by power of two into shift. */ + if (GET_CODE (trueop1) == CONST_INT + && (val = exact_log2 (INTVAL (trueop1))) > 0) + return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (val)); + break; case DIV: /* Handle floating point and integers separately. */ - if (GET_MODE_CLASS (mode) == MODE_FLOAT) + if (SCALAR_FLOAT_MODE_P (mode)) { /* Maybe change 0.0 / x to 0.0. This transformation isn't safe for modes with NaNs, since 0.0 / 0.0 will then be @@ -1795,8 +2493,8 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, return simplify_gen_unary (NEG, mode, op0, mode); /* Change FP division by a constant into multiplication. - Only do this with -funsafe-math-optimizations. */ - if (flag_unsafe_math_optimizations + Only do this with -freciprocal-math. */ + if (flag_reciprocal_math && !REAL_VALUES_EQUAL (d, dconst0)) { REAL_ARITHMETIC (d, RDIV_EXPR, dconst1, d); @@ -1808,12 +2506,14 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, else { /* 0/x is 0 (or x&0 if x has side-effects). */ - if (trueop0 == const0_rtx) - return side_effects_p (op1) - ? simplify_gen_binary (AND, mode, op1, const0_rtx) - : const0_rtx; + if (trueop0 == CONST0_RTX (mode)) + { + if (side_effects_p (op1)) + return simplify_gen_binary (AND, mode, op1, trueop0); + return trueop0; + } /* x/1 is x. */ - if (trueop1 == const1_rtx) + if (trueop1 == CONST1_RTX (mode)) return rtl_hooks.gen_lowpart_no_emit (mode, op0); /* x/-1 is -x. */ if (trueop1 == constm1_rtx) @@ -1826,53 +2526,94 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, case UMOD: /* 0%x is 0 (or x&0 if x has side-effects). */ - if (trueop0 == const0_rtx) - return side_effects_p (op1) - ? simplify_gen_binary (AND, mode, op1, const0_rtx) - : const0_rtx; - /* x%1 is 0 (of x&0 if x has side-effects). */ - if (trueop1 == const1_rtx) - return side_effects_p (op0) - ? simplify_gen_binary (AND, mode, op0, const0_rtx) - : const0_rtx; - /* Implement modulus by power of two as AND. */ - if (GET_CODE (trueop1) == CONST_INT - && exact_log2 (INTVAL (trueop1)) > 0) - return simplify_gen_binary (AND, mode, op0, - GEN_INT (INTVAL (op1) - 1)); - break; + if (trueop0 == CONST0_RTX (mode)) + { + if (side_effects_p (op1)) + return simplify_gen_binary (AND, mode, op1, trueop0); + return trueop0; + } + /* x%1 is 0 (of x&0 if x has side-effects). */ + if (trueop1 == CONST1_RTX (mode)) + { + if (side_effects_p (op0)) + return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode)); + return CONST0_RTX (mode); + } + /* Implement modulus by power of two as AND. */ + if (GET_CODE (trueop1) == CONST_INT + && exact_log2 (INTVAL (trueop1)) > 0) + return simplify_gen_binary (AND, mode, op0, + GEN_INT (INTVAL (op1) - 1)); + break; case MOD: /* 0%x is 0 (or x&0 if x has side-effects). */ - if (trueop0 == const0_rtx) - return side_effects_p (op1) - ? simplify_gen_binary (AND, mode, op1, const0_rtx) - : const0_rtx; - /* x%1 and x%-1 is 0 (or x&0 if x has side-effects). */ - if (trueop1 == const1_rtx || trueop1 == constm1_rtx) - return side_effects_p (op0) - ? simplify_gen_binary (AND, mode, op0, const0_rtx) - : const0_rtx; - break; + if (trueop0 == CONST0_RTX (mode)) + { + if (side_effects_p (op1)) + return simplify_gen_binary (AND, mode, op1, trueop0); + return trueop0; + } + /* x%1 and x%-1 is 0 (or x&0 if x has side-effects). */ + if (trueop1 == CONST1_RTX (mode) || trueop1 == constm1_rtx) + { + if (side_effects_p (op0)) + return simplify_gen_binary (AND, mode, op0, CONST0_RTX (mode)); + return CONST0_RTX (mode); + } + break; case ROTATERT: case ROTATE: case ASHIFTRT: + if (trueop1 == CONST0_RTX (mode)) + return op0; + if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1)) + return op0; /* Rotating ~0 always results in ~0. */ if (GET_CODE (trueop0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT && (unsigned HOST_WIDE_INT) INTVAL (trueop0) == GET_MODE_MASK (mode) && ! side_effects_p (op1)) return op0; - - /* Fall through.... */ + canonicalize_shift: + if (SHIFT_COUNT_TRUNCATED && GET_CODE (op1) == CONST_INT) + { + val = INTVAL (op1) & (GET_MODE_BITSIZE (mode) - 1); + if (val != INTVAL (op1)) + return simplify_gen_binary (code, mode, op0, GEN_INT (val)); + } + break; case ASHIFT: + case SS_ASHIFT: + case US_ASHIFT: + if (trueop1 == CONST0_RTX (mode)) + return op0; + if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1)) + return op0; + goto canonicalize_shift; + case LSHIFTRT: - if (trueop1 == const0_rtx) + if (trueop1 == CONST0_RTX (mode)) return op0; - if (trueop0 == const0_rtx && ! side_effects_p (op1)) + if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1)) return op0; - break; + /* Optimize (lshiftrt (clz X) C) as (eq X 0). */ + if (GET_CODE (op0) == CLZ + && GET_CODE (trueop1) == CONST_INT + && STORE_FLAG_VALUE == 1 + && INTVAL (trueop1) < (HOST_WIDE_INT)width) + { + enum machine_mode imode = GET_MODE (XEXP (op0, 0)); + unsigned HOST_WIDE_INT zero_val = 0; + + if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val) + && zero_val == GET_MODE_BITSIZE (imode) + && INTVAL (trueop1) == exact_log2 (zero_val)) + return simplify_gen_relational (EQ, mode, imode, + XEXP (op0, 0), const0_rtx); + } + goto canonicalize_shift; case SMIN: if (width <= HOST_BITS_PER_WIDE_INT @@ -1902,7 +2643,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, break; case UMIN: - if (trueop1 == const0_rtx && ! side_effects_p (op0)) + if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0)) return op1; if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)) return op0; @@ -1925,6 +2666,10 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, case US_PLUS: case SS_MINUS: case US_MINUS: + case SS_MULT: + case US_MULT: + case SS_DIV: + case US_DIV: /* ??? There are simplifications that can be done. */ return 0; @@ -1940,6 +2685,85 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, if (GET_CODE (trueop0) == CONST_VECTOR) return CONST_VECTOR_ELT (trueop0, INTVAL (XVECEXP (trueop1, 0, 0))); + + /* Extract a scalar element from a nested VEC_SELECT expression + (with optional nested VEC_CONCAT expression). Some targets + (i386) extract scalar element from a vector using chain of + nested VEC_SELECT expressions. When input operand is a memory + operand, this operation can be simplified to a simple scalar + load from an offseted memory address. */ + if (GET_CODE (trueop0) == VEC_SELECT) + { + rtx op0 = XEXP (trueop0, 0); + rtx op1 = XEXP (trueop0, 1); + + enum machine_mode opmode = GET_MODE (op0); + int elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode)); + int n_elts = GET_MODE_SIZE (opmode) / elt_size; + + int i = INTVAL (XVECEXP (trueop1, 0, 0)); + int elem; + + rtvec vec; + rtx tmp_op, tmp; + + gcc_assert (GET_CODE (op1) == PARALLEL); + gcc_assert (i < n_elts); + + /* Select element, pointed by nested selector. */ + elem = INTVAL (XVECEXP (op1, 0, i)); + + /* Handle the case when nested VEC_SELECT wraps VEC_CONCAT. */ + if (GET_CODE (op0) == VEC_CONCAT) + { + rtx op00 = XEXP (op0, 0); + rtx op01 = XEXP (op0, 1); + + enum machine_mode mode00, mode01; + int n_elts00, n_elts01; + + mode00 = GET_MODE (op00); + mode01 = GET_MODE (op01); + + /* Find out number of elements of each operand. */ + if (VECTOR_MODE_P (mode00)) + { + elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode00)); + n_elts00 = GET_MODE_SIZE (mode00) / elt_size; + } + else + n_elts00 = 1; + + if (VECTOR_MODE_P (mode01)) + { + elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode01)); + n_elts01 = GET_MODE_SIZE (mode01) / elt_size; + } + else + n_elts01 = 1; + + gcc_assert (n_elts == n_elts00 + n_elts01); + + /* Select correct operand of VEC_CONCAT + and adjust selector. */ + if (elem < n_elts01) + tmp_op = op00; + else + { + tmp_op = op01; + elem -= n_elts00; + } + } + else + tmp_op = op0; + + vec = rtvec_alloc (1); + RTVEC_ELT (vec, 0) = GEN_INT (elem); + + tmp = gen_rtx_fmt_ee (code, mode, + tmp_op, gen_rtx_PARALLEL (VOIDmode, vec)); + return tmp; + } } else { @@ -1968,6 +2792,33 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, return gen_rtx_CONST_VECTOR (mode, v); } } + + if (XVECLEN (trueop1, 0) == 1 + && GET_CODE (XVECEXP (trueop1, 0, 0)) == CONST_INT + && GET_CODE (trueop0) == VEC_CONCAT) + { + rtx vec = trueop0; + int offset = INTVAL (XVECEXP (trueop1, 0, 0)) * GET_MODE_SIZE (mode); + + /* Try to find the element in the VEC_CONCAT. */ + while (GET_MODE (vec) != mode + && GET_CODE (vec) == VEC_CONCAT) + { + HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0))); + if (offset < vec_size) + vec = XEXP (vec, 0); + else + { + offset -= vec_size; + vec = XEXP (vec, 1); + } + vec = avoid_constant_pool_reference (vec); + } + + if (GET_MODE (vec) == mode) + return vec; + } + return 0; case VEC_CONCAT: { @@ -2078,7 +2929,12 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode, if (VECTOR_MODE_P (mode) && code == VEC_CONCAT - && CONSTANT_P (op0) && CONSTANT_P (op1)) + && (CONST_INT_P (op0) + || GET_CODE (op0) == CONST_DOUBLE + || GET_CODE (op0) == CONST_FIXED) + && (CONST_INT_P (op1) + || GET_CODE (op1) == CONST_DOUBLE + || GET_CODE (op1) == CONST_FIXED)) { unsigned n_elts = GET_MODE_NUNITS (mode); rtvec v = rtvec_alloc (n_elts); @@ -2111,7 +2967,7 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode, return gen_rtx_CONST_VECTOR (mode, v); } - if (GET_MODE_CLASS (mode) == MODE_FLOAT + if (SCALAR_FLOAT_MODE_P (mode) && GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE && mode == GET_MODE (op0) && mode == GET_MODE (op1)) @@ -2207,6 +3063,17 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode, &f0, &f1); real_convert (&result, mode, &value); + /* Don't constant fold this floating point operation if + the result has overflowed and flag_trapping_math. */ + + if (flag_trapping_math + && MODE_HAS_INFINITIES (mode) + && REAL_VALUE_ISINF (result) + && !REAL_VALUE_ISINF (f0) + && !REAL_VALUE_ISINF (f1)) + /* Overflow plus exception. */ + return 0; + /* Don't constant fold this floating point operation if the result may dependent upon the run-time rounding mode and flag_rounding_math is set, or if GCC's software emulation @@ -2517,6 +3384,12 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode, case US_PLUS: case SS_MINUS: case US_MINUS: + case SS_MULT: + case US_MULT: + case SS_DIV: + case US_DIV: + case SS_ASHIFT: + case US_ASHIFT: /* ??? There are simplifications that can be done. */ return 0; @@ -2537,37 +3410,39 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode, 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. - - If FORCE is true, then always generate the rtx. This is used to - canonicalize stuff emitted from simplify_gen_binary. Note that this - can still fail if the rtx is too complex. It won't fail just because - the result is not 'simpler' than the input, however. */ + we rebuild the operation. */ struct simplify_plus_minus_op_data { rtx op; - int neg; + short neg; }; -static int -simplify_plus_minus_op_data_cmp (const void *p1, const void *p2) +static bool +simplify_plus_minus_op_data_cmp (rtx x, rtx y) { - const struct simplify_plus_minus_op_data *d1 = p1; - const struct simplify_plus_minus_op_data *d2 = p2; + int result; - return (commutative_operand_precedence (d2->op) - - commutative_operand_precedence (d1->op)); + result = (commutative_operand_precedence (y) + - commutative_operand_precedence (x)); + if (result) + return result > 0; + + /* Group together equal REGs to do more simplification. */ + if (REG_P (x) && REG_P (y)) + return REGNO (x) > REGNO (y); + else + return false; } static rtx simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, - rtx op1, int force) + rtx op1) { struct simplify_plus_minus_op_data ops[8]; rtx result, tem; - int n_ops = 2, input_ops = 2, input_consts = 0, n_consts; - int first, changed; + int n_ops = 2, input_ops = 2; + int changed, n_constants = 0, canonicalized = 0; int i, j; memset (ops, 0, sizeof ops); @@ -2605,12 +3480,14 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, ops[i].op = XEXP (this_op, 0); input_ops++; changed = 1; + canonicalized |= this_neg; break; case NEG: ops[i].op = XEXP (this_op, 0); ops[i].neg = ! this_neg; changed = 1; + canonicalized = 1; break; case CONST: @@ -2623,8 +3500,8 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, ops[n_ops].op = XEXP (XEXP (this_op, 0), 1); ops[n_ops].neg = this_neg; n_ops++; - input_consts++; changed = 1; + canonicalized = 1; } break; @@ -2637,15 +3514,18 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, ops[i].op = XEXP (this_op, 0); ops[i].neg = !this_neg; changed = 1; + canonicalized = 1; } break; case CONST_INT: + n_constants++; if (this_neg) { ops[i].op = neg_const_int (mode, this_op); ops[i].neg = 0; changed = 1; + canonicalized = 1; } break; @@ -2656,31 +3536,69 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, } while (changed); - /* If we only have two operands, we can't do anything. */ - if (n_ops <= 2 && !force) - return NULL_RTX; + if (n_constants > 1) + canonicalized = 1; - /* Count the number of CONSTs we didn't split above. */ - for (i = 0; i < n_ops; i++) - if (GET_CODE (ops[i].op) == CONST) - input_consts++; + gcc_assert (n_ops >= 2); - /* Now simplify each pair of operands until nothing changes. The first - time through just simplify constants against each other. */ + /* If we only have two operands, we can avoid the loops. */ + if (n_ops == 2) + { + enum rtx_code code = ops[0].neg || ops[1].neg ? MINUS : PLUS; + rtx lhs, rhs; - first = 1; + /* Get the two operands. Be careful with the order, especially for + the cases where code == MINUS. */ + if (ops[0].neg && ops[1].neg) + { + lhs = gen_rtx_NEG (mode, ops[0].op); + rhs = ops[1].op; + } + else if (ops[0].neg) + { + lhs = ops[1].op; + rhs = ops[0].op; + } + else + { + lhs = ops[0].op; + rhs = ops[1].op; + } + + return simplify_const_binary_operation (code, mode, lhs, rhs); + } + + /* Now simplify each pair of operands until nothing changes. */ do { - changed = first; + /* Insertion sort is good enough for an eight-element array. */ + for (i = 1; i < n_ops; i++) + { + struct simplify_plus_minus_op_data save; + j = i - 1; + if (!simplify_plus_minus_op_data_cmp (ops[j].op, ops[i].op)) + continue; + + canonicalized = 1; + save = ops[i]; + do + ops[j + 1] = ops[j]; + while (j-- && simplify_plus_minus_op_data_cmp (ops[j].op, save.op)); + ops[j + 1] = save; + } + + /* This is only useful the first time through. */ + if (!canonicalized) + return NULL_RTX; - for (i = 0; i < n_ops - 1; i++) - for (j = i + 1; j < n_ops; j++) + changed = 0; + for (i = n_ops - 1; i > 0; i--) + for (j = i - 1; j >= 0; j--) { - rtx lhs = ops[i].op, rhs = ops[j].op; - int lneg = ops[i].neg, rneg = ops[j].neg; + rtx lhs = ops[j].op, rhs = ops[i].op; + int lneg = ops[j].neg, rneg = ops[i].neg; - if (lhs != 0 && rhs != 0 - && (! first || (CONSTANT_P (lhs) && CONSTANT_P (rhs)))) + if (lhs != 0 && rhs != 0) { enum rtx_code ncode = PLUS; @@ -2693,8 +3611,21 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, else if (swap_commutative_operands_p (lhs, rhs)) tem = lhs, lhs = rhs, rhs = tem; - tem = simplify_binary_operation (ncode, mode, lhs, rhs); + if ((GET_CODE (lhs) == CONST || GET_CODE (lhs) == CONST_INT) + && (GET_CODE (rhs) == CONST || GET_CODE (rhs) == CONST_INT)) + { + rtx tem_lhs, tem_rhs; + + tem_lhs = GET_CODE (lhs) == CONST ? XEXP (lhs, 0) : lhs; + tem_rhs = GET_CODE (rhs) == CONST ? XEXP (rhs, 0) : rhs; + tem = simplify_binary_operation (ncode, mode, tem_lhs, tem_rhs); + if (tem && !CONSTANT_P (tem)) + tem = gen_rtx_CONST (GET_MODE (tem), tem); + } + else + tem = simplify_binary_operation (ncode, mode, lhs, rhs); + /* Reject "simplifications" that just wrap the two arguments in a CONST. Failure to do so can result in infinite recursion with simplify_binary_operation @@ -2703,13 +3634,7 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, && ! (GET_CODE (tem) == CONST && GET_CODE (XEXP (tem, 0)) == ncode && XEXP (XEXP (tem, 0), 0) == lhs - && XEXP (XEXP (tem, 0), 1) == rhs) - /* Don't allow -x + -1 -> ~x simplifications in the - first pass. This allows us the chance to combine - the -1 with other constants. */ - && ! (first - && GET_CODE (tem) == NOT - && XEXP (tem, 0) == rhs)) + && XEXP (XEXP (tem, 0), 1) == rhs)) { lneg &= rneg; if (GET_CODE (tem) == NEG) @@ -2725,19 +3650,17 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, } } - first = 0; + /* Pack all the operands to the lower-numbered entries. */ + for (i = 0, j = 0; j < n_ops; j++) + if (ops[j].op) + { + ops[i] = ops[j]; + i++; + } + n_ops = i; } while (changed); - /* Pack all the operands to the lower-numbered entries. */ - for (i = 0, j = 0; j < n_ops; j++) - if (ops[j].op) - ops[i++] = ops[j]; - n_ops = i; - - /* Sort the operations based on swap_commutative_operands_p. */ - qsort (ops, n_ops, sizeof (*ops), simplify_plus_minus_op_data_cmp); - /* Create (minus -C X) instead of (neg (const (plus X C))). */ if (n_ops == 2 && GET_CODE (ops[1].op) == CONST_INT @@ -2751,6 +3674,24 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, one CONST_INT, and the sort will have ensured that it is last in the array and that any other constant will be next-to-last. */ + if (GET_CODE (ops[n_ops - 1].op) == CONST_INT) + i = n_ops - 2; + else + i = n_ops - 1; + + if (i >= 1 + && ops[i].neg + && !ops[i - 1].neg + && CONSTANT_P (ops[i].op) + && GET_CODE (ops[i].op) == GET_CODE (ops[i - 1].op)) + { + ops[i - 1].op = gen_rtx_MINUS (mode, ops[i - 1].op, ops[i].op); + ops[i - 1].op = gen_rtx_CONST (mode, ops[i - 1].op); + if (i < n_ops - 1) + ops[i] = ops[i + 1]; + n_ops--; + } + if (n_ops > 1 && GET_CODE (ops[n_ops - 1].op) == CONST_INT && CONSTANT_P (ops[n_ops - 2].op)) @@ -2762,21 +3703,6 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, n_ops--; } - /* Count the number of CONSTs that we generated. */ - n_consts = 0; - for (i = 0; i < n_ops; i++) - if (GET_CODE (ops[i].op) == CONST) - n_consts++; - - /* 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 before, this - is also an improvement, so accept it. */ - if (!force - && (n_ops + n_consts > input_ops - || (n_ops + n_consts == input_ops && n_consts <= input_consts))) - return NULL_RTX; - /* Put a non-negated operand first, if possible. */ for (i = 0; i < n_ops && ops[i].neg; i++) @@ -2802,7 +3728,7 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, /* Check whether an operand is suitable for calling simplify_plus_minus. */ static bool -plus_minus_operand_p (rtx x) +plus_minus_operand_p (const_rtx x) { return GET_CODE (x) == PLUS || GET_CODE (x) == MINUS @@ -2834,7 +3760,7 @@ simplify_relational_operation (enum rtx_code code, enum machine_mode mode, tem = simplify_const_relational_operation (code, cmp_mode, op0, op1); if (tem) { - if (GET_MODE_CLASS (mode) == MODE_FLOAT) + if (SCALAR_FLOAT_MODE_P (mode)) { if (tem == const0_rtx) return CONST0_RTX (mode); @@ -2887,8 +3813,7 @@ simplify_relational_operation (enum rtx_code code, enum machine_mode mode, return simplify_relational_operation (code, mode, VOIDmode, XEXP (op0, 0), XEXP (op0, 1)); - if (mode == VOIDmode - || GET_MODE_CLASS (cmp_mode) == MODE_CC + if (GET_MODE_CLASS (cmp_mode) == MODE_CC || CC0_P (op0)) return NULL_RTX; @@ -2910,29 +3835,78 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode, { enum rtx_code op0code = GET_CODE (op0); - if (GET_CODE (op1) == CONST_INT) + if (op1 == const0_rtx && COMPARISON_P (op0)) { - if (INTVAL (op1) == 0 && COMPARISON_P (op0)) + /* If op0 is a comparison, extract the comparison arguments + from it. */ + if (code == NE) { - /* If op0 is a comparison, extract the comparison arguments form it. */ - if (code == NE) - { - if (GET_MODE (op0) == mode) - return simplify_rtx (op0); - else - return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode, - XEXP (op0, 0), XEXP (op0, 1)); - } - else if (code == EQ) - { - enum rtx_code new_code = reversed_comparison_code (op0, NULL_RTX); - if (new_code != UNKNOWN) - return simplify_gen_relational (new_code, mode, VOIDmode, - XEXP (op0, 0), XEXP (op0, 1)); - } + if (GET_MODE (op0) == mode) + return simplify_rtx (op0); + else + return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode, + XEXP (op0, 0), XEXP (op0, 1)); + } + else if (code == EQ) + { + enum rtx_code new_code = reversed_comparison_code (op0, NULL_RTX); + if (new_code != UNKNOWN) + return simplify_gen_relational (new_code, mode, VOIDmode, + XEXP (op0, 0), XEXP (op0, 1)); } } + /* Canonicalize (LTU/GEU (PLUS a b) b) as (LTU/GEU (PLUS a b) a). */ + if ((code == LTU || code == GEU) + && GET_CODE (op0) == PLUS + && rtx_equal_p (op1, XEXP (op0, 1)) + /* Don't recurse "infinitely" for (LTU/GEU (PLUS b b) b). */ + && !rtx_equal_p (op1, XEXP (op0, 0))) + return simplify_gen_relational (code, mode, cmp_mode, op0, XEXP (op0, 0)); + + if (op1 == const0_rtx) + { + /* Canonicalize (GTU x 0) as (NE x 0). */ + if (code == GTU) + return simplify_gen_relational (NE, mode, cmp_mode, op0, op1); + /* Canonicalize (LEU x 0) as (EQ x 0). */ + if (code == LEU) + return simplify_gen_relational (EQ, mode, cmp_mode, op0, op1); + } + else if (op1 == const1_rtx) + { + switch (code) + { + case GE: + /* Canonicalize (GE x 1) as (GT x 0). */ + return simplify_gen_relational (GT, mode, cmp_mode, + op0, const0_rtx); + case GEU: + /* Canonicalize (GEU x 1) as (NE x 0). */ + return simplify_gen_relational (NE, mode, cmp_mode, + op0, const0_rtx); + case LT: + /* Canonicalize (LT x 1) as (LE x 0). */ + return simplify_gen_relational (LE, mode, cmp_mode, + op0, const0_rtx); + case LTU: + /* Canonicalize (LTU x 1) as (EQ x 0). */ + return simplify_gen_relational (EQ, mode, cmp_mode, + op0, const0_rtx); + default: + break; + } + } + else if (op1 == constm1_rtx) + { + /* Canonicalize (LE x -1) as (LT x 0). */ + if (code == LE) + return simplify_gen_relational (LT, mode, cmp_mode, op0, const0_rtx); + /* Canonicalize (GT x -1) as (GE x 0). */ + if (code == GT) + return simplify_gen_relational (GE, mode, cmp_mode, op0, const0_rtx); + } + /* (eq/ne (plus x cst1) cst2) simplifies to (eq/ne x (cst2 - cst1)) */ if ((code == EQ || code == NE) && (op0code == PLUS || op0code == MINUS) @@ -2963,9 +3937,125 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode, ? simplify_gen_unary (ZERO_EXTEND, mode, op0, cmp_mode) : lowpart_subreg (mode, op0, cmp_mode); + /* (eq/ne (xor x y) 0) simplifies to (eq/ne x y). */ + if ((code == EQ || code == NE) + && op1 == const0_rtx + && op0code == XOR) + return simplify_gen_relational (code, mode, cmp_mode, + XEXP (op0, 0), XEXP (op0, 1)); + + /* (eq/ne (xor x y) x) simplifies to (eq/ne y 0). */ + if ((code == EQ || code == NE) + && op0code == XOR + && rtx_equal_p (XEXP (op0, 0), op1) + && !side_effects_p (XEXP (op0, 0))) + return simplify_gen_relational (code, mode, cmp_mode, + XEXP (op0, 1), const0_rtx); + + /* Likewise (eq/ne (xor x y) y) simplifies to (eq/ne x 0). */ + if ((code == EQ || code == NE) + && op0code == XOR + && rtx_equal_p (XEXP (op0, 1), op1) + && !side_effects_p (XEXP (op0, 1))) + return simplify_gen_relational (code, mode, cmp_mode, + XEXP (op0, 0), const0_rtx); + + /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)). */ + if ((code == EQ || code == NE) + && op0code == XOR + && (GET_CODE (op1) == CONST_INT + || GET_CODE (op1) == CONST_DOUBLE) + && (GET_CODE (XEXP (op0, 1)) == CONST_INT + || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE)) + return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0), + simplify_gen_binary (XOR, cmp_mode, + XEXP (op0, 1), op1)); + + if (op0code == POPCOUNT && op1 == const0_rtx) + switch (code) + { + case EQ: + case LE: + case LEU: + /* (eq (popcount x) (const_int 0)) -> (eq x (const_int 0)). */ + return simplify_gen_relational (EQ, mode, GET_MODE (XEXP (op0, 0)), + XEXP (op0, 0), const0_rtx); + + case NE: + case GT: + case GTU: + /* (ne (popcount x) (const_int 0)) -> (ne x (const_int 0)). */ + return simplify_gen_relational (NE, mode, GET_MODE (XEXP (op0, 0)), + XEXP (op0, 0), const0_rtx); + + default: + break; + } + return NULL_RTX; } +enum +{ + CMP_EQ = 1, + CMP_LT = 2, + CMP_GT = 4, + CMP_LTU = 8, + CMP_GTU = 16 +}; + + +/* Convert the known results for EQ, LT, GT, LTU, GTU contained in + KNOWN_RESULT to a CONST_INT, based on the requested comparison CODE + For KNOWN_RESULT to make sense it should be either CMP_EQ, or the + logical OR of one of (CMP_LT, CMP_GT) and one of (CMP_LTU, CMP_GTU). + For floating-point comparisons, assume that the operands were ordered. */ + +static rtx +comparison_result (enum rtx_code code, int known_results) +{ + switch (code) + { + case EQ: + case UNEQ: + return (known_results & CMP_EQ) ? const_true_rtx : const0_rtx; + case NE: + case LTGT: + return (known_results & CMP_EQ) ? const0_rtx : const_true_rtx; + + case LT: + case UNLT: + return (known_results & CMP_LT) ? const_true_rtx : const0_rtx; + case GE: + case UNGE: + return (known_results & CMP_LT) ? const0_rtx : const_true_rtx; + + case GT: + case UNGT: + return (known_results & CMP_GT) ? const_true_rtx : const0_rtx; + case LE: + case UNLE: + return (known_results & CMP_GT) ? const0_rtx : const_true_rtx; + + case LTU: + return (known_results & CMP_LTU) ? const_true_rtx : const0_rtx; + case GEU: + return (known_results & CMP_LTU) ? const0_rtx : const_true_rtx; + + case GTU: + return (known_results & CMP_GTU) ? const_true_rtx : const0_rtx; + case LEU: + return (known_results & CMP_GTU) ? const0_rtx : const_true_rtx; + + case ORDERED: + return const_true_rtx; + case UNORDERED: + return const0_rtx; + default: + gcc_unreachable (); + } +} + /* Check if the given comparison (done in the given MODE) is actually a tautology or a contradiction. If no simplification is possible, this function returns zero. @@ -2976,7 +4066,6 @@ simplify_const_relational_operation (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1) { - int equal, op0lt, op0ltu, op1lt, op1ltu; rtx tem; rtx trueop0; rtx trueop1; @@ -2987,7 +4076,17 @@ simplify_const_relational_operation (enum rtx_code code, /* 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); + { + op1 = XEXP (op0, 1); + op0 = XEXP (op0, 0); + + if (GET_MODE (op0) != VOIDmode) + mode = GET_MODE (op0); + else if (GET_MODE (op1) != VOIDmode) + mode = GET_MODE (op1); + else + return 0; + } /* We can't simplify MODE_CC values since we don't know what the actual comparison is. */ @@ -3009,40 +4108,44 @@ simplify_const_relational_operation (enum rtx_code code, 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; but we cannot do it even for - signed comparisons for languages such as Java, so test flag_wrapv. */ + We can only do this for EQ and NE comparisons as otherwise we may + lose or introduce overflow which we cannot disregard as undefined as + we do not know the signedness of the operation on either the left or + the right hand side of the comparison. */ - if (!flag_wrapv && INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx + if (INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx + && (code == EQ || code == NE) && ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT) && (REG_P (op1) || GET_CODE (trueop1) == CONST_INT)) && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1)) - /* We cannot do this for == or != if tem is a nonzero address. */ - && ((code != EQ && code != NE) || ! nonzero_address_p (tem)) - && code != GTU && code != GEU && code != LTU && code != LEU) + /* We cannot do this if tem is a nonzero address. */ + && ! nonzero_address_p (tem)) return simplify_const_relational_operation (signed_condition (code), mode, tem, const0_rtx); - if (flag_unsafe_math_optimizations && code == ORDERED) + if (! HONOR_NANS (mode) && code == ORDERED) return const_true_rtx; - if (flag_unsafe_math_optimizations && code == UNORDERED) + if (! HONOR_NANS (mode) && code == UNORDERED) return const0_rtx; /* For modes without NaNs, if the two operands are equal, we know the - result except if they have side-effects. */ - if (! HONOR_NANS (GET_MODE (trueop0)) + result except if they have side-effects. Even with NaNs we know + the result of unordered comparisons and, if signaling NaNs are + irrelevant, also the result of LT/GT/LTGT. */ + if ((! HONOR_NANS (GET_MODE (trueop0)) + || code == UNEQ || code == UNLE || code == UNGE + || ((code == LT || code == GT || code == LTGT) + && ! HONOR_SNANS (GET_MODE (trueop0)))) && rtx_equal_p (trueop0, trueop1) && ! side_effects_p (trueop0)) - equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0; + return comparison_result (code, CMP_EQ); /* If the operands are floating-point constants, see if we can fold the result. */ - else if (GET_CODE (trueop0) == CONST_DOUBLE - && GET_CODE (trueop1) == CONST_DOUBLE - && GET_MODE_CLASS (GET_MODE (trueop0)) == MODE_FLOAT) + if (GET_CODE (trueop0) == CONST_DOUBLE + && GET_CODE (trueop1) == CONST_DOUBLE + && SCALAR_FLOAT_MODE_P (GET_MODE (trueop0))) { REAL_VALUE_TYPE d0, d1; @@ -3073,17 +4176,17 @@ simplify_const_relational_operation (enum rtx_code code, return 0; } - equal = REAL_VALUES_EQUAL (d0, d1); - op0lt = op0ltu = REAL_VALUES_LESS (d0, d1); - op1lt = op1ltu = REAL_VALUES_LESS (d1, d0); + return comparison_result (code, + (REAL_VALUES_EQUAL (d0, d1) ? CMP_EQ : + REAL_VALUES_LESS (d0, d1) ? CMP_LT : CMP_GT)); } /* Otherwise, see if the operands are both integers. */ - else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode) - && (GET_CODE (trueop0) == CONST_DOUBLE - || GET_CODE (trueop0) == CONST_INT) - && (GET_CODE (trueop1) == CONST_DOUBLE - || GET_CODE (trueop1) == CONST_INT)) + if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode) + && (GET_CODE (trueop0) == CONST_DOUBLE + || GET_CODE (trueop0) == CONST_INT) + && (GET_CODE (trueop1) == CONST_DOUBLE + || GET_CODE (trueop1) == CONST_INT)) { int width = GET_MODE_BITSIZE (mode); HOST_WIDE_INT l0s, h0s, l1s, h1s; @@ -3128,162 +4231,232 @@ simplify_const_relational_operation (enum rtx_code code, if (width != 0 && width <= HOST_BITS_PER_WIDE_INT) h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s); - equal = (h0u == h1u && l0u == l1u); - op0lt = (h0s < h1s || (h0s == h1s && l0u < l1u)); - op1lt = (h1s < h0s || (h1s == h0s && l1u < l0u)); - op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u)); - op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u)); + if (h0u == h1u && l0u == l1u) + return comparison_result (code, CMP_EQ); + else + { + int cr; + cr = (h0s < h1s || (h0s == h1s && l0u < l1u)) ? CMP_LT : CMP_GT; + cr |= (h0u < h1u || (h0u == h1u && l0u < l1u)) ? CMP_LTU : CMP_GTU; + return comparison_result (code, cr); + } } - /* Otherwise, there are some code-specific tests we can make. */ - else + /* Optimize comparisons with upper and lower bounds. */ + if (SCALAR_INT_MODE_P (mode) + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT + && GET_CODE (trueop1) == CONST_INT) { - /* Optimize comparisons with upper and lower bounds. */ - if (SCALAR_INT_MODE_P (mode) - && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) - { - rtx mmin, mmax; - int sign; - - if (code == GEU - || code == LEU - || code == GTU - || code == LTU) - sign = 0; - else - sign = 1; + int sign; + unsigned HOST_WIDE_INT nonzero = nonzero_bits (trueop0, mode); + HOST_WIDE_INT val = INTVAL (trueop1); + HOST_WIDE_INT mmin, mmax; + + if (code == GEU + || code == LEU + || code == GTU + || code == LTU) + sign = 0; + else + sign = 1; - get_mode_bounds (mode, sign, mode, &mmin, &mmax); + /* Get a reduced range if the sign bit is zero. */ + if (nonzero <= (GET_MODE_MASK (mode) >> 1)) + { + mmin = 0; + mmax = nonzero; + } + else + { + rtx mmin_rtx, mmax_rtx; + get_mode_bounds (mode, sign, mode, &mmin_rtx, &mmax_rtx); - tem = NULL_RTX; - switch (code) + mmin = INTVAL (mmin_rtx); + mmax = INTVAL (mmax_rtx); + if (sign) { - case GEU: - case GE: - /* x >= min is always true. */ - if (rtx_equal_p (trueop1, mmin)) - tem = const_true_rtx; - else - break; - - case LEU: - case LE: - /* x <= max is always true. */ - if (rtx_equal_p (trueop1, mmax)) - tem = const_true_rtx; - break; + unsigned int sign_copies = num_sign_bit_copies (trueop0, mode); - case GTU: - case GT: - /* x > max is always false. */ - if (rtx_equal_p (trueop1, mmax)) - tem = const0_rtx; - break; - - case LTU: - case LT: - /* x < min is always false. */ - if (rtx_equal_p (trueop1, mmin)) - tem = const0_rtx; - break; - - default: - break; + mmin >>= (sign_copies - 1); + mmax >>= (sign_copies - 1); } - if (tem == const0_rtx - || tem == const_true_rtx) - return tem; } switch (code) { + /* x >= y is always true for y <= mmin, always false for y > mmax. */ + case GEU: + if ((unsigned HOST_WIDE_INT) val <= (unsigned HOST_WIDE_INT) mmin) + return const_true_rtx; + if ((unsigned HOST_WIDE_INT) val > (unsigned HOST_WIDE_INT) mmax) + return const0_rtx; + break; + case GE: + if (val <= mmin) + return const_true_rtx; + if (val > mmax) + return const0_rtx; + break; + + /* x <= y is always true for y >= mmax, always false for y < mmin. */ + case LEU: + if ((unsigned HOST_WIDE_INT) val >= (unsigned HOST_WIDE_INT) mmax) + return const_true_rtx; + if ((unsigned HOST_WIDE_INT) val < (unsigned HOST_WIDE_INT) mmin) + return const0_rtx; + break; + case LE: + if (val >= mmax) + return const_true_rtx; + if (val < mmin) + return const0_rtx; + break; + case EQ: - if (trueop1 == const0_rtx && nonzero_address_p (op0)) + /* x == y is always false for y out of range. */ + if (val < mmin || val > mmax) return const0_rtx; break; + /* x > y is always false for y >= mmax, always true for y < mmin. */ + case GTU: + if ((unsigned HOST_WIDE_INT) val >= (unsigned HOST_WIDE_INT) mmax) + return const0_rtx; + if ((unsigned HOST_WIDE_INT) val < (unsigned HOST_WIDE_INT) mmin) + return const_true_rtx; + break; + case GT: + if (val >= mmax) + return const0_rtx; + if (val < mmin) + return const_true_rtx; + break; + + /* x < y is always false for y <= mmin, always true for y > mmax. */ + case LTU: + if ((unsigned HOST_WIDE_INT) val <= (unsigned HOST_WIDE_INT) mmin) + return const0_rtx; + if ((unsigned HOST_WIDE_INT) val > (unsigned HOST_WIDE_INT) mmax) + return const_true_rtx; + break; + case LT: + if (val <= mmin) + return const0_rtx; + if (val > mmax) + return const_true_rtx; + break; + case NE: - if (trueop1 == const0_rtx && nonzero_address_p (op0)) + /* x != y is always true for y out of range. */ + if (val < mmin || val > mmax) return const_true_rtx; break; + default: + break; + } + } + + /* Optimize integer comparisons with zero. */ + if (trueop1 == const0_rtx) + { + /* Some addresses are known to be nonzero. We don't know + their sign, but equality comparisons are known. */ + if (nonzero_address_p (trueop0)) + { + if (code == EQ || code == LEU) + return const0_rtx; + if (code == NE || code == GTU) + return const_true_rtx; + } + + /* See if the first operand is an IOR with a constant. If so, we + may be able to determine the result of this comparison. */ + if (GET_CODE (op0) == IOR) + { + rtx inner_const = avoid_constant_pool_reference (XEXP (op0, 1)); + if (GET_CODE (inner_const) == CONST_INT && inner_const != const0_rtx) + { + int sign_bitnum = GET_MODE_BITSIZE (mode) - 1; + int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum + && (INTVAL (inner_const) + & ((HOST_WIDE_INT) 1 << sign_bitnum))); + + switch (code) + { + case EQ: + case LEU: + return const0_rtx; + case NE: + case GTU: + return const_true_rtx; + case LT: + case LE: + if (has_sign) + return const_true_rtx; + break; + case GT: + case GE: + if (has_sign) + return const0_rtx; + break; + default: + break; + } + } + } + } + + /* Optimize comparison of ABS with zero. */ + if (trueop1 == CONST0_RTX (mode) + && (GET_CODE (trueop0) == ABS + || (GET_CODE (trueop0) == FLOAT_EXTEND + && GET_CODE (XEXP (trueop0, 0)) == ABS))) + { + switch (code) + { case LT: /* Optimize abs(x) < 0.0. */ - if (trueop1 == CONST0_RTX (mode) && !HONOR_SNANS (mode)) + if (!HONOR_SNANS (mode) + && (!INTEGRAL_MODE_P (mode) + || (!flag_wrapv && !flag_trapv && flag_strict_overflow))) { - tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0) - : trueop0; - if (GET_CODE (tem) == ABS) - return const0_rtx; + if (INTEGRAL_MODE_P (mode) + && (issue_strict_overflow_warning + (WARN_STRICT_OVERFLOW_CONDITIONAL))) + warning (OPT_Wstrict_overflow, + ("assuming signed overflow does not occur when " + "assuming abs (x) < 0 is false")); + return const0_rtx; } break; case GE: /* Optimize abs(x) >= 0.0. */ - if (trueop1 == CONST0_RTX (mode) && !HONOR_NANS (mode)) + if (!HONOR_NANS (mode) + && (!INTEGRAL_MODE_P (mode) + || (!flag_wrapv && !flag_trapv && flag_strict_overflow))) { - tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0) - : trueop0; - if (GET_CODE (tem) == ABS) - return const_true_rtx; + if (INTEGRAL_MODE_P (mode) + && (issue_strict_overflow_warning + (WARN_STRICT_OVERFLOW_CONDITIONAL))) + warning (OPT_Wstrict_overflow, + ("assuming signed overflow does not occur when " + "assuming abs (x) >= 0 is true")); + return const_true_rtx; } break; case UNGE: /* Optimize ! (abs(x) < 0.0). */ - if (trueop1 == CONST0_RTX (mode)) - { - tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0) - : trueop0; - if (GET_CODE (tem) == ABS) - return const_true_rtx; - } - break; + return const_true_rtx; default: break; } - - return 0; } - /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set - as appropriate. */ - switch (code) - { - case EQ: - case UNEQ: - return equal ? const_true_rtx : const0_rtx; - case NE: - case LTGT: - return ! equal ? const_true_rtx : const0_rtx; - case LT: - case UNLT: - return op0lt ? const_true_rtx : const0_rtx; - case GT: - case UNGT: - 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: - case UNLE: - return equal || op0lt ? const_true_rtx : const0_rtx; - case GE: - case UNGE: - 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; - case ORDERED: - return const_true_rtx; - case UNORDERED: - return const0_rtx; - default: - gcc_unreachable (); - } + return 0; } /* Simplify CODE, an operation with result mode MODE and three operands, @@ -3460,8 +4633,9 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode, return 0; } -/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_VECTOR, - returning another CONST_INT or CONST_DOUBLE or CONST_VECTOR. +/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_FIXED + or CONST_VECTOR, + returning another CONST_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR. Works by unpacking OP into a collection of 8-bit values represented as a little-endian array of 'unsigned char', selecting by BYTE, @@ -3564,7 +4738,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op, } /* It shouldn't matter what's done here, so fill it with zero. */ - for (; i < max_bitsize; i += value_bit) + for (; i < elem_bitsize; i += value_bit) *vp++ = 0; } else @@ -3572,7 +4746,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op, long tmp[max_bitsize / 32]; int bitsize = GET_MODE_BITSIZE (GET_MODE (el)); - gcc_assert (GET_MODE_CLASS (GET_MODE (el)) == MODE_FLOAT); + gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el))); gcc_assert (bitsize <= elem_bitsize); gcc_assert (bitsize % value_bit == 0); @@ -3599,6 +4773,25 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op, *vp++ = 0; } break; + + case CONST_FIXED: + if (elem_bitsize <= HOST_BITS_PER_WIDE_INT) + { + for (i = 0; i < elem_bitsize; i += value_bit) + *vp++ = CONST_FIXED_VALUE_LOW (el) >> i; + } + else + { + for (i = 0; i < HOST_BITS_PER_WIDE_INT; i += value_bit) + *vp++ = CONST_FIXED_VALUE_LOW (el) >> i; + for (; i < 2 * HOST_BITS_PER_WIDE_INT && i < elem_bitsize; + i += value_bit) + *vp++ = CONST_FIXED_VALUE_HIGH (el) + >> (i - HOST_BITS_PER_WIDE_INT); + for (; i < elem_bitsize; i += value_bit) + *vp++ = 0; + } + break; default: gcc_unreachable (); @@ -3684,12 +4877,15 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op, know why. */ if (elem_bitsize <= HOST_BITS_PER_WIDE_INT) elems[elem] = gen_int_mode (lo, outer_submode); - else + else if (elem_bitsize <= 2 * HOST_BITS_PER_WIDE_INT) elems[elem] = immed_double_const (lo, hi, outer_submode); + else + return NULL_RTX; } break; case MODE_FLOAT: + case MODE_DECIMAL_FLOAT: { REAL_VALUE_TYPE r; long tmp[max_bitsize / 32]; @@ -3714,6 +4910,28 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op, elems[elem] = CONST_DOUBLE_FROM_REAL_VALUE (r, outer_submode); } break; + + case MODE_FRACT: + case MODE_UFRACT: + case MODE_ACCUM: + case MODE_UACCUM: + { + FIXED_VALUE_TYPE f; + f.data.low = 0; + f.data.high = 0; + f.mode = outer_submode; + + for (i = 0; + i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize; + i += value_bit) + f.data.low |= (HOST_WIDE_INT)(*vp++ & value_mask) << i; + for (; i < elem_bitsize; i += value_bit) + f.data.high |= ((HOST_WIDE_INT)(*vp++ & value_mask) + << (i - HOST_BITS_PER_WIDE_INT)); + + elems[elem] = CONST_FIXED_FROM_FIXED_VALUE (f, outer_submode); + } + break; default: gcc_unreachable (); @@ -3748,6 +4966,7 @@ simplify_subreg (enum machine_mode outermode, rtx op, if (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE + || GET_CODE (op) == CONST_FIXED || GET_CODE (op) == CONST_VECTOR) return simplify_immed_subreg (outermode, op, innermode, byte); @@ -3820,10 +5039,33 @@ simplify_subreg (enum machine_mode outermode, rtx op, return newx; if (validate_subreg (outermode, innermostmode, SUBREG_REG (op), final_offset)) - return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset); + { + newx = gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset); + if (SUBREG_PROMOTED_VAR_P (op) + && SUBREG_PROMOTED_UNSIGNED_P (op) >= 0 + && GET_MODE_CLASS (outermode) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (outermode), + GET_MODE_SIZE (innermode), + GET_MODE_SIZE (innermostmode)) + && subreg_lowpart_p (newx)) + { + SUBREG_PROMOTED_VAR_P (newx) = 1; + SUBREG_PROMOTED_UNSIGNED_SET + (newx, SUBREG_PROMOTED_UNSIGNED_P (op)); + } + return newx; + } return NULL_RTX; } + /* Merge implicit and explicit truncations. */ + + if (GET_CODE (op) == TRUNCATE + && GET_MODE_SIZE (outermode) < GET_MODE_SIZE (innermode) + && subreg_lowpart_offset (outermode, innermode) == byte) + return simplify_gen_unary (TRUNCATE, outermode, XEXP (op, 0), + GET_MODE (XEXP (op, 0))); + /* SUBREG of a hard register => just change the register number and/or mode. If the hard register is not valid in that mode, suppress this simplification. If the hard register is the stack, @@ -3859,7 +5101,22 @@ simplify_subreg (enum machine_mode outermode, rtx op, if (HARD_REGNO_MODE_OK (final_regno, outermode) || ! HARD_REGNO_MODE_OK (regno, innermode)) { - rtx x = gen_rtx_REG_offset (op, outermode, final_regno, byte); + rtx x; + int final_offset = byte; + + /* Adjust offset for paradoxical subregs. */ + if (byte == 0 + && GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode)) + { + int difference = (GET_MODE_SIZE (innermode) + - GET_MODE_SIZE (outermode)); + if (WORDS_BIG_ENDIAN) + final_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + final_offset += difference % UNITS_PER_WORD; + } + + x = gen_rtx_REG_offset (op, outermode, final_regno, final_offset); /* Propagate original regno. We don't have any way to specify the offset inside original regno, so do so only for lowpart. @@ -3890,13 +5147,22 @@ simplify_subreg (enum machine_mode outermode, rtx op, of real and imaginary part. */ if (GET_CODE (op) == CONCAT) { - unsigned int inner_size, final_offset; + unsigned int part_size, final_offset; rtx part, res; - inner_size = GET_MODE_UNIT_SIZE (innermode); - part = byte < inner_size ? XEXP (op, 0) : XEXP (op, 1); - final_offset = byte % inner_size; - if (final_offset + GET_MODE_SIZE (outermode) > inner_size) + part_size = GET_MODE_UNIT_SIZE (GET_MODE (XEXP (op, 0))); + if (byte < part_size) + { + part = XEXP (op, 0); + final_offset = byte; + } + else + { + part = XEXP (op, 1); + final_offset = byte - part_size; + } + + if (final_offset + GET_MODE_SIZE (outermode) > part_size) return NULL_RTX; res = simplify_subreg (outermode, part, GET_MODE (part), final_offset); @@ -3991,6 +5257,22 @@ simplify_subreg (enum machine_mode outermode, rtx op, return simplify_gen_binary (ASHIFT, outermode, XEXP (XEXP (op, 0), 0), XEXP (op, 1)); + /* Recognize a word extraction from a multi-word subreg. */ + if ((GET_CODE (op) == LSHIFTRT + || GET_CODE (op) == ASHIFTRT) + && SCALAR_INT_MODE_P (outermode) + && GET_MODE_BITSIZE (outermode) >= BITS_PER_WORD + && GET_MODE_BITSIZE (innermode) >= (2 * GET_MODE_BITSIZE (outermode)) + && GET_CODE (XEXP (op, 1)) == CONST_INT + && (INTVAL (XEXP (op, 1)) & (GET_MODE_BITSIZE (outermode) - 1)) == 0 + && byte == subreg_lowpart_offset (outermode, innermode)) + { + int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT; + return simplify_gen_subreg (outermode, XEXP (op, 0), innermode, + (WORDS_BIG_ENDIAN + ? byte - shifted_bytes : byte + shifted_bytes)); + } + return NULL_RTX; } @@ -4058,10 +5340,10 @@ simplify_gen_subreg (enum machine_mode outermode, rtx op, simplification and 1 for tree simplification. */ rtx -simplify_rtx (rtx x) +simplify_rtx (const_rtx x) { - enum rtx_code code = GET_CODE (x); - enum machine_mode mode = GET_MODE (x); + const enum rtx_code code = GET_CODE (x); + const enum machine_mode mode = GET_MODE (x); switch (GET_RTX_CLASS (code)) { @@ -4095,9 +5377,9 @@ simplify_rtx (rtx x) case RTX_EXTRA: if (code == SUBREG) - return simplify_gen_subreg (mode, SUBREG_REG (x), - GET_MODE (SUBREG_REG (x)), - SUBREG_BYTE (x)); + return simplify_subreg (mode, SUBREG_REG (x), + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x)); break; case RTX_OBJ: