]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
AVR: ad target/114100 - Don't print unused frame pointer adjustments.
authorGeorg-Johann Lay <avr@gjlay.de>
Sun, 3 Mar 2024 17:15:58 +0000 (18:15 +0100)
committerGeorg-Johann Lay <avr@gjlay.de>
Sun, 3 Mar 2024 17:15:58 +0000 (18:15 +0100)
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.

gcc/config/avr/avr-protos.h
gcc/config/avr/avr.cc

index f4f3ffd8f28c5184b1bcd53f83d80c0efd325c9b..3e19409d636967b30b87da730f5b704afaee0afc 100644 (file)
@@ -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);
index 44d6e141b623ac92c0f8a2425f6db032e9f34a1a..7df21432ddaff1b247e437da9bb0418595c8663f 100644 (file)
@@ -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