Closed as not planned
Closed as not planned
Description
Given
a.cpp:
export module a;
and
b.cpp:
import a;
Then after compiling with
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:
import bounded;
In my compiler explorer output I see
_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