Compiling the following program with -target arm-eabi -mcpu=cortex-m23 -O2
struct S { int a; }; extern struct S *test8_u(); extern int test8_g(int, int, int); extern int test8_h(int); void test8(int (*fn)(int, int, int), int x) { struct S *p = test8_u(); test8_g(p->a, test8_h(0), 0); p->a = x; fn(1, 2, 3); }
results in internal compiler error ran out of registers during register allocation.
We have the function pointer spilled on the stack. When the compiler tries to load
it into a register, it creates a virtual register of class tGPR, which is the operand
class of the destination operand in the load instruction. This virtual register, though,
is also used by a TCRETURN instruction, which requires register class tcGPR, so
the destination of the load becomes tcGPR_and_tGPR. However,
Thumb1InstrInfo::loadRegFromStackSlot accepts only the tGPR register
class. The latter function server to emit a tLDRspi instruction and certainly any
subset of the tGPR register class is a valid destination of the load.
(The class tcGPR_and_tGPR can be also a result of register coalescing).