RFC: Speeding up small ISRs: PR20296

Georg-Johann Lay <[email protected]> Thu, 15 Jun 2017 14:43:54 +0200
Newsgroups gmane.comp.hardware.avr.gcc
Message-ID <[email protected]>
https://gcc.gnu.org/PR20296

is about speeding up "small" ISRs, and is open for 12 years now...

Anyone familiar with avr-gcc knows that a fix would be high effort and 
risk, and that's the major reason for why PR20296 is still open (and 
even classified "suspended").

In some forum discussion (again!) on that issue, there was the following 
proposal to approach that PR:

1) Let GCC emit directives / pseudo-instructions in non-naked ISR 
prologue / epilogue

2) Let GAS scan the code and replace the directives with code as needed.

Currently,

#include <avr/io.h>
#include <avr/interrupt.h>

ISR (INT0_vect)
{
     __asm ("; Code");
}

emit something like:


__vector_1:
	push r1
	push r0
	in r0,__SREG__
	push r0
	clr __zero_reg__
.L__stack_usage = 3

	; Code

	pop r0
	out __SREG__,r0
	pop r0
	pop r1
	reti


which would change to:


__vector_1:
	.maybe_isr_prologue 123
	;; Rest of prologue

	; Code

	;; Rest of epilogue
	.maybe_isr_epilogue 123
	reti

GAS would then scan the code associated to the function and replace the 
.maybe by appropriate sequence to safe / init / restore tmp-reg, 
zero-reg and SREG.  Other registers like R24 are handled by GCC as 
usual.  For example, if the scan reveals that tmp-reg is not needed but 
zero-reg is (which will imply SREG due to the CLR) the replacement code 
would be:


__vector_1:
	push r1
	in r1,__SREG__
	push r1
	clr __zero_reg__

	; Code

	pop r1
	out __SREG__,r1
	pop r1
	reti


Maybe someone is interested in implementing the GAS part, and if that is 
the case and the proposal is feasible, I would take care of the GCC part.

Caveats:

a) .L__stack_usage can no more be computed by GCC

b) It's hard to find the end of the relevant code.  We might have 
interleaved sections (like with dispatch tables), there might be code 
that is emit after the epilogue, there might be more than 1 epilogue, 
dunno if GAS can infer whether JMP is local or non-local.

We could add a new GCC pass that filters out situations that are 
pointless to scan like code with dispatch tables or function calls, and 
fall back to classical prologue / epilogue in such cases.

The .maybe gets function-unique identifiers (123 in the example) so that 
GAS knows which epilogue belongs to which .prologue provided that's helpful.

I am not familiar with Binutils / GAS though and don't know if it's easy 
to add the 2 new passes: One to scan and one to replace the .maybe with 
appropriate code.  IIUC GAS only works on sections, and the scan would 
be on BFD internal representation (like relaxing) after the parser read 
in the asm sources?

The GCC change would add a new option, configure test whether GAS 
supports this, let ISR prologue and epilogue emit new unspec_volatile 
pseudo insns and add a scan pass to detect situations that are pointless 
should fall back to old code, like when dispatch tables, calls or 
non-local goto is seen.


Johann