https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127388
Bug ID: 127388
Summary: armv8-m.main prefers to spill r4 to the stack; rather
than use r12
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: david.c.mcgarry at gmail dot com
Target Milestone: ---
gcc -march=armv8-m.main -mthumb -Os will not use r12 for a simple ldr/orr/str
sequence.
GCC will push/pop r4 preferring thumb instructions; even though it's 2 extra
instructions and 2 bytes longer. Clang does the right thing.
While the trunk version at godbolt.org appears to actually pop r4, the version
I'm using (.pico-sdk/toolchain/13_2_Rel1/bin/arm-none-eabi-gcc) used a 4 byte
"f85d 4b04 ldr.w r4, [sp], #4". Regardless of pop or ldr.w, it shouldn't be
using the stack at all in this example.
https://www.godbolt.org/z/qGeGPqjG9
#include <string.h>
#include <stdint.h>
struct Test
{
uintptr_t ptr;
void set_bit()
{
ptr |= 1;
}
void set_bit_r12()
{
register uintptr_t r12 __asm__("r12") = ptr;
asm volatile("" : "+r"(r12));
r12 |= 1;
asm volatile("" : "+r"(r12));
ptr = r12;
}
};
__attribute__((used))
void write(char* dst, const char* src, size_t len, Test& test)
{
test.set_bit();
memcpy(dst, src, len);
}
__attribute__((used))
void write_r12(char* dst, const char* src, size_t len, Test& test)
{
test.set_bit_r12();
memcpy(dst, src, len);
}
This compiles to:
write(char*, char const*, unsigned int, Test&):
push {r4}
ldr r4, [r3]
orr r4, r4, #1
str r4, [r3]
pop {r4}
b memcpy
write_r12(char*, char const*, unsigned int, Test&):
ldr ip, [r3]
orr ip, ip, #1
str ip, [r3]
b memcpy