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...
--
Summary: ARM : poor register allocation around inline assembler
Product: gcc
Version: 4.0.2
Status: UNCONFIRMED
Severity: enhancement
Priority: P3
Component: inline-asm
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: armcc2000 at yahoo dot com
GCC host triplet: i686-host_pc-linux-gnu
GCC target triplet: arm-9tdmi-linux-gnu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24751