<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">