GCC produces unneccessary register pushes for simple ISR on AVR
Solution 1:
Simple answer:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=20296
The difficulty is, that the present architecture of the avr back-end does not easily permit to improve this case: Every instruction pattern (like "multiply two 16 bit integers" or "sign-extend a 16 bit variable to 32 bits") presently is free to assume that may overwrite or change r0 and r1 unless it leaves the "zero_reg" with 0 after finishing it's task.
Resolving this issue, IMHO, would require a major refactoring of the back-end.
This is a long standing bug / enhancement request to avr-backend.
Solution 2:
GCC pushes all used registers. Your only real recourse is to enable the naked
attribute, which will only push the stack pointer. Or change to assembly language.
Solution 3:
The reason is that you are using an outdated compiler. The mentioned optimization has been added in v8 (released spring 2018), see GCC v8 Release Notes:
The compiler now generates efficient interrupt service routine (ISR) prologues and epilogues. This is achieved by using the new AVR pseudo instruction __gcc_isr which is supported and resolved by the GNU assembler.