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).