}
+/* Return true when REGNO is set by INSN but not used by the following code.
+ The difference to reg_unused_after() is that reg_unused_after() returns
+ true for the entire result even when the result *IS* being used atfer. */
+
+static bool
+avr_result_regno_unused_p (rtx_insn *insn, unsigned regno)
+{
+ if (!insn || !single_set (insn) || regno >= REG_32)
+ return false;
+
+ rtx dest = SET_DEST (single_set (insn));
+ if (!REG_P (dest) || !IN_RANGE (regno, REGNO (dest), END_REGNO (dest) - 1))
+ return false;
+
+ return (avr_insn_has_reg_unused_note_p (insn, all_regs_rtx[regno])
+ || _reg_unused_after (insn, all_regs_rtx[regno], false));
+}
+
+
/* Fixme: This is a hack because secondary reloads don't works as expected.
Find an unused d-register to be used as scratch in INSN.
/* Output addition of register XOP[0] and compile time constant XOP[2].
- INSN is a single_set insn or an insn pattern.
+ XINSN is a single_set insn or an insn pattern.
CODE == PLUS: perform addition by using ADD instructions or
CODE == MINUS: perform addition by using SUB instructions:
fixed-point rounding, cf. `avr_out_round'. */
static void
-avr_out_plus_1 (rtx insn, rtx *xop, int *plen, rtx_code code,
+avr_out_plus_1 (rtx xinsn, rtx *xop, int *plen, rtx_code code,
rtx_code code_sat, int sign, bool out_label)
{
+ rtx_insn *insn = xinsn && INSN_P (xinsn)
+ ? as_a <rtx_insn *> (xinsn)
+ : nullptr;
+
/* MODE of the operation. */
machine_mode mode = GET_MODE (xop[0]);
/* Number of bytes to operate on. */
int n_bytes = GET_MODE_SIZE (mode);
+ int regno0 = REGNO (xop[0]);
+ if (optimize && code_sat == UNKNOWN)
+ while (n_bytes && avr_result_regno_unused_p (insn, regno0 + n_bytes - 1))
+ n_bytes -= 1;
+
/* Value (0..0xff) held in clobber register op[3] or -1 if unknown. */
int clobber_val = -1;
if (REG_P (xop[2]))
{
- if (REGNO (xop[0]) != REGNO (xop[2])
+ if (optimize
+ && REGNO (xop[0]) != REGNO (xop[2])
&& reg_overlap_mentioned_p (xop[0], xop[2]))
{
/* PR118878: Paradoxical SUBREGs may result in overlapping
registers. The assumption is that the overlapping part
is unused garbage. */
gcc_assert (n_bytes <= 4);
- n_bytes = std::abs ((int) REGNO (xop[0]) - (int) REGNO (xop[2]));
+ int delta = (int) REGNO (xop[0]) - (int) REGNO (xop[2]);
+ n_bytes = std::min (n_bytes, std::abs (delta));
}
for (int i = 0; i < n_bytes; i++)
&& frame_pointer_needed
&& REGNO (xop[0]) == FRAME_POINTER_REGNUM)
{
- if (INSN_P (insn)
- && _reg_unused_after (as_a <rtx_insn *> (insn), xop[0], false))
+ if (insn
+ && _reg_unused_after (insn, xop[0], false))
return;
if (AVR_HAVE_8BIT_SP)
We have to compute A = A <op> B where A is a register and
B is a register or a non-zero compile time constant CONST.
A is register class "r" if unsigned && B is REG. Otherwise, A is in "d".
- B stands for the original operand $2 in INSN. In the case of B = CONST,
+ B stands for the original operand $2 in XINSN. In the case of B = CONST,
SIGN in { -1, 1 } is the sign of B. Otherwise, SIGN is 0.
CODE is the instruction flavor we use in the asm sequence to perform <op>.
operation; otherwise, set *PLEN to the length of the instruction sequence
(in words) printed with PLEN == NULL. XOP[3] is either an 8-bit clobber
register or SCRATCH if no clobber register is needed for the operation.
- INSN is an INSN_P or a pattern of an insn. */
+ XINSN is an INSN_P or a pattern of an insn. */
const char *
-avr_out_bitop (rtx insn, rtx *xop, int *plen)
+avr_out_bitop (rtx xinsn, rtx *xop, int *plen)
{
+ rtx_insn *insn = xinsn && INSN_P (xinsn)
+ ? as_a <rtx_insn *> (xinsn)
+ : nullptr;
+ rtx xpattern = insn ? single_set (insn) : xinsn;
+
/* CODE and MODE of the operation. */
- rtx xpattern = INSN_P (insn) ? single_set (as_a <rtx_insn *> (insn)) : insn;
rtx_code code = GET_CODE (SET_SRC (xpattern));
machine_mode mode = GET_MODE (xop[0]);
/* We operate byte-wise on the destination. */
rtx reg8 = avr_byte (xop[0], i);
+ if (optimize
+ && avr_result_regno_unused_p (insn, REGNO (reg8)))
+ continue;
+
/* 8-bit value to operate with this byte. */
unsigned int val8 = avr_uint8 (xop[2], i);