<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/67582>67582</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[C++20][Modules] Missed optimization: Unnecessary code emitted for empty module initializers
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
davidstone
</td>
</tr>
</table>
<pre>
Given
```cpp
export module a;
```
and
```cpp
import a;
```
Then after compiling with
```cmd
clang++ -std=c++20 -O3 -x c++-module -fmodule-output=a.pcm --precompile -c a.cpp
clang++ -std=c++20 -O3 -fmodule-file=a=a.pcm -S b.cpp -emit-llvm
```
We end up with the generated code for `b` as:
```
; ModuleID = '/home/david/test/b.cpp'
source_filename = "/home/david/test/b.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_b.cpp, ptr null }]
declare void @_ZGIW1a() local_unnamed_addr
; Function Attrs: uwtable
define internal void @_GLOBAL__sub_I_b.cpp() #0 section ".text.startup" {
entry:
tail call void @_ZGIW1a()
ret void
}
attributes #0 = { uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
!llvm.linker.options = !{}
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{!"clang version 18.0.0 (https://github.com/llvm/llvm-project.git cd7f1714dea16261e0362b80958296f9782d625e)"}
```
The module initializer for `a` is empty, yet we still do a tail call to it. I would expect there to be no reference to the initializer of module `a` anywhere in the generated code for `b`.
It actually seems to be significantly worse than this. For instance, in my local compiler explorer instance I have an umbrella module `bounded` that imports various sub-modules. I see an unnecessary initializer of the umbrella module (which internally has unnecessary initializers for all its imports), and then I see unnecessary initializers of all of those sub-modules:
```cpp
import bounded;
```
In my compiler explorer output I see
```asm
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
push rax
call initializer for module bounded@PLT
call initializer for module bounded.arithmetic.operators@PLT
call initializer for module bounded.arithmetic.operators_builtin@PLT
call initializer for module bounded.arithmetic.round_up_divide@PLT
call initializer for module bounded.abs@PLT
call initializer for module bounded.builtin_min_max_value@PLT
call initializer for module bounded.cast@PLT
call initializer for module bounded.check_in_range@PLT
call initializer for module bounded.clamp@PLT
call initializer for module bounded.comparison@PLT
call initializer for module bounded.comparison_builtin@PLT
call initializer for module bounded.construct@PLT
call initializer for module bounded.construct_at@PLT
call initializer for module bounded.copy@PLT
call initializer for module bounded.hash@PLT
call initializer for module bounded.integer@PLT
call initializer for module bounded.integer_tombstone_traits@PLT
call initializer for module bounded.is_bounded_integer@PLT
call initializer for module bounded.lazy_init@PLT
call initializer for module bounded.literal@PLT
call initializer for module bounded.log@PLT
call initializer for module bounded.minmax@PLT
call initializer for module bounded.normalize@PLT
call initializer for module bounded.number_of@PLT
call initializer for module bounded.pow@PLT
call initializer for module bounded.representation_digits@PLT
call initializer for module bounded.size_of@PLT
call initializer for module bounded.std_iterator@PLT
call initializer for module bounded.stream@PLT
pop rax
jmp initializer for module bounded.to_integer@PLT # TAILCALL
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJysWF9vo7oS_zTui0UEJn_IQx6a5mZVqatzpLNXR7ovyOAh-KyxkT3kz376KxtIk2671REbtWDw_H6eGY89Y7hz8qABNmSxJYvdA--wNnYj-FEKh0bDQ2HEZfNFHkGTeEfix-G6jPu_sm37N3BujUXaGNEpoJyk2zeSt3Cuxa_ZZBPYPqH5VoOmvEKwtDRNK5XUB3qSWL9P3gyDlorrA2FbwrY0cihIuiv7RxbT6I-URmc6vIgGe6Kqb0Smw7ZDku74rC0bGkWthX5soFFJ-exqwuejjJyVVOAZX1n_ooUnohE0EiOljs0vvPA3UNCCdm0wnWIN9AAaLEcQtDQCaGUsJcu4IMuYckfSx3f9MzymW_o16PW8oyTdUcJWhO1r0wBh-xAYhO0RHBK2D1p6gQB1prMl5N4czRsY0OwzNOvRyO0BkAqOXPGL6XDEQ9SQ9BGilq1ikj6mLFz8Y3L_6FvLebhEcmxUmQclLIt05hvLEbOcR38lLHs7PlrZqqvu52yZL-dRp79rc9KRkro7RwfdXVHDdR77SZodlCm4yks01gUK3raghQ_LvouSxTahZ0pWWypTRtgTbdEON0pWO7LYeZkP-0ckXS4W6eLaMY_zLy9_bB9f8tx1Rf6cD77tu3Wn1EB-q7WAUnEL9GikCBT_-_L8d8KJd8qaKlNylXfaT6XIuRD2zuJ0S_edLlEaTR8RrQ8r2p2QFwpG-kpqoFIjWM3V6zDvahrGJCyNqYOelTA2QzjjzCG32PlI8dYP241Ge7lGMqXIpaIlV-p9a0YxCxgEBiNWd_7giFYWHYLrFQkxsNqOVnmFGqkjBQeuoiP4WY5OUmDtoyHdEcbioCNj2kRoedtKfYgafiOAtoNBxiEvv0etNdgzFV1VgY2c_AFX8WyQ7WMzKtvu2nXOltFyft9fAcfOgrsKEbYtG3Mk7Mm3zlnfqM7O9q2mOfcN5-DaYH3rnK1G9k7D3dhhe5FlPyF3LiQsCQtBSf0d7My0fibdsJoSP3tX-UGy3wNnleKHOzmWxD58CUuS4c6Ge_oThxSg8R48_1mx-EbCr6CRlzB2Kmtu89H17CmssPntOMkbcPYK_vP5ib7AEdQNlt1i2Rvs6hb7n19j04-x42L7ADm_dwhhLGQkegTr_PJKslk8iylhWY3YhqzA9oTtDxLrrpiVpiFsH1JPf_Oh-g-UODtIpKVYVckqmQvgyZItE4jTJSuyeL3I2HpZrVcZE0u2AL_02I1aH2TxsWyQWqLkSv4AOyYt7pOWdBSaFi_e0AsgPQF1KJWiwlB-s_bRUIkz-kxPplOCwrmFEn1GtOD7CqDaUAsVWNBleOWz5e2ophp1Gcfm-nIKBFJ_kltnt1Y9I-UldlypC3UAjRsU8PWWrGTJNaoLPRnrgGLNPbd0M7o3lkrtkOsSwrRq2lz6vXioccB6u5Sx8CpJn2nNj0C5pl1TWFCK35hRmE4LEN4YrDnSvrhy9MitNJ2jriuGOsd53znoibSGEpzj9vLWQ94NP43DslMty_q636sLrbn7iMYFx_k5k-hGjUK0PFGuhR9CD7p8yGCqQBAUMg5u7fioxnlbYI6u-WWZ-Rzm4Gfv97Vgr-W7o3E31G1vUh6cedMqCIkvfaS3P8LSd3LkLWDIZP2v7Vzt75af7zvCcni7nIapGo2ex3--fHsHRuknyBm3EusGUJYz0_rVYKz7zXR50UmFUv8eWutf5V2bC3mUAqaQFlMsHYzKG__Pz_mRq26KNiV3OAVeQ_k9lzq3XB8m6aF4007Bm6blVjozZb5fSX5D8JRGO7RdOcm9I0fOp9G0lwnwmrt6Atzv5wew0xlyNE0RPirkaLnEKetIunxo5tP1U_zHJfcyUzgkguVqCoM5TEA3Ujf8PIFAG9uE3ikcXVOAzU01gaM1pwloC60FBxq5P3jkQh6mxZk_Ekyzx6HIQ2ygmRKjDi3w5j2C1rTh_lMJ8E_Td3zCjOZ-CfU1yLfH55enx5eXNxXNg9ikYp2u-QNskuV6kaWrVTZ_qDccVnESz4sVjxdxCmsmIM5W62UFIo7Lgj3IDYtZGq_ZKsniNE5nrBJ8lQghYF1BtkjIPIaGSzULRzpjDw_SuQ42y9UiYw-KF6Bc-EzJmIYTDZ3-bLHYPdhNOKAU3cHPtZIO3SsLSlTh--bT-PWNLHZksf06VIqLHf0qnQNB_Wm1kT9C6Pi67L83hWeo9aGR6At_78VwHnnn3OIeOqs2_-5IRdg-mOMI2wdz_x8AAP__XgSaCQ">