From 4d480ed5451e9af88e84bcf8be62f8befa915bed Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 21 Apr 2016 21:44:25 +0000 Subject: [PATCH] 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 --- lld/ELF/InputFiles.cpp | 8 +++++-- lld/ELF/Symbols.cpp | 8 ++++++- lld/ELF/Symbols.h | 6 +++++ .../ELF/lto/Inputs/internalize-exportdyn.ll | 6 +++++ lld/test/ELF/lto/internalize-exportdyn.ll | 22 +++++++++++++++++-- 5 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 lld/test/ELF/lto/Inputs/internalize-exportdyn.ll diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 71d7a5855837..bccbddf50585 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 @@ BitcodeFile::createSymbolBody(const DenseSet &KeptComdats, 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 747161efe8be..e6f8842b80d3 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -109,6 +109,7 @@ void SymbolBody::init() { K == DefinedSyntheticKind || K == UndefinedElfKind; CanKeepUndefined = false; MustBeInDynSym = false; + CanOmitFromDynSym = false; NeedsCopyOrPltAddr = false; } @@ -241,6 +242,9 @@ int SymbolBody::compare(SymbolBody *Other) { 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 @@ bool SymbolBody::includeInDynsym() const { 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(uint32_t) const; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 11fcdcb5a45a..da2ab59a72ce 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -147,6 +147,12 @@ protected: 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 000000000000..21ac3580762c --- /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 fd70812fef76..4a71289c68ff 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 @@ define hidden void @bar() { 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()