title: Why does GCC aggregate initialization of an array fill the whole thing with zeros first, including non-zero elements?
body: <p>Why does gcc fill the whole array with zeros instead of only the remaining 96 integers?  The non-zero initializers are all at the start of the array.</p>
  
  <pre><code>void *sink;
  void bar() {
      int a[100]{1,2,3,4};
      sink = a;             // a escapes the function
      asm("":::"memory");   // and compiler memory barrier
      // forces the compiler to materialize a[] in memory instead of optimizing away
  }
  </code></pre>
  
  <p>MinGW8.1 and gcc9.2 both make asm like this (<a href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:14,j:1,lang:c%2B%2B,source:&#39;void+ext(int*)%3B%0Avoid+*sink%3B%0Avoid+bar()+%7B%0A++++int+a%5B100%5D%7B1,2,3,4%7D%3B%0A++++sink+%3D+a%3B+++++++++++++//+a+escapes+the+function%0A++++asm(%22%22:::%22memory%22)%3B+++//+compiler+memory+barrier%0A++++//ext(a)%3B++++++++++++//+or+force+init+by+calling+a+non-inline+function%0A%7D%0A%0A%23if+0%0Avoid+foo()+%7B%0A++++//+GCC+reserves+space+for+2+arrays+and+copies!!%0A++++volatile+int+a%5B100%5D%7B1,2,3,4%7D%3B%0A%7D%0A%23endif&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:32.69594732071503,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:g92,filters:(b:&#39;0&#39;,binary:&#39;1&#39;,commentOnly:&#39;0&#39;,demangle:&#39;0&#39;,directives:&#39;0&#39;,execute:&#39;1&#39;,intel:&#39;0&#39;,libraryCode:&#39;1&#39;,trim:&#39;1&#39;),fontScale:14,lang:c%2B%2B,libs:!(),options:&#39;-O3+-m32+-mno-sse+-fverbose-asm&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+gcc+9.2+(Editor+%231,+Compiler+%231)+C%2B%2B&#39;,t:&#39;0&#39;)),header:(),k:33.97071934595164,l:&#39;4&#39;,m:100,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:clang900,filters:(b:&#39;0&#39;,binary:&#39;1&#39;,commentOnly:&#39;0&#39;,demangle:&#39;0&#39;,directives:&#39;0&#39;,execute:&#39;1&#39;,intel:&#39;0&#39;,libraryCode:&#39;1&#39;,trim:&#39;1&#39;),fontScale:14,lang:c%2B%2B,libs:!(),options:&#39;-O3+-m32&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+clang+9.0.0+(Editor+%231,+Compiler+%232)+C%2B%2B&#39;,t:&#39;0&#39;)),k:33.33333333333333,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,m:100,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4" rel="noreferrer"><strong>Godbolt compiler explorer</strong></a>).</p>
  
  <pre><code># gcc9.2 -O3 -m32 -mno-sse
  bar():
      push    edi                       # save call-preserved EDI which rep stos uses
      xor     eax, eax                  # eax=0
      mov     ecx, 100                  # repeat-count = 100
      sub     esp, 400                  # reserve 400 bytes on the stack
      mov     edi, esp                  # dst for rep stos
          mov     DWORD PTR sink, esp       # sink = a
      rep stosd                         # memset(a, 0, 400) 
  
      mov     DWORD PTR [esp], 1        # then store the non-zero initializers
      mov     DWORD PTR [esp+4], 2      # over the zeroed part of the array
      mov     DWORD PTR [esp+8], 3
      mov     DWORD PTR [esp+12], 4
   # memory barrier empty asm statement is here.
  
      add     esp, 400                  # cleanup the stack
      pop     edi                       # and restore caller's EDI
      ret
  </code></pre>
  
  <p>(with SSE enabled it would copy all 4 initializers with movdqa load/store)</p>
  
  <p><strong>Why doesn't GCC do <code>lea edi, [esp+16]</code> and memset (with <code>rep stosd</code>) only the last 96 elements, like Clang does?</strong>  Is this a missed optimization, or is it somehow more efficient to do it this way?  (Clang actually calls <code>memset</code> instead of inlining <code>rep stos</code>)</p>
  
  <hr>
  
  <p>Editor's note: the question originally had un-optimized compiler output which worked the same way, but inefficient code at <code>-O0</code> doesn't prove anything.  But it turns out that this optimization is missed by GCC even at <code>-O3</code>.</p>
  
  <p>Passing a pointer to <code>a</code> to a non-inline function would be another way to force the compiler to materialize <code>a[]</code>, but in 32-bit code that leads to significant clutter of the asm.  (Stack args result in pushes, which gets mixed in with stores to the stack to init the array.)</p>
  
  <p>Using <code>volatile a[100]{1,2,3,4}</code> gets GCC to create and then <em>copy</em> the array, which is insane.  Normally <code>volatile</code> is good for looking at how compilers init local variables or lay them out on the stack.</p>