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