<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/107298>107298</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Feature request: manual outlining control (pragma to outline a statement)
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          zygoloid
      </td>
    </tr>
</table>

<pre>
    ### Problem

Tracing / logging / checking macros are pretty common, and [some popular modern ones](https://abseil.io/docs/cpp/guides/logging) use an interface such as:

```c++
void f(int n) {
  CHECK(n >= 5) << "n value of " << n << " was too small!";
}
```

The use of such macros is problematic, however, as they can generate quite a lot of code that can block inlining of the enclosing function. C++ gives us a way to sidestep this, by wrapping the expensive part in a lambda, but that doesn't work in this case due to the trailing stream:

```c++
// Can't wrap a lambda around the streaming of the diagnostic.
#define CHECK(cond) \
  if (cond) {} else ::MyLib::CheckFailInDestructor(), ::MyLib::GetCheckFailStream()
```

Similarly to how we provide `[[clang::always_inline]]` to allow manual inlining control, it would be useful to also provide manual outlining control.

### Proposal

Add a pragma:

```c++
#praga clang outline
<statement>
```

Similar to `#pragma clang __debug captured`, this wraps a captured statement around the given substatement, and emits the captured statement as a separate function. The call to the function is marked `noinline`.

### Usage

- For assertion / verbose logging / etc. macros:

```c++
// Can't wrap a lambda around the streaming of the diagnostic.
#define CHECK(cond) \
  if (cond) {} else _Pragma("clang outline") ::MyLib::CheckFailInDestructor(), ::MyLib::GetCheckFailStream()
```

- To manually outline a cold / slow / unlikely path in a function

```c++
inline void MyFunction(int n) {
  DoThing1(n);
  if (!OnHappyPath(n))
  #pragma clang outline
  {
    // expensive stuff
  }
 DoThing2(n);
}
```

### Alternatives

We could instead make the `[[unlikely]]` attribute have this effect whenever possible. However, while branch weights and outlining are related, they're really separate concerns, and any automatic solution will necessarily be imperfect and won't entirely address the desire for manual control.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzUVk-P27YT_TT0ZbCGTa3X9sGHXTv-5Yc2aIBs0eNiRI4kdilS4R-76qcvSElrO02anAoUMHYlzXA4nHnvDdF7VRuiHVs9sdVhhjE01u3-7GurrZKz0sp-x3gx_OCjs6Wmli0ObPE4_H12KJSpgfEjaFvX07NoSLymlxaFsx7QEXSOQuhB2La1hvE9oJHAVk_etgSd7aJGB62V5AxYQ56tDoxvmhA6z4pHxo-MH7H0pPRcWcaP0grP-FF0HePHOipJ6XXMgvEtRE-ABpQJ5CoUBD6KBjBHuzoDe1gMP8H4U_rlryerJFSMb5QJYFI4th5NAPv37_Y_Mb4xwIp3rDjAKjsUe1bsgXFu4IQ6EtgqvU0Gc-UBZ_QQrAXfotaMLxnnrBg3YOvDF6nd1LyhfDRbDQcaS6w8dEODMCiR6tvYM53I5VJ7CA31INBATYYcBoLPUQUCBG1DCiasJAgNhuxVaiteQRmtTOqjrVIAICO09elDFY0Iypo57IeyQa1O5CF6QDhjD8GCTz0J1EFolE9plD2cHXZdCpDD_dGR8epE0KELoEzKBttSYvaOYchHWvKG8XWAs3UpqRwQBHoCGSltlaIFh0qn0D44wvaH2jzACvY4xnfYveUA6Gw0MsceQl5VQiqsjfVBifkUqZBUKUNv6BDWyIyL1X4CjkqAuBjWT2x9ANKeIGVbPH7of1bl8LhPFDqi0v83B_LBRRGsY3zD-DYV52_-_6PwtuTTUIDB-dtI-qRapdHp3KzGnuGcWGpPShIk16QKT0KjqYctUJ-x9y8ZFJTouTqwh0VajFrbM7RoIuoLaIQ1wVmd0lWpd1FLKDN4q6iHZd6-7TiutjHcLp_fdPFajTrrUV9bH6UEhM5h3eIPtr9I3gj5lOPeNNqKvQ8YqCUTEs2_W8d0omQZYrZT0JcXSWWsQWAXoiOZXfYDhBPeEmEmG7zteA2-xCwDPpaXfEb5pFaFTO2vRkiRPXWY2X4h7HN213rizWRJEtKieyWZjmHs2OeHxTc68KvHmq5Nd3C0DtB7cjleYtaJXGk93UwHCmI-ytZ_i6QvHwdoJWLxW8hwPoyAf5_Fd_BsR_LofsonYcpqmcvtEzfTQzRavZLuocPQDGo79f77TRjQAHkufuiP07qvD8iDfW6UqZdpRqbsi6fb4jK-_MW8x67rP2JoJq_pmABfcuiGmHC9U_LN6LjMEh9iVV1cx1k65cS_zOmfp-0F7o86kDMY0pi79viNQGRpU8YHQgktvlKG35uGToW_aCaG4FQZA0GDJxrEgKqKRIBzQybNbeis96rUNIf3l0l-bpQmKB0a0cCZVN0En6XgopvpsuVIYyA5CA31jK_zxwyRN0kQ1ghyxk9qgqYHjMHmGwR4q2Om8VlpDYYEeY9O6T5puGo7cjndtPBsB2aSCcolgKGUjvygTJK8cgSVdZPET8I-k7tCbostzmi3XPPV_Xp7v-GzZlfJ5UO5oQ1WKOTD_RKLh_JB8jVtt7SocDVTO77g94vt4n65XS05n5eLarvhK6pWq4Kvllt2v6AWlZ5rfWrn1tUz5X2k3XKx5tvNTGNJ2ud7L-eGzpCticSrw8zt0qK7Mtae3S-08sFfwgQVNO2OhEltwdHnSD6w4vGb4yvBfcRysFf0vNLy7Sw6vbu96dYqNLGcC9umS60-Tf_uOmd_JxEYP-ac0513PNRpx_8KAAD___0pqbU">