Internalize linkonce_odr more often.
Since there is a copy in every translation unit that uses them, they can
be omitted from the symbol table if the address is not significant.
This still doesn't catch as many cases as the gold plugin. The
difference is that we check canBeOmittedFromSymbolTable in each file and
use lazy loading which limits what it can do. Gold checks it in the merged file.
I think the correct way of getting the same results as gold is just to
cache in the IR the result of canBeOmittedFromSymbolTable.
llvm-svn: 267063
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 71d7a58..bccbddf 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -12,6 +12,7 @@
#include "InputSection.h"
#include "Symbols.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/Analysis.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Object/IRObjectFile.h"
@@ -498,8 +499,11 @@
Body = new (Alloc) DefinedBitcode(NameRef, IsWeak, Visibility);
}
// FIXME: Expose a thread-local flag for module asm symbols.
- if (GV && GV->isThreadLocal())
- Body->Type = STT_TLS;
+ if (GV) {
+ if (GV->isThreadLocal())
+ Body->Type = STT_TLS;
+ Body->CanOmitFromDynSym = canBeOmittedFromSymbolTable(GV);
+ }
return Body;
}
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 747161e..e6f8842 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -109,6 +109,7 @@
K == DefinedSyntheticKind || K == UndefinedElfKind;
CanKeepUndefined = false;
MustBeInDynSym = false;
+ CanOmitFromDynSym = false;
NeedsCopyOrPltAddr = false;
}
@@ -241,6 +242,9 @@
if (IsUsedInRegularObj || Other->IsUsedInRegularObj)
IsUsedInRegularObj = Other->IsUsedInRegularObj = true;
+ if (!CanOmitFromDynSym || !Other->CanOmitFromDynSym)
+ CanOmitFromDynSym = Other->CanOmitFromDynSym = false;
+
if (L != R)
return -1;
if (!isDefined() || isShared() || isWeak())
@@ -360,7 +364,9 @@
uint8_t V = getVisibility();
if (V != STV_DEFAULT && V != STV_PROTECTED)
return false;
- return Config->ExportDynamic || Config->Shared;
+ if (!Config->ExportDynamic && !Config->Shared)
+ return false;
+ return !CanOmitFromDynSym;
}
template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 11fcdcb..da2ab59 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -147,6 +147,12 @@
unsigned IsUsedInRegularObj : 1;
public:
+ // True if this symbol can be omitted from the symbol table if nothing else
+ // requires it to be there. Right now this is only used for linkonce_odr in
+ // LTO, but we could add the feature to ELF. It would be similar to
+ // MachO's .weak_def_can_be_hidden.
+ unsigned CanOmitFromDynSym : 1;
+
// If true, the symbol is added to .dynsym symbol table.
unsigned MustBeInDynSym : 1;
diff --git a/lld/test/ELF/lto/Inputs/internalize-exportdyn.ll b/lld/test/ELF/lto/Inputs/internalize-exportdyn.ll
new file mode 100644
index 0000000..21ac358
--- /dev/null
+++ b/lld/test/ELF/lto/Inputs/internalize-exportdyn.ll
@@ -0,0 +1,6 @@
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define weak_odr void @bah() {
+ ret void
+}
diff --git a/lld/test/ELF/lto/internalize-exportdyn.ll b/lld/test/ELF/lto/internalize-exportdyn.ll
index fd70812..4a71289 100644
--- a/lld/test/ELF/lto/internalize-exportdyn.ll
+++ b/lld/test/ELF/lto/internalize-exportdyn.ll
@@ -1,6 +1,7 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
-; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 --export-dynamic -save-temps
+; RUN: llvm-as %p/Inputs/internalize-exportdyn.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t2 --export-dynamic -save-temps
; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
target triple = "x86_64-unknown-linux-gnu"
@@ -18,7 +19,24 @@
ret void
}
-; Check that _start and foo are not internalized, but bar is.
+define linkonce_odr void @zed() unnamed_addr {
+ ret void
+}
+
+define linkonce_odr void @bah() {
+ ret void
+}
+
+define linkonce_odr void @baz() {
+ ret void
+}
+
+@use_baz = global void ()* @baz
+
+; Check what gets internalized.
; CHECK: define void @_start()
; CHECK: define void @foo()
; CHECK: define internal void @bar()
+; CHECK: define internal void @zed()
+; CHECK: define weak_odr void @bah()
+; CHECK: define weak_odr void @baz()