diff lld/MachO/LTO.cpp @ 207:2e18cbf3894f

LLVM12
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 08 Jun 2021 06:07:14 +0900
parents
children 5f17cb93ff66
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lld/MachO/LTO.cpp	Tue Jun 08 06:07:14 2021 +0900
@@ -0,0 +1,131 @@
+//===- LTO.cpp ------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LTO.h"
+#include "Config.h"
+#include "Driver.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/ObjCARC.h"
+
+using namespace lld;
+using namespace lld::macho;
+using namespace llvm;
+using namespace llvm::MachO;
+using namespace llvm::sys;
+
+static lto::Config createConfig() {
+  lto::Config c;
+  c.Options = initTargetOptionsFromCodeGenFlags();
+  c.CodeModel = getCodeModelFromCMModel();
+  c.CPU = getCPUStr();
+  c.MAttrs = getMAttrs();
+  c.UseNewPM = config->ltoNewPassManager;
+  c.PreCodeGenPassesHook = [](legacy::PassManager &pm) {
+    pm.add(createObjCARCContractPass());
+  };
+  c.TimeTraceEnabled = config->timeTraceEnabled;
+  c.TimeTraceGranularity = config->timeTraceGranularity;
+  if (config->saveTemps)
+    checkError(c.addSaveTemps(config->outputFile.str() + ".",
+                              /*UseInputModulePath=*/true));
+  return c;
+}
+
+BitcodeCompiler::BitcodeCompiler() {
+  lto::ThinBackend backend = lto::createInProcessThinBackend(
+      heavyweight_hardware_concurrency(config->thinLTOJobs));
+  ltoObj = std::make_unique<lto::LTO>(createConfig(), backend);
+}
+
+void BitcodeCompiler::add(BitcodeFile &f) {
+  ArrayRef<lto::InputFile::Symbol> objSyms = f.obj->symbols();
+  std::vector<lto::SymbolResolution> resols;
+  resols.reserve(objSyms.size());
+
+  // Provide a resolution to the LTO API for each symbol.
+  auto symIt = f.symbols.begin();
+  for (const lto::InputFile::Symbol &objSym : objSyms) {
+    resols.emplace_back();
+    lto::SymbolResolution &r = resols.back();
+    Symbol *sym = *symIt++;
+
+    // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+    // reports two symbols for module ASM defined. Without this check, lld
+    // flags an undefined in IR with a definition in ASM as prevailing.
+    // Once IRObjectFile is fixed to report only one symbol this hack can
+    // be removed.
+    r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
+
+    // FIXME: What about other output types? And we can probably be less
+    // restrictive with -flat_namespace, but it's an infrequent use case.
+    r.VisibleToRegularObj = config->outputType != MH_EXECUTE ||
+                            config->namespaceKind == NamespaceKind::flat ||
+                            sym->isUsedInRegularObj;
+
+    // Un-define the symbol so that we don't get duplicate symbol errors when we
+    // load the ObjFile emitted by LTO compilation.
+    if (r.Prevailing)
+      replaceSymbol<Undefined>(sym, sym->getName(), sym->getFile(),
+                               RefState::Strong);
+
+    // TODO: set the other resolution configs properly
+  }
+  checkError(ltoObj->add(std::move(f.obj), resols));
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting ObjectFile(s).
+std::vector<ObjFile *> BitcodeCompiler::compile() {
+  unsigned maxTasks = ltoObj->getMaxTasks();
+  buf.resize(maxTasks);
+
+  checkError(ltoObj->run([&](size_t task) {
+    return std::make_unique<lto::NativeObjectStream>(
+        std::make_unique<raw_svector_ostream>(buf[task]));
+  }));
+
+  if (config->saveTemps) {
+    if (!buf[0].empty())
+      saveBuffer(buf[0], config->outputFile + ".lto.o");
+    for (unsigned i = 1; i != maxTasks; ++i)
+      saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o");
+  }
+
+  if (!config->ltoObjPath.empty())
+    fs::create_directories(config->ltoObjPath);
+
+  std::vector<ObjFile *> ret;
+  for (unsigned i = 0; i != maxTasks; ++i) {
+    if (buf[i].empty())
+      continue;
+    SmallString<261> filePath("/tmp/lto.tmp");
+    uint32_t modTime = 0;
+    if (!config->ltoObjPath.empty()) {
+      filePath = config->ltoObjPath;
+      path::append(filePath, Twine(i) + "." +
+                                 getArchitectureName(config->arch()) +
+                                 ".lto.o");
+      saveBuffer(buf[i], filePath);
+      modTime = getModTime(filePath);
+    }
+    ret.push_back(make<ObjFile>(
+        MemoryBufferRef(buf[i], saver.save(filePath.str())), modTime, ""));
+  }
+
+  return ret;
+}