brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.0 KiB · 399306f Raw
630 lines · cpp
1//===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This program takes in a list of bitcode files, links them and performs10// link-time optimization according to the provided symbol resolutions using the11// resolution-based LTO interface, and outputs one or more object files.12//13// This program is intended to eventually replace llvm-lto which uses the legacy14// LTO interface.15//16//===----------------------------------------------------------------------===//17 18#include "llvm/Bitcode/BitcodeReader.h"19#include "llvm/CodeGen/CommandFlags.h"20#include "llvm/IR/DiagnosticPrinter.h"21#include "llvm/LTO/LTO.h"22#include "llvm/Passes/PassPlugin.h"23#include "llvm/Remarks/HotnessThresholdParser.h"24#include "llvm/Support/Caching.h"25#include "llvm/Support/CommandLine.h"26#include "llvm/Support/FileSystem.h"27#include "llvm/Support/InitLLVM.h"28#include "llvm/Support/PluginLoader.h"29#include "llvm/Support/TargetSelect.h"30#include "llvm/Support/Threading.h"31#include <atomic>32 33using namespace llvm;34using namespace lto;35 36static codegen::RegisterCodeGenFlags CGF;37 38static cl::opt<char>39    OptLevel("O",40             cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "41                      "(default = '-O2')"),42             cl::Prefix, cl::init('2'));43 44static cl::opt<char> CGOptLevel(45    "cg-opt-level",46    cl::desc("Codegen optimization level (0, 1, 2 or 3, default = '2')"),47    cl::init('2'));48 49static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,50                                            cl::desc("<input bitcode files>"));51 52static cl::opt<std::string> OutputFilename("o", cl::Required,53                                           cl::desc("Output filename"),54                                           cl::value_desc("filename"));55 56static cl::opt<std::string> CacheDir("cache-dir", cl::desc("Cache Directory"),57                                     cl::value_desc("directory"));58 59static cl::opt<std::string> OptPipeline("opt-pipeline",60                                        cl::desc("Optimizer Pipeline"),61                                        cl::value_desc("pipeline"));62 63static cl::opt<std::string> AAPipeline("aa-pipeline",64                                       cl::desc("Alias Analysis Pipeline"),65                                       cl::value_desc("aapipeline"));66 67static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temporary files"));68 69static cl::list<std::string> SelectSaveTemps(70    "select-save-temps",71    cl::value_desc("One, or multiple of: "72                   "resolution,preopt,promote,internalize,import,opt,precodegen"73                   ",combinedindex"),74    cl::desc("Save selected temporary files. Cannot be specified together with "75             "-save-temps"),76    cl::CommaSeparated);77 78constexpr const char *SaveTempsValues[] = {79    "resolution", "preopt", "promote",    "internalize",80    "import",     "opt",    "precodegen", "combinedindex"};81 82static cl::opt<bool>83    ThinLTODistributedIndexes("thinlto-distributed-indexes",84                              cl::desc("Write out individual index and "85                                       "import files for the "86                                       "distributed backend case"));87 88static cl::opt<bool>89    ThinLTOEmitIndexes("thinlto-emit-indexes",90                       cl::desc("Write out individual index files via "91                                "InProcessThinLTO"));92 93static cl::opt<bool>94    ThinLTOEmitImports("thinlto-emit-imports",95                       cl::desc("Write out individual imports files via "96                                "InProcessThinLTO. Has no effect unless "97                                "specified with -thinlto-emit-indexes or "98                                "-thinlto-distributed-indexes"));99 100static cl::opt<std::string> DTLTODistributor(101    "dtlto-distributor",102    cl::desc("Distributor to use for ThinLTO backend compilations. Specifying "103             "this enables DTLTO."));104 105static cl::list<std::string> DTLTODistributorArgs(106    "dtlto-distributor-arg", cl::CommaSeparated,107    cl::desc("Arguments to pass to the DTLTO distributor process."),108    cl::value_desc("arg"));109 110static cl::opt<std::string> DTLTOCompiler(111    "dtlto-compiler",112    cl::desc("Compiler to use for DTLTO ThinLTO backend compilations."));113 114static cl::list<std::string> DTLTOCompilerPrependArgs(115    "dtlto-compiler-prepend-arg", cl::CommaSeparated,116    cl::desc("Prepend arguments to pass to the remote compiler for backend "117             "compilations."),118    cl::value_desc("arg"));119 120static cl::list<std::string> DTLTOCompilerArgs(121    "dtlto-compiler-arg", cl::CommaSeparated,122    cl::desc("Arguments to pass to the remote compiler for backend "123             "compilations."),124    cl::value_desc("arg"));125 126// Default to using all available threads in the system, but using only one127// thread per core (no SMT).128// Use -thinlto-threads=all to use hardware_concurrency() instead, which means129// to use all hardware threads or cores in the system.130static cl::opt<std::string> Threads("thinlto-threads");131 132static cl::list<std::string> SymbolResolutions(133    "r",134    cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n"135             "where \"resolution\" is a sequence (which may be empty) of the\n"136             "following characters:\n"137             " p - prevailing: the linker has chosen this definition of the\n"138             "     symbol\n"139             " l - local: the definition of this symbol is unpreemptable at\n"140             "     runtime and is known to be in this linkage unit\n"141             " x - externally visible: the definition of this symbol is\n"142             "     visible outside of the LTO unit\n"143             "A resolution for each symbol must be specified"));144 145static cl::opt<std::string> OverrideTriple(146    "override-triple",147    cl::desc("Replace target triples in input files with this triple"));148 149static cl::opt<std::string> DefaultTriple(150    "default-triple",151    cl::desc(152        "Replace unspecified target triples in input files with this triple"));153 154static cl::opt<bool> RemarksWithHotness(155    "pass-remarks-with-hotness",156    cl::desc("With PGO, include profile count in optimization remarks"),157    cl::Hidden);158 159static cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>160    RemarksHotnessThreshold(161        "pass-remarks-hotness-threshold",162        cl::desc("Minimum profile count required for an "163                 "optimization remark to be output."164                 " Use 'auto' to apply the threshold from profile summary."),165        cl::value_desc("uint or 'auto'"), cl::init(0), cl::Hidden);166 167static cl::opt<std::string>168    RemarksFilename("pass-remarks-output",169                    cl::desc("Output filename for pass remarks"),170                    cl::value_desc("filename"));171 172static cl::opt<std::string>173    RemarksPasses("pass-remarks-filter",174                  cl::desc("Only record optimization remarks from passes whose "175                           "names match the given regular expression"),176                  cl::value_desc("regex"));177 178static cl::opt<std::string> RemarksFormat(179    "pass-remarks-format",180    cl::desc("The format used for serializing remarks (default: YAML)"),181    cl::value_desc("format"), cl::init("yaml"));182 183static cl::opt<std::string>184    SamplePGOFile("lto-sample-profile-file",185                  cl::desc("Specify a SamplePGO profile file"));186 187static cl::opt<std::string>188    CSPGOFile("lto-cspgo-profile-file",189              cl::desc("Specify a context sensitive PGO profile file"));190 191static cl::opt<bool>192    RunCSIRInstr("lto-cspgo-gen",193                 cl::desc("Run PGO context sensitive IR instrumentation"),194                 cl::Hidden);195 196static cl::opt<bool>197    DebugPassManager("debug-pass-manager", cl::Hidden,198                     cl::desc("Print pass management debugging information"));199 200static cl::opt<std::string>201    StatsFile("stats-file", cl::desc("Filename to write statistics to"));202 203static cl::list<std::string>204    PassPlugins("load-pass-plugin",205                cl::desc("Load passes from plugin library"));206 207static cl::opt<LTO::LTOKind> UnifiedLTOMode(208    "unified-lto", cl::Optional,209    cl::desc("Set LTO mode with the following options:"),210    cl::values(clEnumValN(LTO::LTOK_UnifiedThin, "thin",211                          "ThinLTO with Unified LTO enabled"),212               clEnumValN(LTO::LTOK_UnifiedRegular, "full",213                          "Regular LTO with Unified LTO enabled"),214               clEnumValN(LTO::LTOK_Default, "default",215                          "Any LTO mode without Unified LTO")),216    cl::value_desc("mode"), cl::init(LTO::LTOK_Default));217 218static cl::opt<bool> EnableFreestanding(219    "lto-freestanding",220    cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),221    cl::Hidden);222 223static cl::opt<bool> WholeProgramVisibilityEnabledInLTO(224    "whole-program-visibility-enabled-in-lto",225    cl::desc("Enable whole program visibility during LTO"), cl::Hidden);226 227static cl::opt<bool> ValidateAllVtablesHaveTypeInfos(228    "validate-all-vtables-have-type-infos",229    cl::desc("Validate that all vtables have type infos in LTO"), cl::Hidden);230 231static cl::opt<bool>232    AllVtablesHaveTypeInfos("all-vtables-have-type-infos", cl::Hidden,233                            cl::desc("All vtables have type infos"));234 235static void check(Error E, std::string Msg) {236  if (!E)237    return;238  handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {239    errs() << "llvm-lto2: " << Msg << ": " << EIB.message().c_str() << '\n';240  });241  exit(1);242}243 244template <typename T> static T check(Expected<T> E, std::string Msg) {245  if (E)246    return std::move(*E);247  check(E.takeError(), Msg);248  return T();249}250 251static void check(std::error_code EC, std::string Msg) {252  check(errorCodeToError(EC), Msg);253}254 255template <typename T> static T check(ErrorOr<T> E, std::string Msg) {256  if (E)257    return std::move(*E);258  check(E.getError(), Msg);259  return T();260}261 262static int usage() {263  errs() << "Available subcommands: dump-symtab run print-guid\n";264  return 1;265}266 267static int run(int argc, char **argv) {268  cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");269 270  // FIXME: Workaround PR30396 which means that a symbol can appear271  // more than once if it is defined in module-level assembly and272  // has a GV declaration. We allow (file, symbol) pairs to have multiple273  // resolutions and apply them in the order observed.274  std::map<std::pair<std::string, std::string>, std::list<SymbolResolution>>275      CommandLineResolutions;276  for (StringRef R : SymbolResolutions) {277    StringRef Rest, FileName, SymbolName;278    std::tie(FileName, Rest) = R.split(',');279    if (Rest.empty()) {280      llvm::errs() << "invalid resolution: " << R << '\n';281      return 1;282    }283    std::tie(SymbolName, Rest) = Rest.split(',');284    SymbolResolution Res;285    for (char C : Rest) {286      if (C == 'p')287        Res.Prevailing = true;288      else if (C == 'l')289        Res.FinalDefinitionInLinkageUnit = true;290      else if (C == 'x')291        Res.VisibleToRegularObj = true;292      else if (C == 'r')293        Res.LinkerRedefined = true;294      else {295        llvm::errs() << "invalid character " << C << " in resolution: " << R296                     << '\n';297        return 1;298      }299    }300    CommandLineResolutions[{std::string(FileName), std::string(SymbolName)}]301        .push_back(Res);302  }303 304  std::vector<std::unique_ptr<MemoryBuffer>> MBs;305 306  Config Conf;307 308  Conf.CPU = codegen::getMCPU();309  Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());310  Conf.MAttrs = codegen::getMAttrs();311  if (auto RM = codegen::getExplicitRelocModel())312    Conf.RelocModel = *RM;313  Conf.CodeModel = codegen::getExplicitCodeModel();314 315  Conf.DebugPassManager = DebugPassManager;316 317  if (SaveTemps && !SelectSaveTemps.empty()) {318    llvm::errs() << "-save-temps cannot be specified with -select-save-temps\n";319    return 1;320  }321  if (SaveTemps || !SelectSaveTemps.empty()) {322    DenseSet<StringRef> SaveTempsArgs;323    for (auto &S : SelectSaveTemps)324      if (is_contained(SaveTempsValues, S))325        SaveTempsArgs.insert(S);326      else {327        llvm::errs() << ("invalid -select-save-temps argument: " + S) << '\n';328        return 1;329      }330    check(Conf.addSaveTemps(OutputFilename + ".", false, SaveTempsArgs),331          "Config::addSaveTemps failed");332  }333 334  // Optimization remarks.335  Conf.RemarksFilename = RemarksFilename;336  Conf.RemarksPasses = RemarksPasses;337  Conf.RemarksWithHotness = RemarksWithHotness;338  Conf.RemarksHotnessThreshold = RemarksHotnessThreshold;339  Conf.RemarksFormat = RemarksFormat;340 341  Conf.SampleProfile = SamplePGOFile;342  Conf.CSIRProfile = CSPGOFile;343  Conf.RunCSIRInstr = RunCSIRInstr;344 345  // Run a custom pipeline, if asked for.346  Conf.OptPipeline = OptPipeline;347  Conf.AAPipeline = AAPipeline;348 349  Conf.OptLevel = OptLevel - '0';350  Conf.Freestanding = EnableFreestanding;351  llvm::append_range(Conf.PassPlugins, PassPlugins);352  if (auto Level = CodeGenOpt::parseLevel(CGOptLevel)) {353    Conf.CGOptLevel = *Level;354  } else {355    llvm::errs() << "invalid cg optimization level: " << CGOptLevel << '\n';356    return 1;357  }358 359  if (auto FT = codegen::getExplicitFileType())360    Conf.CGFileType = *FT;361 362  Conf.OverrideTriple = OverrideTriple;363  Conf.DefaultTriple = DefaultTriple;364  Conf.StatsFile = StatsFile;365  Conf.PTO.LoopVectorization = Conf.OptLevel > 1;366  Conf.PTO.SLPVectorization = Conf.OptLevel > 1;367 368  if (WholeProgramVisibilityEnabledInLTO.getNumOccurrences() > 0)369    Conf.HasWholeProgramVisibility = WholeProgramVisibilityEnabledInLTO;370  if (ValidateAllVtablesHaveTypeInfos.getNumOccurrences() > 0)371    Conf.ValidateAllVtablesHaveTypeInfos = ValidateAllVtablesHaveTypeInfos;372  if (AllVtablesHaveTypeInfos.getNumOccurrences() > 0)373    Conf.AllVtablesHaveTypeInfos = AllVtablesHaveTypeInfos;374 375  if (ThinLTODistributedIndexes && !DTLTODistributor.empty())376    llvm::errs() << "-thinlto-distributed-indexes cannot be specfied together "377                    "with -dtlto-distributor\n";378  auto DTLTODistributorArgsSV = llvm::to_vector<0>(llvm::map_range(379      DTLTODistributorArgs, [](const std::string &S) { return StringRef(S); }));380  auto DTLTOCompilerPrependArgsSV = llvm::to_vector<0>(381      llvm::map_range(DTLTOCompilerPrependArgs,382                      [](const std::string &S) { return StringRef(S); }));383  auto DTLTOCompilerArgsSV = llvm::to_vector<0>(llvm::map_range(384      DTLTOCompilerArgs, [](const std::string &S) { return StringRef(S); }));385 386  ThinBackend Backend;387  if (ThinLTODistributedIndexes)388    Backend = createWriteIndexesThinBackend(llvm::hardware_concurrency(Threads),389                                            /*OldPrefix=*/"",390                                            /*NewPrefix=*/"",391                                            /*NativeObjectPrefix=*/"",392                                            ThinLTOEmitImports,393                                            /*LinkedObjectsFile=*/nullptr,394                                            /*OnWrite=*/{});395  else if (!DTLTODistributor.empty()) {396    Backend = createOutOfProcessThinBackend(397        llvm::heavyweight_hardware_concurrency(Threads),398        /*OnWrite=*/{}, ThinLTOEmitIndexes, ThinLTOEmitImports, OutputFilename,399        DTLTODistributor, DTLTODistributorArgsSV, DTLTOCompiler,400        DTLTOCompilerPrependArgsSV, DTLTOCompilerArgsSV, SaveTemps);401  } else402    Backend = createInProcessThinBackend(403        llvm::heavyweight_hardware_concurrency(Threads),404        /* OnWrite */ {}, ThinLTOEmitIndexes, ThinLTOEmitImports);405 406  // Track whether we hit an error; in particular, in the multi-threaded case,407  // we can't exit() early because the rest of the threads wouldn't have had a408  // change to be join-ed, and that would result in a "terminate called without409  // an active exception". Altogether, this results in nondeterministic410  // behavior. Instead, we don't exit in the multi-threaded case, but we make411  // sure to report the error and then at the end (after joining cleanly)412  // exit(1).413  std::atomic<bool> HasErrors{false};414  Conf.DiagHandler = [&](const DiagnosticInfo &DI) {415    DiagnosticPrinterRawOStream DP(errs());416    DI.print(DP);417    errs() << '\n';418    if (DI.getSeverity() == DS_Error)419      HasErrors = true;420  };421 422  LTO::LTOKind LTOMode = UnifiedLTOMode;423 424  LTO Lto(std::move(Conf), std::move(Backend), 1, LTOMode);425 426  for (std::string F : InputFilenames) {427    std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);428    std::unique_ptr<InputFile> Input =429        check(InputFile::create(MB->getMemBufferRef()), F);430 431    std::vector<SymbolResolution> Res;432    for (const InputFile::Symbol &Sym : Input->symbols()) {433      auto I = CommandLineResolutions.find({F, std::string(Sym.getName())});434      // If it isn't found, look for ".", which would have been added435      // (followed by a hash) when the symbol was promoted during module436      // splitting if it was defined in one part and used in the other.437      // Try looking up the symbol name before the suffix.438      if (I == CommandLineResolutions.end()) {439        auto SplitName = Sym.getName().rsplit(".");440        I = CommandLineResolutions.find({F, std::string(SplitName.first)});441      }442      if (I == CommandLineResolutions.end()) {443        llvm::errs() << argv[0] << ": missing symbol resolution for " << F444                     << ',' << Sym.getName() << '\n';445        HasErrors = true;446      } else {447        Res.push_back(I->second.front());448        I->second.pop_front();449        if (I->second.empty())450          CommandLineResolutions.erase(I);451      }452    }453 454    if (HasErrors)455      continue;456 457    MBs.push_back(std::move(MB));458    check(Lto.add(std::move(Input), Res), F);459  }460 461  if (!CommandLineResolutions.empty()) {462    HasErrors = true;463    for (auto UnusedRes : CommandLineResolutions)464      llvm::errs() << argv[0] << ": unused symbol resolution for "465                   << UnusedRes.first.first << ',' << UnusedRes.first.second466                   << '\n';467  }468  if (HasErrors)469    return 1;470 471  auto AddStream =472      [&](size_t Task,473          const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {474    std::string Path = OutputFilename + "." + utostr(Task);475 476    std::error_code EC;477    auto S = std::make_unique<raw_fd_ostream>(Path, EC, sys::fs::OF_None);478    check(EC, Path);479    return std::make_unique<CachedFileStream>(std::move(S), Path);480  };481 482  auto AddBuffer = [&](size_t Task, const Twine &ModuleName,483                       std::unique_ptr<MemoryBuffer> MB) {484    auto Stream = AddStream(Task, ModuleName);485    *Stream->OS << MB->getBuffer();486    check(Stream->commit(), "Failed to commit cache");487  };488 489  FileCache Cache;490  if (!CacheDir.empty())491    Cache = check(localCache("ThinLTO", "Thin", CacheDir, AddBuffer),492                  "failed to create cache");493 494  check(Lto.run(AddStream, Cache), "LTO::run failed");495  return static_cast<int>(HasErrors);496}497 498static int dumpSymtab(int argc, char **argv) {499  for (StringRef F : make_range(argv + 1, argv + argc)) {500    std::unique_ptr<MemoryBuffer> MB =501        check(MemoryBuffer::getFile(F), std::string(F));502    BitcodeFileContents BFC =503        check(getBitcodeFileContents(*MB), std::string(F));504 505    if (BFC.Symtab.size() >= sizeof(irsymtab::storage::Header)) {506      auto *Hdr = reinterpret_cast<const irsymtab::storage::Header *>(507          BFC.Symtab.data());508      outs() << "version: " << Hdr->Version << '\n';509      if (Hdr->Version == irsymtab::storage::Header::kCurrentVersion)510        outs() << "producer: " << Hdr->Producer.get(BFC.StrtabForSymtab)511               << '\n';512    }513 514    std::unique_ptr<InputFile> Input =515        check(InputFile::create(MB->getMemBufferRef()), std::string(F));516 517    outs() << "target triple: " << Input->getTargetTriple() << '\n';518    Triple TT(Input->getTargetTriple());519 520    outs() << "source filename: " << Input->getSourceFileName() << '\n';521 522    if (TT.isOSBinFormatCOFF())523      outs() << "linker opts: " << Input->getCOFFLinkerOpts() << '\n';524 525    if (TT.isOSBinFormatELF()) {526      outs() << "dependent libraries:";527      for (auto L : Input->getDependentLibraries())528        outs() << " \"" << L << "\"";529      outs() << '\n';530    }531 532    ArrayRef<std::pair<StringRef, Comdat::SelectionKind>> ComdatTable =533        Input->getComdatTable();534    for (const InputFile::Symbol &Sym : Input->symbols()) {535      switch (Sym.getVisibility()) {536      case GlobalValue::HiddenVisibility:537        outs() << 'H';538        break;539      case GlobalValue::ProtectedVisibility:540        outs() << 'P';541        break;542      case GlobalValue::DefaultVisibility:543        outs() << 'D';544        break;545      }546 547      auto PrintBool = [&](char C, bool B) { outs() << (B ? C : '-'); };548      PrintBool('U', Sym.isUndefined());549      PrintBool('C', Sym.isCommon());550      PrintBool('W', Sym.isWeak());551      PrintBool('I', Sym.isIndirect());552      PrintBool('O', Sym.canBeOmittedFromSymbolTable());553      PrintBool('T', Sym.isTLS());554      PrintBool('X', Sym.isExecutable());555      outs() << ' ' << Sym.getName() << '\n';556 557      if (Sym.isCommon())558        outs() << "         size " << Sym.getCommonSize() << " align "559               << Sym.getCommonAlignment() << '\n';560 561      int Comdat = Sym.getComdatIndex();562      if (Comdat != -1) {563        outs() << "         comdat ";564        switch (ComdatTable[Comdat].second) {565        case Comdat::Any:566          outs() << "any";567          break;568        case Comdat::ExactMatch:569          outs() << "exactmatch";570          break;571        case Comdat::Largest:572          outs() << "largest";573          break;574        case Comdat::NoDeduplicate:575          outs() << "nodeduplicate";576          break;577        case Comdat::SameSize:578          outs() << "samesize";579          break;580        }581        outs() << ' ' << ComdatTable[Comdat].first << '\n';582      }583 584      if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect())585        outs() << "         fallback " << Sym.getCOFFWeakExternalFallback()586               << '\n';587 588      if (!Sym.getSectionName().empty())589        outs() << "         section " << Sym.getSectionName() << "\n";590    }591 592    outs() << '\n';593  }594 595  return 0;596}597 598int main(int argc, char **argv) {599  InitLLVM X(argc, argv);600  InitializeAllTargets();601  InitializeAllTargetMCs();602  InitializeAllAsmPrinters();603  InitializeAllAsmParsers();604 605  // FIXME: This should use llvm::cl subcommands, but it isn't currently606  // possible to pass an argument not associated with a subcommand to a607  // subcommand (e.g. -use-new-pm).608  if (argc < 2)609    return usage();610 611  StringRef Subcommand = argv[1];612  // Ensure that argv[0] is correct after adjusting argv/argc.613  argv[1] = argv[0];614  if (Subcommand == "dump-symtab")615    return dumpSymtab(argc - 1, argv + 1);616  if (Subcommand == "run")617    return run(argc - 1, argv + 1);618  if (Subcommand == "print-guid" && argc > 2) {619    // Note the name of the function we're calling: this won't return the right620    // answer for internal linkage symbols.621    outs() << GlobalValue::getGUIDAssumingExternalLinkage(argv[2]) << '\n';622    return 0;623  }624  if (Subcommand == "--version") {625    cl::PrintVersionMessage();626    return 0;627  }628  return usage();629}630