https://gcc.gnu.org/g:f3d9c120a1959c5b094001516c1e5cb4ba6f4080
commit r14-10597-gf3d9c120a1959c5b094001516c1e5cb4ba6f4080 Author: Georg-Johann Lay <a...@gjlay.de> Date: Sat Aug 17 12:49:42 2024 +0200 AVR: target/116390 - Fix an avrtiny asm out template. PR target/116390 gcc/ * config/avr/avr.cc (avr_out_movsi_mr_r_reg_disp_tiny): Fix output templates for the reg_base == reg_src and reg_src == reg_base - 2 cases. gcc/testsuite/ * gcc.target/avr/torture/pr116390.c: New test. (cherry picked from commit 4065d163151b07b274241377e71dad028576db88) Diff: --- gcc/config/avr/avr.cc | 30 +++++------ gcc/testsuite/gcc.target/avr/torture/pr116390.c | 71 +++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 71929b28160..3c1a0bf707f 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -5501,33 +5501,33 @@ avr_out_movsi_mr_r_reg_disp_tiny (rtx op[], int *l) rtx src = op[1]; rtx base = XEXP (dest, 0); int reg_base = REGNO (XEXP (base, 0)); - int reg_src =true_regnum (src); + int reg_src = true_regnum (src); if (reg_base == reg_src) { *l = 11; - return ("mov __tmp_reg__,%A2" CR_TAB - "mov __zero_reg__,%B2" CR_TAB + return ("mov __tmp_reg__,%A1" CR_TAB + "mov __zero_reg__,%B1" CR_TAB TINY_ADIW (%I0, %J0, %o0) CR_TAB "st %b0+,__tmp_reg__" CR_TAB "st %b0+,__zero_reg__" CR_TAB - "st %b0+,%C2" CR_TAB - "st %b0,%D2" CR_TAB + "st %b0+,%C1" CR_TAB + "st %b0,%D1" CR_TAB "clr __zero_reg__" CR_TAB TINY_SBIW (%I0, %J0, %o0+3)); } else if (reg_src == reg_base - 2) { - *l = 11; - return ("mov __tmp_reg__,%C2" CR_TAB - "mov __zero_reg__,%D2" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,%A0" CR_TAB - "st %b0+,%B0" CR_TAB - "st %b0+,__tmp_reg__" CR_TAB - "st %b0,__zero_reg__" CR_TAB - "clr __zero_reg__" CR_TAB - TINY_SBIW (%I0, %J0, %o0+3)); + // This awkward case can occur when ext-dce turns zero-extend:SI(HI) + // into a paradoxical subreg, which register allocation may turn into + // something like *(R28:HI + 7) = R26:SI. There is actually no need + // to store the upper 2 bytes of R26:SI as they are unused rubbish. + // See PR116390. + *l = 6; + return (TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,%A1" CR_TAB + "st %b0,%B1" CR_TAB + TINY_SBIW (%I0, %J0, %o0+1)); } *l = 8; return (TINY_ADIW (%I0, %J0, %o0) CR_TAB diff --git a/gcc/testsuite/gcc.target/avr/torture/pr116390.c b/gcc/testsuite/gcc.target/avr/torture/pr116390.c new file mode 100644 index 00000000000..70c1ad62936 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/pr116390.c @@ -0,0 +1,71 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99" } */ + +typedef struct +{ + int i; +} MyStruct; + +void f_ic (int, char); +void f_pi (char const *, int); +void f_iic (int, int, char); + +const MyStruct *f_rms (void); + +char *f_rcp (void); +int f_ri (void); + +void badFoo (void) +{ + const MyStruct* ps = f_rms (); + const char* pc = f_rcp (); + + unsigned n1 = f_rcp () - pc; + + if (n1) + { + long n2 = n1 - ps->i; + if (n2 > 0) + { + if (f_ri ()) + n2 = n1; + + if (f_ri ()) + { + f_iic (1, 2 * n2, ' '); + } + else + f_pi (pc, n2); + } + if (ps->i > 0) + { + if (n2 >= 0) + f_pi (pc + n2, ps->i); + else + { + f_ic (n2, ' '); + } + } + + const int which = f_ri (); + switch (which) + { + case 1: + if (f_ri ()) + f_rcp ()[1] = ' '; + break; + + case 2: + f_pi (f_rcp (), 1); + break; + + case 3: + if (f_ri () && n1 < 0) + f_ic (n1, ' '); + else + f_rcp ()[1] = ' '; + break; + + } + } +}