示例#1
0
/// Create a combined index file from the input IR files and write it.
///
/// This is meant to enable testing of ThinLTO combined index generation,
/// currently available via the gold plugin via -thinlto.
static int createCombinedFunctionIndex(StringRef Command) {
  LLVMContext Context;
  FunctionInfoIndex CombinedIndex;
  uint64_t NextModuleId = 0;
  for (auto &Filename : InputFilenames) {
    std::string Error;
    std::unique_ptr<FunctionInfoIndex> Index =
        getFunctionIndexForFile(Filename, Error, Context);
    if (!Index) {
      errs() << Command << ": error loading file '" << Filename
             << "': " << Error << "\n";
      return 1;
    }
    CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
  }
  std::error_code EC;
  assert(!OutputFilename.empty());
  raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
                    sys::fs::OpenFlags::F_None);
  if (EC) {
    errs() << Command << ": error opening the file '" << OutputFilename
           << ".thinlto.bc': " << EC.message() << "\n";
    return 1;
  }
  WriteFunctionSummaryToFile(CombinedIndex, OS);
  OS.close();
  return 0;
}
示例#2
0
/// Create a combined index file from the input IR files and write it.
///
/// This is meant to enable testing of ThinLTO combined index generation,
/// currently available via the gold plugin via -thinlto.
static int createCombinedFunctionIndex(StringRef Command) {
  FunctionInfoIndex CombinedIndex;
  uint64_t NextModuleId = 0;
  for (auto &Filename : InputFilenames) {
    ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr =
        getFunctionIndexForFile(Filename, diagnosticHandler);
    if (std::error_code EC = IndexOrErr.getError()) {
      std::string Error = EC.message();
      errs() << Command << ": error loading file '" << Filename
             << "': " << Error << "\n";
      return 1;
    }
    std::unique_ptr<FunctionInfoIndex> Index = std::move(IndexOrErr.get());
    // Skip files without a function summary.
    if (!Index)
      continue;
    CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
  }
  std::error_code EC;
  assert(!OutputFilename.empty());
  raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
                    sys::fs::OpenFlags::F_None);
  if (EC) {
    errs() << Command << ": error opening the file '" << OutputFilename
           << ".thinlto.bc': " << EC.message() << "\n";
    return 1;
  }
  WriteFunctionSummaryToFile(CombinedIndex, OS);
  OS.close();
  return 0;
}
示例#3
0
/// Walk through the instructions in \p F looking for external
/// calls not already in the \p CalledFunctions set. If any are
/// found they are added to the \p Worklist for importing.
static void findExternalCalls(const Module &DestModule, Function &F,
                              const FunctionInfoIndex &Index,
                              StringSet<> &CalledFunctions,
                              SmallVector<StringRef, 64> &Worklist) {
  // We need to suffix internal function calls imported from other modules,
  // prepare the suffix ahead of time.
  std::string Suffix;
  if (F.getParent() != &DestModule)
    Suffix =
        (Twine(".llvm.") +
         Twine(Index.getModuleId(F.getParent()->getModuleIdentifier()))).str();

  for (auto &BB : F) {
    for (auto &I : BB) {
      if (isa<CallInst>(I)) {
        auto CalledFunction = cast<CallInst>(I).getCalledFunction();
        // Insert any new external calls that have not already been
        // added to set/worklist.
        if (!CalledFunction || !CalledFunction->hasName())
          continue;
        // Ignore intrinsics early
        if (CalledFunction->isIntrinsic()) {
          assert(CalledFunction->getIntrinsicID() != 0);
          continue;
        }
        auto ImportedName = CalledFunction->getName();
        auto Renamed = (ImportedName + Suffix).str();
        // Rename internal functions
        if (CalledFunction->hasInternalLinkage()) {
          ImportedName = Renamed;
        }
        auto It = CalledFunctions.insert(ImportedName);
        if (!It.second) {
          // This is a call to a function we already considered, skip.
          continue;
        }
        // Ignore functions already present in the destination module
        auto *SrcGV = DestModule.getNamedValue(ImportedName);
        if (SrcGV) {
          assert(isa<Function>(SrcGV) && "Name collision during import");
          if (!cast<Function>(SrcGV)->isDeclaration()) {
            DEBUG(dbgs() << DestModule.getModuleIdentifier() << ": Ignoring "
                         << ImportedName << " already in DestinationModule\n");
            continue;
          }
        }

        Worklist.push_back(It.first->getKey());
        DEBUG(dbgs() << DestModule.getModuleIdentifier()
                     << ": Adding callee for : " << ImportedName << " : "
                     << F.getName() << "\n");
      }
    }
  }
}
示例#4
0
std::vector<std::unique_ptr<MemoryBuffer>>
loadAllFilesForIndex(const FunctionInfoIndex &Index) {
  std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;

  for (auto &ModPath : Index.modPathStringEntries()) {
    const auto &Filename = ModPath.first();
    auto CurrentActivity = "loading file '" + Filename + "'";
    auto InputOrErr = MemoryBuffer::getFile(Filename);
    error(InputOrErr, "error " + CurrentActivity);
    InputBuffers.push_back(std::move(*InputOrErr));
  }
  return InputBuffers;
}
示例#5
0
/// Create a combined index file from the input IR files and write it.
///
/// This is meant to enable testing of ThinLTO combined index generation,
/// currently available via the gold plugin via -thinlto.
static void createCombinedFunctionIndex() {
  FunctionInfoIndex CombinedIndex;
  uint64_t NextModuleId = 0;
  for (auto &Filename : InputFilenames) {
    CurrentActivity = "loading file '" + Filename + "'";
    ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr =
        llvm::getFunctionIndexForFile(Filename, diagnosticHandler);
    std::unique_ptr<FunctionInfoIndex> Index = std::move(IndexOrErr.get());
    CurrentActivity = "";
    // Skip files without a function summary.
    if (!Index)
      continue;
    CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
  }
  std::error_code EC;
  assert(!OutputFilename.empty());
  raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
                    sys::fs::OpenFlags::F_None);
  error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'");
  WriteFunctionSummaryToFile(CombinedIndex, OS);
  OS.close();
}
示例#6
0
// Helper function: given a worklist and an index, will process all the worklist
// and decide what to import based on the summary information.
//
// Nothing is actually imported, functions are materialized in their source
// module and analyzed there.
//
// \p ModuleToFunctionsToImportMap is filled with the set of Function to import
// per Module.
static void GetImportList(Module &DestModule,
                          SmallVector<StringRef, 64> &Worklist,
                          StringSet<> &CalledFunctions,
                          std::map<StringRef, DenseSet<const GlobalValue *>>
                              &ModuleToFunctionsToImportMap,
                          const FunctionInfoIndex &Index,
                          ModuleLazyLoaderCache &ModuleLoaderCache) {
  while (!Worklist.empty()) {
    auto CalledFunctionName = Worklist.pop_back_val();
    DEBUG(dbgs() << DestModule.getModuleIdentifier() << ": Process import for "
                 << CalledFunctionName << "\n");

    // Try to get a summary for this function call.
    auto InfoList = Index.findFunctionInfoList(CalledFunctionName);
    if (InfoList == Index.end()) {
      DEBUG(dbgs() << DestModule.getModuleIdentifier() << ": No summary for "
                   << CalledFunctionName << " Ignoring.\n");
      continue;
    }
    assert(!InfoList->second.empty() && "No summary, error at import?");

    // Comdat can have multiple entries, FIXME: what do we do with them?
    auto &Info = InfoList->second[0];
    assert(Info && "Nullptr in list, error importing summaries?\n");

    auto *Summary = Info->functionSummary();
    if (!Summary) {
      // FIXME: in case we are lazyloading summaries, we can do it now.
      DEBUG(dbgs() << DestModule.getModuleIdentifier()
                   << ": Missing summary for  " << CalledFunctionName
                   << ", error at import?\n");
      llvm_unreachable("Missing summary");
    }

    if (Summary->instCount() > ImportInstrLimit) {
      DEBUG(dbgs() << DestModule.getModuleIdentifier() << ": Skip import of "
                   << CalledFunctionName << " with " << Summary->instCount()
                   << " instructions (limit " << ImportInstrLimit << ")\n");
      continue;
    }

    // Get the module path from the summary.
    auto ModuleIdentifier = Summary->modulePath();
    DEBUG(dbgs() << DestModule.getModuleIdentifier() << ": Importing "
                 << CalledFunctionName << " from " << ModuleIdentifier << "\n");

    auto &SrcModule = ModuleLoaderCache(ModuleIdentifier);

    // The function that we will import!
    GlobalValue *SGV = SrcModule.getNamedValue(CalledFunctionName);

    if (!SGV) {
      // The destination module is referencing function using their renamed name
      // when importing a function that was originally local in the source
      // module. The source module we have might not have been renamed so we try
      // to remove the suffix added during the renaming to recover the original
      // name in the source module.
      std::pair<StringRef, StringRef> Split =
          CalledFunctionName.split(".llvm.");
      SGV = SrcModule.getNamedValue(Split.first);
      assert(SGV && "Can't find function to import in source module");
    }
    if (!SGV) {
      report_fatal_error(Twine("Can't load function '") + CalledFunctionName +
                         "' in Module '" + SrcModule.getModuleIdentifier() +
                         "', error in the summary?\n");
    }

    Function *F = dyn_cast<Function>(SGV);
    if (!F && isa<GlobalAlias>(SGV)) {
      auto *SGA = dyn_cast<GlobalAlias>(SGV);
      F = dyn_cast<Function>(SGA->getBaseObject());
      CalledFunctionName = F->getName();
    }
    assert(F && "Imported Function is ... not a Function");

    // We cannot import weak_any functions/aliases without possibly affecting
    // the order they are seen and selected by the linker, changing program
    // semantics.
    if (SGV->hasWeakAnyLinkage()) {
      DEBUG(dbgs() << DestModule.getModuleIdentifier()
                   << ": Ignoring import request for weak-any "
                   << (isa<Function>(SGV) ? "function " : "alias ")
                   << CalledFunctionName << " from "
                   << SrcModule.getModuleIdentifier() << "\n");
      continue;
    }

    // Add the function to the import list
    auto &Entry = ModuleToFunctionsToImportMap[SrcModule.getModuleIdentifier()];
    Entry.insert(F);

    // Process the newly imported functions and add callees to the worklist.
    F->materialize();
    findExternalCalls(DestModule, *F, Index, CalledFunctions, Worklist);
  }
}
示例#7
0
/// gold informs us that all symbols have been read. At this point, we use
/// get_symbols to see if any of our definitions have been overridden by a
/// native object file. Then, perform optimization and codegen.
static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
  if (Modules.empty())
    return LDPS_OK;

  LLVMContext Context;
  Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true);

  // If we are doing ThinLTO compilation, simply build the combined
  // function index/summary and emit it. We don't need to parse the modules
  // and link them in this case.
  if (options::thinlto) {
    FunctionInfoIndex CombinedIndex;
    uint64_t NextModuleId = 0;
    for (claimed_file &F : Modules) {
      ld_plugin_input_file File;
      if (get_input_file(F.handle, &File) != LDPS_OK)
        message(LDPL_FATAL, "Failed to get file information");

      std::unique_ptr<FunctionInfoIndex> Index =
          getFunctionIndexForFile(F, File);

      // Skip files without a function summary.
      if (!Index)
        continue;

      CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
    }

    std::error_code EC;
    raw_fd_ostream OS(output_name + ".thinlto.bc", EC,
                      sys::fs::OpenFlags::F_None);
    if (EC)
      message(LDPL_FATAL, "Unable to open %s.thinlto.bc for writing: %s",
              output_name.data(), EC.message().c_str());
    WriteFunctionSummaryToFile(CombinedIndex, OS);
    OS.close();

    cleanup_hook();
    exit(0);
  }

  std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context));
  Linker L(Combined.get());

  std::string DefaultTriple = sys::getDefaultTargetTriple();

  StringSet<> Internalize;
  StringSet<> Maybe;
  for (claimed_file &F : Modules) {
    ld_plugin_input_file File;
    if (get_input_file(F.handle, &File) != LDPS_OK)
      message(LDPL_FATAL, "Failed to get file information");
    std::unique_ptr<Module> M =
        getModuleForFile(Context, F, File, ApiFile, Internalize, Maybe);
    if (!options::triple.empty())
      M->setTargetTriple(options::triple.c_str());
    else if (M->getTargetTriple().empty()) {
      M->setTargetTriple(DefaultTriple);
    }

    if (L.linkInModule(M.get()))
      message(LDPL_FATAL, "Failed to link module");
    if (release_input_file(F.handle) != LDPS_OK)
      message(LDPL_FATAL, "Failed to release file information");
  }

  for (const auto &Name : Internalize) {
    GlobalValue *GV = Combined->getNamedValue(Name.first());
    if (GV)
      internalize(*GV);
  }

  for (const auto &Name : Maybe) {
    GlobalValue *GV = Combined->getNamedValue(Name.first());
    if (!GV)
      continue;
    GV->setLinkage(GlobalValue::LinkOnceODRLinkage);
    if (canBeOmittedFromSymbolTable(GV))
      internalize(*GV);
  }

  if (options::TheOutputType == options::OT_DISABLE)
    return LDPS_OK;

  if (options::TheOutputType != options::OT_NORMAL) {
    std::string path;
    if (options::TheOutputType == options::OT_BC_ONLY)
      path = output_name;
    else
      path = output_name + ".bc";
    saveBCFile(path, *L.getModule());
    if (options::TheOutputType == options::OT_BC_ONLY)
      return LDPS_OK;
  }

  codegen(std::move(Combined));

  if (!options::extra_library_path.empty() &&
      set_extra_library_path(options::extra_library_path.c_str()) != LDPS_OK)
    message(LDPL_FATAL, "Unable to set the extra library path.");

  return LDPS_OK;
}