#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 "flags.h"
#include "insn-config.h"
#include "recog.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
-#include "input.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"
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, machine_mode, rtx, rtx);
static rtx simplify_immed_subreg (machine_mode, rtx, machine_mode,
unsigned int);
/* 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);
}
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;
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);
= (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)))
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)
/* 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);
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,
/* (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;
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
\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. */
+/* 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. */
-struct simplify_plus_minus_op_data
-{
- rtx op;
- short neg;
-};
-
-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, machine_mode mode, rtx op0,
rtx op1)
{
- struct simplify_plus_minus_op_data ops[16];
+ struct simplify_plus_minus_op_data
+ {
+ rtx op;
+ short neg;
+ } ops[16];
rtx result, tem;
int n_ops = 2;
int changed, n_constants, canonicalized = 0;
ops[i].op = XEXP (this_op, 0);
changed = 1;
- canonicalized |= this_neg || i != n_ops - 2;
+ /* 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:
ops[n_ops].neg = this_neg;
n_ops++;
changed = 1;
- canonicalized = 1;
+ canonicalized = 1;
}
break;
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 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);
}
}
- /* 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
/* 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)
if ((code == EQ || code == NE)
&& op0code == AND
&& rtx_equal_p (XEXP (op0, 0), op1)
- && !side_effects_p (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));
if ((code == EQ || code == NE)
&& op0code == AND
&& rtx_equal_p (XEXP (op0, 1), op1)
- && !side_effects_p (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));
/* 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);
}
/* 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);