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; +}