https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98762

            Bug ID: 98762
           Summary: Wrong code for avrtiny if source is Z and destination
                    is R30 or R31
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: saaadhu at gcc dot gnu.org
  Target Milestone: ---

avr_out_movqi_r_mr_reg_disp_tiny skips restoration of the base pointer reg pair
(using subi/sbci) if reg_overlap_mentioned_p or reg_unused_after returns true
for the pointer reg.

In the below case, (reg:HI 30) is the base reg, and (reg:QI 31) is the
destination. reg_overlap_mentioned_p (correctly) returns true, and therefore
*both* R30 and R31 are not restored to their original values, instead of just
R31. reg_unused_after also returns true for this case, as it also checks if
reg_overlap_mentioned_p for the current insn.

This causes miscompilation if the compiler later uses R30 with the assumption
that it is unmodified (which is what movqi_insn promises). In the below case
(reduced from execute/961122-1.c), the compiler only sets R31 again (with R19),
as it believes R30 is unmodified. 

Note that the bug is exposed if the splitter for HImode move to two QImode move
runs - otherwise, movhi_insn ensures both R30 and R31 are loaded again. 

$ cat reduced.c
long long acc;

void addhi (short a)
{
  acc += (long long) a << 32;
}

$ avr-gcc -mmcu=attiny40 -Os -dP -S reduce.c -o -
<snip>
; (insn 53 52 264 (set (reg:QI 31 r31)
 ;         (mem/c:QI (plus:HI (reg:HI 30 r30)
 ;                 (const_int 3 [0x3])) [1 acc+3 S1 A8])) "reduce.c":5:7 56
{movqi_insn}
 ;      (expr_list:REG_EQUAL (mem/c:QI (const:HI (plus:HI (symbol_ref:HI
("acc") [flags 0x2] <var_decl 0x7f85d5def120 acc>)
 ;                     (const_int 3 [0x3]))) [1 acc+3 S1 A8])
 ;         (nil)))
        subi r30,lo8(-(3))       ;  53  [c=4 l=3]  movqi_insn/3
        sbci r31,hi8(-(3))
        ld r31,Z
 ; (insn 264 53 296 (set (mem/c:QI (plus:HI (reg/f:HI 28 r28)
 ;                 (const_int 16 [0x10])) [3 %sfp+16 S1 A8])
 ;         (reg:QI 31 r31)) "reduce.c":5:7 56 {movqi_insn}
 ;      (expr_list:REG_DEAD (reg:QI 31 r31)
 ;         (nil)))
        subi r28,lo8(-(16))      ;  264 [c=4 l=5]  movqi_insn/2
        sbci r29,hi8(-(16))
        st Y,r31
        subi r28,lo8((16))
        sbci r29,hi8((16))
 ; (insn 296 264 54 (set (reg:QI 31 r31 [+1 ])
 ;         (reg:QI 19 r19 [+1 ])) "reduce.c":5:7 56 {movqi_insn}
 ;      (nil))
        mov r31,r19      ;  296 [c=4 l=1]  movqi_insn/0
 ; (insn 54 296 266 (set (reg:QI 31 r31)
 ;         (mem/c:QI (plus:HI (reg:HI 30 r30)
 ;                 (const_int 4 [0x4])) [1 acc+4 S1 A8])) "reduce.c":5:7 56
{movqi_insn}
 ;      (expr_list:REG_EQUAL (mem/c:QI (const:HI (plus:HI (symbol_ref:HI
("acc") [flags 0x2] <var_decl 0x7f85d5def120 acc>)
 ;                     (const_int 4 [0x4]))) [1 acc+4 S1 A8])
 ;         (nil)))
        subi r30,lo8(-(4))       ;  54  [c=4 l=3]  movqi_insn/3
        sbci r31,hi8(-(4))
        ld r31,Z
 ; (insn 266 54 298 (set (mem/c:QI (plus:HI (reg/f:HI 28 r28)
 ;                 (const_int 17 [0x11])) [3 %sfp+17 S1 A8])
 ;         (reg:QI 31 r31)) "reduce.c":5:7 56 {movqi_insn}
 ;      (expr_list:REG_DEAD (reg:QI 31 r31)
 ;         (nil)))
        subi r28,lo8(-(17))      ;  266 [c=4 l=5]  movqi_insn/2
        sbci r29,hi8(-(17))
        st Y,r31

Reply via email to