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

    <tr>
        <th>Summary</th>
        <td>
            (When) does Clang respect noinline, and how?
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang
      </td>
    </tr>

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

    <tr>
      <th>Reporter</th>
      <td>
          higher-performance
      </td>
    </tr>
</table>

<pre>
    This issue appears to exist with GCC and MSVC as well, but (in my various attempts) Clang appears to be the least willing to respect noinline.

Consider this code:
```
#include <utility>

#if defined(_MSC_VER)
#define NOINLINE [[msvc::noinline]]
#elif defined(__clang__)
#define NOINLINE [[gnu::noinline]]
#elif defined(__GNUC__)
#define NOINLINE [[gnu::noinline]]
#else
#error unable to prevent inlining
#endif

using R = int;
using P = R*;

NOINLINE        R bar1(P arg);
NOINLINE        R bar2(P arg) { return arg ? 1 : 0; }
NOINLINE static R bar3(P arg) { return arg ? 1 : 0; }

R foo1(int x) { return (x ? 0 : bar1(&x)); }
R foo2(int x) { return (x ? 0 : bar2(&x)); }
R foo3(int x) { return (x ? 0 : bar3(&x)); }
```
In this code, all the `fooN` are equivalent, and:
- Must contain calls to `barN` because all `barN` are noinline (mandatory)
- Should result in identical codegen (optional, but preferable)

Instead, [what I see](https://godbolt.org/z/G9zjYY1fe) is:
- With the exception of `foo2` & `foo3` on MSVC, no pair of `fooN` result in identical codegen on any compiler
- None of the compilers produce a `call` instruction in `foo3`, implying that `noinline` isn't guaranteeing the generation of a new stack frame
- Clang is the only compiler that **completely elides** any reference to any `barN` (see `foo3`), making the `noinline` function disappear entirely in some cases.

```
Clang               │ GCC                  │ MSVC
━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━
foo1:               │ foo1:                │ foo1:
  push rax          │   sub  rsp, 24       │   mov  [rsp+8], ecx
  mov  [rsp+4], edi │   xor  eax, eax      │   sub  rsp, 40
  xor  eax, eax     │   mov  [rsp+12], edi │   test ecx, ecx
  test edi, edi     │   test edi, edi      │   je   LABEL
  je   LABEL        │   je   LABEL         │   xor  eax, eax
  pop  rcx          │   add  rsp, 24       │   add  rsp, 40
  ret               │   ret                │   ret  0
LABEL:              │ LABEL:               │ LABEL:
  lea  rdi, [rsp+4] │   lea  rdi, [rsp+12] │   lea  rcx, [rsp]
  call bar1@PLT     │   call bar1          │   call bar1
  pop  rcx          │   add  rsp, 24       │   add  rsp, 40
  ret               │   ret                │   ret  0
────────────────────┼──────────────────────┼────────────────────
foo2:               │ foo2:                │ foo2:
  xor  eax, eax     │   test edi, edi      │   test ecx, ecx
  test edi, edi     │   jne  LABEL         │   je   LABEL
  je   LABEL        │   sub  rsp, 8        │   xor  eax, eax
  ret               │   lea  rdi, [rsp+4]  │   ret  0
LABEL:              │   call bar2          │ LABEL:
  push rax          │   add  rsp, 8        │   lea  rcx, [rsp]
  lea  rdi, [rsp+4] │   ret                │   jmp  bar2
  call bar2         │ LABEL:               │
  add  rsp, 8       │   xor  eax, eax      │
  ret               │   ret                │
────────────────────┼──────────────────────┼────────────────────
foo3:               │ foo3:                │ foo3:
  xor  eax, eax     │   test edi, edi      │   test ecx, ecx
  test edi, edi     │   jne  LABEL         │   je   LABEL
  sete al           │   lea  rdi, [rsp-4]  │   xor  eax, eax
  ret               │   jmp  bar2          │   ret  0
                    │ LABEL:               │ LABEL:
                    │   xor  eax, eax      │   lea  rcx, [rsp]
                    │   ret                │   jmp  bar3
```

Note that I haven't tried LTO yet, but I imagine that would produce interesting results as well.

This made me wonder:
- What _are_ the precise semantics of `noinline`? i.e. what guarantee(s) can users actually rely on when using `noinline`, if any?
- Are these behaviors bugs, or intended behavior?
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWV1v27gS_TX0yyCBRNmx_OAH2Y2LAGm2SHt3sU8BJY0tZilSl6Qce3_9BSn5W3bc3ZcGvUKAyJzh0RyScygNmTF8IRHHZDAhg089VttC6XHBFwXqmwr1XOmSyQx7qcrX4-8FN8CNqRFYVSHTBqwCXHFj4Y3bAj5Pp8BkDl--_T4FZuANhSB0CmltgdCYSyjXsGSaq9oAsxbLyhpCRzAVTC72QVMEWyAIZB5bCC4Xrl2jqTCzIBWXgku8JUFCgmSqpOE5arAuxEzlSCLXTu6C9i9ICI24zESdI5BoWlsuuF2T6L5BcNY55DjnEnNC45cv36Yvv98_EzpqrI0Jnn57eHp8eLoHP2ST0iwz96go2UREBp_cn--D4hDzJXM8X17eAV3I-gcwPz_9Z_pvIQ22d1orDbVkqUA33JXGJUoLvg-Xi9ZL5nzeDFtt3MQ8A4k-AZeWRJNt41ff-Exo0rSSINkG1V7PkDIdEhp_BaYXjoL37HSje25AhhPQaGstXQuQaAYhkCiBgEQTIMNP-yjGMsuzBiX6URQSJM8wVyr069fC6qgjofHK9wx8z5YPoXfOsWHUInkYejUMvQQTXQ0TnYHZz4wHuZc3dApMCJ995C6YK_VE7gJgGgH_W_MlEyitd5J5k2M38KU2FjIlLeMSMiaET2FyF6RM-94pZqw26IH3mh3oZj260Esmc2aVXjeL-Qa-FaoWuUv6WrhFCDxHaXnGhI91gZ6xqixXkm2VptI4R-2WcJsUjqGxyHLnQQaTt4JZeACDPgtoXFhbGUeGzgidLVSeKmFvlVsks78JnX0e_f3655_h3OEBNxvafzjJc-OEqwx9DKDm7aBRx4_Qu_Zn5H4q6YXRBSEVVIzrnb8fj0s8lQQm15CpsuICtQ_gSUl0EC6GjcFApVVeZwjMQbvZcNBcGqvrzAfJ5V5ULhpeVmLtBdYNDLkLtiLhehpJ6NDComaaSYvYOCIsUKJmG9oMJL65VMv-grlmJfoIG13nxndQUuwItM-iCaGJaxNoUawBBc_RNM2esJ9LlJmXI9ewt34IjQ3iAZmR41OyvzZBHpGZ17IZg5ybZrcBN9DaPZpLMKpEyJhB0-4r-1nScDm8yD0loz6Jqd_6Tq6d2U98kGwawo93M5n9FGH84nSCxO9FUXJ2pXXbTx1IkABUtSlAs1WXH4CpUwBtKpdTtN_hUKolOEH1PpPYq-kUMFt58ENrf2PN-QHGSmkAZCtv20RyLop-4JG7-pyPK6RnHm3RWB_tXtBNW843_sfQXfYDh1cEgMdkcv_o8XY_u0b41HppbJopUxWAzs5MGcvzy1O279COpkZ7drF0WU_NDqehfLzwdq7d9g4HH5NABqCbYT5YQgcP7_Ty093h1sxz6-ZffcG_rDTvbP3g6-P3E3Zbezf5XfefeWY2jcHHu5lMf4owfnE6ftOh72w6HfZTh6vU-12J_Se6_SrxktL-kGrv70hxl0OXbl_O5fN698_UdqdN9F2tvfwSsC9LnWTPq-t1Iv6OjL2WFTTfw_uCTS-QOgfmAbroXP868i9V-f9i_BPdfFA6Xoyjd8S4w37q8FHE2KBFYOJMvp2KzM2pbv64IG9l50KWNy9pp9f1knQoxJeQrvhQOi_El4GvFODouJ4eJE_KYlPIeYCCLbGpFFnNMYfH77_BGu2mKPcAvGQLLlv_N1_Y25SquLSo0VguF20RzGyOD9pCjD96KFmOUCK8KZmj3pbhHN4L0_jiKz6VxowbBIMlk5Znpi2y7ZWBSDQDfou34AuB28IWobE_jMiYhNqgNsAyWzMh1uALRErCW4HO5uI8gqRT4HNgck2imQ8r0f4IwyCkWLAlV9pAWi-M81TaU5Y55lsriWa9fBzlo2jEejgOh_0w7AfBYNgrxqPwLg0xDvvBqD8cYr8_zNIgDCIWxCwcsrjHxzSggyAKBgF1fW4jRvtxTONRlKcDZDnpB1gyLm6FWJa3Si96_hxnHNJRHA56gqUojD8GotQfUhDqPqN6euw63PjA-4HgxpodhOVW4JjQ-I_CTf0IcoWmrfkdH9S0JWMo1JtjWmsxPiq7clvU6W2mSkJn7hHtv5tKq1fMLKEzH7IhdNZGvRzT_wUAAP__uT-uIg">