aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/LTO/LTO.cpp
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2022-11-16 22:13:22 -0800
committerFangrui Song <i@maskray.me>2022-11-16 22:13:22 -0800
commit12050a3fb7344694cfd7527d4cca0033729bcfc5 (patch)
tree3278d6ea0f7b86f2a041a7ad3713ef6e0e6a6e8e /llvm/lib/LTO/LTO.cpp
parent2c239da6913dc7cb0710577c8e6b8e71cc1833c6 (diff)
downloadllvm-12050a3fb7344694cfd7527d4cca0033729bcfc5.zip
llvm-12050a3fb7344694cfd7527d4cca0033729bcfc5.tar.gz
llvm-12050a3fb7344694cfd7527d4cca0033729bcfc5.tar.bz2
[LTO] Make local linkage GlobalValue in non-prevailing COMDAT available_externally
For a local linkage GlobalObject in a non-prevailing COMDAT, it remains defined while its leader has been made available_externally. This violates the COMDAT rule that its members must be retained or discarded as a unit. To fix this, update the regular LTO change D34803 to track local linkage GlobalValues, and port the code to ThinLTO (GlobalAliases are not handled.) This fixes two problems. (a) `__cxx_global_var_init` in a non-prevailing COMDAT group used to linger around (unreferenced, hence benign), and is now correctly discarded. ``` int foo(); inline int v = foo(); ``` (b) Fix https://github.com/llvm/llvm-project/issues/58215: as a size optimization, we place private `__profd_` in a COMDAT with a `__profc_` key. When FuncImport.cpp makes `__profc_` available_externally due to a non-prevailing COMDAT, `__profd_` incorrectly remains private. This change makes the `__profd_` available_externally. ``` cat > c.h <<'eof' extern void bar(); inline __attribute__((noinline)) void foo() {} eof cat > m1.cc <<'eof' #include "c.h" int main() { bar(); foo(); } eof cat > m2.cc <<'eof' #include "c.h" __attribute__((noinline)) void bar() { foo(); } eof clang -O2 -fprofile-generate=./t m1.cc m2.cc -flto -fuse-ld=lld -o t_gen rm -fr t && ./t_gen && llvm-profdata show -function=foo t/default_*.profraw clang -O2 -fprofile-generate=./t m1.cc m2.cc -flto=thin -fuse-ld=lld -o t_gen rm -fr t && ./t_gen && llvm-profdata show -function=foo t/default_*.profraw ``` If a GlobalAlias references a GlobalValue which is just changed to available_externally, change the GlobalAlias as well (e.g. C5/D5 comdats due to cc1 -mconstructor-aliases). The GlobalAlias may be referenced by other available_externally functions, so it cannot easily be removed. Depends on D137441: we use available_externally to mark a GlobalAlias in a non-prevailing COMDAT, similar to how we handle GlobalVariable/Function. GlobalAlias may refer to a ConstantExpr, not changing GlobalAlias to GlobalVariable gives flexibility for future extensions (the use case is niche. For simplicity we don't handle it yet). In addition, available_externally GlobalAlias is the most straightforward implementation and retains the aliasee information to help optimizers. See windows-vftable.ll: Windows vftable uses an alias pointing to a private constant where the alias is the COMDAT leader. The COMDAT use case is skeptical and ThinLTO does not discard the alias in the non-prevailing COMDAT. This patch retains the behavior. See new tests ctor-dtor-alias2.ll: depending on whether the complete object destructor emitted, when ctor/dtor aliases are used, we may see D0/D2 COMDATs in one TU and D0/D1/D2 in a D5 COMDAT in another TU. Allow such a mix-and-match with `if (GO->getComdat()->getName() == GO->getName()) NonPrevailingComdats.insert(GO->getComdat());` GlobalAlias handling in ThinLTO is still weird, but this patch should hopefully improve the situation for at least all cases I can think of. Reviewed By: tejohnson Differential Revision: https://reviews.llvm.org/D135427
Diffstat (limited to 'llvm/lib/LTO/LTO.cpp')
-rw-r--r--llvm/lib/LTO/LTO.cpp10
1 files changed, 5 insertions, 5 deletions
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index d3f29a6..9bfbabc 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -712,11 +712,11 @@ handleNonPrevailingComdat(GlobalValue &GV,
if (!NonPrevailingComdats.count(C))
return;
- // Additionally need to drop externally visible global values from the comdat
- // to available_externally, so that there aren't multiply defined linker
- // errors.
- if (!GV.hasLocalLinkage())
- GV.setLinkage(GlobalValue::AvailableExternallyLinkage);
+ // Additionally need to drop all global values from the comdat to
+ // available_externally, to satisfy the COMDAT requirement that all members
+ // are discarded as a unit. The non-local linkage global values avoid
+ // duplicate definition linker errors.
+ GV.setLinkage(GlobalValue::AvailableExternallyLinkage);
if (auto GO = dyn_cast<GlobalObject>(&GV))
GO->setComdat(nullptr);