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