https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79716
Bug ID: 79716 Summary: memset followed by overwrite not eliminated Product: gcc Version: 7.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org Target Milestone: --- The following two functions represent a common programming pattern of initializing a dynamically allocated object by allocating storage, clearing it, and then proceeding to write data into all or most of it. The clearing is often done with large data structures "just in case" the subsequent assignments do not set all the data members. GCC transforms both functions into a call calloc to allocate and clear the storage in one step, followed by either a call to memcpy or assignments to the individual members. In both functions, however, clearing all the allocated memory is unnecessary and inefficient because it immediately gets overwritten. When all or most of the allocated storage is written into it would be more efficient to just malloc the memory and then call memcpy or assign to it, and call memset to clear (or assign zero to) only the members that aren't explicitly written into. Clang 5.0 emits optimal code for both functions. $ cat t.c && gcc -O2 -S -Wall -Wextra -Wpedantic -Wunused-result -fdump-tree-optimized=/dev/stdout t.c #include <stdlib.h> #include <string.h> void* f (const char *s, size_t n) { char *p = malloc (n); memset (p, 0, n); memcpy (p, s, n); return p; } struct S { int a, b, c, d; }; void* g (void) { struct S *p = malloc (sizeof (struct S)); memset (p, 0, sizeof (struct S)); p->a = 1; p->b = 2; p->c = 3; p->d = 4; return p; } ;; Function f (f, funcdef_no=22, decl_uid=2738, cgraph_uid=22, symbol_order=22) f (const char * s, size_t n) { char * p; <bb 2> [100.00%]: p_4 = __builtin_calloc (n_2(D), 1); memcpy (p_4, s_6(D), n_2(D)); return p_4; } ;; Function g (g, funcdef_no=23, decl_uid=2747, cgraph_uid=23, symbol_order=23) g () { struct S * p; <bb 2> [100.00%]: p_3 = __builtin_calloc (16, 1); MEM[(int *)p_3] = 8589934593; MEM[(int *)p_3 + 8B] = 17179869187; return p_3; }