diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2024-03-03 18:15:58 +0100 |
---|---|---|
committer | Georg-Johann Lay <avr@gjlay.de> | 2024-03-03 18:15:58 +0100 |
commit | c0f5b6caff669037444506cb6008a378356ec209 (patch) | |
tree | 757d6b50f7d89eeeb514258f2becfca1012558ed /gcc/config/avr | |
parent | dae3456965064c9664c097c785ae9bf9fa203fa0 (diff) | |
download | gcc-c0f5b6caff669037444506cb6008a378356ec209.zip gcc-c0f5b6caff669037444506cb6008a378356ec209.tar.gz gcc-c0f5b6caff669037444506cb6008a378356ec209.tar.bz2 |
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.
Diffstat (limited to 'gcc/config/avr')
-rw-r--r-- | gcc/config/avr/avr-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/avr/avr.cc | 36 |
2 files changed, 21 insertions, 16 deletions
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index f4f3ffd..3e19409 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 44d6e14..7df2143 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 |