https://gcc.gnu.org/g:58c8882ff5ba249ef4cfc99f3c3f8ada8810f75a

commit r13-8980-g58c8882ff5ba249ef4cfc99f3c3f8ada8810f75a
Author: Georg-Johann Lay <a...@gjlay.de>
Date:   Sun Aug 18 15:00:55 2024 +0200

    AVR: target/116407 - Fix linker error "relocation truncated to fit".
    
    Some text peepholes output extra instructions prior to a branch
    instruction and that increase the jump offset of backward branches.
    
            PR target/116407
    gcc/
            * config/avr/avr-protos.h (avr_jump_mode): Add an int argument.
            * config/avr/avr.cc (avr_jump_mode): Add an int argument to increase
            the computed jump offset of backwards branches.
            * config/avr/avr.md (*dec-and-branchhi!=-1, *dec-and-branchsi!=-1):
            Increase the jump offset used by avr_jump_mode() as needed.
    gcc/testsuite/
            * gcc.target/avr/torture/pr116407-2.c: New test.
            * gcc.target/avr/torture/pr116407-4.c: New test.
    
    (cherry picked from commit dfb2e8caa85d1059a0ab8ed4f19568c04c9f13a4)

Diff:
---
 gcc/config/avr/avr-protos.h                       |  2 +-
 gcc/config/avr/avr.cc                             | 11 +++++---
 gcc/config/avr/avr.md                             | 24 ++++++----------
 gcc/testsuite/gcc.target/avr/torture/pr116407-2.c | 34 +++++++++++++++++++++++
 gcc/testsuite/gcc.target/avr/torture/pr116407-4.c | 34 +++++++++++++++++++++++
 5 files changed, 84 insertions(+), 21 deletions(-)

diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index cf45a8c4499..27659bc8e15 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -108,7 +108,7 @@ 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 avr_jump_mode (rtx x, rtx_insn *insn, int = 0);
 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 676ab2405db..f5e53aba708 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -3388,19 +3388,22 @@ avr_use_by_pieces_infrastructure_p (unsigned 
HOST_WIDE_INT size,
 /* Choose mode for jump insn:
    1 - relative jump in range -63 <= x <= 62 ;
    2 - relative jump in range -2046 <= x <= 2045 ;
-   3 - absolute jump (only for ATmega[16]03).  */
+   3 - absolute jump (only when we have JMP / CALL).
+
+   When jumping backwards, assume the jump offset is EXTRA words
+   bigger than inferred from insn addresses.  */
 
 int
-avr_jump_mode (rtx x, rtx_insn *insn)
+avr_jump_mode (rtx x, rtx_insn *insn, int extra)
 {
   int dest_addr = INSN_ADDRESSES (INSN_UID (GET_CODE (x) == LABEL_REF
                                             ? XEXP (x, 0) : x));
   int cur_addr = INSN_ADDRESSES (INSN_UID (insn));
   int jump_distance = cur_addr - dest_addr;
 
-  if (IN_RANGE (jump_distance, -63, 62))
+  if (IN_RANGE (jump_distance, -63, 62 - extra))
     return 1;
-  else if (IN_RANGE (jump_distance, -2046, 2045))
+  else if (IN_RANGE (jump_distance, -2046, 2045 - extra))
     return 2;
   else if (AVR_HAVE_JMP_CALL)
     return 3;
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index c8b5ccaf098..9bd6b9119ec 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -7625,8 +7625,6 @@
                       (pc)))]
   "dead_or_set_regno_p (insn, REG_CC)"
   {
-    const char *op;
-    int jump_mode;
     if (avr_adiw_reg_p (operands[0]))
       output_asm_insn ("sbiw %0,1" CR_TAB
                        "sbc %C0,__zero_reg__" CR_TAB
@@ -7637,8 +7635,8 @@
                        "sbc %C0,__zero_reg__" CR_TAB
                        "sbc %D0,__zero_reg__", operands);
 
-    jump_mode = avr_jump_mode (operands[2], insn);
-    op = ((EQ == <CODE>) ^ (jump_mode == 1)) ? "brcc" : "brcs";
+    int jump_mode = avr_jump_mode (operands[2], insn, 3 - avr_adiw_reg_p 
(operands[0]));
+    const char *op = ((EQ == <CODE>) ^ (jump_mode == 1)) ? "brcc" : "brcs";
     operands[1] = gen_rtx_CONST_STRING (VOIDmode, op);
 
     switch (jump_mode)
@@ -7668,16 +7666,14 @@
                       (pc)))]
   "dead_or_set_regno_p (insn, REG_CC)"
   {
-    const char *op;
-    int jump_mode;
     if (avr_adiw_reg_p (operands[0]))
       output_asm_insn ("sbiw %0,1", operands);
     else
       output_asm_insn ("subi %A0,1" CR_TAB
                        "sbc %B0,__zero_reg__", operands);
 
-    jump_mode = avr_jump_mode (operands[2], insn);
-    op = ((EQ == <CODE>) ^ (jump_mode == 1)) ? "brcc" : "brcs";
+    int jump_mode = avr_jump_mode (operands[2], insn, 1 - avr_adiw_reg_p 
(operands[0]));
+    const char *op = ((EQ == <CODE>) ^ (jump_mode == 1)) ? "brcc" : "brcs";
     operands[1] = gen_rtx_CONST_STRING (VOIDmode, op);
 
     switch (jump_mode)
@@ -7709,16 +7705,14 @@
                       (pc)))]
   "dead_or_set_regno_p (insn, REG_CC)"
   {
-    const char *op;
-    int jump_mode;
     if (avr_adiw_reg_p (operands[0]))
       output_asm_insn ("sbiw %0,1", operands);
     else
       output_asm_insn ("subi %A0,1" CR_TAB
                        "sbc %B0,__zero_reg__", operands);
 
-    jump_mode = avr_jump_mode (operands[2], insn);
-    op = ((EQ == <CODE>) ^ (jump_mode == 1)) ? "brcc" : "brcs";
+    int jump_mode = avr_jump_mode (operands[2], insn, 1 - avr_adiw_reg_p 
(operands[0]));
+    const char *op = ((EQ == <CODE>) ^ (jump_mode == 1)) ? "brcc" : "brcs";
     operands[1] = gen_rtx_CONST_STRING (VOIDmode, op);
 
     switch (jump_mode)
@@ -7750,14 +7744,12 @@
                       (pc)))]
   "dead_or_set_regno_p (insn, REG_CC)"
   {
-    const char *op;
-    int jump_mode;
     output_asm_insn ("ldi %3,1"   CR_TAB
                      "sub %A0,%3" CR_TAB
                      "sbc %B0,__zero_reg__", operands);
 
-    jump_mode = avr_jump_mode (operands[2], insn);
-    op = ((EQ == <CODE>) ^ (jump_mode == 1)) ? "brcc" : "brcs";
+    int jump_mode = avr_jump_mode (operands[2], insn, 2);
+    const char *op = ((EQ == <CODE>) ^ (jump_mode == 1)) ? "brcc" : "brcs";
     operands[1] = gen_rtx_CONST_STRING (VOIDmode, op);
 
     switch (jump_mode)
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr116407-2.c 
b/gcc/testsuite/gcc.target/avr/torture/pr116407-2.c
new file mode 100644
index 00000000000..f580d129b5b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/pr116407-2.c
@@ -0,0 +1,34 @@
+/* { dg-do link } */
+
+typedef __UINT16_TYPE__ u16;
+typedef __INT16_TYPE__  T;
+
+#ifdef __OPTIMIZE__
+
+static __inline__ __attribute__((always_inline))
+void delay (T x, u16 nops)
+{
+    do
+        __builtin_avr_nops (nops);
+    while (--x != -1);
+}
+
+#ifdef __AVR_HAVE_JMP_CALL__
+
+void delay_2043 (T x) { delay (x, 2043); }
+void delay_2044 (T x) { delay (x, 2044); }
+void delay_2045 (T x) { delay (x, 2045); }
+void delay_2046 (T x) { delay (x, 2046); }
+
+#endif /* have JUMP, CALL */
+
+void delay_61 (T x) { delay (x, 61); }
+void delay_62 (T x) { delay (x, 62); }
+void delay_63 (T x) { delay (x, 63); }
+
+#endif /* optimize */
+
+int main (void)
+{
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr116407-4.c 
b/gcc/testsuite/gcc.target/avr/torture/pr116407-4.c
new file mode 100644
index 00000000000..4347d85e552
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/pr116407-4.c
@@ -0,0 +1,34 @@
+/* { dg-do link } */
+
+typedef __UINT16_TYPE__ u16;
+typedef __INT32_TYPE__  T;
+
+#ifdef __OPTIMIZE__
+
+static __inline__ __attribute__((always_inline))
+void delay (T x, u16 nops)
+{
+    do
+        __builtin_avr_nops (nops);
+    while (--x != -1);
+}
+
+#ifdef __AVR_HAVE_JMP_CALL__
+
+void delay_2043 (T x) { delay (x, 2043); }
+void delay_2044 (T x) { delay (x, 2044); }
+void delay_2045 (T x) { delay (x, 2045); }
+void delay_2046 (T x) { delay (x, 2046); }
+
+#endif /* have JUMP, CALL */
+
+void delay_61 (T x) { delay (x, 61); }
+void delay_62 (T x) { delay (x, 62); }
+void delay_63 (T x) { delay (x, 63); }
+
+#endif /* optimize */
+
+int main (void)
+{
+    return 0;
+}

Reply via email to