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.