llvm.org GIT mirror llvm / 7e667c5
Use LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN instead of the "dso list". There are two ways one could implement hiding of linkonce_odr symbols in LTO: * LLVM tells the linker which symbols can be hidden if not used from native files. * The linker tells LLVM which symbols are not used from other object files, but will be put in the dso symbol table if present. GOLD's API is the second option. It was implemented almost 1:1 in llvm by passing the list down to internalize. LLVM already had partial support for the first option. It is also very similar to how ld64 handles hiding these symbols when *not* doing LTO. This patch then * removes the APIs for the DSO list. * marks LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN all linkonce_odr unnamed_addr global values and other linkonce_odr whose address is not used. * makes the gold plugin responsible for handling the API mismatch. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193800 91177308-0d34-0410-b5e6-96231b3b80d8 Rafael Espindola 6 years ago
15 changed file(s) with 131 addition(s) and 165 deletion(s). Raw diff Collapse all Expand all
7272
7373 void addMustPreserveSymbol(const char *sym) { MustPreserveSymbols[sym] = 1; }
7474
75 void addDSOSymbol(const char* Sym) {
76 DSOSymbols[Sym] = 1;
77 }
78
7975 // To pass options to the driver and optimization passes. These options are
8076 // not necessarily for debugging purpose (The function name is misleading).
8177 // This function should be called before LTOCodeGenerator::compilexxx(),
129125 void applyScopeRestrictions();
130126 void applyRestriction(llvm::GlobalValue &GV,
131127 std::vector &MustPreserveList,
132 std::vector &SymtabList,
133128 llvm::SmallPtrSet &AsmUsed,
134129 llvm::Mangler &Mangler);
135130 bool determineTarget(std::string &errMsg);
142137 bool EmitDwarfDebugInfo;
143138 bool ScopeRestrictionsDone;
144139 lto_codegen_model CodeModel;
145 StringSet DSOSymbols;
146140 StringSet MustPreserveSymbols;
147141 StringSet AsmUndefinedRefs;
148142 llvm::MemoryBuffer *NativeObjectFile;
110110 /// The symbol in DSOList are internalized if it is safe to drop them from
111111 /// the symbol table.
112112 ///
113 /// For example of the difference, consider a dynamic library being built from
114 /// two translation units. The first one compiled to a native object
115 /// (ELF/MachO/COFF) and second one compiled to IL. Translation unit A has a
116 /// copy of linkonce_odr unnamed_addr function F. The translation unit B has a
117 /// copy of the linkonce_odr unnamed_addr functions F and G.
118 ///
119 /// Assume the linker decides to keep the copy of F in B. This means that LLVM
120 /// must produce F in the object file it passes to the linker, otherwise we
121 /// will have an undefined reference. For G the situation is different. The
122 /// linker puts the function in the DSOList, since it is only wanted for the
123 /// symbol table. With this information internalize can now reason that since
124 /// the function is a linkonce_odr and its address is not important, it can be
125 /// omitted. Any other shared library needing this function will have a copy of
126 /// it.
127 ///
128113 /// Note that commandline options that are used with the above function are not
129114 /// used now!
130 ModulePass *createInternalizePass(ArrayRef ExportList,
131 ArrayRef DSOList);
115 ModulePass *createInternalizePass(ArrayRef ExportList);
132116 /// createInternalizePass - Same as above, but with an empty exportList.
133117 ModulePass *createInternalizePass();
134118
269269 extern void
270270 lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol);
271271
272
273 /**
274 * Tells LTO optimization passes that a dynamic shared library is being
275 * built and this symbol may be exported. Unless IR semantics allow the symbol
276 * to be made local to the library, it should remain so it can be exported by
277 * the shared library.
278 */
279 extern void lto_codegen_add_dso_symbol(lto_code_gen_t cg, const char *symbol);
280
281272 /**
282273 * Writes a new object file at the specified path that contains the
283274 * merged contents of all modules added so far.
312312 void LTOCodeGenerator::
313313 applyRestriction(GlobalValue &GV,
314314 std::vector &MustPreserveList,
315 std::vector &DSOList,
316315 SmallPtrSet &AsmUsed,
317316 Mangler &Mangler) {
318317 SmallString<64> Buffer;
322321 return;
323322 if (MustPreserveSymbols.count(Buffer))
324323 MustPreserveList.push_back(GV.getName().data());
325 if (DSOSymbols.count(Buffer))
326 DSOList.push_back(GV.getName().data());
327324 if (AsmUndefinedRefs.count(Buffer))
328325 AsmUsed.insert(&GV);
329326 }
351348 // mark which symbols can not be internalized
352349 Mangler Mangler(TargetMach);
353350 std::vector MustPreserveList;
354 std::vector DSOList;
355351 SmallPtrSet AsmUsed;
356352
357353 for (Module::iterator f = mergedModule->begin(),
358354 e = mergedModule->end(); f != e; ++f)
359 applyRestriction(*f, MustPreserveList, DSOList, AsmUsed, Mangler);
355 applyRestriction(*f, MustPreserveList, AsmUsed, Mangler);
360356 for (Module::global_iterator v = mergedModule->global_begin(),
361357 e = mergedModule->global_end(); v != e; ++v)
362 applyRestriction(*v, MustPreserveList, DSOList, AsmUsed, Mangler);
358 applyRestriction(*v, MustPreserveList, AsmUsed, Mangler);
363359 for (Module::alias_iterator a = mergedModule->alias_begin(),
364360 e = mergedModule->alias_end(); a != e; ++a)
365 applyRestriction(*a, MustPreserveList, DSOList, AsmUsed, Mangler);
361 applyRestriction(*a, MustPreserveList, AsmUsed, Mangler);
366362
367363 GlobalVariable *LLVMCompilerUsed =
368364 mergedModule->getGlobalVariable("llvm.compiler.used");
390386 LLVMCompilerUsed->setSection("llvm.metadata");
391387 }
392388
393 passes.add(createInternalizePass(MustPreserveList, DSOList));
389 passes.add(createInternalizePass(MustPreserveList));
394390
395391 // apply scope restrictions
396392 passes.run(*mergedModule);
3737 #include "llvm/Support/TargetSelect.h"
3838 #include "llvm/Support/system_error.h"
3939 #include "llvm/Target/TargetRegisterInfo.h"
40 #include "llvm/Transforms/Utils/GlobalStatus.h"
4041 using namespace llvm;
4142
4243 LTOModule::LTOModule(llvm::Module *m, llvm::TargetMachine *t)
161162
162163 TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr,
163164 options);
165 m->MaterializeAllPermanently();
166
164167 LTOModule *Ret = new LTOModule(m.take(), target);
165168 if (Ret->parseSymbols(errMsg)) {
166169 delete Ret;
332335 addDefinedSymbol(f, true);
333336 }
334337
338 static bool canBeHidden(const GlobalValue *GV) {
339 GlobalValue::LinkageTypes L = GV->getLinkage();
340
341 if (L == GlobalValue::LinkOnceODRAutoHideLinkage)
342 return true;
343
344 if (L != GlobalValue::LinkOnceODRLinkage)
345 return false;
346
347 if (GV->hasUnnamedAddr())
348 return true;
349
350 GlobalStatus GS;
351 if (GlobalStatus::analyzeGlobal(GV, GS))
352 return false;
353
354 return !GS.IsCompared;
355 }
356
335357 /// addDefinedSymbol - Add a defined symbol to the list.
336358 void LTOModule::addDefinedSymbol(const GlobalValue *def, bool isFunction) {
337359 // ignore all llvm.* symbols
371393 attr |= LTO_SYMBOL_SCOPE_HIDDEN;
372394 else if (def->hasProtectedVisibility())
373395 attr |= LTO_SYMBOL_SCOPE_PROTECTED;
396 else if (canBeHidden(def))
397 attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN;
374398 else if (def->hasExternalLinkage() || def->hasWeakLinkage() ||
375399 def->hasLinkOnceLinkage() || def->hasCommonLinkage() ||
376400 def->hasLinkerPrivateWeakLinkage())
377401 attr |= LTO_SYMBOL_SCOPE_DEFAULT;
378 else if (def->hasLinkOnceODRAutoHideLinkage())
379 attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN;
380402 else
381403 attr |= LTO_SYMBOL_SCOPE_INTERNAL;
382404
9797 std::vector Export;
9898 if (AllButMain)
9999 Export.push_back("main");
100 unwrap(PM)->add(createInternalizePass(Export, None));
100 unwrap(PM)->add(createInternalizePass(Export));
101101 }
102102
103103 void LLVMAddStripDeadPrototypesPass(LLVMPassManagerRef PM) {
1010 // If the function or variable is not in the list of external names given to
1111 // the pass it is marked as internal.
1212 //
13 // This transformation would not be legal or profitable in a regular
14 // compilation, but it gets extra information from the linker about what is safe
15 // or profitable.
16 //
17 // As an example of a normally illegal transformation: Internalizing a function
18 // with external linkage. Only if we are told it is only used from within this
19 // module, it is safe to do it.
20 //
21 // On the profitability side: It is always legal to internalize a linkonce_odr
22 // whose address is not used. Doing so normally would introduce code bloat, but
23 // if we are told by the linker that the only use of this would be for a
24 // DSO symbol table, it is profitable to hide it.
13 // This transformation would not be legal in a regular compilation, but it gets
14 // extra information from the linker about what is safe.
15 //
16 // For example: Internalizing a function with external linkage. Only if we are
17 // told it is only used from within this module, it is safe to do it.
2518 //
2619 //===----------------------------------------------------------------------===//
2720
5750 cl::desc("A list of symbol names to preserve"),
5851 cl::CommaSeparated);
5952
60 static cl::list
61 DSOList("internalize-dso-list", cl::value_desc("list"),
62 cl::desc("A list of symbol names need for a dso symbol table"),
63 cl::CommaSeparated);
64
6553 namespace {
6654 class InternalizePass : public ModulePass {
6755 std::set ExternalNames;
68 std::set DSONames;
6956 public:
7057 static char ID; // Pass identification, replacement for typeid
7158 explicit InternalizePass();
72 explicit InternalizePass(ArrayRef ExportList,
73 ArrayRef DSOList);
59 explicit InternalizePass(ArrayRef ExportList);
7460 void LoadFile(const char *Filename);
7561 virtual bool runOnModule(Module &M);
7662
9177 if (!APIFile.empty()) // If a filename is specified, use it.
9278 LoadFile(APIFile.c_str());
9379 ExternalNames.insert(APIList.begin(), APIList.end());
94 DSONames.insert(DSOList.begin(), DSOList.end());
95 }
96
97 InternalizePass::InternalizePass(ArrayRef ExportList,
98 ArrayRef DSOList)
80 }
81
82 InternalizePass::InternalizePass(ArrayRef ExportList)
9983 : ModulePass(ID){
10084 initializeInternalizePassPass(*PassRegistry::getPassRegistry());
10185 for(ArrayRef::const_iterator itr = ExportList.begin();
10286 itr != ExportList.end(); itr++) {
10387 ExternalNames.insert(*itr);
104 }
105 for(ArrayRef::const_iterator itr = DSOList.begin();
106 itr != DSOList.end(); itr++) {
107 DSONames.insert(*itr);
10888 }
10989 }
11090
125105 }
126106
127107 static bool shouldInternalize(const GlobalValue &GV,
128 const std::set &ExternalNames,
129 const std::set &DSONames) {
108 const std::set &ExternalNames) {
130109 // Function must be defined here
131110 if (GV.isDeclaration())
132111 return false;
143122 if (ExternalNames.count(GV.getName()))
144123 return false;
145124
146 // Not needed for the symbol table?
147 if (!DSONames.count(GV.getName()))
148 return true;
149
150 // Not a linkonce. Someone can depend on it being on the symbol table.
151 if (!GV.hasLinkOnceLinkage())
152 return false;
153
154 // The address is not important, we can hide it.
155 if (GV.hasUnnamedAddr())
156 return true;
157
158 GlobalStatus GS;
159 if (GlobalStatus::analyzeGlobal(&GV, GS))
160 return false;
161
162 return !GS.IsCompared;
125 return true;
163126 }
164127
165128 bool InternalizePass::runOnModule(Module &M) {
188151 // Mark all functions not in the api as internal.
189152 // FIXME: maybe use private linkage?
190153 for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
191 if (!shouldInternalize(*I, ExternalNames, DSONames))
154 if (!shouldInternalize(*I, ExternalNames))
192155 continue;
193156
194157 I->setLinkage(GlobalValue::InternalLinkage);
225188 // FIXME: maybe use private linkage?
226189 for (Module::global_iterator I = M.global_begin(), E = M.global_end();
227190 I != E; ++I) {
228 if (!shouldInternalize(*I, ExternalNames, DSONames))
191 if (!shouldInternalize(*I, ExternalNames))
229192 continue;
230193
231194 I->setLinkage(GlobalValue::InternalLinkage);
237200 // Mark all aliases that are not in the api as internal as well.
238201 for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
239202 I != E; ++I) {
240 if (!shouldInternalize(*I, ExternalNames, DSONames))
203 if (!shouldInternalize(*I, ExternalNames))
241204 continue;
242205
243206 I->setLinkage(GlobalValue::InternalLinkage);
253216 return new InternalizePass();
254217 }
255218
256 ModulePass *llvm::createInternalizePass(ArrayRef ExportList,
257 ArrayRef DSOList) {
258 return new InternalizePass(ExportList, DSOList);
259 }
219 ModulePass *llvm::createInternalizePass(ArrayRef ExportList) {
220 return new InternalizePass(ExportList);
221 }
276276 // for a main function. If main is defined, mark all other functions
277277 // internal.
278278 if (Internalize)
279 PM.add(createInternalizePass("main", None));
279 PM.add(createInternalizePass("main"));
280280
281281 // Propagate constants at call sites into the functions they call. This
282282 // opens opportunities for globalopt (and inlining) by substituting function
0 ; RUN: llvm-as < %s >%t1
1 ; RUN: llvm-lto -o %t2 -dso-symbol=foo1 -dso-symbol=foo2 -dso-symbol=foo3 \
2 ; RUN: -dso-symbol=foo4 %t1 -disable-opt
3 ; RUN: llvm-nm %t2 | FileCheck %s
4
5 ; CHECK: t foo1
6 define linkonce_odr void @foo1() noinline {
7 ret void
8 }
9
10 ; CHECK: W foo2
11 define linkonce_odr void @foo2() noinline {
12 ret void
13 }
14
15 ; CHECK: t foo3
16 define linkonce_odr void @foo3() noinline {
17 ret void
18 }
19
20 ; CHECK: W foo4
21 define linkonce_odr void @foo4() noinline {
22 ret void
23 }
24
25 declare void @f(void()*)
26
27 declare void @p()
28
29 define void @bar() {
30 bb0:
31 call void @foo1()
32 call void @f(void()* @foo2)
33 invoke void @foo3() to label %bb1 unwind label %clean
34 bb1:
35 invoke void @f(void()* @foo4) to label %bb2 unwind label %clean
36 bb2:
37 ret void
38 clean:
39 landingpad {i32, i32} personality void()* @p cleanup
40 ret void
41 }
+0
-37
test/Transforms/Internalize/linkonce_odr_func.ll less more
None ; RUN: opt < %s -internalize -internalize-dso-list foo1,foo2,foo3,foo4 -S | FileCheck %s
1
2 ; CHECK: define internal void @foo1(
3 define linkonce_odr void @foo1() noinline {
4 ret void
5 }
6
7 ; CHECK: define linkonce_odr void @foo2(
8 define linkonce_odr void @foo2() noinline {
9 ret void
10 }
11
12 ; CHECK: define internal void @foo3(
13 define linkonce_odr void @foo3() noinline {
14 ret void
15 }
16
17 ; CHECK: define linkonce_odr void @foo4(
18 define linkonce_odr void @foo4() noinline {
19 ret void
20 }
21
22 declare void @f(void()*)
23
24 define void @bar() {
25 bb0:
26 call void @foo1()
27 call void @f(void()* @foo2)
28 invoke void @foo3() to label %bb1 unwind label %clean
29 bb1:
30 invoke void @f(void()* @foo4) to label %bb2 unwind label %clean
31 bb2:
32 ret void
33 clean:
34 landingpad i32 personality i8* null cleanup
35 ret void
36 }
1212 ; -file and -list options should be merged, the apifile contains foo and j
1313 ; RUN: opt < %s -internalize -internalize-public-api-list bar -internalize-public-api-file %S/apifile -S | FileCheck --check-prefix=FOO_J_AND_BAR %s
1414
15 ; Put zed1 and zed2 in the symbol table. If the address is not relevant, we
16 ; internalize them.
17 ; RUN: opt < %s -internalize -internalize-dso-list zed1,zed2,zed3 -S | FileCheck --check-prefix=ZEDS %s
18
1915 ; ALL: @i = internal global
2016 ; FOO_AND_J: @i = internal global
2117 ; FOO_AND_BAR: @i = internal global
2723 ; FOO_AND_BAR: @j = internal global
2824 ; FOO_J_AND_BAR: @j = global
2925 @j = global i32 0
30
31 ; ZEDS: @zed1 = internal global i32 42
32 @zed1 = linkonce_odr global i32 42
33
34 ; ZEDS: @zed2 = internal unnamed_addr global i32 42
35 @zed2 = linkonce_odr unnamed_addr global i32 42
36
37 ; ZEDS: @zed3 = linkonce_odr global i32 42
38 @zed3 = linkonce_odr global i32 42
39 define i32* @get_zed3() {
40 ret i32* @zed3
41 }
4226
4327 ; ALL: define internal void @main() {
4428 ; FOO_AND_J: define internal void @main() {
1414 #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
1515 #include "plugin-api.h"
1616 #include "llvm-c/lto.h"
17 #include "llvm/ADT/StringSet.h"
1718 #include "llvm/ADT/OwningPtr.h"
1819 #include "llvm/Support/Errno.h"
1920 #include "llvm/Support/FileSystem.h"
6667 std::list Modules;
6768 std::vector Cleanup;
6869 lto_code_gen_t code_gen = NULL;
70 StringSet<> CannotBeHidden;
6971 }
7072
7173 namespace options {
296298 sym.version = NULL;
297299
298300 int scope = attrs & LTO_SYMBOL_SCOPE_MASK;
301 bool CanBeHidden = scope == LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN;
302 if (!CanBeHidden)
303 CannotBeHidden.insert(sym.name);
299304 switch (scope) {
300305 case LTO_SYMBOL_SCOPE_HIDDEN:
301306 sym.visibility = LDPV_HIDDEN;
305310 break;
306311 case 0: // extern
307312 case LTO_SYMBOL_SCOPE_DEFAULT:
313 case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN:
308314 sym.visibility = LDPV_DEFAULT;
309315 break;
310316 default:
361367 lto_module_dispose(M);
362368
363369 return LDPS_OK;
370 }
371
372 static bool mustPreserve(const claimed_file &F, int i) {
373 if (F.syms[i].resolution == LDPR_PREVAILING_DEF)
374 return true;
375 if (F.syms[i].resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
376 return CannotBeHidden.count(F.syms[i].name);
377 return false;
364378 }
365379
366380 /// all_symbols_read_hook - gold informs us that all symbols have been read.
385399 continue;
386400 (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]);
387401 for (unsigned i = 0, e = I->syms.size(); i != e; i++) {
388 if (I->syms[i].resolution == LDPR_PREVAILING_DEF) {
402 if (mustPreserve(*I, i)) {
389403 lto_codegen_add_must_preserve_symbol(code_gen, I->syms[i].name);
390404
391405 if (options::generate_api_file)
392406 api_file << I->syms[i].name << "\n";
393 } else if (I->syms[i].resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) {
394 lto_codegen_add_dso_symbol(code_gen, I->syms[i].name);
395
396 if (options::generate_api_file)
397 api_file << I->syms[i].name << " dso only\n";
398407 }
399408 }
400409 }
1111 //
1212 //===----------------------------------------------------------------------===//
1313
14 #include "llvm/ADT/StringSet.h"
1415 #include "llvm/CodeGen/CommandFlags.h"
1516 #include "llvm/LTO/LTOCodeGenerator.h"
1617 #include "llvm/LTO/LTOModule.h"
5354 DSOSymbols("dso-symbol",
5455 cl::desc("Symbol to put in the symtab in the resulting dso"),
5556 cl::ZeroOrMore);
57
58 namespace {
59 struct ModuleInfo {
60 std::vector CanBeHidden;
61 };
62 }
5663
5764 int main(int argc, char **argv) {
5865 // Print a stack trace if we signal out.
98105 CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
99106 CodeGen.setTargetOptions(Options);
100107
108 llvm::StringSet DSOSymbolsSet;
109 for (unsigned i = 0; i < DSOSymbols.size(); ++i)
110 DSOSymbolsSet.insert(DSOSymbols[i]);
111
112 std::vector KeptDSOSyms;
113
101114 for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {
102115 std::string error;
103116 OwningPtr Module(LTOModule::makeLTOModule(InputFilenames[i].c_str(),
114127 << "': " << error << "\n";
115128 return 1;
116129 }
130
131 unsigned NumSyms = Module->getSymbolCount();
132 for (unsigned I = 0; I < NumSyms; ++I) {
133 StringRef Name = Module->getSymbolName(I);
134 if (!DSOSymbolsSet.count(Name))
135 continue;
136 lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);
137 unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
138 if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
139 KeptDSOSyms.push_back(Name);
140 }
117141 }
118142
119143 // Add all the exported symbols to the table of symbols to preserve.
121145 CodeGen.addMustPreserveSymbol(ExportedSymbols[i].c_str());
122146
123147 // Add all the dso symbols to the table of symbols to expose.
124 for (unsigned i = 0; i < DSOSymbols.size(); ++i)
125 CodeGen.addDSOSymbol(DSOSymbols[i].c_str());
148 for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
149 CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str());
126150
127151 if (!OutputFilename.empty()) {
128152 size_t len = 0;
259259 cg->addMustPreserveSymbol(symbol);
260260 }
261261
262 void lto_codegen_add_dso_symbol(lto_code_gen_t cg, const char *symbol) {
263 cg->addDSOSymbol(symbol);
264 }
265
266262 /// lto_codegen_write_merged_modules - Writes a new file at the specified path
267263 /// that contains the merged contents of all modules added so far. Returns true
268264 /// on error (check lto_get_error_message() for details).
1414 lto_module_is_object_file_in_memory
1515 lto_module_is_object_file_in_memory_for_target
1616 lto_module_dispose
17 lto_codegen_add_dso_symbol
1817 lto_codegen_add_module
1918 lto_codegen_add_must_preserve_symbol
2019 lto_codegen_compile