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 inr1
'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
Post a Comment