Skip to content

Commit f99573b

Browse files
committedAug 11, 2016
Resolution-based LTO API.
Summary: This introduces a resolution-based LTO API. The main advantage of this API over existing APIs is that it allows the linker to supply a resolution for each symbol in each object, rather than the combined object as a whole. This will become increasingly important for use cases such as ThinLTO which require us to process symbol resolutions in a more complicated way than just adjusting linkage. Patch by Peter Collingbourne. Reviewers: rafael, tejohnson, mehdi_amini Subscribers: lhames, tejohnson, mehdi_amini, llvm-commits Differential Revision: https://reviews.llvm.org/D20268 Address review comments llvm-svn: 278330
1 parent 5c91764 commit f99573b

37 files changed

+2052
-1049
lines changed
 

‎llvm/include/llvm/LTO/Config.h

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
//===-Config.h - LLVM Link Time Optimizer Configuration -------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file defines the lto::Config data structure, which allows clients to
11+
// configure LTO.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_LTO_CONFIG_H
16+
#define LLVM_LTO_CONFIG_H
17+
18+
#include "llvm/IR/DiagnosticInfo.h"
19+
#include "llvm/Target/TargetOptions.h"
20+
21+
#include <functional>
22+
23+
namespace llvm {
24+
25+
class Error;
26+
class Module;
27+
class ModuleSummaryIndex;
28+
class raw_pwrite_stream;
29+
30+
namespace lto {
31+
32+
/// LTO configuration. A linker can configure LTO by setting fields in this data
33+
/// structure and passing it to the lto::LTO constructor.
34+
struct Config {
35+
std::string CPU;
36+
std::string Features;
37+
TargetOptions Options;
38+
std::vector<std::string> MAttrs;
39+
Reloc::Model RelocModel = Reloc::PIC_;
40+
CodeModel::Model CodeModel = CodeModel::Default;
41+
CodeGenOpt::Level CGOptLevel = CodeGenOpt::Default;
42+
unsigned OptLevel = 2;
43+
bool DisableVerify = false;
44+
45+
/// Setting this field will replace target triples in input files with this
46+
/// triple.
47+
std::string OverrideTriple;
48+
49+
/// Setting this field will replace unspecified target triples in input files
50+
/// with this triple.
51+
std::string DefaultTriple;
52+
53+
bool ShouldDiscardValueNames = true;
54+
DiagnosticHandlerFunction DiagHandler;
55+
56+
/// If this field is set, LTO will write input file paths and symbol
57+
/// resolutions here in llvm-lto2 command line flag format. This can be
58+
/// used for testing and for running the LTO pipeline outside of the linker
59+
/// with llvm-lto2.
60+
std::unique_ptr<raw_ostream> ResolutionFile;
61+
62+
/// The following callbacks deal with tasks, which normally represent the
63+
/// entire optimization and code generation pipeline for what will become a
64+
/// single native object file. Each task has a unique identifier between 0 and
65+
/// getMaxTasks()-1, which is supplied to the callback via the Task parameter.
66+
/// A task represents the entire pipeline for ThinLTO and regular
67+
/// (non-parallel) LTO, but a parallel code generation task will be split into
68+
/// N tasks before code generation, where N is the parallelism level.
69+
///
70+
/// LTO may decide to stop processing a task at any time, for example if the
71+
/// module is empty or if a module hook (see below) returns false. For this
72+
/// reason, the client should not expect to receive exactly getMaxTasks()
73+
/// native object files.
74+
75+
/// A module hook may be used by a linker to perform actions during the LTO
76+
/// pipeline. For example, a linker may use this function to implement
77+
/// -save-temps, or to add its own resolved symbols to the module. If this
78+
/// function returns false, any further processing for that task is aborted.
79+
///
80+
/// Module hooks must be thread safe with respect to the linker's internal
81+
/// data structures. A module hook will never be called concurrently from
82+
/// multiple threads with the same task ID, or the same module.
83+
///
84+
/// Note that in out-of-process backend scenarios, none of the hooks will be
85+
/// called for ThinLTO tasks.
86+
typedef std::function<bool(size_t Task, Module &)> ModuleHookFn;
87+
88+
/// This module hook is called after linking (regular LTO) or loading
89+
/// (ThinLTO) the module, before modifying it.
90+
ModuleHookFn PreOptModuleHook;
91+
92+
/// This hook is called after promoting any internal functions
93+
/// (ThinLTO-specific).
94+
ModuleHookFn PostPromoteModuleHook;
95+
96+
/// This hook is called after internalizing the module.
97+
ModuleHookFn PostInternalizeModuleHook;
98+
99+
/// This hook is called after importing from other modules (ThinLTO-specific).
100+
ModuleHookFn PostImportModuleHook;
101+
102+
/// This module hook is called after optimization is complete.
103+
ModuleHookFn PostOptModuleHook;
104+
105+
/// This module hook is called before code generation. It is similar to the
106+
/// PostOptModuleHook, but for parallel code generation it is called after
107+
/// splitting the module.
108+
ModuleHookFn PreCodeGenModuleHook;
109+
110+
/// A combined index hook is called after all per-module indexes have been
111+
/// combined (ThinLTO-specific). It can be used to implement -save-temps for
112+
/// the combined index.
113+
///
114+
/// If this function returns false, any further processing for ThinLTO tasks
115+
/// is aborted.
116+
///
117+
/// It is called regardless of whether the backend is in-process, although it
118+
/// is not called from individual backend processes.
119+
typedef std::function<bool(const ModuleSummaryIndex &Index)>
120+
CombinedIndexHookFn;
121+
CombinedIndexHookFn CombinedIndexHook;
122+
123+
/// This is a convenience function that configures this Config object to write
124+
/// temporary files named after the given OutputFileName for each of the LTO
125+
/// phases to disk. A client can use this function to implement -save-temps.
126+
///
127+
/// FIXME: Temporary files derived from ThinLTO backends are currently named
128+
/// after the input file name, rather than the output file name.
129+
///
130+
/// Specifically, it (1) sets each of the above module hooks and the combined
131+
/// index hook to a function that calls the hook function (if any) that was
132+
/// present in the appropriate field when the addSaveTemps function was
133+
/// called, and writes the module to a bitcode file with a name prefixed by
134+
/// the given output file name, and (2) creates a resolution file whose name
135+
/// is prefixed by the given output file name and sets ResolutionFile to its
136+
/// file handle.
137+
Error addSaveTemps(std::string OutputFileName);
138+
};
139+
140+
/// This type defines a stream callback. A stream callback is used to add a
141+
/// native object that is generated on the fly. The callee must set up and
142+
/// return a output stream to write the native object to.
143+
///
144+
/// Stream callbacks must be thread safe.
145+
typedef std::function<std::unique_ptr<raw_pwrite_stream>(size_t Task)>
146+
AddStreamFn;
147+
148+
/// A derived class of LLVMContext that initializes itself according to a given
149+
/// Config object. The purpose of this class is to tie ownership of the
150+
/// diagnostic handler to the context, as opposed to the Config object (which
151+
/// may be ephemeral).
152+
struct LTOLLVMContext : LLVMContext {
153+
static void funcDiagHandler(const DiagnosticInfo &DI, void *Context) {
154+
auto *Fn = static_cast<DiagnosticHandlerFunction *>(Context);
155+
(*Fn)(DI);
156+
}
157+
158+
LTOLLVMContext(const Config &C) : DiagHandler(C.DiagHandler) {
159+
setDiscardValueNames(C.ShouldDiscardValueNames);
160+
enableDebugTypeODRUniquing();
161+
setDiagnosticHandler(funcDiagHandler, &DiagHandler, true);
162+
}
163+
DiagnosticHandlerFunction DiagHandler;
164+
};
165+
166+
}
167+
}
168+
169+
#endif

‎llvm/include/llvm/LTO/LTO.h

+327-1
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,27 @@
1616
#ifndef LLVM_LTO_LTO_H
1717
#define LLVM_LTO_LTO_H
1818

19+
#include "llvm/ADT/MapVector.h"
1920
#include "llvm/ADT/StringMap.h"
21+
#include "llvm/ADT/StringSet.h"
22+
#include "llvm/CodeGen/Analysis.h"
23+
#include "llvm/IR/DiagnosticInfo.h"
2024
#include "llvm/IR/ModuleSummaryIndex.h"
25+
#include "llvm/LTO/Config.h"
26+
#include "llvm/Linker/IRMover.h"
27+
#include "llvm/Object/IRObjectFile.h"
28+
#include "llvm/Support/thread.h"
29+
#include "llvm/Target/TargetOptions.h"
30+
#include "llvm/Transforms/IPO/FunctionImport.h"
2131

2232
namespace llvm {
2333

34+
class Error;
2435
class LLVMContext;
2536
class MemoryBufferRef;
2637
class Module;
38+
class Target;
39+
class raw_pwrite_stream;
2740

2841
/// Helper to load a module from bitcode.
2942
std::unique_ptr<Module> loadModuleFromBuffer(const MemoryBufferRef &Buffer,
@@ -69,6 +82,319 @@ void thinLTOResolveWeakForLinkerInIndex(
6982
void thinLTOInternalizeAndPromoteInIndex(
7083
ModuleSummaryIndex &Index,
7184
function_ref<bool(StringRef, GlobalValue::GUID)> isExported);
72-
}
85+
86+
namespace lto {
87+
88+
class LTO;
89+
struct SymbolResolution;
90+
class ThinBackendProc;
91+
92+
/// An input file. This is a wrapper for IRObjectFile that exposes only the
93+
/// information that an LTO client should need in order to do symbol resolution.
94+
class InputFile {
95+
// FIXME: Remove LTO class friendship once we have bitcode symbol tables.
96+
friend LTO;
97+
InputFile() = default;
98+
99+
// FIXME: Remove the LLVMContext once we have bitcode symbol tables.
100+
LLVMContext Ctx;
101+
std::unique_ptr<object::IRObjectFile> Obj;
102+
103+
public:
104+
/// Create an InputFile.
105+
static Expected<std::unique_ptr<InputFile>> create(MemoryBufferRef Object);
106+
107+
class symbol_iterator;
108+
109+
/// This is a wrapper for object::basic_symbol_iterator that exposes only the
110+
/// information that an LTO client should need in order to do symbol
111+
/// resolution.
112+
///
113+
/// This object is ephemeral; it is only valid as long as an iterator obtained
114+
/// from symbols() refers to it.
115+
class Symbol {
116+
friend symbol_iterator;
117+
friend LTO;
118+
119+
object::basic_symbol_iterator I;
120+
const GlobalValue *GV;
121+
uint32_t Flags;
122+
SmallString<64> Name;
123+
124+
bool shouldSkip() {
125+
return !(Flags & object::BasicSymbolRef::SF_Global) ||
126+
(Flags & object::BasicSymbolRef::SF_FormatSpecific);
127+
}
128+
129+
void skip() {
130+
const object::SymbolicFile *Obj = I->getObject();
131+
auto E = Obj->symbol_end();
132+
while (I != E) {
133+
Flags = I->getFlags();
134+
if (!shouldSkip())
135+
break;
136+
++I;
137+
}
138+
if (I == E)
139+
return;
140+
141+
Name.clear();
142+
{
143+
raw_svector_ostream OS(Name);
144+
I->printName(OS);
145+
}
146+
GV = cast<object::IRObjectFile>(Obj)->getSymbolGV(I->getRawDataRefImpl());
147+
}
148+
149+
public:
150+
Symbol(object::basic_symbol_iterator I) : I(I) { skip(); }
151+
152+
StringRef getName() const { return Name; }
153+
StringRef getIRName() const {
154+
if (GV)
155+
return GV->getName();
156+
return StringRef();
157+
}
158+
uint32_t getFlags() const { return Flags; }
159+
GlobalValue::VisibilityTypes getVisibility() const {
160+
if (GV)
161+
return GV->getVisibility();
162+
return GlobalValue::DefaultVisibility;
163+
}
164+
bool canBeOmittedFromSymbolTable() const {
165+
return GV && llvm::canBeOmittedFromSymbolTable(GV);
166+
}
167+
Expected<const Comdat *> getComdat() const {
168+
const GlobalObject *GO;
169+
if (auto *GA = dyn_cast<GlobalAlias>(GV)) {
170+
GO = GA->getBaseObject();
171+
if (!GO)
172+
return make_error<StringError>("Unable to determine comdat of alias!",
173+
inconvertibleErrorCode());
174+
} else {
175+
GO = cast<GlobalObject>(GV);
176+
}
177+
if (GV)
178+
return GV->getComdat();
179+
return nullptr;
180+
}
181+
size_t getCommonSize() const {
182+
assert(Flags & object::BasicSymbolRef::SF_Common);
183+
if (!GV)
184+
return 0;
185+
return GV->getParent()->getDataLayout().getTypeAllocSize(
186+
GV->getType()->getElementType());
187+
}
188+
unsigned getCommonAlignment() const {
189+
assert(Flags & object::BasicSymbolRef::SF_Common);
190+
if (!GV)
191+
return 0;
192+
return GV->getAlignment();
193+
}
194+
};
195+
196+
class symbol_iterator {
197+
Symbol Sym;
198+
199+
public:
200+
symbol_iterator(object::basic_symbol_iterator I) : Sym(I) {}
201+
202+
symbol_iterator &operator++() {
203+
++Sym.I;
204+
Sym.skip();
205+
return *this;
206+
}
207+
208+
symbol_iterator operator++(int) {
209+
symbol_iterator I = *this;
210+
++*this;
211+
return I;
212+
}
213+
214+
const Symbol &operator*() const { return Sym; }
215+
const Symbol *operator->() const { return &Sym; }
216+
217+
bool operator!=(const symbol_iterator &Other) const {
218+
return Sym.I != Other.Sym.I;
219+
}
220+
};
221+
222+
/// A range over the symbols in this InputFile.
223+
iterator_range<symbol_iterator> symbols() {
224+
return llvm::make_range(symbol_iterator(Obj->symbol_begin()),
225+
symbol_iterator(Obj->symbol_end()));
226+
}
227+
228+
StringRef getSourceFileName() const {
229+
return Obj->getModule().getSourceFileName();
230+
}
231+
};
232+
233+
/// A ThinBackend defines what happens after the thin-link phase during ThinLTO.
234+
/// The details of this type definition aren't important; clients can only
235+
/// create a ThinBackend using one of the create*ThinBackend() functions below.
236+
typedef std::function<std::unique_ptr<ThinBackendProc>(
237+
Config &C, ModuleSummaryIndex &CombinedIndex,
238+
StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
239+
AddStreamFn AddStream)>
240+
ThinBackend;
241+
242+
/// This ThinBackend runs the individual backend jobs in-process.
243+
ThinBackend createInProcessThinBackend(unsigned ParallelismLevel);
244+
245+
/// This ThinBackend writes individual module indexes to files, instead of
246+
/// running the individual backend jobs. This backend is for distributed builds
247+
/// where separate processes will invoke the real backends.
248+
///
249+
/// To find the path to write the index to, the backend checks if the path has a
250+
/// prefix of OldPrefix; if so, it replaces that prefix with NewPrefix. It then
251+
/// appends ".thinlto.bc" and writes the index to that path. If
252+
/// ShouldEmitImportsFiles is true it also writes a list of imported files to a
253+
/// similar path with ".imports" appended instead.
254+
ThinBackend createWriteIndexesThinBackend(std::string OldPrefix,
255+
std::string NewPrefix,
256+
bool ShouldEmitImportsFiles,
257+
std::string LinkedObjectsFile);
258+
259+
/// This class implements a resolution-based interface to LLVM's LTO
260+
/// functionality. It supports regular LTO, parallel LTO code generation and
261+
/// ThinLTO. You can use it from a linker in the following way:
262+
/// - Set hooks and code generation options (see lto::Config struct defined in
263+
/// Config.h), and use the lto::Config object to create an lto::LTO object.
264+
/// - Create lto::InputFile objects using lto::InputFile::create(), then use
265+
/// the symbols() function to enumerate its symbols and compute a resolution
266+
/// for each symbol (see SymbolResolution below).
267+
/// - After the linker has visited each input file (and each regular object
268+
/// file) and computed a resolution for each symbol, take each lto::InputFile
269+
/// and pass it and an array of symbol resolutions to the add() function.
270+
/// - Call the getMaxTasks() function to get an upper bound on the number of
271+
/// native object files that LTO may add to the link.
272+
/// - Call the run() function. This function will use the supplied AddStream
273+
/// function to add up to getMaxTasks() native object files to the link.
274+
class LTO {
275+
friend InputFile;
276+
277+
public:
278+
/// Create an LTO object. A default constructed LTO object has a reasonable
279+
/// production configuration, but you can customize it by passing arguments to
280+
/// this constructor.
281+
/// FIXME: We do currently require the DiagHandler field to be set in Conf.
282+
/// Until that is fixed, a Config argument is required.
283+
LTO(Config Conf, ThinBackend Backend = nullptr,
284+
unsigned ParallelCodeGenParallelismLevel = 1);
285+
286+
/// Add an input file to the LTO link, using the provided symbol resolutions.
287+
/// The symbol resolutions must appear in the enumeration order given by
288+
/// InputFile::symbols().
289+
Error add(std::unique_ptr<InputFile> Obj, ArrayRef<SymbolResolution> Res);
290+
291+
/// Returns an upper bound on the number of tasks that the client may expect.
292+
/// This may only be called after all IR object files have been added. For a
293+
/// full description of tasks see LTOBackend.h.
294+
size_t getMaxTasks() const;
295+
296+
/// Runs the LTO pipeline. This function calls the supplied AddStream function
297+
/// to add native object files to the link.
298+
Error run(AddStreamFn AddStream);
299+
300+
private:
301+
Config Conf;
302+
303+
struct RegularLTOState {
304+
RegularLTOState(unsigned ParallelCodeGenParallelismLevel, Config &Conf);
305+
306+
unsigned ParallelCodeGenParallelismLevel;
307+
LTOLLVMContext Ctx;
308+
bool HasModule = false;
309+
std::unique_ptr<Module> CombinedModule;
310+
IRMover Mover;
311+
} RegularLTO;
312+
313+
struct ThinLTOState {
314+
ThinLTOState(ThinBackend Backend);
315+
316+
ThinBackend Backend;
317+
ModuleSummaryIndex CombinedIndex;
318+
MapVector<StringRef, MemoryBufferRef> ModuleMap;
319+
DenseMap<GlobalValue::GUID, StringRef> PrevailingModuleForGUID;
320+
} ThinLTO;
321+
322+
// The global resolution for a particular (mangled) symbol name. This is in
323+
// particular necessary to track whether each symbol can be internalized.
324+
// Because any input file may introduce a new cross-partition reference, we
325+
// cannot make any final internalization decisions until all input files have
326+
// been added and the client has called run(). During run() we apply
327+
// internalization decisions either directly to the module (for regular LTO)
328+
// or to the combined index (for ThinLTO).
329+
struct GlobalResolution {
330+
/// The unmangled name of the global.
331+
std::string IRName;
332+
333+
bool UnnamedAddr = true;
334+
335+
/// This field keeps track of the partition number of this global. The
336+
/// regular LTO object is partition 0, while each ThinLTO object has its own
337+
/// partition number from 1 onwards.
338+
///
339+
/// Any global that is defined or used by more than one partition, or that
340+
/// is referenced externally, may not be internalized.
341+
///
342+
/// Partitions generally have a one-to-one correspondence with tasks, except
343+
/// that we use partition 0 for all parallel LTO code generation partitions.
344+
/// Any partitioning of the combined LTO object is done internally by the
345+
/// LTO backend.
346+
size_t Partition = Unknown;
347+
348+
/// Special partition numbers.
349+
enum {
350+
/// A partition number has not yet been assigned to this global.
351+
Unknown = -1ull,
352+
353+
/// This global is either used by more than one partition or has an
354+
/// external reference, and therefore cannot be internalized.
355+
External = -2ull,
356+
};
357+
};
358+
359+
// Global mapping from mangled symbol names to resolutions.
360+
StringMap<GlobalResolution> GlobalResolutions;
361+
362+
void writeToResolutionFile(InputFile *Input, ArrayRef<SymbolResolution> Res);
363+
364+
void addSymbolToGlobalRes(object::IRObjectFile *Obj,
365+
SmallPtrSet<GlobalValue *, 8> &Used,
366+
const InputFile::Symbol &Sym, SymbolResolution Res,
367+
size_t Partition);
368+
369+
Error addRegularLTO(std::unique_ptr<InputFile> Input,
370+
ArrayRef<SymbolResolution> Res);
371+
Error addThinLTO(std::unique_ptr<InputFile> Input,
372+
ArrayRef<SymbolResolution> Res);
373+
374+
Error runRegularLTO(AddStreamFn AddStream);
375+
Error runThinLTO(AddStreamFn AddStream);
376+
377+
mutable bool CalledGetMaxTasks = false;
378+
};
379+
380+
/// The resolution for a symbol. The linker must provide a SymbolResolution for
381+
/// each global symbol based on its internal resolution of that symbol.
382+
struct SymbolResolution {
383+
SymbolResolution()
384+
: Prevailing(0), FinalDefinitionInLinkageUnit(0), VisibleToRegularObj(0) {
385+
}
386+
/// The linker has chosen this definition of the symbol.
387+
unsigned Prevailing : 1;
388+
389+
/// The definition of this symbol is unpreemptable at runtime and is known to
390+
/// be in this linkage unit.
391+
unsigned FinalDefinitionInLinkageUnit : 1;
392+
393+
/// The definition of this symbol is visible outside of the LTO unit.
394+
unsigned VisibleToRegularObj : 1;
395+
};
396+
397+
} // namespace lto
398+
} // namespace llvm
73399

74400
#endif

‎llvm/include/llvm/LTO/LTOBackend.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===-LTOBackend.h - LLVM Link Time Optimizer Backend ---------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file implements the "backend" phase of LTO, i.e. it performs
11+
// optimization and code generation on a loaded module. It is generally used
12+
// internally by the LTO class but can also be used independently, for example
13+
// to implement a standalone ThinLTO backend.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef LLVM_LTO_LTOBACKEND_H
18+
#define LLVM_LTO_LTOBACKEND_H
19+
20+
#include "llvm/ADT/MapVector.h"
21+
#include "llvm/IR/DiagnosticInfo.h"
22+
#include "llvm/IR/ModuleSummaryIndex.h"
23+
#include "llvm/LTO/Config.h"
24+
#include "llvm/Support/MemoryBuffer.h"
25+
#include "llvm/Target/TargetOptions.h"
26+
#include "llvm/Transforms/IPO/FunctionImport.h"
27+
28+
namespace llvm {
29+
30+
class Error;
31+
class Module;
32+
class Target;
33+
34+
namespace lto {
35+
36+
/// Runs a regular LTO backend.
37+
Error backend(Config &C, AddStreamFn AddStream,
38+
unsigned ParallelCodeGenParallelismLevel,
39+
std::unique_ptr<Module> M);
40+
41+
/// Runs a ThinLTO backend.
42+
Error thinBackend(Config &C, size_t Task, AddStreamFn AddStream, Module &M,
43+
ModuleSummaryIndex &CombinedIndex,
44+
const FunctionImporter::ImportMapTy &ImportList,
45+
const GVSummaryMapTy &DefinedGlobals,
46+
MapVector<StringRef, MemoryBufferRef> &ModuleMap);
47+
48+
}
49+
}
50+
51+
#endif

‎llvm/lib/LTO/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ endif()
4949

5050
add_llvm_library(LLVMLTO
5151
LTO.cpp
52+
LTOBackend.cpp
5253
LTOModule.cpp
5354
LTOCodeGenerator.cpp
5455
UpdateCompilerUsed.cpp

‎llvm/lib/LTO/LLVMBuild.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ required_libraries =
3434
Scalar
3535
Support
3636
Target
37-
TransformUtils
37+
TransformUtils

‎llvm/lib/LTO/LTO.cpp

+531-5
Large diffs are not rendered by default.

‎llvm/lib/LTO/LTOBackend.cpp

+277
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
//===-LTOBackend.cpp - LLVM Link Time Optimizer Backend -------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file implements the "backend" phase of LTO, i.e. it performs
11+
// optimization and code generation on a loaded module. It is generally used
12+
// internally by the LTO class but can also be used independently, for example
13+
// to implement a standalone ThinLTO backend.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "llvm/LTO/LTOBackend.h"
18+
#include "llvm/Analysis/TargetLibraryInfo.h"
19+
#include "llvm/Analysis/TargetTransformInfo.h"
20+
#include "llvm/Bitcode/ReaderWriter.h"
21+
#include "llvm/IR/LegacyPassManager.h"
22+
#include "llvm/MC/SubtargetFeature.h"
23+
#include "llvm/Support/Error.h"
24+
#include "llvm/Support/FileSystem.h"
25+
#include "llvm/Support/TargetRegistry.h"
26+
#include "llvm/Support/ThreadPool.h"
27+
#include "llvm/Target/TargetMachine.h"
28+
#include "llvm/Transforms/IPO.h"
29+
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
30+
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
31+
#include "llvm/Transforms/Utils/SplitModule.h"
32+
33+
using namespace llvm;
34+
using namespace lto;
35+
36+
Error Config::addSaveTemps(std::string OutputFileName) {
37+
ShouldDiscardValueNames = false;
38+
39+
std::error_code EC;
40+
ResolutionFile = make_unique<raw_fd_ostream>(
41+
OutputFileName + ".resolution.txt", EC, sys::fs::OpenFlags::F_Text);
42+
if (EC)
43+
return errorCodeToError(EC);
44+
45+
auto setHook = [&](std::string PathSuffix, ModuleHookFn &Hook) {
46+
// Keep track of the hook provided by the linker, which also needs to run.
47+
ModuleHookFn LinkerHook = Hook;
48+
Hook = [=](size_t Task, Module &M) {
49+
// If the linker's hook returned false, we need to pass that result
50+
// through.
51+
if (LinkerHook && !LinkerHook(Task, M))
52+
return false;
53+
54+
std::string PathPrefix;
55+
PathPrefix = OutputFileName;
56+
if (Task != 0)
57+
PathPrefix += "." + utostr(Task);
58+
std::string Path = PathPrefix + "." + PathSuffix + ".bc";
59+
std::error_code EC;
60+
raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
61+
if (EC) {
62+
// Because -save-temps is a debugging feature, we report the error
63+
// directly and exit.
64+
llvm::errs() << "failed to open " << Path << ": " << EC.message()
65+
<< '\n';
66+
exit(1);
67+
}
68+
WriteBitcodeToFile(&M, OS, /*ShouldPreserveUseListOrder=*/false);
69+
return true;
70+
};
71+
};
72+
73+
setHook("0.preopt", PreOptModuleHook);
74+
setHook("1.promote", PostPromoteModuleHook);
75+
setHook("2.internalize", PostInternalizeModuleHook);
76+
setHook("3.import", PostImportModuleHook);
77+
setHook("4.opt", PostOptModuleHook);
78+
setHook("5.precodegen", PreCodeGenModuleHook);
79+
80+
CombinedIndexHook = [=](const ModuleSummaryIndex &Index) {
81+
std::string Path = OutputFileName + ".index.bc";
82+
std::error_code EC;
83+
raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
84+
if (EC) {
85+
// Because -save-temps is a debugging feature, we report the error
86+
// directly and exit.
87+
llvm::errs() << "failed to open " << Path << ": " << EC.message() << '\n';
88+
exit(1);
89+
}
90+
WriteIndexToFile(Index, OS);
91+
return true;
92+
};
93+
94+
return Error();
95+
}
96+
97+
namespace {
98+
99+
std::unique_ptr<TargetMachine>
100+
createTargetMachine(Config &C, StringRef TheTriple, const Target *TheTarget) {
101+
SubtargetFeatures Features;
102+
Features.getDefaultSubtargetFeatures(Triple(TheTriple));
103+
for (const std::string &A : C.MAttrs)
104+
Features.AddFeature(A);
105+
106+
return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
107+
TheTriple, C.CPU, Features.getString(), C.Options, C.RelocModel,
108+
C.CodeModel, C.CGOptLevel));
109+
}
110+
111+
bool opt(Config &C, TargetMachine *TM, size_t Task, Module &M, bool IsThinLto) {
112+
M.setDataLayout(TM->createDataLayout());
113+
114+
legacy::PassManager passes;
115+
passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
116+
117+
PassManagerBuilder PMB;
118+
PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()));
119+
PMB.Inliner = createFunctionInliningPass();
120+
// Unconditionally verify input since it is not verified before this
121+
// point and has unknown origin.
122+
PMB.VerifyInput = true;
123+
PMB.VerifyOutput = !C.DisableVerify;
124+
PMB.LoopVectorize = true;
125+
PMB.SLPVectorize = true;
126+
PMB.OptLevel = C.OptLevel;
127+
if (IsThinLto)
128+
PMB.populateThinLTOPassManager(passes);
129+
else
130+
PMB.populateLTOPassManager(passes);
131+
passes.run(M);
132+
133+
if (C.PostOptModuleHook && !C.PostOptModuleHook(Task, M))
134+
return false;
135+
136+
return true;
137+
}
138+
139+
void codegen(Config &C, TargetMachine *TM, AddStreamFn AddStream, size_t Task,
140+
Module &M) {
141+
if (C.PreCodeGenModuleHook && !C.PreCodeGenModuleHook(Task, M))
142+
return;
143+
144+
std::unique_ptr<raw_pwrite_stream> OS = AddStream(Task);
145+
legacy::PassManager CodeGenPasses;
146+
if (TM->addPassesToEmitFile(CodeGenPasses, *OS,
147+
TargetMachine::CGFT_ObjectFile))
148+
report_fatal_error("Failed to setup codegen");
149+
CodeGenPasses.run(M);
150+
}
151+
152+
void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream,
153+
unsigned ParallelCodeGenParallelismLevel,
154+
std::unique_ptr<Module> M) {
155+
ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel);
156+
unsigned ThreadCount = 0;
157+
const Target *T = &TM->getTarget();
158+
159+
SplitModule(
160+
std::move(M), ParallelCodeGenParallelismLevel,
161+
[&](std::unique_ptr<Module> MPart) {
162+
// We want to clone the module in a new context to multi-thread the
163+
// codegen. We do it by serializing partition modules to bitcode
164+
// (while still on the main thread, in order to avoid data races) and
165+
// spinning up new threads which deserialize the partitions into
166+
// separate contexts.
167+
// FIXME: Provide a more direct way to do this in LLVM.
168+
SmallString<0> BC;
169+
raw_svector_ostream BCOS(BC);
170+
WriteBitcodeToFile(MPart.get(), BCOS);
171+
172+
// Enqueue the task
173+
CodegenThreadPool.async(
174+
[&](const SmallString<0> &BC, unsigned ThreadId) {
175+
LTOLLVMContext Ctx(C);
176+
ErrorOr<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
177+
MemoryBufferRef(StringRef(BC.data(), BC.size()), "ld-temp.o"),
178+
Ctx);
179+
if (!MOrErr)
180+
report_fatal_error("Failed to read bitcode");
181+
std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
182+
183+
std::unique_ptr<TargetMachine> TM =
184+
createTargetMachine(C, MPartInCtx->getTargetTriple(), T);
185+
codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx);
186+
},
187+
// Pass BC using std::move to ensure that it get moved rather than
188+
// copied into the thread's context.
189+
std::move(BC), ThreadCount++);
190+
},
191+
false);
192+
}
193+
194+
Expected<const Target *> initAndLookupTarget(Config &C, Module &M) {
195+
if (!C.OverrideTriple.empty())
196+
M.setTargetTriple(C.OverrideTriple);
197+
else if (M.getTargetTriple().empty())
198+
M.setTargetTriple(C.DefaultTriple);
199+
200+
std::string Msg;
201+
const Target *T = TargetRegistry::lookupTarget(M.getTargetTriple(), Msg);
202+
if (!T)
203+
return make_error<StringError>(Msg, inconvertibleErrorCode());
204+
return T;
205+
}
206+
207+
}
208+
209+
Error lto::backend(Config &C, AddStreamFn AddStream,
210+
unsigned ParallelCodeGenParallelismLevel,
211+
std::unique_ptr<Module> M) {
212+
Expected<const Target *> TOrErr = initAndLookupTarget(C, *M);
213+
if (!TOrErr)
214+
return TOrErr.takeError();
215+
216+
std::unique_ptr<TargetMachine> TM =
217+
createTargetMachine(C, M->getTargetTriple(), *TOrErr);
218+
219+
if (!opt(C, TM.get(), 0, *M, /*IsThinLto=*/false))
220+
return Error();
221+
222+
if (ParallelCodeGenParallelismLevel == 1)
223+
codegen(C, TM.get(), AddStream, 0, *M);
224+
else
225+
splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel,
226+
std::move(M));
227+
return Error();
228+
}
229+
230+
Error lto::thinBackend(Config &C, size_t Task, AddStreamFn AddStream, Module &M,
231+
ModuleSummaryIndex &CombinedIndex,
232+
const FunctionImporter::ImportMapTy &ImportList,
233+
const GVSummaryMapTy &DefinedGlobals,
234+
MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
235+
Expected<const Target *> TOrErr = initAndLookupTarget(C, M);
236+
if (!TOrErr)
237+
return TOrErr.takeError();
238+
239+
std::unique_ptr<TargetMachine> TM =
240+
createTargetMachine(C, M.getTargetTriple(), *TOrErr);
241+
242+
if (C.PreOptModuleHook && !C.PreOptModuleHook(Task, M))
243+
return Error();
244+
245+
thinLTOResolveWeakForLinkerModule(M, DefinedGlobals);
246+
247+
renameModuleForThinLTO(M, CombinedIndex);
248+
249+
if (C.PostPromoteModuleHook && !C.PostPromoteModuleHook(Task, M))
250+
return Error();
251+
252+
if (!DefinedGlobals.empty())
253+
thinLTOInternalizeModule(M, DefinedGlobals);
254+
255+
if (C.PostInternalizeModuleHook && !C.PostInternalizeModuleHook(Task, M))
256+
return Error();
257+
258+
auto ModuleLoader = [&](StringRef Identifier) {
259+
return std::move(getLazyBitcodeModule(MemoryBuffer::getMemBuffer(
260+
ModuleMap[Identifier], false),
261+
M.getContext(),
262+
/*ShouldLazyLoadMetadata=*/true)
263+
.get());
264+
};
265+
266+
FunctionImporter Importer(CombinedIndex, ModuleLoader);
267+
Importer.importFunctions(M, ImportList);
268+
269+
if (C.PostImportModuleHook && !C.PostImportModuleHook(Task, M))
270+
return Error();
271+
272+
if (!opt(C, TM.get(), Task, M, /*IsThinLto=*/true))
273+
return Error();
274+
275+
codegen(C, TM.get(), AddStream, Task, M);
276+
return Error();
277+
}

‎llvm/lib/Object/IRObjectFile.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -324,5 +324,5 @@ llvm::object::IRObjectFile::create(MemoryBufferRef Object,
324324
return EC;
325325

326326
std::unique_ptr<Module> &M = MOrErr.get();
327-
return llvm::make_unique<IRObjectFile>(Object, std::move(M));
327+
return llvm::make_unique<IRObjectFile>(BCOrErr.get(), std::move(M));
328328
}

‎llvm/test/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ set(LLVM_TEST_DEPENDS
4343
llvm-extract
4444
llvm-lib
4545
llvm-link
46+
llvm-lto2
4647
llvm-mc
4748
llvm-mcmarkup
4849
llvm-nm
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
2+
target triple = "x86_64-unknown-linux-gnu"
3+
4+
@a = global i32 42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
2+
target triple = "x86_64-unknown-linux-gnu"
3+
4+
$c2 = comdat any
5+
$c1 = comdat any
6+
7+
; This is only present in this file. The linker will keep $c1 from the first
8+
; file and this will be undefined.
9+
@will_be_undefined = global i32 1, comdat($c1)
10+
11+
@v1 = weak_odr global i32 41, comdat($c2)
12+
define weak_odr protected i32 @f1(i8* %this) comdat($c2) {
13+
bb20:
14+
store i8* %this, i8** null
15+
br label %bb21
16+
bb21:
17+
ret i32 41
18+
}
19+
20+
@r21 = global i32* @v1
21+
@r22 = global i32(i8*)* @f1
22+
23+
@a21 = alias i32, i32* @v1
24+
@a22 = alias i16, bitcast (i32* @v1 to i16*)
25+
26+
@a23 = alias i32(i8*), i32(i8*)* @f1
27+
@a24 = alias i16, bitcast (i32(i8*)* @f1 to i16*)
28+
@a25 = alias i16, i16* @a24

‎llvm/test/LTO/Resolution/X86/alias.ll

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; RUN: llvm-as %s -o %t1.o
2+
; RUN: llvm-as %p/Inputs/alias-1.ll -o %t2.o
3+
; RUN: llvm-lto2 -o %t3.o %t2.o %t1.o -r %t2.o,a,px -r %t1.o,a, -r %t1.o,b,px -save-temps
4+
; RUN: llvm-dis < %t3.o.0.preopt.bc -o - | FileCheck %s
5+
; RUN: FileCheck --check-prefix=RES %s < %t3.o.resolution.txt
6+
7+
; CHECK-NOT: alias
8+
; CHECK: @a = global i32 42
9+
; CHECK-NEXT: @b = global i32 1
10+
; CHECK-NOT: alias
11+
12+
; RES: 2.o{{$}}
13+
; RES: {{^}}-r={{.*}}2.o,a,px{{$}}
14+
; RES: 1.o{{$}}
15+
; RES: {{^}}-r={{.*}}1.o,b,px{{$}}
16+
; RES: {{^}}-r={{.*}}1.o,a,{{$}}
17+
18+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
19+
target triple = "x86_64-unknown-linux-gnu"
20+
21+
@a = weak alias i32, i32* @b
22+
@b = global i32 1
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
; RUN: llvm-as %s -o %t.o
2+
; RUN: llvm-as %p/Inputs/comdat.ll -o %t2.o
3+
; RUN: llvm-lto2 -save-temps -o %t3.o %t.o %t2.o \
4+
; RUN: -r=%t.o,f1,plx \
5+
; RUN: -r=%t.o,v1,px \
6+
; RUN: -r=%t.o,r11,px \
7+
; RUN: -r=%t.o,r12,px \
8+
; RUN: -r=%t.o,a11,px \
9+
; RUN: -r=%t.o,a12,px \
10+
; RUN: -r=%t.o,a13,px \
11+
; RUN: -r=%t.o,a14,px \
12+
; RUN: -r=%t.o,a15,px \
13+
; RUN: -r=%t2.o,f1,l \
14+
; RUN: -r=%t2.o,will_be_undefined, \
15+
; RUN: -r=%t2.o,v1, \
16+
; RUN: -r=%t2.o,r21,px \
17+
; RUN: -r=%t2.o,r22,px \
18+
; RUN: -r=%t2.o,a21,px \
19+
; RUN: -r=%t2.o,a22,px \
20+
; RUN: -r=%t2.o,a23,px \
21+
; RUN: -r=%t2.o,a24,px \
22+
; RUN: -r=%t2.o,a25,px
23+
; RUN: llvm-dis %t3.o.2.internalize.bc -o - | FileCheck %s
24+
25+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
26+
target triple = "x86_64-unknown-linux-gnu"
27+
28+
$c1 = comdat any
29+
30+
@v1 = weak_odr global i32 42, comdat($c1)
31+
define weak_odr i32 @f1(i8*) comdat($c1) {
32+
bb10:
33+
br label %bb11
34+
bb11:
35+
ret i32 42
36+
}
37+
38+
@r11 = global i32* @v1
39+
@r12 = global i32 (i8*)* @f1
40+
41+
@a11 = alias i32, i32* @v1
42+
@a12 = alias i16, bitcast (i32* @v1 to i16*)
43+
44+
@a13 = alias i32 (i8*), i32 (i8*)* @f1
45+
@a14 = alias i16, bitcast (i32 (i8*)* @f1 to i16*)
46+
@a15 = alias i16, i16* @a14
47+
48+
; CHECK: $c1 = comdat any
49+
; CHECK: $c2 = comdat any
50+
51+
; CHECK-DAG: @v1 = weak_odr global i32 42, comdat($c1)
52+
53+
; CHECK-DAG: @r11 = global i32* @v1{{$}}
54+
; CHECK-DAG: @r12 = global i32 (i8*)* @f1{{$}}
55+
56+
; CHECK-DAG: @r21 = global i32* @v1{{$}}
57+
; CHECK-DAG: @r22 = global i32 (i8*)* @f1{{$}}
58+
59+
; CHECK-DAG: @v1.1 = internal global i32 41, comdat($c2)
60+
61+
; CHECK-DAG: @a11 = alias i32, i32* @v1{{$}}
62+
; CHECK-DAG: @a12 = alias i16, bitcast (i32* @v1 to i16*)
63+
64+
; CHECK-DAG: @a13 = alias i32 (i8*), i32 (i8*)* @f1{{$}}
65+
; CHECK-DAG: @a14 = alias i16, bitcast (i32 (i8*)* @f1 to i16*)
66+
67+
; CHECK-DAG: @a21 = alias i32, i32* @v1.1{{$}}
68+
; CHECK-DAG: @a22 = alias i16, bitcast (i32* @v1.1 to i16*)
69+
70+
; CHECK-DAG: @a23 = alias i32 (i8*), i32 (i8*)* @f1.2{{$}}
71+
; CHECK-DAG: @a24 = alias i16, bitcast (i32 (i8*)* @f1.2 to i16*)
72+
73+
; CHECK: define weak_odr i32 @f1(i8*) comdat($c1) {
74+
; CHECK-NEXT: bb10:
75+
; CHECK-NEXT: br label %bb11{{$}}
76+
; CHECK: bb11:
77+
; CHECK-NEXT: ret i32 42
78+
; CHECK-NEXT: }
79+
80+
; CHECK: define internal i32 @f1.2(i8* %this) comdat($c2) {
81+
; CHECK-NEXT: bb20:
82+
; CHECK-NEXT: store i8* %this, i8** null
83+
; CHECK-NEXT: br label %bb21
84+
; CHECK: bb21:
85+
; CHECK-NEXT: ret i32 41
86+
; CHECK-NEXT: }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
if not 'X86' in config.root.targets:
2+
config.unsupported = True

‎llvm/test/lit.cfg

+1
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ for pattern in [r"\bbugpoint\b(?!-)",
295295
r"\bllvm-lib\b",
296296
r"\bllvm-link\b",
297297
r"\bllvm-lto\b",
298+
r"\bllvm-lto2\b",
298299
r"\bllvm-mc\b",
299300
r"\bllvm-mcmarkup\b",
300301
r"\bllvm-nm\b",

‎llvm/test/tools/gold/X86/coff.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ define hidden void @g() {
1616
ret void
1717
}
1818

19-
; CHECK: define internal void @h() local_unnamed_addr {
19+
; CHECK: define internal void @h() {
2020
define linkonce_odr void @h() local_unnamed_addr {
2121
ret void
2222
}

‎llvm/test/tools/gold/X86/comdat.ll

+38-42
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
; RUN: llvm-as %s -o %t.o
1+
; RUN: llvm-as %s -o %t1.o
22
; RUN: llvm-as %p/Inputs/comdat.ll -o %t2.o
3-
; RUN: %gold -shared -o %t3.o -plugin %llvmshlibdir/LLVMgold.so %t.o %t2.o \
3+
; RUN: %gold -shared -o %t3.o -plugin %llvmshlibdir/LLVMgold.so %t1.o %t2.o \
44
; RUN: -plugin-opt=save-temps
5-
; RUN: llvm-dis %t3.o.bc -o - | FileCheck %s
5+
; RUN: FileCheck --check-prefix=RES %s < %t3.o.resolution.txt
6+
; RUN: llvm-readobj -t %t3.o | FileCheck --check-prefix=OBJ %s
67

78
$c1 = comdat any
89

@@ -24,42 +25,37 @@ bb11:
2425
@a14 = alias i16, bitcast (i32 (i8*)* @f1 to i16*)
2526
@a15 = alias i16, i16* @a14
2627

27-
; CHECK: $c1 = comdat any
28-
; CHECK: $c2 = comdat any
29-
30-
; CHECK-DAG: @v1 = weak_odr global i32 42, comdat($c1)
31-
32-
; CHECK-DAG: @r11 = global i32* @v1{{$}}
33-
; CHECK-DAG: @r12 = global i32 (i8*)* @f1{{$}}
34-
35-
; CHECK-DAG: @r21 = global i32* @v1{{$}}
36-
; CHECK-DAG: @r22 = global i32 (i8*)* @f1{{$}}
37-
38-
; CHECK-DAG: @v1.1 = internal global i32 41, comdat($c2)
39-
40-
; CHECK-DAG: @a11 = alias i32, i32* @v1{{$}}
41-
; CHECK-DAG: @a12 = alias i16, bitcast (i32* @v1 to i16*)
42-
43-
; CHECK-DAG: @a13 = alias i32 (i8*), i32 (i8*)* @f1{{$}}
44-
; CHECK-DAG: @a14 = alias i16, bitcast (i32 (i8*)* @f1 to i16*)
45-
46-
; CHECK-DAG: @a21 = alias i32, i32* @v1.1{{$}}
47-
; CHECK-DAG: @a22 = alias i16, bitcast (i32* @v1.1 to i16*)
48-
49-
; CHECK-DAG: @a23 = alias i32 (i8*), i32 (i8*)* @f1.2{{$}}
50-
; CHECK-DAG: @a24 = alias i16, bitcast (i32 (i8*)* @f1.2 to i16*)
51-
52-
; CHECK: define weak_odr protected i32 @f1(i8*) comdat($c1) {
53-
; CHECK-NEXT: bb10:
54-
; CHECK-NEXT: br label %bb11{{$}}
55-
; CHECK: bb11:
56-
; CHECK-NEXT: ret i32 42
57-
; CHECK-NEXT: }
58-
59-
; CHECK: define internal i32 @f1.2(i8* %this) comdat($c2) {
60-
; CHECK-NEXT: bb20:
61-
; CHECK-NEXT: store i8* %this, i8** null
62-
; CHECK-NEXT: br label %bb21
63-
; CHECK: bb21:
64-
; CHECK-NEXT: ret i32 41
65-
; CHECK-NEXT: }
28+
; gold's resolutions should tell us that our $c1 wins, and the other input's $c2
29+
; wins. f1 is also local due to having protected visibility in the other object.
30+
31+
; RES: 1.o,f1,plx{{$}}
32+
; RES: 1.o,v1,px{{$}}
33+
; RES: 1.o,r11,px{{$}}
34+
; RES: 1.o,r12,px{{$}}
35+
; RES: 1.o,a11,px{{$}}
36+
; RES: 1.o,a12,px{{$}}
37+
; RES: 1.o,a13,px{{$}}
38+
; RES: 1.o,a14,px{{$}}
39+
; RES: 1.o,a15,px{{$}}
40+
41+
; RES: 2.o,f1,l{{$}}
42+
; RES: 2.o,will_be_undefined,{{$}}
43+
; RES: 2.o,v1,{{$}}
44+
; RES: 2.o,r21,px{{$}}
45+
; RES: 2.o,r22,px{{$}}
46+
; RES: 2.o,a21,px{{$}}
47+
; RES: 2.o,a22,px{{$}}
48+
; RES: 2.o,a23,px{{$}}
49+
; RES: 2.o,a24,px{{$}}
50+
; RES: 2.o,a25,px{{$}}
51+
52+
; f1's protected visibility should be reflected in the DSO.
53+
54+
; OBJ: Name: f1 (
55+
; OBJ-NEXT: Value:
56+
; OBJ-NEXT: Size:
57+
; OBJ-NEXT: Binding:
58+
; OBJ-NEXT: Type:
59+
; OBJ-NEXT: Other [
60+
; OBJ-NEXT: STV_PROTECTED
61+
; OBJ-NEXT: ]

‎llvm/test/tools/gold/X86/common.ll

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,31 @@
1111
; RUN: llvm-dis %t3.o -o - | FileCheck %s --check-prefix=A
1212

1313
; Shared library case, we merge @a as common and keep it for the symbol table.
14-
; A: @a = common global i32 0, align 8
14+
; A: @a = common global [4 x i8] zeroinitializer, align 8
1515

1616
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
1717
; RUN: --plugin-opt=emit-llvm \
1818
; RUN: -shared %t1.o %t2b.o -o %t3.o
1919
; RUN: llvm-dis %t3.o -o - | FileCheck %s --check-prefix=B
2020

2121
; (i16 align 8) + (i8 align 16) = i16 align 16
22-
; B: @a = common global i16 0, align 16
22+
; B: @a = common global [2 x i8] zeroinitializer, align 16
2323

2424
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
2525
; RUN: --plugin-opt=emit-llvm \
2626
; RUN: -shared %t1.o %t2c.o -o %t3.o
2727
; RUN: llvm-dis %t3.o -o - | FileCheck %s --check-prefix=C
2828

2929
; (i16 align 8) + (i8 align 1) = i16 align 8.
30-
; C: @a = common global i16 0, align 8
30+
; C: @a = common global [2 x i8] zeroinitializer, align 8
3131

3232
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
3333
; RUN: --plugin-opt=emit-llvm \
3434
; RUN: %t1.o %t2.o -o %t3.o
3535
; RUN: llvm-dis %t3.o -o - | FileCheck --check-prefix=EXEC %s
3636

3737
; All IR case, we internalize a after merging.
38-
; EXEC: @a = internal global i32 0, align 8
38+
; EXEC: @a = internal global [4 x i8] zeroinitializer, align 8
3939

4040
; RUN: llc %p/Inputs/common.ll -o %t2native.o -filetype=obj
4141
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
@@ -44,4 +44,4 @@
4444
; RUN: llvm-dis %t3.o -o - | FileCheck --check-prefix=MIXED %s
4545

4646
; Mixed ELF and IR. We keep ours as common so the linker will finish the merge.
47-
; MIXED: @a = common global i16 0, align 8
47+
; MIXED: @a = common global [2 x i8] zeroinitializer, align 8

‎llvm/test/tools/gold/X86/emit-llvm.ll

+28-23
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22

33
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
44
; RUN: --plugin-opt=emit-llvm \
5-
; RUN: --plugin-opt=generate-api-file \
65
; RUN: -shared %t.o -o %t2.o
76
; RUN: llvm-dis %t2.o -o - | FileCheck %s
8-
; RUN: FileCheck --check-prefix=API %s < %T/../apifile.txt
97

108
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
119
; RUN: -m elf_x86_64 --plugin-opt=save-temps \
1210
; RUN: -shared %t.o -o %t3.o
13-
; RUN: llvm-dis %t3.o.bc -o - | FileCheck %s
14-
; RUN: llvm-dis %t3.o.opt.bc -o - | FileCheck --check-prefix=OPT %s
15-
; RUN: llvm-dis %t3.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
11+
; RUN: FileCheck --check-prefix=RES %s < %t3.o.resolution.txt
12+
; RUN: llvm-dis %t3.o.2.internalize.bc -o - | FileCheck %s
13+
; RUN: llvm-dis %t3.o.4.opt.bc -o - | FileCheck --check-prefix=OPT %s
14+
; RUN: llvm-dis %t3.o.4.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
1615
; RUN: llvm-nm %t3.o.o | FileCheck --check-prefix=NM %s
1716

1817
; RUN: rm -f %t4.o
@@ -25,19 +24,19 @@
2524

2625
target triple = "x86_64-unknown-linux-gnu"
2726

28-
; CHECK-DAG: @g1 = linkonce_odr constant i32 32
27+
; CHECK-DAG: @g1 = weak_odr constant i32 32
2928
@g1 = linkonce_odr constant i32 32
3029

31-
; CHECK-DAG: @g2 = internal local_unnamed_addr constant i32 32
30+
; CHECK-DAG: @g2 = internal constant i32 32
3231
@g2 = linkonce_odr local_unnamed_addr constant i32 32
3332

3433
; CHECK-DAG: @g3 = internal unnamed_addr constant i32 32
3534
@g3 = linkonce_odr unnamed_addr constant i32 32
3635

37-
; CHECK-DAG: @g4 = linkonce_odr global i32 32
36+
; CHECK-DAG: @g4 = weak_odr global i32 32
3837
@g4 = linkonce_odr global i32 32
3938

40-
; CHECK-DAG: @g5 = linkonce_odr local_unnamed_addr global i32 32
39+
; CHECK-DAG: @g5 = weak_odr global i32 32
4140
@g5 = linkonce_odr local_unnamed_addr global i32 32
4241

4342
; CHECK-DAG: @g6 = internal unnamed_addr global i32 32
@@ -75,8 +74,8 @@ define linkonce_odr void @f4() local_unnamed_addr {
7574
ret void
7675
}
7776

78-
; CHECK-DAG: define linkonce_odr void @f5()
79-
; OPT-DAG: define linkonce_odr void @f5()
77+
; CHECK-DAG: define weak_odr void @f5()
78+
; OPT-DAG: define weak_odr void @f5()
8079
define linkonce_odr void @f5() {
8180
ret void
8281
}
@@ -97,15 +96,21 @@ define i32* @f8() {
9796
ret i32* @g8
9897
}
9998

100-
; API: f1 PREVAILING_DEF_IRONLY
101-
; API: f2 PREVAILING_DEF_IRONLY
102-
; API: f3 PREVAILING_DEF_IRONLY_EXP
103-
; API: f4 PREVAILING_DEF_IRONLY_EXP
104-
; API: f5 PREVAILING_DEF_IRONLY_EXP
105-
; API: f6 PREVAILING_DEF_IRONLY_EXP
106-
; API: f7 PREVAILING_DEF_IRONLY_EXP
107-
; API: f8 PREVAILING_DEF_IRONLY_EXP
108-
; API: g7 UNDEF
109-
; API: g8 UNDEF
110-
; API: g9 PREVAILING_DEF_IRONLY_EXP
111-
; API: g10 PREVAILING_DEF_IRONLY_EXP
99+
; RES: .o,f1,pl{{$}}
100+
; RES: .o,f2,pl{{$}}
101+
; RES: .o,f3,px{{$}}
102+
; RES: .o,f4,p{{$}}
103+
; RES: .o,f5,px{{$}}
104+
; RES: .o,f6,p{{$}}
105+
; RES: .o,f7,px{{$}}
106+
; RES: .o,f8,px{{$}}
107+
; RES: .o,g1,px{{$}}
108+
; RES: .o,g2,p{{$}}
109+
; RES: .o,g3,p{{$}}
110+
; RES: .o,g4,px{{$}}
111+
; RES: .o,g5,px{{$}}
112+
; RES: .o,g6,p{{$}}
113+
; RES: .o,g7,{{$}}
114+
; RES: .o,g8,{{$}}
115+
; RES: .o,g9,px{{$}}
116+
; RES: .o,g10,px{{$}}

‎llvm/test/tools/gold/X86/opt-level.ll

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
; RUN: llvm-as -o %t.bc %s
22
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -plugin-opt=save-temps \
33
; RUN: -plugin-opt=O0 -r -o %t.o %t.bc
4-
; RUN: llvm-dis < %t.o.opt.bc -o - | FileCheck --check-prefix=CHECK-O0 %s
4+
; RUN: llvm-dis < %t.o.4.opt.bc -o - | FileCheck --check-prefix=CHECK-O0 %s
55
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -plugin-opt=save-temps \
66
; RUN: -plugin-opt=O1 -r -o %t.o %t.bc
7-
; RUN: llvm-dis < %t.o.opt.bc -o - | FileCheck --check-prefix=CHECK-O1 %s
7+
; RUN: llvm-dis < %t.o.4.opt.bc -o - | FileCheck --check-prefix=CHECK-O1 %s
88
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -plugin-opt=save-temps \
99
; RUN: -plugin-opt=O2 -r -o %t.o %t.bc
10-
; RUN: llvm-dis < %t.o.opt.bc -o - | FileCheck --check-prefix=CHECK-O2 %s
10+
; RUN: llvm-dis < %t.o.4.opt.bc -o - | FileCheck --check-prefix=CHECK-O2 %s
1111

1212
; CHECK-O0: define internal void @foo(
1313
; CHECK-O1: define internal void @foo(

‎llvm/test/tools/gold/X86/parallel.ll

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
; RUN: llvm-as -o %t.bc %s
2+
; RUN: rm -f %t.opt.bc0 %t.opt.bc1 %t.o0 %t.o1
23
; RUN: env LD_PRELOAD=%llvmshlibdir/LLVMgold.so %gold -plugin %llvmshlibdir/LLVMgold.so -u foo -u bar -plugin-opt jobs=2 -plugin-opt save-temps -m elf_x86_64 -o %t %t.bc
3-
; RUN: llvm-dis %t.opt.bc0 -o - | FileCheck --check-prefix=CHECK-BC0 %s
4-
; RUN: llvm-dis %t.opt.bc1 -o - | FileCheck --check-prefix=CHECK-BC1 %s
4+
; RUN: llvm-dis %t.5.precodegen.bc -o - | FileCheck --check-prefix=CHECK-BC0 %s
5+
; RUN: llvm-dis %t.1.5.precodegen.bc -o - | FileCheck --check-prefix=CHECK-BC1 %s
56
; RUN: llvm-nm %t.o0 | FileCheck --check-prefix=CHECK0 %s
67
; RUN: llvm-nm %t.o1 | FileCheck --check-prefix=CHECK1 %s
78

‎llvm/test/tools/gold/X86/slp-vectorize.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold.so \
44
; RUN: --plugin-opt=save-temps \
55
; RUN: -shared %t.o -o %t2.o
6-
; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck %s
6+
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s
77

88
; test that the vectorizer is run.
99
; CHECK: fadd <4 x float>

‎llvm/test/tools/gold/X86/start-lib-common.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@
1919

2020
; Check that the common symbol is not dropped completely, which was a regression
2121
; in r262676.
22-
; CHECK: @x = common global i32 0
22+
; CHECK: @x = common global [4 x i8] zeroinitializer

‎llvm/test/tools/gold/X86/strip_names.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
44
; RUN: --plugin-opt=save-temps \
55
; RUN: -shared %t.o -o %t2.o
6-
; RUN: llvm-dis %t2.o.bc -o - | FileCheck %s
6+
; RUN: llvm-dis %t2.o.2.internalize.bc -o - | FileCheck %s
77

88
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
99
; RUN: --plugin-opt=emit-llvm \

‎llvm/test/tools/gold/X86/thinlto.ll

+6-4
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,23 @@
2525
; RUN: llvm-bcanalyzer -dump %t2.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND2
2626
; RUN: not test -e %t3
2727

28-
; Ensure gold generates an index as well as a binary by default in ThinLTO mode.
28+
; Ensure gold generates an index as well as a binary with save-temps in ThinLTO mode.
2929
; First force single-threaded mode
3030
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
31+
; RUN: --plugin-opt=save-temps \
3132
; RUN: --plugin-opt=thinlto \
3233
; RUN: --plugin-opt=jobs=1 \
3334
; RUN: -shared %t.o %t2.o -o %t4
34-
; RUN: llvm-bcanalyzer -dump %t4.thinlto.bc | FileCheck %s --check-prefix=COMBINED
35+
; RUN: llvm-bcanalyzer -dump %t4.index.bc | FileCheck %s --check-prefix=COMBINED
3536
; RUN: llvm-nm %t4 | FileCheck %s --check-prefix=NM
3637

3738
; Next force multi-threaded mode
3839
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
40+
; RUN: --plugin-opt=save-temps \
3941
; RUN: --plugin-opt=thinlto \
4042
; RUN: --plugin-opt=jobs=2 \
4143
; RUN: -shared %t.o %t2.o -o %t4
42-
; RUN: llvm-bcanalyzer -dump %t4.thinlto.bc | FileCheck %s --check-prefix=COMBINED
44+
; RUN: llvm-bcanalyzer -dump %t4.index.bc | FileCheck %s --check-prefix=COMBINED
4345
; RUN: llvm-nm %t4 | FileCheck %s --check-prefix=NM
4446

4547
; Test --plugin-opt=obj-path to ensure unique object files generated.
@@ -48,8 +50,8 @@
4850
; RUN: --plugin-opt=jobs=2 \
4951
; RUN: --plugin-opt=obj-path=%t5.o \
5052
; RUN: -shared %t.o %t2.o -o %t4
51-
; RUN: llvm-nm %t5.o0 | FileCheck %s --check-prefix=NM2
5253
; RUN: llvm-nm %t5.o1 | FileCheck %s --check-prefix=NM2
54+
; RUN: llvm-nm %t5.o2 | FileCheck %s --check-prefix=NM2
5355

5456
; NM: T f
5557
; NM2: T {{f|g}}

‎llvm/test/tools/gold/X86/thinlto_alias.ll

+8-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,14 @@
1414
; RUN: --plugin-opt=save-temps \
1515
; RUN: -o %t3.o %t2.o %t.o
1616
; RUN: llvm-nm %t3.o | FileCheck %s
17-
; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck --check-prefix=OPT %s
18-
; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
17+
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck --check-prefix=OPT %s
18+
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
19+
20+
; This does not currently pass because the gold plugin now uses the
21+
; combined summary rather than the IRMover to change the module's linkage
22+
; during the ThinLTO backend. The internalization step implemented by IRMover
23+
; for preempted symbols has not yet been implemented for the combined summary.
24+
; XFAIL: *
1925

2026
; CHECK-NOT: U f
2127
; OPT: define hidden void @weakfunc.llvm.0()

‎llvm/test/tools/gold/X86/thinlto_internalize.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
; RUN: --plugin-opt=-import-instr-limit=0 \
77
; RUN: --plugin-opt=save-temps \
88
; RUN: -o %t3.o %t2.o %t.o
9-
; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck %s
9+
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s
1010

1111
; f() should be internalized and eliminated after inlining
1212
; CHECK-NOT: @f()

‎llvm/test/tools/gold/X86/thinlto_linkonceresolution.ll

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
; RUN: -shared \
1515
; RUN: -o %t3.o %t2.o %t.o
1616
; RUN: llvm-nm %t3.o | FileCheck %s
17-
; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck --check-prefix=OPT %s
18-
; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
17+
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck --check-prefix=OPT %s
18+
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
1919

2020
; Ensure that f() is defined in resulting object file, and also
2121
; confirm the weak linkage directly in the saved opt bitcode files.
2222
; CHECK-NOT: U f
23-
; OPT: declare hidden void @f()
23+
; OPT-NOT: @f()
2424
; OPT2: define weak_odr hidden void @f()
2525

2626
target triple = "x86_64-unknown-linux-gnu"

‎llvm/test/tools/gold/X86/thinlto_weak_resolution.ll

+9-4
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@
1313
; RUN: llvm-nm %t3.o | FileCheck %s
1414
; CHECK: weakfunc
1515

16-
; All of the preempted functions should have been eliminated (the plugin will
17-
; not link them in).
18-
; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
16+
; Most of the preempted functions should have been eliminated (the plugin will
17+
; set linkage of odr functions to available_externally and linkonce functions
18+
; are removed by globaldce). FIXME: Need to introduce combined index linkage
19+
; that means "drop this function" so we can avoid importing linkonce functions
20+
; and drop weak functions.
21+
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
22+
; OPT2-NOT: @
23+
; OPT2: @weakfunc
1924
; OPT2-NOT: @
2025

21-
; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck --check-prefix=OPT %s
26+
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck --check-prefix=OPT %s
2227

2328
target triple = "x86_64-unknown-linux-gnu"
2429

‎llvm/test/tools/gold/X86/type-merge2.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
44
; RUN: --plugin-opt=save-temps \
55
; RUN: -shared %t.o %t2.o -o %t3.o
6-
; RUN: llvm-dis %t3.o.bc -o - | FileCheck %s
6+
; RUN: llvm-dis %t3.o.2.internalize.bc -o - | FileCheck %s
77

88
%zed = type { i8 }
99
define void @foo() {

‎llvm/test/tools/gold/X86/vectorize.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold.so \
44
; RUN: --plugin-opt=save-temps \
55
; RUN: -shared %t.o -o %t2.o
6-
; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck %s
6+
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s
77

88
; test that the vectorizer is run.
99
; CHECK: fadd <4 x float>

‎llvm/test/tools/gold/X86/visibility.ll

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
; RUN: --plugin-opt=save-temps \
66
; RUN: -shared %t.o %t2.o -o %t.so
77
; RUN: llvm-readobj -t %t.so | FileCheck %s
8-
; RUN: llvm-dis %t.so.bc -o - | FileCheck --check-prefix=IR %s
8+
; RUN: llvm-dis %t.so.2.internalize.bc -o - | FileCheck --check-prefix=IR %s
99

1010
; CHECK: Name: foo
1111
; CHECK-NEXT: Value:
@@ -16,7 +16,7 @@
1616
; CHECK-NEXT: STV_PROTECTED
1717
; CHECK-NEXT: ]
1818

19-
; IR: define protected void @foo
19+
; IR: define void @foo
2020

2121
define weak protected void @foo() {
2222
ret void

‎llvm/test/tools/llvm-lto2/errors.ll

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: not llvm-lto2 -o %t2.o %t.bc 2>&1 | FileCheck --check-prefix=ERR1 %s
3+
; RUN: not llvm-lto2 -o %t2.o -r %t.bc,foo,p -r %t.bc,bar,p %t.bc 2>&1 | FileCheck --check-prefix=ERR2 %s
4+
; RUN: not llvm-lto2 -o %t2.o -r %t.bc,foo,q %t.bc 2>&1 | FileCheck --check-prefix=ERR3 %s
5+
; RUN: not llvm-lto2 -o %t2.o -r foo %t.bc 2>&1 | FileCheck --check-prefix=ERR4 %s
6+
7+
; ERR1: missing symbol resolution for {{.*}}.bc,foo
8+
; ERR2: unused symbol resolution for {{.*}}.bc,bar
9+
; ERR3: invalid character q in resolution: {{.*}}.bc,foo
10+
; ERR4: invalid resolution: foo
11+
@foo = global i32 0

‎llvm/tools/gold/gold-plugin.cpp

+227-944
Large diffs are not rendered by default.

‎llvm/tools/llvm-lto2/CMakeLists.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
set(LLVM_LINK_COMPONENTS
2+
${LLVM_TARGETS_TO_BUILD}
3+
LTO
4+
Object
5+
Support
6+
)
7+
8+
add_llvm_tool(llvm-lto2
9+
llvm-lto2.cpp
10+
)

‎llvm/tools/llvm-lto2/LLVMBuild.txt

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
;===- ./tools/llvm-lto2/LLVMBuild.txt --------------------------*- Conf -*--===;
2+
;
3+
; The LLVM Compiler Infrastructure
4+
;
5+
; This file is distributed under the University of Illinois Open Source
6+
; License. See LICENSE.TXT for details.
7+
;
8+
;===------------------------------------------------------------------------===;
9+
;
10+
; This is an LLVMBuild description file for the components in this subdirectory.
11+
;
12+
; For more information on the LLVMBuild system, please see:
13+
;
14+
; http://llvm.org/docs/LLVMBuild.html
15+
;
16+
;===------------------------------------------------------------------------===;
17+
18+
[component_0]
19+
type = Tool
20+
name = llvm-lto2
21+
parent = Tools
22+
required_libraries = LTO Object all-targets

‎llvm/tools/llvm-lto2/llvm-lto2.cpp

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
//===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This program takes in a list of bitcode files, links them and performs
11+
// link-time optimization according to the provided symbol resolutions using the
12+
// resolution-based LTO interface, and outputs one or more object files.
13+
//
14+
// This program is intended to eventually replace llvm-lto which uses the legacy
15+
// LTO interface.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#include "llvm/LTO/LTO.h"
20+
#include "llvm/Support/CommandLine.h"
21+
#include "llvm/Support/TargetSelect.h"
22+
23+
using namespace llvm;
24+
using namespace lto;
25+
using namespace object;
26+
27+
static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
28+
cl::desc("<input bitcode files>"));
29+
30+
static cl::opt<std::string> OutputFilename("o", cl::Required,
31+
cl::desc("Output filename"),
32+
cl::value_desc("filename"));
33+
34+
static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temporary files"));
35+
36+
static cl::list<std::string> SymbolResolutions(
37+
"r",
38+
cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n"
39+
"where \"resolution\" is a sequence (which may be empty) of the\n"
40+
"following characters:\n"
41+
" p - prevailing: the linker has chosen this definition of the\n"
42+
" symbol\n"
43+
" l - local: the definition of this symbol is unpreemptable at\n"
44+
" runtime and is known to be in this linkage unit\n"
45+
" x - externally visible: the definition of this symbol is\n"
46+
" visible outside of the LTO unit\n"
47+
"A resolution for each symbol must be specified."),
48+
cl::ZeroOrMore);
49+
50+
static void check(Error E, std::string Msg) {
51+
if (!E)
52+
return;
53+
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
54+
errs() << "llvm-lto: " << Msg << ": " << EIB.message().c_str() << '\n';
55+
});
56+
exit(1);
57+
}
58+
59+
template <typename T> static T check(Expected<T> E, std::string Msg) {
60+
if (E)
61+
return std::move(*E);
62+
check(E.takeError(), Msg);
63+
return T();
64+
}
65+
66+
static void check(std::error_code EC, std::string Msg) {
67+
check(errorCodeToError(EC), Msg);
68+
}
69+
70+
template <typename T> static T check(ErrorOr<T> E, std::string Msg) {
71+
if (E)
72+
return std::move(*E);
73+
check(E.getError(), Msg);
74+
return T();
75+
}
76+
77+
int main(int argc, char **argv) {
78+
InitializeAllTargets();
79+
InitializeAllTargetMCs();
80+
InitializeAllAsmPrinters();
81+
InitializeAllAsmParsers();
82+
83+
cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");
84+
85+
std::map<std::pair<std::string, std::string>, SymbolResolution>
86+
CommandLineResolutions;
87+
for (std::string R : SymbolResolutions) {
88+
StringRef Rest = R;
89+
StringRef FileName, SymbolName;
90+
std::tie(FileName, Rest) = Rest.split(',');
91+
if (Rest.empty()) {
92+
llvm::errs() << "invalid resolution: " << R << '\n';
93+
return 1;
94+
}
95+
std::tie(SymbolName, Rest) = Rest.split(',');
96+
SymbolResolution Res;
97+
for (char C : Rest) {
98+
if (C == 'p')
99+
Res.Prevailing = true;
100+
else if (C == 'l')
101+
Res.FinalDefinitionInLinkageUnit = true;
102+
else if (C == 'x')
103+
Res.VisibleToRegularObj = true;
104+
else
105+
llvm::errs() << "invalid character " << C << " in resolution: " << R
106+
<< '\n';
107+
}
108+
CommandLineResolutions[{FileName, SymbolName}] = Res;
109+
}
110+
111+
std::vector<std::unique_ptr<MemoryBuffer>> MBs;
112+
113+
Config Conf;
114+
Conf.DiagHandler = [](const DiagnosticInfo &) {
115+
exit(1);
116+
};
117+
118+
if (SaveTemps)
119+
check(Conf.addSaveTemps(OutputFilename), "Config::addSaveTemps failed");
120+
121+
LTO Lto(std::move(Conf));
122+
123+
bool HasErrors = false;
124+
for (std::string F : InputFilenames) {
125+
std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);
126+
std::unique_ptr<InputFile> Input =
127+
check(InputFile::create(MB->getMemBufferRef()), F);
128+
129+
std::vector<SymbolResolution> Res;
130+
for (const InputFile::Symbol &Sym : Input->symbols()) {
131+
auto I = CommandLineResolutions.find({F, Sym.getName()});
132+
if (I == CommandLineResolutions.end()) {
133+
llvm::errs() << argv[0] << ": missing symbol resolution for " << F
134+
<< ',' << Sym.getName() << '\n';
135+
HasErrors = true;
136+
} else {
137+
Res.push_back(I->second);
138+
CommandLineResolutions.erase(I);
139+
}
140+
}
141+
142+
if (HasErrors)
143+
continue;
144+
145+
MBs.push_back(std::move(MB));
146+
check(Lto.add(std::move(Input), Res), F);
147+
}
148+
149+
if (!CommandLineResolutions.empty()) {
150+
HasErrors = true;
151+
for (auto UnusedRes : CommandLineResolutions)
152+
llvm::errs() << argv[0] << ": unused symbol resolution for "
153+
<< UnusedRes.first.first << ',' << UnusedRes.first.second
154+
<< '\n';
155+
}
156+
if (HasErrors)
157+
return 1;
158+
159+
auto AddStream = [&](size_t Task) {
160+
std::string Path = OutputFilename + "." + utostr(Task);
161+
std::error_code EC;
162+
auto S = make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
163+
check(EC, Path);
164+
return S;
165+
};
166+
167+
check(Lto.run(AddStream), "LTO::run failed");
168+
}

0 commit comments

Comments
 (0)
Please sign in to comment.