aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2025-09-04 22:03:31 +0200
committerGeorg-Johann Lay <avr@gjlay.de>2025-09-05 14:38:31 +0200
commite3d14112b266479da9f8fd9c304e0ae15bf0ad25 (patch)
tree09a38d9c0290e01a41d18af5da66ca3701876f71
parent2965a67c7ef34de74904b600a3e4a4cc858ea37b (diff)
downloadgcc-e3d14112b266479da9f8fd9c304e0ae15bf0ad25.zip
gcc-e3d14112b266479da9f8fd9c304e0ae15bf0ad25.tar.gz
gcc-e3d14112b266479da9f8fd9c304e0ae15bf0ad25.tar.bz2
AVR: target/121794 - Invoke zero_reg less.
There are some cases where involing zero_reg is not needed and where there are other sequences with the same efficiency. An example is to use SBCI R,0 instead of SBC R,__zero_reg__ when R >= R16. This may turn out to be better for small ISRs. PR target/121794 gcc/ * config/avr/avr.cc (avr_out_compare): Only use zero_reg when there is no other sequence of the same length. (avr_out_plus_ext): Same. (avr_out_plus_1): Same.
-rw-r--r--gcc/config/avr/avr.cc74
1 files changed, 47 insertions, 27 deletions
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index ae49d4d..6c7ad4f 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -6597,34 +6597,14 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen)
}
}
- /* Comparing against 0 is easy. */
+ /* Otherwise, compare a single byte with CP / CPC or equivalent. */
- if (val8 == 0)
- {
- avr_asm_len (i == start
- ? "cp %0,__zero_reg__"
- : "cpc %0,__zero_reg__", xop, plen, 1);
- continue;
- }
+ const bool ldreg_p = test_hard_reg_class (LD_REGS, xop[0]);
- /* Upper registers can compare and subtract-with-carry immediates.
- Notice that compare instructions do the same as respective subtract
- instruction; the only difference is that comparisons don't write
- the result back to the target register. */
-
- if (test_hard_reg_class (LD_REGS, xop[0]))
+ if (ldreg_p && i == start)
{
- if (i == start)
- {
- avr_asm_len ("cpi %0,%1", xop, plen, 1);
- continue;
- }
- else if (reg_unused_after (insn, xreg))
- {
- avr_asm_len ("sbci %0,%1", xop, plen, 1);
- changed[i] = true;
- continue;
- }
+ avr_asm_len ("cpi %0,%1", xop, plen, 1);
+ continue;
}
/* When byte comparisons for an EQ or NE comparison look like
@@ -6641,7 +6621,7 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen)
for (int j = start; j < i && ! found; ++j)
if (val8 == avr_uint8 (xval, j)
- // Make sure that we didn't clobber x[j] above.
+ // Make sure that we didn't clobber x[j] with SBCI.
&& ! changed[j])
{
rtx op[] = { xop[0], avr_byte (xreg, j) };
@@ -6653,6 +6633,37 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen)
continue;
}
+ /* Upper registers can SBCI which has the same effect like CPC on
+ SREG, but it writes back the result of the subtraction to %0.
+ Therefore, SBCI can only replace CPC when %0 is unused after,
+ or when the comparison is against 0x..0000. */
+
+ if (ldreg_p && i > start)
+ {
+ bool zero_p = true;
+
+ for (int j = start; j <= i; ++j)
+ zero_p &= avr_uint8 (xval, j) == 0;
+
+ if (zero_p || reg_unused_after (insn, xreg))
+ {
+ avr_asm_len ("sbci %0,%1", xop, plen, 1);
+ changed[i] = !zero_p;
+ continue;
+ }
+ }
+
+ /* Comparing against 0 is easy, but only invoke __zero_reg__ when
+ nothing else has been found. This is better for small ISRs. */
+
+ if (val8 == 0)
+ {
+ avr_asm_len (i == start
+ ? "cp %0,__zero_reg__"
+ : "cpc %0,__zero_reg__", xop, plen, 1);
+ continue;
+ }
+
/* Must load the value into the scratch register. */
gcc_assert (REG_P (xop[2]));
@@ -8533,11 +8544,17 @@ avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen)
const int n_bytes0 = GET_MODE_SIZE (GET_MODE (xop[0]));
const int n_bytes1 = GET_MODE_SIZE (GET_MODE (xop[1]));
rtx msb1 = all_regs_rtx[n_bytes1 - 1 + REGNO (xop[1])];
+ // Prefer SBCI *,0 over SBC *,__zero_reg__.
+ const bool sbci_p = add == MINUS && n_bytes0 > n_bytes1
+ ? test_hard_reg_class (LD_REGS, avr_byte (xop[0], n_bytes1))
+ : false;
const char *const s_ADD = add == PLUS ? "add %0,%1" : "sub %0,%1";
const char *const s_ADC = add == PLUS ? "adc %0,%1" : "sbc %0,%1";
const char *const s_DEC = add == PLUS
? "adc %0,__zero_reg__" CR_TAB "sbrc %1,7" CR_TAB "dec %0"
+ : sbci_p
+ ? "sbci %0,0" CR_TAB "sbrc %1,7" CR_TAB "inc %0"
: "sbc %0,__zero_reg__" CR_TAB "sbrc %1,7" CR_TAB "inc %0";
// A register that containts 8 copies of $1.msb.
@@ -8582,6 +8599,8 @@ avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen)
regs[1] = msb1;
avr_asm_len (s_DEC, regs, plen, 3);
}
+ else if (sbci_p && regs[1] == zero_reg_rtx)
+ avr_asm_len ("sbci %0,0", regs, plen, 1);
else
avr_asm_len (s_ADC, regs, plen, 1);
}
@@ -8890,7 +8909,8 @@ avr_out_plus_1 (rtx xinsn, rtx *xop, int *plen, rtx_code code,
{
if (started)
avr_asm_len (code == PLUS
- ? "adc %0,__zero_reg__" : "sbc %0,__zero_reg__",
+ ? "adc %0,__zero_reg__"
+ : ld_reg_p ? "sbci %0,0" : "sbc %0,__zero_reg__",
op, plen, 1);
continue;
}