c - GCC generating useless code in ISR -


i have simple interrupt service routine(isr) written atmega328 , compiled avrgcc (using -os) using avr studio.

isr (timer0_ovf_vect) {      txofcnt++;  //count overflows , store in uint16_t  } 

if note assembly generated (below), uses r24, r25 job incrementing volatile uint16_t txofcnt, push-write-pop r1, r28, r29 without ever reading them. has push/pop of r0 without ever using in between.

i flat out don't understand why r1 pushed, cleared , poped. why gcc feel need load eimsk , gpior0 registers , not use them. bonus points if can tell me gpior0 for, datasheet says exists has no description.

00000258 <__vector_16>:  isr (timer0_ovf_vect) {  258:   1f 92           push    r1  25a:   0f 92           push    r0  25c:   00 90 5f 00     lds r0, 0x005f  260:   0f 92           push    r0  262:   11 24           eor r1, r1  264:   8f 93           push    r24  266:   9f 93           push    r25  268:   cf 93           push    r28  26a:   df 93           push    r29  26c:   cd b7           in  r28, 0x3d   ; 61 reads register eimsk  26e:   de b7           in  r29, 0x3e   ; 62 reads register gpior0     txofcnt++;    270:   80 91 0a 01     lds r24, 0x010a  274:   90 91 0b 01     lds r25, 0x010b  278:   01 96           adiw    r24, 0x01   ; 1  27a:   90 93 0b 01     sts 0x010b, r25  27e:   80 93 0a 01     sts 0x010a, r24 }  282:   df 91           pop r29  284:   cf 91           pop r28  286:   9f 91           pop r25  288:   8f 91           pop r24  28a:   0f 90           pop r0  28c:   00 92 5f 00     sts 0x005f, r0  290:   0f 90           pop r0  292:   1f 90           pop r1  294:   18 95           reti 

there documentation on gcc's register usage avr @ https://gcc.gnu.org/wiki/avr-gcc

some passages relevant question:

fixed registers

fixed registers registers won't allocated gcc's register allocator. registers r0 , r1 fixed , used implicitly while printing out assembler instructions:

  • r0

    is used scratch register need not restored after usage. must saved , restored in interrupt service routine's (isr) prologue , epilogue. in inline assembler can use __tmp_reg__ scratch register.

  • r1

    always contains zero. during insn content might destroyed, e.g. mul instruction uses r0/r1 implicit output register. if insn destroys r1, insn must restore r1 0 afterwards. register must saved in isr prologues , must set 0 because r1 might contain values other zero. isr epilogue restores value. in inline assembler can use __zero_reg__ 0 register.

    ...

call-used registers

the call-used or call-clobbered general purpose registers (gprs) registers might destroyed (clobbered) function call.

  • r18–r27, r30, r31

    these gprs call clobbered. ordinary function may use them without restoring contents. interrupt service routines (isrs) must save , restore each register use.

    ...

call-saved registers

  • r2–r17, r28, r29

    the remaining gprs call-saved, i.e. function uses such registers must restore original content. applies if register used pass function argument.

what follows speculation on why compiler performs apparently unnecessary register save/restores in isr prologue/epilogue:

  • r0 , r1 saved/restored because code compiler generates or calls make assumptions outlined them above. since aren't tracked gcc's register allocator, prologue must make sure they're saved (and in r1's case initialized 0).

  • r28 , r29 used save stack pointer (0x3d/spl , 0x3e/sph). i'm guessing (and want stress guess) compiler writers assume might common interrupt handler swap stacks, , makes sure isr can restore stack in use when interrupt occurred. compiler can assume these registers won't altered called functions since "call-saved" registers.

also, should note apparently "extra" push & pop of r0 save sreg status register on stack. though r0 isn't used between push , pop instructions, remember r0 register scratch register isn't tracked register allocator, compiler won't assume r0 not have changed after loads sreg it.

as side note, reads of 0x3d , 0x3e spl , sph stack pointer registers, not eimsk , gpior0 registers. see note 4 of register summary table on page 625 in reference manual here detail on how register addressing differs when using in/out instructions instead of load or store instruction.

and bonus points regarding gpior0:

8.5.1 general purpose i/o registers

the atmega48a/pa/88a/pa/168a/pa/328/p contains 3 general purpose i/o registers. these registers can used storing information, , particularly useful storing global variables , status flags. general purpose i/o registers within address range 0x00 - 0x1f directly bit-accessible using sbi, cbi, sbis, , sbic instructions.


Comments

Popular posts from this blog

c++ - OpenCV Error: Assertion failed <scn == 3 ::scn == 4> in unknown function, -

php - render data via PDO::FETCH_FUNC vs loop -

The canvas has been tainted by cross-origin data in chrome only -