[cfe-users] ARM fast interrupt handlers

Sven Köhler sven.koehler at gmail.com
Mon Mar 2 09:39:51 PST 2015


Hi,

clang/llvm 3.5 was generating bad assembly code for FIQ interrupt
handlers when optimization was enabled. Now with llvm 3.6 the generated
assembly seems to be working, but it's somewhat suboptimal.

If this is not the right place to discuss, please let me know what might
be a better place.

First consider this C-code:

int* global;

__attribute__((interrupt("IRQ")))
void irq() {
  *global++ = 1;
}

__attribute__((interrupt("FIQ")))
void fiq() {
  *global++ = 1;
}

I'm generating the assembly like this:
clang --target=armv7-linux-gnu -mfloat-abi=hard -O2 -S

With llvm 3.5.0 I got severely broken code for fiq():

fiq:
	movw	r8, :lower16:global
	subs	pc, lr, #4
	movt	r8, :upper16:global
	ldr	r9, [r8]
	add	r10, r9, #4
	str	r10, [r8]
	mov	r8, #1
	str	r8, [r9]

The jump that exits the function basically was "optimized" to the
beginning of the function. The resulting could would basically not do
anything. With -O0, the generated assembly was fine.

Now with llvm 3.6.0, the code is a bit more "lengthy" but correct:

fiq:
	push	{r11}
	mov	r11, sp
	sub	sp, sp, #4
	bfc	sp, #0, #3
	movw	r8, :lower16:global
	movt	r8, :upper16:global
	ldr	r9, [r8]
	add	r10, r9, #4
	str	r10, [r8]
	mov	r8, #1
	str	r8, [r9]
	mov	sp, r11
	pop	{r11}
	subs	pc, lr, #4

For some reason, clang sets up the frame pointer register (r11). All of
the code busy with managing r11 could be omitted. Not sure what the bfc
command does. Does it try to round down sp to a multiple of four? Even
though the stack has already been used by the push? Push probably
doesn't support unaligned access. And sp is actually never ever used.

The assembly generated for irq() is somewhat similar. Only the assembly
generated for normal() doesn't bother about r11 and looks quite optimal.

I tried using -fomit-frame-pointer, but it didn't improve the assembly.


Any ideas what's going on?


Regards,
  Sven




More information about the cfe-users mailing list