Bug 24751 - ARM : poor register allocation around inline assembler
Summary: ARM : poor register allocation around inline assembler
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: inline-asm (show other bugs)
Version: 4.0.2
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-11-09 05:07 UTC by Andre
Modified: 2005-11-09 06:08 UTC (History)
1 user (show)

See Also:
Host: i686-host_pc-linux-gnu
Target: arm-9tdmi-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andre 2005-11-09 05:07:25 UTC
The following example comes from ARM linux kernel 2.6.14

------------------------------------------------------------

#define local_irq_enable()					\
	({							\
		unsigned long temp;				\
	__asm__ __volatile__(					\
	"mrs	%0, cpsr		@ local_irq_enable\n"	\
"	bic	%0, %0, #128\n"					\
"	msr	cpsr_c, %0"					\
	: "=r" (temp)						\
	:							\
	: "memory", "cc");					\
	})

------------------------------------------------------------

static int
__do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
{
	unsigned int status;
	int ret, retval = 0;

	spin_unlock(&irq_controller_lock);

	if (!(action->flags & SA_INTERRUPT))
		local_irq_enable();

	status = 0;
	do {
		ret = action->handler(irq, action->dev_id, regs);
		if (ret == IRQ_HANDLED)
			status |= action->flags;
		retval |= ret;
		action = action->next;
	} while (action);

	if (status & SA_SAMPLE_RANDOM)
		add_interrupt_randomness(irq);

	spin_lock_irq(&irq_controller_lock);

	return retval;
}

------------------------------------------------------------

With arm-linux-gcc 4.0.2, this compiles to:

<__do_irq>:
    mov     ip, sp
    stmdb   sp!, {r4, r5, r6, r7, r8, fp, ip, lr, pc}
    sub     fp, ip, #4      ; 0x4
    ldr     r3, [r1, #4]
    mov     r4, r1				<-- Unnecessary
    tst     r3, #536870912  ; 0x20000000
    mov     r7, r0				<-- Unnecessary
    mov     r8, r2				<-- Unnecessary
    bne     1f

    mrs     r3, CPSR				; local_irq_enable
    bic     r3, r3, #128    ; 0x80
    msr     CPSR_c, r3

1:  mov     r6, #0  ; 0x0
    mov     r5, r6
    ldr     r1, [r4, #16]
    mov     r0, r7				<-- Unnecessary
    mov     r2, r8				<-- Unnecessary
    mov     lr, pc
    ....
    ....

ie r0, r1 and r2 are copied to callee-saved registers before the inline assembler (and back again afterwards) as if the inline assember were a function call.

Inline assembler such as this gets used a lot in the linux kernel...
Comment 1 Andrew Pinski 2005-11-09 05:17:34 UTC
Do you have a self contained example?
I think what you are seeing is a different artifact of a different issue.
Comment 2 Andrew Pinski 2005-11-09 05:25:18 UTC
Actually I don't think this is a bug:
    ldr     r1, [r4, #16]   <--- action->dev_id
    mov     r0, r7          <----- irq                  
    mov     r2, r8          <----- regs      
    mov     lr, pc
Call action->handler
This is inside a loop so you have to move the registers for the call all the time, now if we striped out the first iteration, then we would not need to do that.
Comment 3 Andre 2005-11-09 05:56:06 UTC
Yes, I think you're absolutely correct.

You've also just explained a bug I've been staring at all day ;-) Reading  action->dev_id was causing a segfault and I couldn't understand why r0 and r7 in the resulting register dump contained different values... but it must be because the segfault happened on the second time around the loop !!

Thanks... and sorry for the noise.
Comment 4 Ian Lance Taylor 2005-11-09 06:08:56 UTC
Not a bug.