Home | History | Annotate | Download | only in llvm-lto
      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 
     33 using namespace llvm;
     34 
     35 static cl::opt<char>
     36 OptLevel("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 
     43 static cl::opt<bool> DisableVerify(
     44     "disable-verify", cl::init(false),
     45     cl::desc("Do not run the verifier during the optimization pipeline"));
     46 
     47 static cl::opt<bool>
     48 DisableInline("disable-inlining", cl::init(false),
     49   cl::desc("Do not run the inliner pass"));
     50 
     51 static cl::opt<bool>
     52 DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
     53   cl::desc("Do not run the GVN load PRE pass"));
     54 
     55 static cl::opt<bool>
     56 DisableLTOVectorization("disable-lto-vectorization", cl::init(false),
     57   cl::desc("Do not run loop or slp vectorization during LTO"));
     58 
     59 static cl::opt<bool>
     60 UseDiagnosticHandler("use-diagnostic-handler", cl::init(false),
     61   cl::desc("Use a diagnostic handler to test the handler interface"));
     62 
     63 static cl::opt<bool>
     64     ThinLTO("thinlto", cl::init(false),
     65             cl::desc("Only write combined global index for ThinLTO backends"));
     66 
     67 static cl::opt<bool>
     68 SaveModuleFile("save-merged-module", cl::init(false),
     69                cl::desc("Write merged LTO module to file before CodeGen"));
     70 
     71 static cl::list<std::string>
     72 InputFilenames(cl::Positional, cl::OneOrMore,
     73   cl::desc("<input bitcode files>"));
     74 
     75 static cl::opt<std::string>
     76 OutputFilename("o", cl::init(""),
     77   cl::desc("Override output filename"),
     78   cl::value_desc("filename"));
     79 
     80 static cl::list<std::string>
     81 ExportedSymbols("exported-symbol",
     82   cl::desc("Symbol to export from the resulting object file"),
     83   cl::ZeroOrMore);
     84 
     85 static cl::list<std::string>
     86 DSOSymbols("dso-symbol",
     87   cl::desc("Symbol to put in the symtab in the resulting dso"),
     88   cl::ZeroOrMore);
     89 
     90 static 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 
     94 static cl::opt<bool> SetMergedModule(
     95     "set-merged-module", cl::init(false),
     96     cl::desc("Use the first input module as the merged module"));
     97 
     98 static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1),
     99                                      cl::desc("Number of backend threads"));
    100 
    101 namespace {
    102 struct ModuleInfo {
    103   std::vector<bool> CanBeHidden;
    104 };
    105 }
    106 
    107 static 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 
    127 static std::string CurrentActivity;
    128 static 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 
    157 static void diagnosticHandlerWithContenxt(const DiagnosticInfo &DI,
    158                                           void *Context) {
    159   diagnosticHandler(DI);
    160 }
    161 
    162 static void error(const Twine &Msg) {
    163   errs() << "llvm-lto: " << Msg << '\n';
    164   exit(1);
    165 }
    166 
    167 static void error(std::error_code EC, const Twine &Prefix) {
    168   if (EC)
    169     error(Prefix + ": " + EC.message());
    170 }
    171 
    172 template <typename T>
    173 static void error(const ErrorOr<T> &V, const Twine &Prefix) {
    174   error(V.getError(), Prefix);
    175 }
    176 
    177 static std::unique_ptr<LTOModule>
    178 getLocalLTOModule(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.
    197 static 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.
    214 static 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 
    237 int 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     std::unique_ptr<LTOModule> &Module = *ModuleOrErr;
    293     CurrentActivity = "";
    294 
    295     unsigned NumSyms = Module->getSymbolCount();
    296     for (unsigned I = 0; I < NumSyms; ++I) {
    297       StringRef Name = Module->getSymbolName(I);
    298       if (!DSOSymbolsSet.count(Name))
    299         continue;
    300       lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);
    301       unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
    302       if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
    303         KeptDSOSyms.push_back(Name);
    304     }
    305 
    306     // We use the first input module as the destination module when
    307     // SetMergedModule is true.
    308     if (SetMergedModule && i == BaseArg) {
    309       // Transfer ownership to the code generator.
    310       CodeGen.setModule(std::move(Module));
    311     } else if (!CodeGen.addModule(Module.get())) {
    312       // Print a message here so that we know addModule() did not abort.
    313       errs() << argv[0] << ": error adding file '" << InputFilenames[i] << "'\n";
    314       return 1;
    315     }
    316   }
    317 
    318   // Add all the exported symbols to the table of symbols to preserve.
    319   for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
    320     CodeGen.addMustPreserveSymbol(ExportedSymbols[i].c_str());
    321 
    322   // Add all the dso symbols to the table of symbols to expose.
    323   for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
    324     CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str());
    325 
    326   // Set cpu and attrs strings for the default target/subtarget.
    327   CodeGen.setCpu(MCPU.c_str());
    328 
    329   CodeGen.setOptLevel(OptLevel - '0');
    330 
    331   std::string attrs;
    332   for (unsigned i = 0; i < MAttrs.size(); ++i) {
    333     if (i > 0)
    334       attrs.append(",");
    335     attrs.append(MAttrs[i]);
    336   }
    337 
    338   if (!attrs.empty())
    339     CodeGen.setAttr(attrs.c_str());
    340 
    341   if (FileType.getNumOccurrences())
    342     CodeGen.setFileType(FileType);
    343 
    344   if (!OutputFilename.empty()) {
    345     if (!CodeGen.optimize(DisableVerify, DisableInline, DisableGVNLoadPRE,
    346                           DisableLTOVectorization)) {
    347       // Diagnostic messages should have been printed by the handler.
    348       errs() << argv[0] << ": error optimizing the code\n";
    349       return 1;
    350     }
    351 
    352     if (SaveModuleFile) {
    353       std::string ModuleFilename = OutputFilename;
    354       ModuleFilename += ".merged.bc";
    355       std::string ErrMsg;
    356 
    357       if (!CodeGen.writeMergedModules(ModuleFilename.c_str())) {
    358         errs() << argv[0] << ": writing merged module failed.\n";
    359         return 1;
    360       }
    361     }
    362 
    363     std::list<tool_output_file> OSs;
    364     std::vector<raw_pwrite_stream *> OSPtrs;
    365     for (unsigned I = 0; I != Parallelism; ++I) {
    366       std::string PartFilename = OutputFilename;
    367       if (Parallelism != 1)
    368         PartFilename += "." + utostr(I);
    369       std::error_code EC;
    370       OSs.emplace_back(PartFilename, EC, sys::fs::F_None);
    371       if (EC) {
    372         errs() << argv[0] << ": error opening the file '" << PartFilename
    373                << "': " << EC.message() << "\n";
    374         return 1;
    375       }
    376       OSPtrs.push_back(&OSs.back().os());
    377     }
    378 
    379     if (!CodeGen.compileOptimized(OSPtrs)) {
    380       // Diagnostic messages should have been printed by the handler.
    381       errs() << argv[0] << ": error compiling the code\n";
    382       return 1;
    383     }
    384 
    385     for (tool_output_file &OS : OSs)
    386       OS.keep();
    387   } else {
    388     if (Parallelism != 1) {
    389       errs() << argv[0] << ": -j must be specified together with -o\n";
    390       return 1;
    391     }
    392 
    393     if (SaveModuleFile) {
    394       errs() << argv[0] << ": -save-merged-module must be specified with -o\n";
    395       return 1;
    396     }
    397 
    398     const char *OutputName = nullptr;
    399     if (!CodeGen.compile_to_file(&OutputName, DisableVerify, DisableInline,
    400                                  DisableGVNLoadPRE, DisableLTOVectorization)) {
    401       // Diagnostic messages should have been printed by the handler.
    402       errs() << argv[0] << ": error compiling the code\n";
    403       return 1;
    404     }
    405 
    406     outs() << "Wrote native object file '" << OutputName << "'\n";
    407   }
    408 
    409   return 0;
    410 }
    411