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;

}

Reply via email to