/* RTL simplification functions for GNU compiler.
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "varasm.h"
#include "tm_p.h"
#include "regs.h"
#include "insn-config.h"
#include "recog.h"
#include "function.h"
+#include "insn-codes.h"
+#include "optabs.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
#include "diagnostic-core.h"
-#include "ggc.h"
#include "target.h"
+#include "predict.h"
/* Simplification and canonicalization of RTL. */
#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, const_rtx);
+static rtx neg_const_int (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,
+static rtx simplify_plus_minus (enum rtx_code, machine_mode, rtx, rtx);
+static rtx simplify_immed_subreg (machine_mode, rtx, machine_mode,
unsigned int);
-static rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
+static rtx simplify_associative_operation (enum rtx_code, machine_mode,
rtx, rtx);
-static rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode,
- enum machine_mode, rtx, rtx);
-static rtx simplify_unary_operation_1 (enum rtx_code, enum machine_mode, rtx);
-static rtx simplify_binary_operation_1 (enum rtx_code, enum machine_mode,
+static rtx simplify_relational_operation_1 (enum rtx_code, machine_mode,
+ machine_mode, rtx, rtx);
+static rtx simplify_unary_operation_1 (enum rtx_code, machine_mode, rtx);
+static rtx simplify_binary_operation_1 (enum rtx_code, machine_mode,
rtx, rtx, rtx, rtx);
\f
/* 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, const_rtx i)
+neg_const_int (machine_mode mode, const_rtx i)
{
return gen_int_mode (-(unsigned HOST_WIDE_INT) INTVAL (i), mode);
}
the most significant bit of machine mode MODE. */
bool
-mode_signbit_p (enum machine_mode mode, const_rtx x)
+mode_signbit_p (machine_mode mode, const_rtx x)
{
unsigned HOST_WIDE_INT val;
unsigned int width;
precision of MODE is too large to handle. */
bool
-val_signbit_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+val_signbit_p (machine_mode mode, unsigned HOST_WIDE_INT val)
{
unsigned int width;
/* Test whether the most significant bit of mode MODE is set in VAL.
Returns false if the precision of MODE is too large to handle. */
bool
-val_signbit_known_set_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+val_signbit_known_set_p (machine_mode mode, unsigned HOST_WIDE_INT val)
{
unsigned int width;
/* Test whether the most significant bit of mode MODE is clear in VAL.
Returns false if the precision of MODE is too large to handle. */
bool
-val_signbit_known_clear_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+val_signbit_known_clear_p (machine_mode mode, unsigned HOST_WIDE_INT val)
{
unsigned int width;
seeing if the expression folds. */
rtx
-simplify_gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0,
+simplify_gen_binary (enum rtx_code code, machine_mode mode, rtx op0,
rtx op1)
{
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;
+ std::swap (op0, op1);
return gen_rtx_fmt_ee (code, mode, op0, op1);
}
avoid_constant_pool_reference (rtx x)
{
rtx c, tmp, addr;
- enum machine_mode cmode;
+ machine_mode cmode;
HOST_WIDE_INT offset = 0;
switch (GET_CODE (x))
&& MEM_OFFSET_KNOWN_P (x))
{
tree decl = MEM_EXPR (x);
- enum machine_mode mode = GET_MODE (x);
+ machine_mode mode = GET_MODE (x);
HOST_WIDE_INT offset = 0;
switch (TREE_CODE (decl))
the specified operation. */
rtx
-simplify_gen_unary (enum rtx_code code, enum machine_mode mode, rtx op,
- enum machine_mode op_mode)
+simplify_gen_unary (enum rtx_code code, machine_mode mode, rtx op,
+ machine_mode op_mode)
{
rtx tem;
/* Likewise for ternary operations. */
rtx
-simplify_gen_ternary (enum rtx_code code, enum machine_mode mode,
- enum machine_mode op0_mode, rtx op0, rtx op1, rtx op2)
+simplify_gen_ternary (enum rtx_code code, machine_mode mode,
+ machine_mode op0_mode, rtx op0, rtx op1, rtx op2)
{
rtx tem;
CMP_MODE specifies mode comparison is done in. */
rtx
-simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
- enum machine_mode cmp_mode, rtx op0, rtx op1)
+simplify_gen_relational (enum rtx_code code, machine_mode mode,
+ machine_mode cmp_mode, rtx op0, rtx op1)
{
rtx tem;
rtx (*fn) (rtx, const_rtx, void *), void *data)
{
enum rtx_code code = GET_CODE (x);
- enum machine_mode mode = GET_MODE (x);
- enum machine_mode op_mode;
+ machine_mode mode = GET_MODE (x);
+ machine_mode op_mode;
const char *fmt;
rtx op0, op1, op2, newx, op;
rtvec vec, newvec;
op0 = simplify_replace_fn_rtx (XEXP (x, 0), old_rtx, fn, data);
op1 = simplify_replace_fn_rtx (XEXP (x, 1), old_rtx, fn, data);
- /* (lo_sum (high x) x) -> x */
- if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1))
- return op1;
+ /* (lo_sum (high x) y) -> y where x and y have the same base. */
+ if (GET_CODE (op0) == HIGH)
+ {
+ rtx base0, base1, offset0, offset1;
+ split_const (XEXP (op0, 0), &base0, &offset0);
+ split_const (op1, &base1, &offset1);
+ if (rtx_equal_p (base0, base1))
+ return op1;
+ }
if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
return x;
assume that truncating it too is a no-op. */
static rtx
-simplify_truncation (enum machine_mode mode, rtx op,
- enum machine_mode op_mode)
+simplify_truncation (machine_mode mode, rtx op,
+ machine_mode op_mode)
{
unsigned int precision = GET_MODE_UNIT_PRECISION (mode);
unsigned int op_precision = GET_MODE_UNIT_PRECISION (op_mode);
truncation without the extension. Finally, if the outermode
is larger than the origmode, we can just extend to the appropriate
mode. */
- enum machine_mode origmode = GET_MODE (XEXP (op, 0));
+ machine_mode origmode = GET_MODE (XEXP (op, 0));
if (mode == origmode)
return XEXP (op, 0);
else if (precision <= GET_MODE_UNIT_PRECISION (origmode))
MODE with input operand OP whose mode was originally OP_MODE.
Return zero if no simplification can be made. */
rtx
-simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
- rtx op, enum machine_mode op_mode)
+simplify_unary_operation (enum rtx_code code, machine_mode mode,
+ rtx op, machine_mode op_mode)
{
rtx trueop, tem;
/* Perform some simplifications we can do even if the operands
aren't constant. */
static rtx
-simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
+simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
{
enum rtx_code reversed;
rtx temp;
so we can perform the above simplification. */
if (STORE_FLAG_VALUE == -1
&& GET_CODE (op) == ASHIFTRT
- && GET_CODE (XEXP (op, 1))
+ && CONST_INT_P (XEXP (op, 1))
&& INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
return simplify_gen_relational (GE, mode, VOIDmode,
XEXP (op, 0), const0_rtx);
&& GET_CODE (SUBREG_REG (op)) == ASHIFT
&& XEXP (SUBREG_REG (op), 0) == const1_rtx)
{
- enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op));
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (op));
rtx x;
x = gen_rtx_ROTATE (inner_mode,
if (GET_CODE (op) == IOR || GET_CODE (op) == AND)
{
rtx in1 = XEXP (op, 0), in2 = XEXP (op, 1);
- enum machine_mode op_mode;
+ machine_mode op_mode;
op_mode = GET_MODE (in1);
in1 = simplify_gen_unary (NOT, op_mode, in1, op_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;
- }
+ std::swap (in1, in2);
return gen_rtx_fmt_ee (GET_CODE (op) == IOR ? AND : IOR,
mode, in1, in2);
&& XEXP (op, 1) == const0_rtx
&& SCALAR_INT_MODE_P (GET_MODE (XEXP (op, 0))))
{
- enum machine_mode inner = GET_MODE (XEXP (op, 0));
+ machine_mode inner = GET_MODE (XEXP (op, 0));
int isize = GET_MODE_PRECISION (inner);
if (STORE_FLAG_VALUE == 1)
{
= (float_truncate:SF foo:DF).
(float_truncate:DF (float_extend:XF foo:SF))
- = (float_extend:SF foo:DF). */
+ = (float_extend:DF foo:SF). */
if ((GET_CODE (op) == FLOAT_TRUNCATE
&& flag_unsafe_math_optimizations)
|| GET_CODE (op) == FLOAT_EXTEND)
XEXP (op, 0), mode);
/* (float_truncate (float x)) is (float x) */
- if (GET_CODE (op) == FLOAT
+ if ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT)
&& (flag_unsafe_math_optimizations
|| (SCALAR_FLOAT_MODE_P (GET_MODE (op))
&& ((unsigned)significand_size (GET_MODE (op))
>= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
- num_sign_bit_copies (XEXP (op, 0),
GET_MODE (XEXP (op, 0))))))))
- return simplify_gen_unary (FLOAT, mode,
+ return simplify_gen_unary (GET_CODE (op), mode,
XEXP (op, 0),
GET_MODE (XEXP (op, 0)));
rounding can't happen.
*/
if (GET_CODE (op) == FLOAT_EXTEND
- || (GET_CODE (op) == FLOAT
+ || ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT)
&& SCALAR_FLOAT_MODE_P (GET_MODE (op))
&& ((unsigned)significand_size (GET_MODE (op))
>= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
&& (rcode == SIGN_EXTEND
|| (rcode == ASHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
{
- enum machine_mode lmode = GET_MODE (lhs);
- enum machine_mode rmode = GET_MODE (rhs);
+ machine_mode lmode = GET_MODE (lhs);
+ machine_mode rmode = GET_MODE (rhs);
int bits;
if (lcode == ASHIFTRT)
target mode is the same as the variable's promotion. */
if (GET_CODE (op) == SUBREG
&& SUBREG_PROMOTED_VAR_P (op)
- && ! SUBREG_PROMOTED_UNSIGNED_P (op)
+ && SUBREG_PROMOTED_SIGNED_P (op)
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
{
temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
(sign_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>). */
if (GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND)
{
- gcc_assert (GET_MODE_BITSIZE (mode)
- > GET_MODE_BITSIZE (GET_MODE (op)));
+ gcc_assert (GET_MODE_PRECISION (mode)
+ > GET_MODE_PRECISION (GET_MODE (op)));
return simplify_gen_unary (GET_CODE (op), mode, XEXP (op, 0),
GET_MODE (XEXP (op, 0)));
}
&& XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
&& GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
{
- enum machine_mode tmode
+ machine_mode tmode
= mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
- INTVAL (XEXP (op, 1)), MODE_INT, 1);
gcc_assert (GET_MODE_BITSIZE (mode)
target mode is the same as the variable's promotion. */
if (GET_CODE (op) == SUBREG
&& SUBREG_PROMOTED_VAR_P (op)
- && SUBREG_PROMOTED_UNSIGNED_P (op) > 0
+ && SUBREG_PROMOTED_UNSIGNED_P (op)
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
{
temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
&& (rcode == ZERO_EXTEND
|| (rcode == LSHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
{
- enum machine_mode lmode = GET_MODE (lhs);
- enum machine_mode rmode = GET_MODE (rhs);
+ machine_mode lmode = GET_MODE (lhs);
+ machine_mode rmode = GET_MODE (rhs);
int bits;
if (lcode == LSHIFTRT)
/* (zero_extend:M (lshiftrt:N (ashift <X> (const_int I)) (const_int I)))
is (zero_extend:M (subreg:O <X>)) if there is mode with
- GET_MODE_BITSIZE (N) - I bits. */
+ GET_MODE_PRECISION (N) - I bits. */
if (GET_CODE (op) == LSHIFTRT
&& GET_CODE (XEXP (op, 0)) == ASHIFT
&& CONST_INT_P (XEXP (op, 1))
&& XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
- && GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
+ && GET_MODE_PRECISION (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
{
- enum machine_mode tmode
- = mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
+ machine_mode tmode
+ = mode_for_size (GET_MODE_PRECISION (GET_MODE (op))
- INTVAL (XEXP (op, 1)), MODE_INT, 1);
if (tmode != BLKmode)
{
be MODE with input operand OP whose mode was originally OP_MODE.
Return zero if the value cannot be computed. */
rtx
-simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
- rtx op, enum machine_mode op_mode)
+simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
+ rtx op, machine_mode op_mode)
{
unsigned int width = GET_MODE_PRECISION (mode);
RTVEC_ELT (v, i) = op;
else
{
- enum machine_mode inmode = GET_MODE (op);
+ machine_mode inmode = GET_MODE (op);
int in_elt_size = GET_MODE_SIZE (GET_MODE_INNER (inmode));
unsigned in_n_elts = (GET_MODE_SIZE (inmode) / in_elt_size);
{
int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
- enum machine_mode opmode = GET_MODE (op);
+ machine_mode opmode = GET_MODE (op);
int op_elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode));
unsigned op_n_elts = (GET_MODE_SIZE (opmode) / op_elt_size);
rtvec v = rtvec_alloc (n_elts);
if (CONST_SCALAR_INT_P (op) && width > 0)
{
wide_int result;
- enum machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
+ machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
rtx_mode_t op0 = std::make_pair (op, imode);
int int_value;
Return zero if no simplification or canonicalization is possible. */
static rtx
-simplify_byte_swapping_operation (enum rtx_code code, enum machine_mode mode,
+simplify_byte_swapping_operation (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1)
{
rtx tem;
canonicalization is possible. */
static rtx
-simplify_associative_operation (enum rtx_code code, enum machine_mode mode,
+simplify_associative_operation (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1)
{
rtx tem;
if (! swap_commutative_operands_p (op1, op0))
return simplify_gen_binary (code, mode, op1, op0);
- tem = op0;
- op0 = op1;
- op1 = tem;
+ std::swap (op0, op1);
}
if (GET_CODE (op0) == code)
Don't use this for relational operations such as EQ or LT.
Use simplify_relational_operation instead. */
rtx
-simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
+simplify_binary_operation (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1)
{
rtx trueop0, trueop1;
/* Make sure the constant is second. */
if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
&& swap_commutative_operands_p (op0, op1))
- {
- tem = op0, op0 = op1, op1 = tem;
- }
+ std::swap (op0, op1);
trueop0 = avoid_constant_pool_reference (op0);
trueop1 = avoid_constant_pool_reference (op1);
actual constants. */
static rtx
-simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
+simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1, rtx trueop0, rtx trueop1)
{
rtx tem, reversed, opleft, opright;
rtx xop00 = XEXP (op0, 0);
rtx xop10 = XEXP (op1, 0);
-#ifdef HAVE_cc0
if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0)
-#else
+ return xop00;
+
if (REG_P (xop00) && REG_P (xop10)
&& GET_MODE (xop00) == GET_MODE (xop10)
&& REGNO (xop00) == REGNO (xop10)
&& GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC
&& GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC)
-#endif
return xop00;
}
break;
XEXP (op0, 1), mode),
op1);
+ /* Given (xor (ior (xor A B) C) D), where B, C and D are
+ constants, simplify to (xor (ior A C) (B&~C)^D), canceling
+ out bits inverted twice and not set by C. Similarly, given
+ (xor (and (xor A B) C) D), simplify without inverting C in
+ the xor operand: (xor (and A C) (B&C)^D).
+ */
+ else if ((GET_CODE (op0) == IOR || GET_CODE (op0) == AND)
+ && GET_CODE (XEXP (op0, 0)) == XOR
+ && CONST_INT_P (op1)
+ && CONST_INT_P (XEXP (op0, 1))
+ && CONST_INT_P (XEXP (XEXP (op0, 0), 1)))
+ {
+ enum rtx_code op = GET_CODE (op0);
+ rtx a = XEXP (XEXP (op0, 0), 0);
+ rtx b = XEXP (XEXP (op0, 0), 1);
+ rtx c = XEXP (op0, 1);
+ rtx d = op1;
+ HOST_WIDE_INT bval = INTVAL (b);
+ HOST_WIDE_INT cval = INTVAL (c);
+ HOST_WIDE_INT dval = INTVAL (d);
+ HOST_WIDE_INT xcval;
+
+ if (op == IOR)
+ xcval = ~cval;
+ else
+ xcval = cval;
+
+ return simplify_gen_binary (XOR, mode,
+ simplify_gen_binary (op, mode, a, c),
+ gen_int_mode ((bval & xcval) ^ dval,
+ mode));
+ }
+
/* Given (xor (and A B) C), using P^Q == (~P&Q) | (~Q&P),
we can transform like this:
(A&B)^C == ~(A&B)&C | ~C&(A&B)
HOST_WIDE_INT bval = INTVAL (b);
HOST_WIDE_INT cval = INTVAL (c);
- rtx na_c
- = simplify_binary_operation (AND, mode,
- simplify_gen_unary (NOT, mode, a, mode),
- c);
+ /* Instead of computing ~A&C, we compute its negated value,
+ ~(A|~C). If it yields -1, ~A&C is zero, so we can
+ optimize for sure. If it does not simplify, we still try
+ to compute ~A&C below, but since that always allocates
+ RTL, we don't try that before committing to returning a
+ simplified expression. */
+ rtx n_na_c = simplify_binary_operation (IOR, mode, a,
+ GEN_INT (~cval));
+
if ((~cval & bval) == 0)
{
+ rtx na_c = NULL_RTX;
+ if (n_na_c)
+ na_c = simplify_gen_unary (NOT, mode, n_na_c, mode);
+ else
+ {
+ /* If ~A does not simplify, don't bother: we don't
+ want to simplify 2 operations into 3, and if na_c
+ were to simplify with na, n_na_c would have
+ simplified as well. */
+ rtx na = simplify_unary_operation (NOT, mode, a, mode);
+ if (na)
+ na_c = simplify_gen_binary (AND, mode, na, c);
+ }
+
/* Try to simplify ~A&C | ~B&C. */
if (na_c != NULL_RTX)
return simplify_gen_binary (IOR, mode, na_c,
else
{
/* If ~A&C is zero, simplify A&(~C&B) | ~B&C. */
- if (na_c == const0_rtx)
+ if (n_na_c == CONSTM1_RTX (mode))
{
rtx a_nc_b = simplify_gen_binary (AND, mode, a,
gen_int_mode (~cval & bval,
&& (~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))
& UINTVAL (trueop1)) == 0)
{
- enum machine_mode imode = GET_MODE (XEXP (op0, 0));
+ machine_mode imode = GET_MODE (XEXP (op0, 0));
tem = simplify_gen_binary (AND, imode, XEXP (op0, 0),
gen_int_mode (INTVAL (trueop1),
imode));
if (GET_CODE (op0) == TRUNCATE && CONST_INT_P (trueop1))
{
rtx x = XEXP (op0, 0);
- enum machine_mode xmode = GET_MODE (x);
+ machine_mode xmode = GET_MODE (x);
tem = simplify_gen_binary (AND, xmode, x,
gen_int_mode (INTVAL (trueop1), xmode));
return simplify_gen_unary (TRUNCATE, mode, tem, xmode);
/* (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))
+ && rtx_equal_p (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))
+ && rtx_equal_p (op1, XEXP (XEXP (op0, 0), 0)))
return simplify_gen_binary (AND, mode, op1, XEXP (op0, 1));
+ /* (and X (ior Y (not X)) -> (and X Y) */
+ if (GET_CODE (op1) == IOR
+ && GET_CODE (XEXP (op1, 1)) == NOT
+ && rtx_equal_p (op0, XEXP (XEXP (op1, 1), 0)))
+ return simplify_gen_binary (AND, mode, op0, XEXP (op1, 0));
+
+ /* (and (ior Y (not X)) X) -> (and X Y) */
+ if (GET_CODE (op0) == IOR
+ && GET_CODE (XEXP (op0, 1)) == NOT
+ && rtx_equal_p (op1, XEXP (XEXP (op0, 1), 0)))
+ return simplify_gen_binary (AND, mode, op1, XEXP (op0, 0));
+
tem = simplify_byte_swapping_operation (code, mode, op0, op1);
if (tem)
return tem;
prefer left rotation, if op1 is from bitsize / 2 + 1 to
bitsize - 1, use other direction of rotate with 1 .. bitsize / 2 - 1
amount instead. */
+#if defined(HAVE_rotate) && defined(HAVE_rotatert)
if (CONST_INT_P (trueop1)
&& IN_RANGE (INTVAL (trueop1),
- GET_MODE_BITSIZE (mode) / 2 + (code == ROTATE),
- GET_MODE_BITSIZE (mode) - 1))
+ GET_MODE_PRECISION (mode) / 2 + (code == ROTATE),
+ GET_MODE_PRECISION (mode) - 1))
return simplify_gen_binary (code == ROTATE ? ROTATERT : ROTATE,
- mode, op0, GEN_INT (GET_MODE_BITSIZE (mode)
+ mode, op0, GEN_INT (GET_MODE_PRECISION (mode)
- INTVAL (trueop1)));
+#endif
/* FALLTHRU */
case ASHIFTRT:
if (trueop1 == CONST0_RTX (mode))
&& UINTVAL (trueop0) == GET_MODE_MASK (mode)
&& ! side_effects_p (op1))
return op0;
+ /* Given:
+ scalar modes M1, M2
+ scalar constants c1, c2
+ size (M2) > size (M1)
+ c1 == size (M2) - size (M1)
+ optimize:
+ (ashiftrt:M1 (subreg:M1 (lshiftrt:M2 (reg:M2) (const_int <c1>))
+ <low_part>)
+ (const_int <c2>))
+ to:
+ (subreg:M1 (ashiftrt:M2 (reg:M2) (const_int <c1 + c2>))
+ <low_part>). */
+ if (code == ASHIFTRT
+ && !VECTOR_MODE_P (mode)
+ && SUBREG_P (op0)
+ && CONST_INT_P (op1)
+ && GET_CODE (SUBREG_REG (op0)) == LSHIFTRT
+ && !VECTOR_MODE_P (GET_MODE (SUBREG_REG (op0)))
+ && CONST_INT_P (XEXP (SUBREG_REG (op0), 1))
+ && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+ > GET_MODE_BITSIZE (mode))
+ && (INTVAL (XEXP (SUBREG_REG (op0), 1))
+ == (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+ - GET_MODE_BITSIZE (mode)))
+ && subreg_lowpart_p (op0))
+ {
+ rtx tmp = GEN_INT (INTVAL (XEXP (SUBREG_REG (op0), 1))
+ + INTVAL (op1));
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+ tmp = simplify_gen_binary (ASHIFTRT,
+ GET_MODE (SUBREG_REG (op0)),
+ XEXP (SUBREG_REG (op0), 0),
+ tmp);
+ return simplify_gen_subreg (mode, tmp, inner_mode,
+ subreg_lowpart_offset (mode,
+ inner_mode));
+ }
canonicalize_shift:
if (SHIFT_COUNT_TRUNCATED && CONST_INT_P (op1))
{
- val = INTVAL (op1) & (GET_MODE_BITSIZE (mode) - 1);
+ val = INTVAL (op1) & (GET_MODE_PRECISION (mode) - 1);
if (val != INTVAL (op1))
return simplify_gen_binary (code, mode, op0, GEN_INT (val));
}
&& STORE_FLAG_VALUE == 1
&& INTVAL (trueop1) < (HOST_WIDE_INT)width)
{
- enum machine_mode imode = GET_MODE (XEXP (op0, 0));
+ machine_mode imode = GET_MODE (XEXP (op0, 0));
unsigned HOST_WIDE_INT zero_val = 0;
if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val)
rtx op0 = XEXP (trueop0, 0);
rtx op1 = XEXP (trueop0, 1);
- enum machine_mode opmode = GET_MODE (op0);
+ 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;
rtx op00 = XEXP (op0, 0);
rtx op01 = XEXP (op0, 1);
- enum machine_mode mode00, mode01;
+ machine_mode mode00, mode01;
int n_elts00, n_elts01;
mode00 = GET_MODE (op00);
return simplify_gen_binary (VEC_CONCAT, mode, subop0, subop1);
}
+
+ /* If we select one half of a vec_concat, return that. */
+ if (GET_CODE (trueop0) == VEC_CONCAT
+ && CONST_INT_P (XVECEXP (trueop1, 0, 0)))
+ {
+ rtx subop0 = XEXP (trueop0, 0);
+ rtx subop1 = XEXP (trueop0, 1);
+ machine_mode mode0 = GET_MODE (subop0);
+ machine_mode mode1 = GET_MODE (subop1);
+ int li = GET_MODE_SIZE (GET_MODE_INNER (mode0));
+ int l0 = GET_MODE_SIZE (mode0) / li;
+ int l1 = GET_MODE_SIZE (mode1) / li;
+ int i0 = INTVAL (XVECEXP (trueop1, 0, 0));
+ if (i0 == 0 && !side_effects_p (op1) && mode == mode0)
+ {
+ bool success = true;
+ for (int i = 1; i < l0; ++i)
+ {
+ rtx j = XVECEXP (trueop1, 0, i);
+ if (!CONST_INT_P (j) || INTVAL (j) != i)
+ {
+ success = false;
+ break;
+ }
+ }
+ if (success)
+ return subop0;
+ }
+ if (i0 == l0 && !side_effects_p (op0) && mode == mode1)
+ {
+ bool success = true;
+ for (int i = 1; i < l1; ++i)
+ {
+ rtx j = XVECEXP (trueop1, 0, i);
+ if (!CONST_INT_P (j) || INTVAL (j) != i0 + i)
+ {
+ success = false;
+ break;
+ }
+ }
+ if (success)
+ return subop1;
+ }
+ }
}
if (XVECLEN (trueop1, 0) == 1
while (GET_MODE (vec) != mode
&& GET_CODE (vec) == VEC_CONCAT)
{
- HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
+ HOST_WIDE_INT vec_size;
+
+ if (CONST_INT_P (XEXP (vec, 0)))
+ {
+ /* vec_concat of two const_ints doesn't make sense with
+ respect to modes. */
+ if (CONST_INT_P (XEXP (vec, 1)))
+ return 0;
+
+ vec_size = GET_MODE_SIZE (GET_MODE (trueop0))
+ - GET_MODE_SIZE (GET_MODE (XEXP (vec, 1)));
+ }
+ else
+ vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
+
if (offset < vec_size)
vec = XEXP (vec, 0);
else
}
}
+ /* If we have two nested selects that are inverses of each
+ other, replace them with the source operand. */
+ if (GET_CODE (trueop0) == VEC_SELECT
+ && GET_MODE (XEXP (trueop0, 0)) == mode)
+ {
+ rtx op0_subop1 = XEXP (trueop0, 1);
+ gcc_assert (GET_CODE (op0_subop1) == PARALLEL);
+ gcc_assert (XVECLEN (trueop1, 0) == GET_MODE_NUNITS (mode));
+
+ /* Apply the outer ordering vector to the inner one. (The inner
+ ordering vector is expressly permitted to be of a different
+ length than the outer one.) If the result is { 0, 1, ..., n-1 }
+ then the two VEC_SELECTs cancel. */
+ for (int i = 0; i < XVECLEN (trueop1, 0); ++i)
+ {
+ rtx x = XVECEXP (trueop1, 0, i);
+ if (!CONST_INT_P (x))
+ return 0;
+ rtx y = XVECEXP (op0_subop1, 0, INTVAL (x));
+ if (!CONST_INT_P (y) || i != INTVAL (y))
+ return 0;
+ }
+ return XEXP (trueop0, 0);
+ }
+
return 0;
case VEC_CONCAT:
{
- enum machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
+ machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
? GET_MODE (trueop0)
: GET_MODE_INNER (mode));
- enum machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
+ machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
? GET_MODE (trueop1)
: GET_MODE_INNER (mode));
}
rtx
-simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
+simplify_const_binary_operation (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1)
{
unsigned int width = GET_MODE_PRECISION (mode);
&& GET_CODE (op1) == CONST_VECTOR)
{
unsigned n_elts = GET_MODE_NUNITS (mode);
- enum machine_mode op0mode = GET_MODE (op0);
+ machine_mode op0mode = GET_MODE (op0);
unsigned op0_n_elts = GET_MODE_NUNITS (op0mode);
- enum machine_mode op1mode = GET_MODE (op1);
+ machine_mode op1mode = GET_MODE (op1);
unsigned op1_n_elts = GET_MODE_NUNITS (op1mode);
rtvec v = rtvec_alloc (n_elts);
unsigned int i;
}
/* We can fold some multi-word operations. */
- if (GET_MODE_CLASS (mode) == MODE_INT
+ if ((GET_MODE_CLASS (mode) == MODE_INT
+ || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
&& CONST_SCALAR_INT_P (op0)
&& CONST_SCALAR_INT_P (op1))
{
\f
-/* 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. */
-
-struct simplify_plus_minus_op_data
-{
- rtx op;
- short neg;
-};
+/* Return a positive integer if X should sort after Y. The value
+ returned is 1 if and only if X and Y are both regs. */
-static bool
+static int
simplify_plus_minus_op_data_cmp (rtx x, rtx y)
{
int result;
result = (commutative_operand_precedence (y)
- commutative_operand_precedence (x));
if (result)
- return result > 0;
+ return result + result;
/* Group together equal REGs to do more simplification. */
if (REG_P (x) && REG_P (y))
return REGNO (x) > REGNO (y);
- else
- return false;
+
+ return 0;
}
+/* Simplify and canonicalize 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.
+
+ May return NULL_RTX when no changes were made. */
+
static rtx
-simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
+simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
rtx op1)
{
- struct simplify_plus_minus_op_data ops[8];
+ struct simplify_plus_minus_op_data
+ {
+ rtx op;
+ short neg;
+ } ops[16];
rtx result, tem;
- int n_ops = 2, input_ops = 2;
- int changed, n_constants = 0, canonicalized = 0;
+ int n_ops = 2;
+ int changed, n_constants, canonicalized = 0;
int i, j;
memset (ops, 0, sizeof ops);
do
{
changed = 0;
+ n_constants = 0;
for (i = 0; i < n_ops; i++)
{
{
case PLUS:
case MINUS:
- if (n_ops == 7)
+ if (n_ops == ARRAY_SIZE (ops))
return NULL_RTX;
ops[n_ops].op = XEXP (this_op, 1);
n_ops++;
ops[i].op = XEXP (this_op, 0);
- input_ops++;
changed = 1;
- canonicalized |= this_neg;
+ /* If this operand was negated then we will potentially
+ canonicalize the expression. Similarly if we don't
+ place the operands adjacent we're re-ordering the
+ expression and thus might be performing a
+ canonicalization. Ignore register re-ordering.
+ ??? It might be better to shuffle the ops array here,
+ but then (plus (plus (A, B), plus (C, D))) wouldn't
+ be seen as non-canonical. */
+ if (this_neg
+ || (i != n_ops - 2
+ && !(REG_P (ops[i].op) && REG_P (ops[n_ops - 1].op))))
+ canonicalized = 1;
break;
case NEG:
break;
case CONST:
- if (n_ops < 7
+ if (n_ops != ARRAY_SIZE (ops)
&& GET_CODE (XEXP (this_op, 0)) == PLUS
&& CONSTANT_P (XEXP (XEXP (this_op, 0), 0))
&& CONSTANT_P (XEXP (XEXP (this_op, 0), 1)))
ops[n_ops].neg = this_neg;
n_ops++;
changed = 1;
- canonicalized = 1;
+ canonicalized = 1;
}
break;
case NOT:
/* ~a -> (-a - 1) */
- if (n_ops != 7)
+ if (n_ops != ARRAY_SIZE (ops))
{
ops[n_ops].op = CONSTM1_RTX (mode);
ops[n_ops++].neg = this_neg;
ops[i].op = XEXP (this_op, 0);
ops[i].neg = !this_neg;
changed = 1;
- canonicalized = 1;
+ canonicalized = 1;
}
break;
ops[i].op = neg_const_int (mode, this_op);
ops[i].neg = 0;
changed = 1;
- canonicalized = 1;
+ canonicalized = 1;
}
break;
}
/* Now simplify each pair of operands until nothing changes. */
- do
+ while (1)
{
- /* Insertion sort is good enough for an eight-element array. */
+ /* Insertion sort is good enough for a small 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))
+ {
+ struct simplify_plus_minus_op_data save;
+ int cmp;
+
+ j = i - 1;
+ cmp = simplify_plus_minus_op_data_cmp (ops[j].op, ops[i].op);
+ if (cmp <= 0)
continue;
+ /* Just swapping registers doesn't count as canonicalization. */
+ if (cmp != 1)
+ canonicalized = 1;
- canonicalized = 1;
- save = ops[i];
- do
+ 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;
- }
+ while (j--
+ && simplify_plus_minus_op_data_cmp (ops[j].op, save.op) > 0);
+ ops[j + 1] = save;
+ }
changed = 0;
for (i = n_ops - 1; i > 0; i--)
{
ncode = MINUS;
if (lneg)
- tem = lhs, lhs = rhs, rhs = tem;
+ std::swap (lhs, rhs);
}
else if (swap_commutative_operands_p (lhs, rhs))
- tem = lhs, lhs = rhs, rhs = tem;
+ std::swap (lhs, rhs);
if ((GET_CODE (lhs) == CONST || CONST_INT_P (lhs))
&& (GET_CODE (rhs) == CONST || CONST_INT_P (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);
+ 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
- when it calls us to simplify CONST operations. */
- if (tem
- && ! (GET_CODE (tem) == CONST
- && GET_CODE (XEXP (tem, 0)) == ncode
- && XEXP (XEXP (tem, 0), 0) == lhs
- && XEXP (XEXP (tem, 0), 1) == rhs))
+ if (tem)
{
+ /* Reject "simplifications" that just wrap the two
+ arguments in a CONST. Failure to do so can result
+ in infinite recursion with simplify_binary_operation
+ when it calls us to simplify CONST operations.
+ Also, if we find such a simplification, don't try
+ any more combinations with this rhs: We must have
+ something like symbol+offset, ie. one of the
+ trivial CONST expressions we handle later. */
+ if (GET_CODE (tem) == CONST
+ && GET_CODE (XEXP (tem, 0)) == ncode
+ && XEXP (XEXP (tem, 0), 0) == lhs
+ && XEXP (XEXP (tem, 0), 1) == rhs)
+ break;
lneg &= rneg;
if (GET_CODE (tem) == NEG)
tem = XEXP (tem, 0), lneg = !lneg;
}
}
- /* If nothing changed, fail. */
- if (!canonicalized)
- return NULL_RTX;
+ if (!changed)
+ break;
/* Pack all the operands to the lower-numbered entries. */
for (i = 0, j = 0; j < n_ops; j++)
- if (ops[j].op)
- {
+ if (ops[j].op)
+ {
ops[i] = ops[j];
i++;
- }
+ }
n_ops = i;
}
- while (changed);
+
+ /* If nothing changed, fail. */
+ if (!canonicalized)
+ return NULL_RTX;
/* Create (minus -C X) instead of (neg (const (plus X C))). */
if (n_ops == 2
the operands or, if both are VOIDmode, the operands are compared in
"infinite precision". */
rtx
-simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
- enum machine_mode cmp_mode, rtx op0, rtx op1)
+simplify_relational_operation (enum rtx_code code, machine_mode mode,
+ machine_mode cmp_mode, rtx op0, rtx op1)
{
rtx tem, trueop0, trueop1;
/* For the following tests, ensure const0_rtx is op1. */
if (swap_commutative_operands_p (op0, op1)
|| (op0 == const0_rtx && op1 != const0_rtx))
- tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
+ std::swap (op0, op1), code = swap_condition (code);
/* If op0 is a compare, extract the comparison arguments from it. */
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
mode the comparison is done in, so it is the mode of the operands. */
static rtx
-simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
- enum machine_mode cmp_mode, rtx op0, rtx op1)
+simplify_relational_operation_1 (enum rtx_code code, machine_mode mode,
+ machine_mode cmp_mode, rtx op0, rtx op1)
{
enum rtx_code op0code = GET_CODE (op0);
&& 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);
+ return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 1),
+ CONST0_RTX (mode));
/* 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);
+ return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
+ CONST0_RTX (mode));
/* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)). */
if ((code == EQ || code == NE)
simplify_gen_binary (XOR, cmp_mode,
XEXP (op0, 1), op1));
+ /* (eq/ne (and x y) x) simplifies to (eq/ne (and (not y) x) 0), which
+ can be implemented with a BICS instruction on some targets, or
+ constant-folded if y is a constant. */
+ if ((code == EQ || code == NE)
+ && op0code == AND
+ && rtx_equal_p (XEXP (op0, 0), op1)
+ && !side_effects_p (op1)
+ && op1 != CONST0_RTX (cmp_mode))
+ {
+ rtx not_y = simplify_gen_unary (NOT, cmp_mode, XEXP (op0, 1), cmp_mode);
+ rtx lhs = simplify_gen_binary (AND, cmp_mode, not_y, XEXP (op0, 0));
+
+ return simplify_gen_relational (code, mode, cmp_mode, lhs,
+ CONST0_RTX (cmp_mode));
+ }
+
+ /* Likewise for (eq/ne (and x y) y). */
+ if ((code == EQ || code == NE)
+ && op0code == AND
+ && rtx_equal_p (XEXP (op0, 1), op1)
+ && !side_effects_p (op1)
+ && op1 != CONST0_RTX (cmp_mode))
+ {
+ rtx not_x = simplify_gen_unary (NOT, cmp_mode, XEXP (op0, 0), cmp_mode);
+ rtx lhs = simplify_gen_binary (AND, cmp_mode, not_x, XEXP (op0, 1));
+
+ return simplify_gen_relational (code, mode, cmp_mode, lhs,
+ CONST0_RTX (cmp_mode));
+ }
+
/* (eq/ne (bswap x) C1) simplifies to (eq/ne x C2) with C2 swapped. */
if ((code == EQ || code == NE)
&& GET_CODE (op0) == BSWAP
rtx
simplify_const_relational_operation (enum rtx_code code,
- enum machine_mode mode,
+ machine_mode mode,
rtx op0, rtx op1)
{
rtx tem;
/* Make sure the constant is second. */
if (swap_commutative_operands_p (op0, op1))
{
- tem = op0, op0 = op1, op1 = tem;
+ std::swap (op0, op1);
code = swap_condition (code);
}
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))
+ if ((! HONOR_NANS (trueop0)
|| code == UNEQ || code == UNLE || code == UNGE
|| ((code == LT || code == GT || code == LTGT)
- && ! HONOR_SNANS (GET_MODE (trueop0))))
+ && ! HONOR_SNANS (trueop0)))
&& rtx_equal_p (trueop0, trueop1)
&& ! side_effects_p (trueop0))
return comparison_result (code, CMP_EQ);
/* It would be nice if we really had a mode here. However, the
largest int representable on the target is as good as
infinite. */
- enum machine_mode cmode = (mode == VOIDmode) ? MAX_MODE_INT : mode;
+ machine_mode cmode = (mode == VOIDmode) ? MAX_MODE_INT : mode;
rtx_mode_t ptrueop0 = std::make_pair (trueop0, cmode);
rtx_mode_t ptrueop1 = std::make_pair (trueop1, cmode);
a constant. Return 0 if no simplifications is possible. */
rtx
-simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
- enum machine_mode op0_mode, rtx op0, rtx op1,
+simplify_ternary_operation (enum rtx_code code, machine_mode mode,
+ machine_mode op0_mode, rtx op0, rtx op1,
rtx op2)
{
unsigned int width = GET_MODE_PRECISION (mode);
/* Canonicalize the two multiplication operands. */
/* a * -b + c => -b * a + c. */
if (swap_commutative_operands_p (op0, op1))
- tem = op0, op0 = op1, op1 = tem, any_change = true;
+ std::swap (op0, op1), any_change = true;
if (any_change)
return gen_rtx_FMA (mode, op0, op1, op2);
if (COMPARISON_P (op0) && ! side_effects_p (op0))
{
- enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
+ machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
? GET_MODE (XEXP (op0, 1))
: GET_MODE (XEXP (op0, 0)));
rtx temp;
op0, XEXP (op1, 0), op2);
}
}
+
+ /* Replace (vec_merge (vec_duplicate (vec_select a parallel (i))) a 1 << i)
+ with a. */
+ if (GET_CODE (op0) == VEC_DUPLICATE
+ && GET_CODE (XEXP (op0, 0)) == VEC_SELECT
+ && GET_CODE (XEXP (XEXP (op0, 0), 1)) == PARALLEL
+ && mode_nunits[GET_MODE (XEXP (op0, 0))] == 1)
+ {
+ tem = XVECEXP ((XEXP (XEXP (op0, 0), 1)), 0, 0);
+ if (CONST_INT_P (tem) && CONST_INT_P (op2))
+ {
+ if (XEXP (XEXP (op0, 0), 0) == op1
+ && UINTVAL (op2) == HOST_WIDE_INT_1U << UINTVAL (tem))
+ return op1;
+ }
+ }
}
if (rtx_equal_p (op0, op1)
and then repacking them again for OUTERMODE. */
static rtx
-simplify_immed_subreg (enum machine_mode outermode, rtx op,
- enum machine_mode innermode, unsigned int byte)
+simplify_immed_subreg (machine_mode outermode, rtx op,
+ machine_mode innermode, unsigned int byte)
{
enum {
value_bit = 8,
rtx result_s;
rtvec result_v = NULL;
enum mode_class outer_class;
- enum machine_mode outer_submode;
+ machine_mode outer_submode;
int max_bitsize;
/* Some ports misuse CCmode. */
HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
wide_int r;
+ if (GET_MODE_PRECISION (outer_submode) > MAX_BITSIZE_MODE_ANY_INT)
+ return NULL_RTX;
for (u = 0; u < units; u++)
{
unsigned HOST_WIDE_INT buf = 0;
tmp[u] = buf;
base += HOST_BITS_PER_WIDE_INT;
}
- gcc_assert (GET_MODE_PRECISION (outer_submode)
- <= MAX_BITSIZE_MODE_ANY_INT);
r = wide_int::from_array (tmp, units,
GET_MODE_PRECISION (outer_submode));
+#if TARGET_SUPPORTS_WIDE_INT == 0
+ /* Make sure r will fit into CONST_INT or CONST_DOUBLE. */
+ if (wi::min_precision (r, SIGNED) > HOST_BITS_PER_DOUBLE_INT)
+ return NULL_RTX;
+#endif
elems[elem] = immed_wide_int_const (r, outer_submode);
}
break;
/* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE)
Return 0 if no simplifications are possible. */
rtx
-simplify_subreg (enum machine_mode outermode, rtx op,
- enum machine_mode innermode, unsigned int byte)
+simplify_subreg (machine_mode outermode, rtx op,
+ machine_mode innermode, unsigned int byte)
{
/* Little bit of sanity checking. */
gcc_assert (innermode != VOIDmode);
or not at all if changing back op starting mode. */
if (GET_CODE (op) == SUBREG)
{
- enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
+ machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
int final_offset = byte + SUBREG_BYTE (op);
rtx newx;
{
newx = gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
if (SUBREG_PROMOTED_VAR_P (op)
- && SUBREG_PROMOTED_UNSIGNED_P (op) >= 0
+ && SUBREG_PROMOTED_SIGN (op) >= 0
&& GET_MODE_CLASS (outermode) == MODE_INT
&& IN_RANGE (GET_MODE_SIZE (outermode),
GET_MODE_SIZE (innermode),
&& subreg_lowpart_p (newx))
{
SUBREG_PROMOTED_VAR_P (newx) = 1;
- SUBREG_PROMOTED_UNSIGNED_SET
- (newx, SUBREG_PROMOTED_UNSIGNED_P (op));
+ SUBREG_PROMOTED_SET (newx, SUBREG_PROMOTED_GET (op));
}
return newx;
}
/* Make a SUBREG operation or equivalent if it folds. */
rtx
-simplify_gen_subreg (enum machine_mode outermode, rtx op,
- enum machine_mode innermode, unsigned int byte)
+simplify_gen_subreg (machine_mode outermode, rtx op,
+ machine_mode innermode, unsigned int byte)
{
rtx newx;
simplify_rtx (const_rtx x)
{
const enum rtx_code code = GET_CODE (x);
- const enum machine_mode mode = GET_MODE (x);
+ const machine_mode mode = GET_MODE (x);
switch (GET_RTX_CLASS (code))
{