return true;
}
+/* If X is an operator that can be treated as a simple move that we
+ can split, then return the operand that is operated on. */
+
+static rtx
+operand_for_swap_move_operator (rtx x)
+{
+ /* A word sized rotate of a register pair is equivalent to swapping
+ the registers in the register pair. */
+ if (GET_CODE (x) == ROTATE
+ && GET_MODE (x) == twice_word_mode
+ && simple_move_operand (XEXP (x, 0))
+ && CONST_INT_P (XEXP (x, 1))
+ && INTVAL (XEXP (x, 1)) == BITS_PER_WORD)
+ return XEXP (x, 0);
+
+ return NULL_RTX;
+}
+
/* If INSN is a single set between two objects that we want to split,
return the single set. SPEED_P says whether we are optimizing
INSN for speed or size.
static rtx
simple_move (rtx_insn *insn, bool speed_p)
{
- rtx x;
+ rtx x, op;
rtx set;
machine_mode mode;
return NULL_RTX;
x = SET_SRC (set);
+ if ((op = operand_for_swap_move_operator (x)) != NULL_RTX)
+ x = op;
+
if (x != recog_data.operand[0] && x != recog_data.operand[1])
return NULL_RTX;
/* For the src we can handle ASM_OPERANDS, and it is beneficial for
{
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
+ rtx op;
unsigned int rd, rs;
bitmap b;
+ if ((op = operand_for_swap_move_operator (src)) != NULL_RTX)
+ src = op;
+
if (!REG_P (dest) || !REG_P (src))
return false;
return true;
}
+/* OPND is a concatn operand this is used with a simple move operator.
+ Return a new rtx with the concatn's operands swapped. */
+
+static rtx
+resolve_operand_for_swap_move_operator (rtx opnd)
+{
+ gcc_assert (GET_CODE (opnd) == CONCATN);
+ rtx concatn = copy_rtx (opnd);
+ rtx op0 = XVECEXP (concatn, 0, 0);
+ rtx op1 = XVECEXP (concatn, 0, 1);
+ XVECEXP (concatn, 0, 0) = op1;
+ XVECEXP (concatn, 0, 1) = op0;
+ return concatn;
+}
+
/* Decompose the registers used in a simple move SET within INSN. If
we don't change anything, return INSN, otherwise return the start
of the sequence of moves. */
static rtx_insn *
resolve_simple_move (rtx set, rtx_insn *insn)
{
- rtx src, dest, real_dest;
+ rtx src, dest, real_dest, src_op;
rtx_insn *insns;
machine_mode orig_mode, dest_mode;
unsigned int orig_size, words;
real_dest = NULL_RTX;
+ if ((src_op = operand_for_swap_move_operator (src)) != NULL_RTX)
+ {
+ if (resolve_reg_p (dest))
+ {
+ /* DEST is a CONCATN, so swap its operands and strip
+ SRC's operator. */
+ dest = resolve_operand_for_swap_move_operator (dest);
+ src = src_op;
+ }
+ else if (resolve_reg_p (src_op))
+ {
+ /* SRC is an operation on a CONCATN, so strip the operator and
+ swap the CONCATN's operands. */
+ src = resolve_operand_for_swap_move_operator (src_op);
+ }
+ }
+
if (GET_CODE (src) == SUBREG
&& resolve_reg_p (SUBREG_REG (src))
&& (maybe_ne (SUBREG_BYTE (src), 0)