summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2024-03-03 18:15:58 +0100
committerGeorg-Johann Lay <avr@gjlay.de>2024-03-03 18:15:58 +0100
commitc0f5b6caff669037444506cb6008a378356ec209 (patch)
tree757d6b50f7d89eeeb514258f2becfca1012558ed
parentdae3456965064c9664c097c785ae9bf9fa203fa0 (diff)
AVR: ad target/114100 - Don't print unused frame pointer adjustments.
Without -mfuse-add, when fake reg+offset addressing is used, the output routines are saving some instructions when the base reg is unused after. This patch adds that optimization for the case when the base is the frame pointer and the frame pointer adjustments are split away from the move insn by -mfuse-add in .split2. Direct usage of reg_unused_after is not possible because that function looks at the destination of the current insn, which won't work for offsetting the frame pointer in printing PLUS code. It can use an extended version of _reg_unused_after though. gcc/ PR target/114100 * config/avr/avr-protos.h (_reg_unused_after): Remove proto. * config/avr/avr.cc (_reg_unused_after): Make static. And add 3rd argument to skip the current insn. (reg_unused_after): Adjust call of reg_unused_after. (avr_out_plus_1) [AVR_TINY && -mfuse-add >= 2]: Don't output unneeded frame pointer adjustments.
-rw-r--r--gcc/config/avr/avr-protos.h1
-rw-r--r--gcc/config/avr/avr.cc36
2 files changed, 21 insertions, 16 deletions
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index f4f3ffd8f28..3e19409d636 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -110,7 +110,6 @@ extern const char* avr_out_reload_inpsi (rtx*, rtx, int*);
extern const char* avr_out_lpm (rtx_insn *, rtx*, int*);
extern void avr_notice_update_cc (rtx body, rtx_insn *insn);
extern int reg_unused_after (rtx_insn *insn, rtx reg);
-extern int _reg_unused_after (rtx_insn *insn, rtx reg);
extern int avr_jump_mode (rtx x, rtx_insn *insn);
extern int test_hard_reg_class (enum reg_class rclass, rtx x);
extern int jump_over_one_insn_p (rtx_insn *insn, rtx dest);
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 44d6e141b62..7df21432dda 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -163,6 +163,7 @@ static int avr_operand_rtx_cost (rtx, machine_mode, enum rtx_code,
int, bool);
static void output_reload_in_const (rtx *, rtx, int *, bool);
static struct machine_function *avr_init_machine_status (void);
+static int _reg_unused_after (rtx_insn *insn, rtx reg, bool look_at_insn);
/* Prototypes for hook implementors if needed before their implementation. */
@@ -8825,7 +8826,7 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len)
fixed-point rounding, cf. `avr_out_round'. */
static void
-avr_out_plus_1 (rtx /*insn*/, rtx *xop, int *plen, enum rtx_code code,
+avr_out_plus_1 (rtx insn, rtx *xop, int *plen, enum rtx_code code,
enum rtx_code code_sat, int sign, bool out_label)
{
/* MODE of the operation. */
@@ -8973,6 +8974,10 @@ avr_out_plus_1 (rtx /*insn*/, rtx *xop, int *plen, enum rtx_code code,
&& frame_pointer_needed
&& REGNO (xop[0]) == FRAME_POINTER_REGNUM)
{
+ if (INSN_P (insn)
+ && _reg_unused_after (as_a <rtx_insn *> (insn), xop[0], false))
+ return;
+
if (AVR_HAVE_8BIT_SP)
{
avr_asm_len ("subi %A0,%n2", xop, plen, 1);
@@ -10818,31 +10823,32 @@ int
reg_unused_after (rtx_insn *insn, rtx reg)
{
return (dead_or_set_p (insn, reg)
- || (REG_P (reg) && _reg_unused_after (insn, reg)));
+ || (REG_P (reg) && _reg_unused_after (insn, reg, true)));
}
-/* Return nonzero if REG is not used after INSN.
+/* A helper for the previous function.
+ Return nonzero if REG is not used after INSN.
We assume REG is a reload reg, and therefore does
not live past labels. It may live past calls or jumps though. */
int
-_reg_unused_after (rtx_insn *insn, rtx reg)
+_reg_unused_after (rtx_insn *insn, rtx reg, bool look_at_insn)
{
- enum rtx_code code;
- rtx set;
-
- /* If the reg is set by this instruction, then it is safe for our
- case. Disregard the case where this is a store to memory, since
- we are checking a register used in the store address. */
- set = single_set (insn);
- if (set && !MEM_P (SET_DEST (set))
- && reg_overlap_mentioned_p (reg, SET_DEST (set)))
- return 1;
+ if (look_at_insn)
+ {
+ /* If the reg is set by this instruction, then it is safe for our
+ case. Disregard the case where this is a store to memory, since
+ we are checking a register used in the store address. */
+ rtx set = single_set (insn);
+ if (set && !MEM_P (SET_DEST (set))
+ && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ return 1;
+ }
while ((insn = NEXT_INSN (insn)))
{
rtx set;
- code = GET_CODE (insn);
+ enum rtx_code code = GET_CODE (insn);
#if 0
/* If this is a label that existed before reload, then the register