1//===-- llvm-lto: a simple command-line program to link modules with LTO --===//
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, performs link-time
11// optimization, and outputs an object file.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ADT/StringSet.h"
16#include "llvm/Bitcode/ReaderWriter.h"
17#include "llvm/CodeGen/CommandFlags.h"
18#include "llvm/IR/DiagnosticPrinter.h"
19#include "llvm/IR/LLVMContext.h"
20#include "llvm/LTO/LTOCodeGenerator.h"
21#include "llvm/LTO/LTOModule.h"
22#include "llvm/Object/FunctionIndexObjectFile.h"
23#include "llvm/Support/CommandLine.h"
24#include "llvm/Support/FileSystem.h"
25#include "llvm/Support/ManagedStatic.h"
26#include "llvm/Support/PrettyStackTrace.h"
27#include "llvm/Support/Signals.h"
28#include "llvm/Support/TargetSelect.h"
29#include "llvm/Support/ToolOutputFile.h"
30#include "llvm/Support/raw_ostream.h"
31#include <list>
32
33using namespace llvm;
34
35static cl::opt<char>
36OptLevel("O",
37         cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
38                  "(default = '-O2')"),
39         cl::Prefix,
40         cl::ZeroOrMore,
41         cl::init('2'));
42
43static cl::opt<bool> DisableVerify(
44    "disable-verify", cl::init(false),
45    cl::desc("Do not run the verifier during the optimization pipeline"));
46
47static cl::opt<bool>
48DisableInline("disable-inlining", cl::init(false),
49  cl::desc("Do not run the inliner pass"));
50
51static cl::opt<bool>
52DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
53  cl::desc("Do not run the GVN load PRE pass"));
54
55static cl::opt<bool>
56DisableLTOVectorization("disable-lto-vectorization", cl::init(false),
57  cl::desc("Do not run loop or slp vectorization during LTO"));
58
59static cl::opt<bool>
60UseDiagnosticHandler("use-diagnostic-handler", cl::init(false),
61  cl::desc("Use a diagnostic handler to test the handler interface"));
62
63static cl::opt<bool>
64    ThinLTO("thinlto", cl::init(false),
65            cl::desc("Only write combined global index for ThinLTO backends"));
66
67static cl::opt<bool>
68SaveModuleFile("save-merged-module", cl::init(false),
69               cl::desc("Write merged LTO module to file before CodeGen"));
70
71static cl::list<std::string>
72InputFilenames(cl::Positional, cl::OneOrMore,
73  cl::desc("<input bitcode files>"));
74
75static cl::opt<std::string>
76OutputFilename("o", cl::init(""),
77  cl::desc("Override output filename"),
78  cl::value_desc("filename"));
79
80static cl::list<std::string>
81ExportedSymbols("exported-symbol",
82  cl::desc("Symbol to export from the resulting object file"),
83  cl::ZeroOrMore);
84
85static cl::list<std::string>
86DSOSymbols("dso-symbol",
87  cl::desc("Symbol to put in the symtab in the resulting dso"),
88  cl::ZeroOrMore);
89
90static cl::opt<bool> ListSymbolsOnly(
91    "list-symbols-only", cl::init(false),
92    cl::desc("Instead of running LTO, list the symbols in each IR file"));
93
94static cl::opt<bool> SetMergedModule(
95    "set-merged-module", cl::init(false),
96    cl::desc("Use the first input module as the merged module"));
97
98static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1),
99                                     cl::desc("Number of backend threads"));
100
101namespace {
102struct ModuleInfo {
103  std::vector<bool> CanBeHidden;
104};
105}
106
107static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
108                              const char *Msg, void *) {
109  errs() << "llvm-lto: ";
110  switch (Severity) {
111  case LTO_DS_NOTE:
112    errs() << "note: ";
113    break;
114  case LTO_DS_REMARK:
115    errs() << "remark: ";
116    break;
117  case LTO_DS_ERROR:
118    errs() << "error: ";
119    break;
120  case LTO_DS_WARNING:
121    errs() << "warning: ";
122    break;
123  }
124  errs() << Msg << "\n";
125}
126
127static std::string CurrentActivity;
128static void diagnosticHandler(const DiagnosticInfo &DI) {
129  raw_ostream &OS = errs();
130  OS << "llvm-lto: ";
131  switch (DI.getSeverity()) {
132  case DS_Error:
133    OS << "error";
134    break;
135  case DS_Warning:
136    OS << "warning";
137    break;
138  case DS_Remark:
139    OS << "remark";
140    break;
141  case DS_Note:
142    OS << "note";
143    break;
144  }
145  if (!CurrentActivity.empty())
146    OS << ' ' << CurrentActivity;
147  OS << ": ";
148
149  DiagnosticPrinterRawOStream DP(OS);
150  DI.print(DP);
151  OS << '\n';
152
153  if (DI.getSeverity() == DS_Error)
154    exit(1);
155}
156
157static void diagnosticHandlerWithContenxt(const DiagnosticInfo &DI,
158                                          void *Context) {
159  diagnosticHandler(DI);
160}
161
162static void error(const Twine &Msg) {
163  errs() << "llvm-lto: " << Msg << '\n';
164  exit(1);
165}
166
167static void error(std::error_code EC, const Twine &Prefix) {
168  if (EC)
169    error(Prefix + ": " + EC.message());
170}
171
172template <typename T>
173static void error(const ErrorOr<T> &V, const Twine &Prefix) {
174  error(V.getError(), Prefix);
175}
176
177static std::unique_ptr<LTOModule>
178getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
179                  const TargetOptions &Options) {
180  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
181      MemoryBuffer::getFile(Path);
182  error(BufferOrErr, "error loading file '" + Path + "'");
183  Buffer = std::move(BufferOrErr.get());
184  CurrentActivity = ("loading file '" + Path + "'").str();
185  ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(
186      Buffer->getBufferStart(), Buffer->getBufferSize(), Options, Path);
187  CurrentActivity = "";
188  return std::move(*Ret);
189}
190
191/// \brief List symbols in each IR file.
192///
193/// The main point here is to provide lit-testable coverage for the LTOModule
194/// functionality that's exposed by the C API to list symbols.  Moreover, this
195/// provides testing coverage for modules that have been created in their own
196/// contexts.
197static void listSymbols(const TargetOptions &Options) {
198  for (auto &Filename : InputFilenames) {
199    std::unique_ptr<MemoryBuffer> Buffer;
200    std::unique_ptr<LTOModule> Module =
201        getLocalLTOModule(Filename, Buffer, Options);
202
203    // List the symbols.
204    outs() << Filename << ":\n";
205    for (int I = 0, E = Module->getSymbolCount(); I != E; ++I)
206      outs() << Module->getSymbolName(I) << "\n";
207  }
208}
209
210/// Create a combined index file from the input IR files and write it.
211///
212/// This is meant to enable testing of ThinLTO combined index generation,
213/// currently available via the gold plugin via -thinlto.
214static void createCombinedFunctionIndex() {
215  FunctionInfoIndex CombinedIndex;
216  uint64_t NextModuleId = 0;
217  for (auto &Filename : InputFilenames) {
218    CurrentActivity = "loading file '" + Filename + "'";
219    ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr =
220        llvm::getFunctionIndexForFile(Filename, diagnosticHandler);
221    std::unique_ptr<FunctionInfoIndex> Index = std::move(IndexOrErr.get());
222    CurrentActivity = "";
223    // Skip files without a function summary.
224    if (!Index)
225      continue;
226    CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
227  }
228  std::error_code EC;
229  assert(!OutputFilename.empty());
230  raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
231                    sys::fs::OpenFlags::F_None);
232  error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'");
233  WriteFunctionSummaryToFile(CombinedIndex, OS);
234  OS.close();
235}
236
237int main(int argc, char **argv) {
238  // Print a stack trace if we signal out.
239  sys::PrintStackTraceOnErrorSignal();
240  PrettyStackTraceProgram X(argc, argv);
241
242  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
243  cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");
244
245  if (OptLevel < '0' || OptLevel > '3')
246    error("optimization level must be between 0 and 3");
247
248  // Initialize the configured targets.
249  InitializeAllTargets();
250  InitializeAllTargetMCs();
251  InitializeAllAsmPrinters();
252  InitializeAllAsmParsers();
253
254  // set up the TargetOptions for the machine
255  TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
256
257  if (ListSymbolsOnly) {
258    listSymbols(Options);
259    return 0;
260  }
261
262  if (ThinLTO) {
263    createCombinedFunctionIndex();
264    return 0;
265  }
266
267  unsigned BaseArg = 0;
268
269  LLVMContext Context;
270  Context.setDiagnosticHandler(diagnosticHandlerWithContenxt, nullptr, true);
271
272  LTOCodeGenerator CodeGen(Context);
273
274  if (UseDiagnosticHandler)
275    CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
276
277  CodeGen.setCodePICModel(RelocModel);
278
279  CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
280  CodeGen.setTargetOptions(Options);
281
282  llvm::StringSet<llvm::MallocAllocator> DSOSymbolsSet;
283  for (unsigned i = 0; i < DSOSymbols.size(); ++i)
284    DSOSymbolsSet.insert(DSOSymbols[i]);
285
286  std::vector<std::string> KeptDSOSyms;
287
288  for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {
289    CurrentActivity = "loading file '" + InputFilenames[i] + "'";
290    ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
291        LTOModule::createFromFile(Context, InputFilenames[i].c_str(), Options);
292    error(ModuleOrErr, "error " + CurrentActivity);
293    std::unique_ptr<LTOModule> &Module = *ModuleOrErr;
294    CurrentActivity = "";
295
296    unsigned NumSyms = Module->getSymbolCount();
297    for (unsigned I = 0; I < NumSyms; ++I) {
298      StringRef Name = Module->getSymbolName(I);
299      if (!DSOSymbolsSet.count(Name))
300        continue;
301      lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);
302      unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
303      if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
304        KeptDSOSyms.push_back(Name);
305    }
306
307    // We use the first input module as the destination module when
308    // SetMergedModule is true.
309    if (SetMergedModule && i == BaseArg) {
310      // Transfer ownership to the code generator.
311      CodeGen.setModule(std::move(Module));
312    } else if (!CodeGen.addModule(Module.get())) {
313      // Print a message here so that we know addModule() did not abort.
314      errs() << argv[0] << ": error adding file '" << InputFilenames[i] << "'\n";
315      return 1;
316    }
317  }
318
319  // Add all the exported symbols to the table of symbols to preserve.
320  for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
321    CodeGen.addMustPreserveSymbol(ExportedSymbols[i].c_str());
322
323  // Add all the dso symbols to the table of symbols to expose.
324  for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
325    CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str());
326
327  // Set cpu and attrs strings for the default target/subtarget.
328  CodeGen.setCpu(MCPU.c_str());
329
330  CodeGen.setOptLevel(OptLevel - '0');
331
332  std::string attrs;
333  for (unsigned i = 0; i < MAttrs.size(); ++i) {
334    if (i > 0)
335      attrs.append(",");
336    attrs.append(MAttrs[i]);
337  }
338
339  if (!attrs.empty())
340    CodeGen.setAttr(attrs.c_str());
341
342  if (FileType.getNumOccurrences())
343    CodeGen.setFileType(FileType);
344
345  if (!OutputFilename.empty()) {
346    if (!CodeGen.optimize(DisableVerify, DisableInline, DisableGVNLoadPRE,
347                          DisableLTOVectorization)) {
348      // Diagnostic messages should have been printed by the handler.
349      errs() << argv[0] << ": error optimizing the code\n";
350      return 1;
351    }
352
353    if (SaveModuleFile) {
354      std::string ModuleFilename = OutputFilename;
355      ModuleFilename += ".merged.bc";
356      std::string ErrMsg;
357
358      if (!CodeGen.writeMergedModules(ModuleFilename.c_str())) {
359        errs() << argv[0] << ": writing merged module failed.\n";
360        return 1;
361      }
362    }
363
364    std::list<tool_output_file> OSs;
365    std::vector<raw_pwrite_stream *> OSPtrs;
366    for (unsigned I = 0; I != Parallelism; ++I) {
367      std::string PartFilename = OutputFilename;
368      if (Parallelism != 1)
369        PartFilename += "." + utostr(I);
370      std::error_code EC;
371      OSs.emplace_back(PartFilename, EC, sys::fs::F_None);
372      if (EC) {
373        errs() << argv[0] << ": error opening the file '" << PartFilename
374               << "': " << EC.message() << "\n";
375        return 1;
376      }
377      OSPtrs.push_back(&OSs.back().os());
378    }
379
380    if (!CodeGen.compileOptimized(OSPtrs)) {
381      // Diagnostic messages should have been printed by the handler.
382      errs() << argv[0] << ": error compiling the code\n";
383      return 1;
384    }
385
386    for (tool_output_file &OS : OSs)
387      OS.keep();
388  } else {
389    if (Parallelism != 1) {
390      errs() << argv[0] << ": -j must be specified together with -o\n";
391      return 1;
392    }
393
394    if (SaveModuleFile) {
395      errs() << argv[0] << ": -save-merged-module must be specified with -o\n";
396      return 1;
397    }
398
399    const char *OutputName = nullptr;
400    if (!CodeGen.compile_to_file(&OutputName, DisableVerify, DisableInline,
401                                 DisableGVNLoadPRE, DisableLTOVectorization)) {
402      // Diagnostic messages should have been printed by the handler.
403      errs() << argv[0] << ": error compiling the code\n";
404      return 1;
405    }
406
407    outs() << "Wrote native object file '" << OutputName << "'\n";
408  }
409
410  return 0;
411}
412