Files
clang-p2996/lld/MachO/LTO.cpp
Jez Ng 697f4e429b [lld-macho] Run ObjCContractPass during LTO
Run the ObjCARCContractPass during LTO. The legacy LTO backend (under
LTO/ThinLTOCodeGenerator.cpp) already does this; this diff just adds that
behavior to the new LTO backend. Without that pass, the objc.clang.arc.use
intrinsic will get passed to the instruction selector, which doesn't know how to
handle it.

In order to test both the new and old pass managers, I've also added support for
the `--[no-]lto-legacy-pass-manager` flags.

P.S. Not sure if the ordering of the pass within the pipeline matters...

Reviewed By: fhahn

Differential Revision: https://reviews.llvm.org/D94547
2021-01-20 14:21:32 -05:00

111 lines
3.5 KiB
C++

//===- 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 "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::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());
};
return c;
}
BitcodeCompiler::BitcodeCompiler() {
auto backend =
lto::createInProcessThinBackend(heavyweight_hardware_concurrency());
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.
for (const lto::InputFile::Symbol &objSym : objSyms) {
resols.emplace_back();
lto::SymbolResolution &r = resols.back();
// 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();
// TODO: set the other resolution configs properly
r.VisibleToRegularObj = true;
}
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;
}