https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125687
Bug ID: 125687
Summary: [avr] Superfluous register moves due to hard-reg
constraints
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: gjl at gcc dot gnu.org
Target Milestone: ---
typedef __UINT32_TYPE__ uint32_t;
uint32_t div7 (uint32_t x)
{
return x / 7;
}
$ avr-gcc x.c -S -Os -mmcu=avr4 -dp && cat x.s
generates the following code:
div7:
push r28 ; 26 [c=4 l=1] pushqi1/0
push r29 ; 27 [c=4 l=1] pushqi1/0
ldi r26,lo8(7) ; 38 [c=4 l=1] movqi_insn/1
ldi r27,0 ; 39 [c=4 l=1] movqi_insn/0
ldi r28,0 ; 40 [c=4 l=1] movqi_insn/0
ldi r29,0 ; 41 [c=4 l=1] movqi_insn/0
movw r20,r28 ; 46 [c=4 l=1] *movhi/0
movw r18,r26 ; 47 [c=4 l=1] *movhi/0
rcall __udivmodsi4 ; 24 [c=0 l=1] *udivmodsi4_call
movw r22,r18 ; 56 [c=4 l=1] *movhi/0
movw r24,r20 ; 57 [c=4 l=1] *movhi/0
pop r29 ; 30 [c=4 l=1] popqi
pop r28 ; 31 [c=4 l=1] popqi
ret ; 32 [c=0 l=1] return_from_epilogue
That is: The constant of 7 is loaded into registers R26..R29 (insns 38..41)
just to move it into R18..R21 afterwards (insns 46..47). To make things even
worse, two of the registers used to load the constant are callee-saved regs,
requiring push/pop (insns 26, 27, 30, 31).
This is caused by using hard-reg constraints in https://gcc.gnu.org/r17-891
Going one git revision prior to that, the generated code loads the constant
into R18..R21 without any further ado:
div7:
ldi r18,lo8(7) ; 29 [c=4 l=1] movqi_insn/1
ldi r19,0 ; 30 [c=4 l=1] movqi_insn/0
ldi r20,0 ; 31 [c=4 l=1] movqi_insn/0
ldi r21,0 ; 32 [c=4 l=1] movqi_insn/0
rcall __udivmodsi4 ; 23 [c=0 l=1] *udivmodsi4_call
movw r22,r18 ; 37 [c=4 l=1] *movhi/0
movw r24,r20 ; 38 [c=4 l=1] *movhi/0
ret ; 27 [c=0 l=1] return