This patch tries to improve the bloated code we are currently generating for
AVR_TINY. It's mostly about printing the memory loads and stores and more
usage of reg_unused_after to print shorter instruction sequences in some cases.
Ok for trunk?
I also played around with PLUS in legitimate_address_p and legitimize_address
and got better code, but the problem with such changes is that almost all tests
for such small devices are failing and no reasonable portion of the testsuite
will pass.
I don't even know if anybody is using avr_tiny + avr-gcc or if users are
resorting to assembler.
Johann
gcc/
(avr_legitimize_address) [AVR_TINY]: Force constant addresses
outside [0,0xc0] into a register.
(avr_out_movhi_r_mr_reg_no_disp_tiny): Pass insn. And handle
cases where the base address register is unused after.
(avr_out_movhi_r_mr_reg_disp_tiny): Same.
(avr_out_movhi_mr_r_reg_disp_tiny): Same.
(avr_out_store_psi_reg_disp_tiny): Same.
gcc/testsuite/
* gcc.target/avr/torture/get-mem.c: New test.
* gcc.target/avr/torture/set-mem.c: New test.
Index: config/avr/avr.c
===
--- config/avr/avr.c (revision 238425)
+++ config/avr/avr.c (working copy)
@@ -1922,6 +1922,16 @@ avr_legitimize_address (rtx x, rtx oldx,
x = oldx;
+ if (AVR_TINY)
+{
+ if (CONSTANT_ADDRESS_P (x)
+ && !(CONST_INT_P (x)
+ && IN_RANGE (INTVAL (x), 0, 0xc0 - GET_MODE_SIZE (mode
+{
+ x = force_reg (Pmode, x);
+}
+}
+
if (GET_CODE (oldx) == PLUS
&& REG_P (XEXP (oldx, 0)))
{
@@ -3510,7 +3520,7 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[]
/* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */
static const char*
-avr_out_movhi_r_mr_reg_no_disp_tiny (rtx op[], int *plen)
+avr_out_movhi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen)
{
rtx dest = op[0];
rtx src = op[1];
@@ -3524,17 +3534,20 @@ avr_out_movhi_r_mr_reg_no_disp_tiny (rtx
"ld %B0,%1" CR_TAB
"mov %A0,__tmp_reg__", op, plen, -3);
- return avr_asm_len ("ld %A0,%1" CR_TAB
- TINY_ADIW (%E1, %F1, 1) CR_TAB
- "ld %B0,%1" CR_TAB
- TINY_SBIW (%E1, %F1, 1), op, plen, -6);
+ avr_asm_len ("ld %A0,%1+" CR_TAB
+ "ld %B0,%1", op, plen, -2);
+
+ if (!reg_unused_after (insn, base))
+avr_asm_len (TINY_SBIW (%E1, %F1, 1), op, plen, 2);
+
+ return "";
}
/* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */
static const char*
-avr_out_movhi_r_mr_reg_disp_tiny (rtx op[], int *plen)
+avr_out_movhi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen)
{
rtx dest = op[0];
rtx src = op[1];
@@ -3552,10 +3565,14 @@ avr_out_movhi_r_mr_reg_disp_tiny (rtx op
}
else
{
- return avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB
- "ld %A0,%b1+" CR_TAB
- "ld %B0,%b1" CR_TAB
- TINY_SBIW (%I1, %J1, %o1+1), op, plen, -6);
+ avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB
+ "ld %A0,%b1+" CR_TAB
+ "ld %B0,%b1", op, plen, -4);
+
+ if (!reg_unused_after (insn, XEXP (base, 0)))
+avr_asm_len (TINY_SBIW (%I1, %J1, %o1+1), op, plen, 2);
+
+ return "";
}
}
@@ -3603,7 +3620,7 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[]
if (reg_base > 0)
{
if (AVR_TINY)
-return avr_out_movhi_r_mr_reg_no_disp_tiny (op, plen);
+return avr_out_movhi_r_mr_reg_no_disp_tiny (insn, op, plen);
if (reg_dest == reg_base) /* R = (R) */
return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB
@@ -3628,7 +3645,7 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[]
int reg_base = true_regnum (XEXP (base, 0));
if (AVR_TINY)
-return avr_out_movhi_r_mr_reg_disp_tiny (op, plen);
+return avr_out_movhi_r_mr_reg_disp_tiny (insn, op, plen);
if (disp > MAX_LD_OFFSET (GET_MODE (src)))
{
@@ -4377,8 +4394,8 @@ avr_out_load_psi_reg_no_disp_tiny (rtx_i
"ld %B0,%1+" CR_TAB
"ld %C0,%1", op, plen, -3);
- if (reg_dest != reg_base - 2 &&
- !reg_unused_after (insn, base))
+ if (reg_dest != reg_base - 2
+ && !reg_unused_after (insn, base))
{
avr_asm_len (TINY_SBIW (%E1, %F1, 2), op, plen, 2);
}
@@ -4408,13 +4425,13 @@ avr_out_load_psi_reg_disp_tiny (rtx_insn
else
{
avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB
- "ld %A0,%b1+" CR_TAB
- "ld %B0,%b1+" CR_TAB
- "ld %C0,%b1", op, plen, -5);
+ "ld %A0,%b1+" CR_TAB
+ "ld %B0,%b1+" CR_TAB