11cf9926bSpatrick //===- LTO.cpp ------------------------------------------------------------===//
21cf9926bSpatrick //
31cf9926bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41cf9926bSpatrick // See https://llvm.org/LICENSE.txt for license information.
51cf9926bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61cf9926bSpatrick //
71cf9926bSpatrick //===----------------------------------------------------------------------===//
81cf9926bSpatrick
91cf9926bSpatrick #include "LTO.h"
101cf9926bSpatrick #include "Config.h"
111cf9926bSpatrick #include "Driver.h"
121cf9926bSpatrick #include "InputFiles.h"
131cf9926bSpatrick #include "Symbols.h"
141cf9926bSpatrick #include "Target.h"
151cf9926bSpatrick
161cf9926bSpatrick #include "lld/Common/Args.h"
17*dfe94b16Srobert #include "lld/Common/CommonLinkerContext.h"
181cf9926bSpatrick #include "lld/Common/Strings.h"
191cf9926bSpatrick #include "lld/Common/TargetOptionsCommandFlags.h"
20*dfe94b16Srobert #include "llvm/Bitcode/BitcodeWriter.h"
211cf9926bSpatrick #include "llvm/LTO/Config.h"
221cf9926bSpatrick #include "llvm/LTO/LTO.h"
23*dfe94b16Srobert #include "llvm/Support/Caching.h"
241cf9926bSpatrick #include "llvm/Support/FileSystem.h"
251cf9926bSpatrick #include "llvm/Support/Path.h"
261cf9926bSpatrick #include "llvm/Support/raw_ostream.h"
271cf9926bSpatrick #include "llvm/Transforms/ObjCARC.h"
281cf9926bSpatrick
291cf9926bSpatrick using namespace lld;
301cf9926bSpatrick using namespace lld::macho;
311cf9926bSpatrick using namespace llvm;
321cf9926bSpatrick using namespace llvm::MachO;
331cf9926bSpatrick using namespace llvm::sys;
341cf9926bSpatrick
35*dfe94b16Srobert // Creates an empty file to store a list of object files for final
36*dfe94b16Srobert // linking of distributed ThinLTO.
openFile(StringRef file)37*dfe94b16Srobert static std::unique_ptr<raw_fd_ostream> openFile(StringRef file) {
38*dfe94b16Srobert std::error_code ec;
39*dfe94b16Srobert auto ret =
40*dfe94b16Srobert std::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::OF_None);
41*dfe94b16Srobert if (ec) {
42*dfe94b16Srobert error("cannot open " + file + ": " + ec.message());
43*dfe94b16Srobert return nullptr;
44*dfe94b16Srobert }
45*dfe94b16Srobert return ret;
46*dfe94b16Srobert }
47*dfe94b16Srobert
getThinLTOOutputFile(StringRef modulePath)48*dfe94b16Srobert static std::string getThinLTOOutputFile(StringRef modulePath) {
49*dfe94b16Srobert return lto::getThinLTOOutputFile(
50*dfe94b16Srobert std::string(modulePath), std::string(config->thinLTOPrefixReplace.first),
51*dfe94b16Srobert std::string(config->thinLTOPrefixReplace.second));
52*dfe94b16Srobert }
53*dfe94b16Srobert
createConfig()541cf9926bSpatrick static lto::Config createConfig() {
551cf9926bSpatrick lto::Config c;
561cf9926bSpatrick c.Options = initTargetOptionsFromCodeGenFlags();
57*dfe94b16Srobert c.Options.EmitAddrsig = config->icfLevel == ICFLevel::safe;
58*dfe94b16Srobert for (StringRef C : config->mllvmOpts)
59*dfe94b16Srobert c.MllvmArgs.emplace_back(C.str());
601cf9926bSpatrick c.CodeModel = getCodeModelFromCMModel();
611cf9926bSpatrick c.CPU = getCPUStr();
621cf9926bSpatrick c.MAttrs = getMAttrs();
63*dfe94b16Srobert c.DiagHandler = diagnosticHandler;
641cf9926bSpatrick c.PreCodeGenPassesHook = [](legacy::PassManager &pm) {
651cf9926bSpatrick pm.add(createObjCARCContractPass());
661cf9926bSpatrick };
67*dfe94b16Srobert
68*dfe94b16Srobert c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty();
69*dfe94b16Srobert
701cf9926bSpatrick c.TimeTraceEnabled = config->timeTraceEnabled;
711cf9926bSpatrick c.TimeTraceGranularity = config->timeTraceGranularity;
721cf9926bSpatrick c.OptLevel = config->ltoo;
731cf9926bSpatrick c.CGOptLevel = args::getCGOptLevel(config->ltoo);
741cf9926bSpatrick if (config->saveTemps)
751cf9926bSpatrick checkError(c.addSaveTemps(config->outputFile.str() + ".",
761cf9926bSpatrick /*UseInputModulePath=*/true));
771cf9926bSpatrick return c;
781cf9926bSpatrick }
791cf9926bSpatrick
80*dfe94b16Srobert // If `originalPath` exists, hardlinks `path` to `originalPath`. If that fails,
81*dfe94b16Srobert // or `originalPath` is not set, saves `buffer` to `path`.
saveOrHardlinkBuffer(StringRef buffer,const Twine & path,std::optional<StringRef> originalPath)82*dfe94b16Srobert static void saveOrHardlinkBuffer(StringRef buffer, const Twine &path,
83*dfe94b16Srobert std::optional<StringRef> originalPath) {
84*dfe94b16Srobert if (originalPath) {
85*dfe94b16Srobert auto err = fs::create_hard_link(*originalPath, path);
86*dfe94b16Srobert if (!err)
87*dfe94b16Srobert return;
88*dfe94b16Srobert }
89*dfe94b16Srobert saveBuffer(buffer, path);
90*dfe94b16Srobert }
91*dfe94b16Srobert
BitcodeCompiler()921cf9926bSpatrick BitcodeCompiler::BitcodeCompiler() {
93*dfe94b16Srobert // Initialize indexFile.
94*dfe94b16Srobert if (!config->thinLTOIndexOnlyArg.empty())
95*dfe94b16Srobert indexFile = openFile(config->thinLTOIndexOnlyArg);
96*dfe94b16Srobert
97*dfe94b16Srobert // Initialize ltoObj.
98*dfe94b16Srobert lto::ThinBackend backend;
99*dfe94b16Srobert auto onIndexWrite = [&](StringRef S) { thinIndices.erase(S); };
100*dfe94b16Srobert if (config->thinLTOIndexOnly) {
101*dfe94b16Srobert backend = lto::createWriteIndexesThinBackend(
102*dfe94b16Srobert std::string(config->thinLTOPrefixReplace.first),
103*dfe94b16Srobert std::string(config->thinLTOPrefixReplace.second),
104*dfe94b16Srobert config->thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite);
105*dfe94b16Srobert } else {
106*dfe94b16Srobert backend = lto::createInProcessThinBackend(
107*dfe94b16Srobert llvm::heavyweight_hardware_concurrency(config->thinLTOJobs),
108*dfe94b16Srobert onIndexWrite, config->thinLTOEmitIndexFiles,
109*dfe94b16Srobert config->thinLTOEmitImportsFiles);
110*dfe94b16Srobert }
111*dfe94b16Srobert
1121cf9926bSpatrick ltoObj = std::make_unique<lto::LTO>(createConfig(), backend);
1131cf9926bSpatrick }
1141cf9926bSpatrick
add(BitcodeFile & f)1151cf9926bSpatrick void BitcodeCompiler::add(BitcodeFile &f) {
116*dfe94b16Srobert lto::InputFile &obj = *f.obj;
117*dfe94b16Srobert
118*dfe94b16Srobert if (config->thinLTOEmitIndexFiles)
119*dfe94b16Srobert thinIndices.insert(obj.getName());
120*dfe94b16Srobert
121*dfe94b16Srobert ArrayRef<lto::InputFile::Symbol> objSyms = obj.symbols();
1221cf9926bSpatrick std::vector<lto::SymbolResolution> resols;
1231cf9926bSpatrick resols.reserve(objSyms.size());
1241cf9926bSpatrick
1251cf9926bSpatrick // Provide a resolution to the LTO API for each symbol.
126*dfe94b16Srobert bool exportDynamic =
127*dfe94b16Srobert config->outputType != MH_EXECUTE || config->exportDynamic;
1281cf9926bSpatrick auto symIt = f.symbols.begin();
1291cf9926bSpatrick for (const lto::InputFile::Symbol &objSym : objSyms) {
1301cf9926bSpatrick resols.emplace_back();
1311cf9926bSpatrick lto::SymbolResolution &r = resols.back();
1321cf9926bSpatrick Symbol *sym = *symIt++;
1331cf9926bSpatrick
1341cf9926bSpatrick // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
1351cf9926bSpatrick // reports two symbols for module ASM defined. Without this check, lld
1361cf9926bSpatrick // flags an undefined in IR with a definition in ASM as prevailing.
1371cf9926bSpatrick // Once IRObjectFile is fixed to report only one symbol this hack can
1381cf9926bSpatrick // be removed.
1391cf9926bSpatrick r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
1401cf9926bSpatrick
141*dfe94b16Srobert if (const auto *defined = dyn_cast<Defined>(sym)) {
142*dfe94b16Srobert r.ExportDynamic =
143*dfe94b16Srobert defined->isExternal() && !defined->privateExtern && exportDynamic;
144*dfe94b16Srobert r.FinalDefinitionInLinkageUnit =
145*dfe94b16Srobert !defined->isExternalWeakDef() && !defined->interposable;
146*dfe94b16Srobert } else if (const auto *common = dyn_cast<CommonSymbol>(sym)) {
147*dfe94b16Srobert r.ExportDynamic = !common->privateExtern && exportDynamic;
148*dfe94b16Srobert r.FinalDefinitionInLinkageUnit = true;
149*dfe94b16Srobert }
150*dfe94b16Srobert
151*dfe94b16Srobert r.VisibleToRegularObj =
152*dfe94b16Srobert sym->isUsedInRegularObj || (r.Prevailing && r.ExportDynamic);
1531cf9926bSpatrick
1541cf9926bSpatrick // Un-define the symbol so that we don't get duplicate symbol errors when we
1551cf9926bSpatrick // load the ObjFile emitted by LTO compilation.
1561cf9926bSpatrick if (r.Prevailing)
1571cf9926bSpatrick replaceSymbol<Undefined>(sym, sym->getName(), sym->getFile(),
158*dfe94b16Srobert RefState::Strong, /*wasBitcodeSymbol=*/true);
1591cf9926bSpatrick
1601cf9926bSpatrick // TODO: set the other resolution configs properly
1611cf9926bSpatrick }
1621cf9926bSpatrick checkError(ltoObj->add(std::move(f.obj), resols));
1631cf9926bSpatrick }
1641cf9926bSpatrick
165*dfe94b16Srobert // If LazyObjFile has not been added to link, emit empty index files.
166*dfe94b16Srobert // This is needed because this is what GNU gold plugin does and we have a
167*dfe94b16Srobert // distributed build system that depends on that behavior.
thinLTOCreateEmptyIndexFiles()168*dfe94b16Srobert static void thinLTOCreateEmptyIndexFiles() {
169*dfe94b16Srobert DenseSet<StringRef> linkedBitCodeFiles;
170*dfe94b16Srobert for (InputFile *file : inputFiles)
171*dfe94b16Srobert if (auto *f = dyn_cast<BitcodeFile>(file))
172*dfe94b16Srobert if (!f->lazy)
173*dfe94b16Srobert linkedBitCodeFiles.insert(f->getName());
174*dfe94b16Srobert
175*dfe94b16Srobert for (InputFile *file : inputFiles) {
176*dfe94b16Srobert if (auto *f = dyn_cast<BitcodeFile>(file)) {
177*dfe94b16Srobert if (!f->lazy)
178*dfe94b16Srobert continue;
179*dfe94b16Srobert if (linkedBitCodeFiles.contains(f->getName()))
180*dfe94b16Srobert continue;
181*dfe94b16Srobert std::string path =
182*dfe94b16Srobert replaceThinLTOSuffix(getThinLTOOutputFile(f->obj->getName()));
183*dfe94b16Srobert std::unique_ptr<raw_fd_ostream> os = openFile(path + ".thinlto.bc");
184*dfe94b16Srobert if (!os)
185*dfe94b16Srobert continue;
186*dfe94b16Srobert
187*dfe94b16Srobert ModuleSummaryIndex m(/*HaveGVs=*/false);
188*dfe94b16Srobert m.setSkipModuleByDistributedBackend();
189*dfe94b16Srobert writeIndexToFile(m, *os);
190*dfe94b16Srobert if (config->thinLTOEmitImportsFiles)
191*dfe94b16Srobert openFile(path + ".imports");
192*dfe94b16Srobert }
193*dfe94b16Srobert }
194*dfe94b16Srobert }
195*dfe94b16Srobert
1961cf9926bSpatrick // Merge all the bitcode files we have seen, codegen the result
1971cf9926bSpatrick // and return the resulting ObjectFile(s).
compile()1981cf9926bSpatrick std::vector<ObjFile *> BitcodeCompiler::compile() {
1991cf9926bSpatrick unsigned maxTasks = ltoObj->getMaxTasks();
2001cf9926bSpatrick buf.resize(maxTasks);
2011cf9926bSpatrick files.resize(maxTasks);
2021cf9926bSpatrick
2031cf9926bSpatrick // The -cache_path_lto option specifies the path to a directory in which
2041cf9926bSpatrick // to cache native object files for ThinLTO incremental builds. If a path was
2051cf9926bSpatrick // specified, configure LTO to use it as the cache directory.
206*dfe94b16Srobert FileCache cache;
2071cf9926bSpatrick if (!config->thinLTOCacheDir.empty())
208*dfe94b16Srobert cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir,
209*dfe94b16Srobert [&](size_t task, const Twine &moduleName,
210*dfe94b16Srobert std::unique_ptr<MemoryBuffer> mb) {
2111cf9926bSpatrick files[task] = std::move(mb);
2121cf9926bSpatrick }));
2131cf9926bSpatrick
2141cf9926bSpatrick checkError(ltoObj->run(
215*dfe94b16Srobert [&](size_t task, const Twine &moduleName) {
216*dfe94b16Srobert return std::make_unique<CachedFileStream>(
2171cf9926bSpatrick std::make_unique<raw_svector_ostream>(buf[task]));
2181cf9926bSpatrick },
2191cf9926bSpatrick cache));
2201cf9926bSpatrick
221*dfe94b16Srobert // Emit empty index files for non-indexed files
222*dfe94b16Srobert for (StringRef s : thinIndices) {
223*dfe94b16Srobert std::string path = getThinLTOOutputFile(s);
224*dfe94b16Srobert openFile(path + ".thinlto.bc");
225*dfe94b16Srobert if (config->thinLTOEmitImportsFiles)
226*dfe94b16Srobert openFile(path + ".imports");
2271cf9926bSpatrick }
2281cf9926bSpatrick
229*dfe94b16Srobert if (config->thinLTOEmitIndexFiles)
230*dfe94b16Srobert thinLTOCreateEmptyIndexFiles();
2311cf9926bSpatrick
232*dfe94b16Srobert // In ThinLTO mode, Clang passes a temporary directory in -object_path_lto,
233*dfe94b16Srobert // while the argument is a single file in FullLTO mode.
234*dfe94b16Srobert bool objPathIsDir = true;
235*dfe94b16Srobert if (!config->ltoObjPath.empty()) {
236*dfe94b16Srobert if (std::error_code ec = fs::create_directories(config->ltoObjPath))
237*dfe94b16Srobert fatal("cannot create LTO object path " + config->ltoObjPath + ": " +
238*dfe94b16Srobert ec.message());
239*dfe94b16Srobert
240*dfe94b16Srobert if (!fs::is_directory(config->ltoObjPath)) {
241*dfe94b16Srobert objPathIsDir = false;
242*dfe94b16Srobert unsigned objCount =
243*dfe94b16Srobert count_if(buf, [](const SmallString<0> &b) { return !b.empty(); });
244*dfe94b16Srobert if (objCount > 1)
245*dfe94b16Srobert fatal("-object_path_lto must specify a directory when using ThinLTO");
246*dfe94b16Srobert }
247*dfe94b16Srobert }
248*dfe94b16Srobert
249*dfe94b16Srobert auto outputFilePath = [objPathIsDir](int i) {
2501cf9926bSpatrick SmallString<261> filePath("/tmp/lto.tmp");
2511cf9926bSpatrick if (!config->ltoObjPath.empty()) {
2521cf9926bSpatrick filePath = config->ltoObjPath;
253*dfe94b16Srobert if (objPathIsDir)
2541cf9926bSpatrick path::append(filePath, Twine(i) + "." +
2551cf9926bSpatrick getArchitectureName(config->arch()) +
2561cf9926bSpatrick ".lto.o");
257*dfe94b16Srobert }
258*dfe94b16Srobert return filePath;
259*dfe94b16Srobert };
260*dfe94b16Srobert
261*dfe94b16Srobert // ThinLTO with index only option is required to generate only the index
262*dfe94b16Srobert // files. After that, we exit from linker and ThinLTO backend runs in a
263*dfe94b16Srobert // distributed environment.
264*dfe94b16Srobert if (config->thinLTOIndexOnly) {
265*dfe94b16Srobert if (!config->ltoObjPath.empty())
266*dfe94b16Srobert saveBuffer(buf[0], outputFilePath(0));
267*dfe94b16Srobert if (indexFile)
268*dfe94b16Srobert indexFile->close();
269*dfe94b16Srobert return {};
270*dfe94b16Srobert }
271*dfe94b16Srobert
272*dfe94b16Srobert if (!config->thinLTOCacheDir.empty())
273*dfe94b16Srobert pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy, files);
274*dfe94b16Srobert
275*dfe94b16Srobert std::vector<ObjFile *> ret;
276*dfe94b16Srobert for (unsigned i = 0; i < maxTasks; ++i) {
277*dfe94b16Srobert // Get the native object contents either from the cache or from memory. Do
278*dfe94b16Srobert // not use the cached MemoryBuffer directly to ensure dsymutil does not
279*dfe94b16Srobert // race with the cache pruner.
280*dfe94b16Srobert StringRef objBuf;
281*dfe94b16Srobert std::optional<StringRef> cachePath;
282*dfe94b16Srobert if (files[i]) {
283*dfe94b16Srobert objBuf = files[i]->getBuffer();
284*dfe94b16Srobert cachePath = files[i]->getBufferIdentifier();
285*dfe94b16Srobert } else {
286*dfe94b16Srobert objBuf = buf[i];
287*dfe94b16Srobert }
288*dfe94b16Srobert if (objBuf.empty())
289*dfe94b16Srobert continue;
290*dfe94b16Srobert
291*dfe94b16Srobert // FIXME: should `saveTemps` and `ltoObjPath` use the same file name?
292*dfe94b16Srobert if (config->saveTemps)
293*dfe94b16Srobert saveBuffer(objBuf,
294*dfe94b16Srobert config->outputFile + ((i == 0) ? "" : Twine(i)) + ".lto.o");
295*dfe94b16Srobert
296*dfe94b16Srobert auto filePath = outputFilePath(i);
297*dfe94b16Srobert uint32_t modTime = 0;
298*dfe94b16Srobert if (!config->ltoObjPath.empty()) {
299*dfe94b16Srobert saveOrHardlinkBuffer(objBuf, filePath, cachePath);
3001cf9926bSpatrick modTime = getModTime(filePath);
3011cf9926bSpatrick }
3021cf9926bSpatrick ret.push_back(make<ObjFile>(
303*dfe94b16Srobert MemoryBufferRef(objBuf, saver().save(filePath.str())), modTime, ""));
3041cf9926bSpatrick }
305*dfe94b16Srobert
3061cf9926bSpatrick return ret;
3071cf9926bSpatrick }
308