title: Why might a C++ compiler duplicate a function exit basic block?
body: <p>Consider the following snippet of code:</p>
  
  <pre><code>int* find_ptr(int* mem, int sz, int val) {
      for (int i = 0; i &lt; sz; i++) {
          if (mem[i] == val) { 
              return &amp;mem[i];
          }
      }
      return nullptr;
  }
  </code></pre>
  
  <p><a href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,lang:c%2B%2B,source:&#39;int*+find_ptr(int*+mem,+int+sz,+int+val)+%7B%0A++++for+(int+i+%3D+0%3B+i+%3C+sz%3B+i%2B%2B)+%7B%0A++++++++if+(mem%5Bi%5D+%3D%3D+val)+%7B+%0A++++++++++++return+%26mem%5Bi%5D%3B%0A++++++++%7D%0A++++%7D%0A++++return+nullptr%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50.83717387205933,l:&#39;4&#39;,m:100,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:gsnapshot,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;),lang:c%2B%2B,libs:!((name:boost,ver:&#39;169&#39;)),options:&#39;-O3+-march%3Dnative&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+gcc+(trunk)+(Editor+%231,+Compiler+%231)+C%2B%2B&#39;,t:&#39;0&#39;)),k:49.162826127940676,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4" rel="noreferrer">GCC on -O3</a> compiles this to:</p>
  
  <pre><code>find_ptr(int*, int, int):
          mov     rax, rdi
          test    esi, esi
          jle     .L4                  # why not .L8?
          lea     ecx, [rsi-1]
          lea     rcx, [rdi+4+rcx*4]
          jmp     .L3
  .L9:
          add     rax, 4
          cmp     rax, rcx
          je      .L8
  .L3:
          cmp     DWORD PTR [rax], edx
          jne     .L9
          ret
  .L8:
          xor     eax, eax
          ret
  .L4:
          xor     eax, eax
          ret
  </code></pre>
  
  <p>In this assembly, the blocks with labels <code>.L4</code> and <code>.L8</code> are identical. Would it not be better to rewrite jumps to <code>.L4</code> to <code>.L8</code> and drop <code>.L4</code>? I thought this might be a bug, but <a href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,lang:c%2B%2B,source:&#39;int*+find_ptr(int*+mem,+int+sz,+int+val)+%7B%0A++++for+(int+i+%3D+0%3B+i+%3C+sz%3B+i%2B%2B)+%7B%0A++++++++if+(mem%5Bi%5D+%3D%3D+val)+%7B+%0A++++++++++++return+%26mem%5Bi%5D%3B%0A++++++++%7D%0A++++%7D%0A++++return+nullptr%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50.83717387205933,l:&#39;4&#39;,m:100,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:clang_trunk,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;),lang:c%2B%2B,libs:!((name:boost,ver:&#39;169&#39;)),options:&#39;-O3+-march%3Dnative&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+clang+(trunk)+(Editor+%231,+Compiler+%231)+C%2B%2B&#39;,t:&#39;0&#39;)),k:49.162826127940676,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4" rel="noreferrer">clang</a> <em>also</em> duplicates the <code>xor</code>-<code>ret</code> sequence back to back. However, <a href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,lang:c%2B%2B,source:&#39;int*+find_ptr(int*+mem,+int+sz,+int+val)+%7B%0A++++for+(int+i+%3D+0%3B+i+%3C+sz%3B+i%2B%2B)+%7B%0A++++++++if+(mem%5Bi%5D+%3D%3D+val)+%7B+%0A++++++++++++return+%26mem%5Bi%5D%3B%0A++++++++%7D%0A++++%7D%0A++++return+nullptr%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50.83717387205933,l:&#39;4&#39;,m:100,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:icc191,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;),lang:c%2B%2B,libs:!((name:boost,ver:&#39;169&#39;)),options:&#39;-O3+-march%3Dnative&#39;,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x86-64+icc+19.0.1+(Editor+%231,+Compiler+%231)+C%2B%2B&#39;,t:&#39;0&#39;)),k:49.162826127940676,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4" rel="noreferrer">ICC</a> and <a href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,lang:c%2B%2B,source:&#39;int*+find_ptr(int*+mem,+int+sz,+int+val)+%7B%0A++++for+(int+i+%3D+0%3B+i+%3C+sz%3B+i%2B%2B)+%7B%0A++++++++if+(mem%5Bi%5D+%3D%3D+val)+%7B+%0A++++++++++++return+%26mem%5Bi%5D%3B%0A++++++++%7D%0A++++%7D%0A++++return+nullptr%3B%0A%7D&#39;),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;C%2B%2B+source+%231&#39;,t:&#39;0&#39;)),k:50.83717387205933,l:&#39;4&#39;,m:100,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;),(g:!((h:compiler,i:(compiler:vcpp_v19_20_x64,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;),lang:c%2B%2B,libs:!((name:boost,ver:&#39;169&#39;)),options:/O2,source:1),l:&#39;5&#39;,n:&#39;0&#39;,o:&#39;x64+msvc+v19.20+(Editor+%231,+Compiler+%231)+C%2B%2B&#39;,t:&#39;0&#39;)),k:49.162826127940676,l:&#39;4&#39;,n:&#39;0&#39;,o:&#39;&#39;,s:0,t:&#39;0&#39;)),l:&#39;2&#39;,n:&#39;0&#39;,o:&#39;&#39;,t:&#39;0&#39;)),version:4" rel="noreferrer">MSVC</a> each take a pretty different approach.</p>
  
  <p>Is this an optimization in this case and, if not, are there times when it <em>would</em> be? What is the rationale behind this behavior?</p>