https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94703
Bug ID: 94703
Summary: Small-sized memcpy leading to unnecessary register
spillage unless done through a dummy union
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: pskocik at gmail dot com
Target Milestone: ---
The problem, demonstrated in code examples below, can be suppressed by
memcpying into a union (possibly just a one-member union), but that seems like
a silly workaround that shouldn't be required.
Examples:
#include <stdint.h>
#include <string.h>
uint64_t get4_1(void const *X)
{
//spills
uint64_t r = 0; memcpy(&r,X,4); return r;
}
uint64_t get4_nospill(void const *X)
{
//doesn't spill
union { uint64_t u64; } u = {0};
memcpy(&u.u64,X,sizeof(uint32_t));
return u.u64;
}
uint64_t get2_1(void const *X)
{
//spills
uint64_t r = 0; memcpy(&r,X,2); return r;
}
uint64_t get2_nospill(void const *X)
{
//doesn't spill
union { uint64_t u64; } u = {0};
memcpy(&u.u64,X,sizeof(uint16_t));
return u.u64;
}
void backend(void const*Src, size_t Sz);
static inline void valInPtrInl(void *Src, size_t Sz)
{
if(Sz<=sizeof(void const*)){
#if 1 //spills
void const*inlSrc;
memcpy(&inlSrc,Src,Sz);
backend(inlSrc,Sz); return;
#else
//doesn't spill
union{ void const*inlSrc; } u;
memcpy(&u.inlSrc,Src,Sz);
backend(u.inlSrc,Sz); return;
#endif
}
backend(Src,Sz);
return;
}
void valInPtr(int X) { valInPtrInl(&X,sizeof(X)); }
GCC 9.3 output on x86_64:
get4_1:
mov QWORD PTR [rsp-8], 0
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsp-8], eax
mov rax, QWORD PTR [rsp-8]
ret
get4_nospill:
mov eax, DWORD PTR [rdi]
ret
get2_1:
mov QWORD PTR [rsp-8], 0
movzx eax, WORD PTR [rdi]
mov WORD PTR [rsp-8], ax
mov rax, QWORD PTR [rsp-8]
ret
get2_nospill:
xor eax, eax
mov ax, WORD PTR [rdi]
ret
valInPtr:
mov DWORD PTR [rsp-16], edi
mov rdi, QWORD PTR [rsp-16]
mov esi, 4
jmp backend
Clang 3.1 output on x86_64:
get4_1: # @get4_1
mov EAX, DWORD PTR [RDI]
ret
get4_nospill: # @get4_nospill
mov EAX, DWORD PTR [RDI]
ret
get2_1: # @get2_1
movzx EAX, WORD PTR [RDI]
ret
get2_nospill: # @get2_nospill
movzx EAX, WORD PTR [RDI]
ret
valInPtr: # @valInPtr
mov EDI, EDI
mov ESI, 4
jmp backend # TAILCALL
https://gcc.godbolt.org/z/rwq2UY