2020-10-27 10:18:29 +08:00
|
|
|
//===- 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"
|
2020-12-03 12:34:17 +08:00
|
|
|
#include "Driver.h"
|
2020-10-27 10:18:29 +08:00
|
|
|
#include "InputFiles.h"
|
[lld-macho] Basic support for linkage and visibility attributes in LTO
When parsing bitcode, convert LTO Symbols to LLD Symbols in order to perform
resolution. The "winning" symbol will then be marked as Prevailing at LTO
compilation time. This is similar to what the other LLD ports do.
This change allows us to handle `linkonce` symbols correctly, and to deal with
duplicate bitcode symbols gracefully. Previously, both scenarios would result in
an assertion failure inside the LTO code, complaining that multiple Prevailing
definitions are not allowed.
While at it, I also added basic logic around visibility. We don't do anything
useful with it yet, but we do check that its value is valid. LLD-ELF appears to
use it only to set FinalDefinitionInLinkageUnit for LTO, which I think is just a
performance optimization.
From my local experimentation, the linker itself doesn't seem to do anything
differently when encountering linkonce / linkonce_odr / weak / weak_odr. So I've
only written a test for one of them. LLD-ELF has more, but they seem to mostly
be testing the intermediate bitcode output of their LTO backend...? I'm far from
an expert here though, so I might very well be missing things.
Reviewed By: #lld-macho, MaskRay, smeenai
Differential Revision: https://reviews.llvm.org/D94342
2021-02-26 02:27:40 +08:00
|
|
|
#include "Symbols.h"
|
2021-04-03 06:46:18 +08:00
|
|
|
#include "Target.h"
|
2020-10-27 10:18:29 +08:00
|
|
|
|
|
|
|
#include "lld/Common/ErrorHandler.h"
|
|
|
|
#include "lld/Common/Strings.h"
|
|
|
|
#include "lld/Common/TargetOptionsCommandFlags.h"
|
|
|
|
#include "llvm/LTO/LTO.h"
|
2020-12-03 12:34:17 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2020-10-27 10:18:29 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2021-01-13 03:41:56 +08:00
|
|
|
#include "llvm/Transforms/ObjCARC.h"
|
2020-10-27 10:18:29 +08:00
|
|
|
|
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::macho;
|
|
|
|
using namespace llvm;
|
2021-04-16 09:14:29 +08:00
|
|
|
using namespace llvm::MachO;
|
2020-12-03 12:34:17 +08:00
|
|
|
using namespace llvm::sys;
|
2020-10-27 10:18:29 +08:00
|
|
|
|
|
|
|
static lto::Config createConfig() {
|
|
|
|
lto::Config c;
|
|
|
|
c.Options = initTargetOptionsFromCodeGenFlags();
|
2020-12-08 21:08:56 +08:00
|
|
|
c.CodeModel = getCodeModelFromCMModel();
|
|
|
|
c.CPU = getCPUStr();
|
|
|
|
c.MAttrs = getMAttrs();
|
2021-01-13 03:41:56 +08:00
|
|
|
c.UseNewPM = config->ltoNewPassManager;
|
|
|
|
c.PreCodeGenPassesHook = [](legacy::PassManager &pm) {
|
|
|
|
pm.add(createObjCARCContractPass());
|
|
|
|
};
|
2021-03-25 12:57:39 +08:00
|
|
|
c.TimeTraceEnabled = config->timeTraceEnabled;
|
|
|
|
c.TimeTraceGranularity = config->timeTraceGranularity;
|
2021-04-16 09:14:29 +08:00
|
|
|
if (config->saveTemps)
|
|
|
|
checkError(c.addSaveTemps(config->outputFile.str() + ".",
|
|
|
|
/*UseInputModulePath=*/true));
|
2020-10-27 10:18:29 +08:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
BitcodeCompiler::BitcodeCompiler() {
|
2021-04-09 00:14:47 +08:00
|
|
|
lto::ThinBackend backend = lto::createInProcessThinBackend(
|
|
|
|
heavyweight_hardware_concurrency(config->thinLTOJobs));
|
2020-10-27 10:18:29 +08:00
|
|
|
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.
|
[lld-macho] Basic support for linkage and visibility attributes in LTO
When parsing bitcode, convert LTO Symbols to LLD Symbols in order to perform
resolution. The "winning" symbol will then be marked as Prevailing at LTO
compilation time. This is similar to what the other LLD ports do.
This change allows us to handle `linkonce` symbols correctly, and to deal with
duplicate bitcode symbols gracefully. Previously, both scenarios would result in
an assertion failure inside the LTO code, complaining that multiple Prevailing
definitions are not allowed.
While at it, I also added basic logic around visibility. We don't do anything
useful with it yet, but we do check that its value is valid. LLD-ELF appears to
use it only to set FinalDefinitionInLinkageUnit for LTO, which I think is just a
performance optimization.
From my local experimentation, the linker itself doesn't seem to do anything
differently when encountering linkonce / linkonce_odr / weak / weak_odr. So I've
only written a test for one of them. LLD-ELF has more, but they seem to mostly
be testing the intermediate bitcode output of their LTO backend...? I'm far from
an expert here though, so I might very well be missing things.
Reviewed By: #lld-macho, MaskRay, smeenai
Differential Revision: https://reviews.llvm.org/D94342
2021-02-26 02:27:40 +08:00
|
|
|
auto symIt = f.symbols.begin();
|
2020-10-27 10:18:29 +08:00
|
|
|
for (const lto::InputFile::Symbol &objSym : objSyms) {
|
|
|
|
resols.emplace_back();
|
|
|
|
lto::SymbolResolution &r = resols.back();
|
[lld-macho] Basic support for linkage and visibility attributes in LTO
When parsing bitcode, convert LTO Symbols to LLD Symbols in order to perform
resolution. The "winning" symbol will then be marked as Prevailing at LTO
compilation time. This is similar to what the other LLD ports do.
This change allows us to handle `linkonce` symbols correctly, and to deal with
duplicate bitcode symbols gracefully. Previously, both scenarios would result in
an assertion failure inside the LTO code, complaining that multiple Prevailing
definitions are not allowed.
While at it, I also added basic logic around visibility. We don't do anything
useful with it yet, but we do check that its value is valid. LLD-ELF appears to
use it only to set FinalDefinitionInLinkageUnit for LTO, which I think is just a
performance optimization.
From my local experimentation, the linker itself doesn't seem to do anything
differently when encountering linkonce / linkonce_odr / weak / weak_odr. So I've
only written a test for one of them. LLD-ELF has more, but they seem to mostly
be testing the intermediate bitcode output of their LTO backend...? I'm far from
an expert here though, so I might very well be missing things.
Reviewed By: #lld-macho, MaskRay, smeenai
Differential Revision: https://reviews.llvm.org/D94342
2021-02-26 02:27:40 +08:00
|
|
|
Symbol *sym = *symIt++;
|
2020-10-27 10:18:29 +08:00
|
|
|
|
|
|
|
// 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.
|
[lld-macho] Basic support for linkage and visibility attributes in LTO
When parsing bitcode, convert LTO Symbols to LLD Symbols in order to perform
resolution. The "winning" symbol will then be marked as Prevailing at LTO
compilation time. This is similar to what the other LLD ports do.
This change allows us to handle `linkonce` symbols correctly, and to deal with
duplicate bitcode symbols gracefully. Previously, both scenarios would result in
an assertion failure inside the LTO code, complaining that multiple Prevailing
definitions are not allowed.
While at it, I also added basic logic around visibility. We don't do anything
useful with it yet, but we do check that its value is valid. LLD-ELF appears to
use it only to set FinalDefinitionInLinkageUnit for LTO, which I think is just a
performance optimization.
From my local experimentation, the linker itself doesn't seem to do anything
differently when encountering linkonce / linkonce_odr / weak / weak_odr. So I've
only written a test for one of them. LLD-ELF has more, but they seem to mostly
be testing the intermediate bitcode output of their LTO backend...? I'm far from
an expert here though, so I might very well be missing things.
Reviewed By: #lld-macho, MaskRay, smeenai
Differential Revision: https://reviews.llvm.org/D94342
2021-02-26 02:27:40 +08:00
|
|
|
r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
|
|
|
|
|
2021-04-16 09:14:29 +08:00
|
|
|
// 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;
|
|
|
|
|
[lld-macho] Basic support for linkage and visibility attributes in LTO
When parsing bitcode, convert LTO Symbols to LLD Symbols in order to perform
resolution. The "winning" symbol will then be marked as Prevailing at LTO
compilation time. This is similar to what the other LLD ports do.
This change allows us to handle `linkonce` symbols correctly, and to deal with
duplicate bitcode symbols gracefully. Previously, both scenarios would result in
an assertion failure inside the LTO code, complaining that multiple Prevailing
definitions are not allowed.
While at it, I also added basic logic around visibility. We don't do anything
useful with it yet, but we do check that its value is valid. LLD-ELF appears to
use it only to set FinalDefinitionInLinkageUnit for LTO, which I think is just a
performance optimization.
From my local experimentation, the linker itself doesn't seem to do anything
differently when encountering linkonce / linkonce_odr / weak / weak_odr. So I've
only written a test for one of them. LLD-ELF has more, but they seem to mostly
be testing the intermediate bitcode output of their LTO backend...? I'm far from
an expert here though, so I might very well be missing things.
Reviewed By: #lld-macho, MaskRay, smeenai
Differential Revision: https://reviews.llvm.org/D94342
2021-02-26 02:27:40 +08:00
|
|
|
// 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);
|
2020-10-27 10:18:29 +08:00
|
|
|
|
|
|
|
// 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");
|
|
|
|
}
|
|
|
|
|
2020-12-03 12:34:17 +08:00
|
|
|
if (!config->ltoObjPath.empty())
|
|
|
|
fs::create_directories(config->ltoObjPath);
|
|
|
|
|
2020-10-27 10:18:29 +08:00
|
|
|
std::vector<ObjFile *> ret;
|
2020-12-03 12:34:17 +08:00
|
|
|
for (unsigned i = 0; i != maxTasks; ++i) {
|
2021-03-17 12:34:28 +08:00
|
|
|
if (buf[i].empty())
|
2020-12-03 12:34:17 +08:00
|
|
|
continue;
|
|
|
|
SmallString<261> filePath("/tmp/lto.tmp");
|
|
|
|
uint32_t modTime = 0;
|
|
|
|
if (!config->ltoObjPath.empty()) {
|
|
|
|
filePath = config->ltoObjPath;
|
2021-04-22 03:43:38 +08:00
|
|
|
path::append(filePath, Twine(i) + "." +
|
|
|
|
getArchitectureName(config->arch()) +
|
|
|
|
".lto.o");
|
2020-12-03 12:34:17 +08:00
|
|
|
saveBuffer(buf[i], filePath);
|
|
|
|
modTime = getModTime(filePath);
|
|
|
|
}
|
|
|
|
ret.push_back(make<ObjFile>(
|
|
|
|
MemoryBufferRef(buf[i], saver.save(filePath.str())), modTime, ""));
|
|
|
|
}
|
2020-10-27 10:18:29 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|