title: clang: export symbols of implicitly instantiated functions with O3
body: <p>TL,DR: <strong>How can I force clang to export the symbols of implicitly instantiated functions even when -O3 is active?</strong></p>
  
  <p>Let's take the following code:</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;llvm/Support/DynamicLibrary.h&gt;
  #include &lt;llvm/ExecutionEngine/ExecutionEngine.h&gt;
  #include &lt;llvm/ExecutionEngine/RTDyldMemoryManager.h&gt;
  
  template &lt;typename T&gt;
  __attribute__((noinline))
  int twice(const T&amp; t) {
      return t * 2;
  }
  
  int thrice(const int&amp; t) {
      return t * 3;
  }
  
  int main() {
      std::cout &lt;&lt; twice(5) &lt;&lt; std::endl;
      std::cout &lt;&lt; thrice(5) &lt;&lt; std::endl;
  
      llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);  // Make symbols from current process visible
      std::cout &lt;&lt; "address of twice: " &lt;&lt; llvm::RTDyldMemoryManager::getSymbolAddressInProcess("__Z5twiceIiEiRKT_") &lt;&lt; std::endl;
      std::cout &lt;&lt; "address of thrice: " &lt;&lt; llvm::RTDyldMemoryManager::getSymbolAddressInProcess("__Z6thriceRKi") &lt;&lt; std::endl;
  }
  </code></pre>
  
  <p>There are two functions, twice and thrice. The first is templated, the second is not. I first call them regularly, then I try to get their address using libLLVM. Think of it as part of a super simplified JIT compiler (that has a mangler that comes up with the name).</p>
  
  <p>With <code>clang++ -O0 -I/usr/local/opt/llvm/include -L/usr/local/opt/llvm/lib/ jit.cpp -lLLVM</code> (clang version 6.0.0 on OS X), the output is as expected:</p>
  
  <pre><code>10
  15
  address of twice: 4350763184
  address of thrice: 4350762224
  </code></pre>
  
  <p>If I enable optimization, the symbol for <code>twice</code> does not get exported anymore, as seen in <code>nm a.out | grep twice</code>:</p>
  
  <pre><code>00000001000010b0 T __Z5twiceIiEiRKT_ (with -O0)
  00000001000009c0 t __Z5twiceIiEiRKT_ (with -O3)
  </code></pre>
  
  <p>As a result, libLLVM does not find the function anymore:</p>
  
  <pre><code>10
  15
  address of twice: 0
  address of thrice: 4315621072
  </code></pre>
  
  <p>With gcc, the symbols get exported.</p>
  
  <p>I can get clang to export the symbol if I explicitly instantiate it:</p>
  
  <pre><code>template int twice&lt;int&gt;(const int&amp; t);
  </code></pre>
  
  <p>That, however, is not really an option, as we don't know which instantiations will be called by the JIT engine.</p>
  
  <p>I am aware of <a href="https://stackoverflow.com/questions/45247906/why-are-only-some-of-these-c-template-instantiations-exported-in-a-shared-libr">this post</a>, but it only deals with explicit instantiations.</p>