1//===- LTO.cpp ------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "LTO.h"
10#include "Config.h"
11#include "Driver.h"
12#include "InputFiles.h"
13#include "Symbols.h"
14#include "Target.h"
15
16#include "lld/Common/CommonLinkerContext.h"
17#include "lld/Common/Filesystem.h"
18#include "lld/Common/Strings.h"
19#include "lld/Common/TargetOptionsCommandFlags.h"
20#include "llvm/Bitcode/BitcodeWriter.h"
21#include "llvm/LTO/Config.h"
22#include "llvm/LTO/LTO.h"
23#include "llvm/Support/Caching.h"
24#include "llvm/Support/FileSystem.h"
25#include "llvm/Support/Path.h"
26#include "llvm/Support/raw_ostream.h"
27
28using namespace lld;
29using namespace lld::macho;
30using namespace llvm;
31using namespace llvm::MachO;
32using namespace llvm::sys;
33
34static std::string getThinLTOOutputFile(StringRef modulePath) {
35 return lto::getThinLTOOutputFile(Path: modulePath, OldPrefix: config->thinLTOPrefixReplaceOld,
36 NewPrefix: config->thinLTOPrefixReplaceNew);
37}
38
39static lto::Config createConfig() {
40 lto::Config c;
41 c.Options = initTargetOptionsFromCodeGenFlags();
42 c.Options.EmitAddrsig = config->icfLevel == ICFLevel::safe;
43 for (StringRef C : config->mllvmOpts)
44 c.MllvmArgs.emplace_back(args: C.str());
45 for (StringRef pluginFn : config->passPlugins)
46 c.PassPlugins.push_back(x: std::string(pluginFn));
47 c.OptPipeline = std::string(config->ltoNewPmPasses);
48 c.CodeModel = getCodeModelFromCMModel();
49 c.CPU = getCPUStr();
50 c.MAttrs = getMAttrs();
51 c.DiagHandler = diagnosticHandler;
52
53 c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty();
54
55 c.TimeTraceEnabled = config->timeTraceEnabled;
56 c.TimeTraceGranularity = config->timeTraceGranularity;
57 c.DebugPassManager = config->ltoDebugPassManager;
58 c.CSIRProfile = std::string(config->csProfilePath);
59 c.RunCSIRInstr = config->csProfileGenerate;
60 c.PGOWarnMismatch = config->pgoWarnMismatch;
61 c.DisableVerify = config->disableVerify;
62 c.OptLevel = config->ltoo;
63 c.CGOptLevel = config->ltoCgo;
64 if (config->saveTemps)
65 checkError(e: c.addSaveTemps(OutputFileName: config->outputFile.str() + ".",
66 /*UseInputModulePath=*/true));
67
68 if (config->emitLLVM) {
69 llvm::StringRef outputFile = config->outputFile;
70 c.PreCodeGenModuleHook = [outputFile](size_t task, const Module &m) {
71 if (std::unique_ptr<raw_fd_ostream> os = openLTOOutputFile(file: outputFile))
72 WriteBitcodeToFile(M: m, Out&: *os, ShouldPreserveUseListOrder: false);
73 return false;
74 };
75 }
76
77 return c;
78}
79
80// If `originalPath` exists, hardlinks `path` to `originalPath`. If that fails,
81// or `originalPath` is not set, saves `buffer` to `path`.
82static void saveOrHardlinkBuffer(StringRef buffer, const Twine &path,
83 std::optional<StringRef> originalPath) {
84 if (originalPath) {
85 auto err = fs::create_hard_link(to: *originalPath, from: path);
86 if (!err)
87 return;
88 }
89 saveBuffer(buffer, path);
90}
91
92BitcodeCompiler::BitcodeCompiler() {
93 // Initialize indexFile.
94 if (!config->thinLTOIndexOnlyArg.empty())
95 indexFile = openFile(file: config->thinLTOIndexOnlyArg);
96
97 // Initialize ltoObj.
98 lto::ThinBackend backend;
99 auto onIndexWrite = [&](StringRef S) { thinIndices.erase(V: S); };
100 if (config->thinLTOIndexOnly) {
101 backend = lto::createWriteIndexesThinBackend(
102 Parallelism: llvm::hardware_concurrency(Num: config->thinLTOJobs),
103 OldPrefix: std::string(config->thinLTOPrefixReplaceOld),
104 NewPrefix: std::string(config->thinLTOPrefixReplaceNew),
105 NativeObjectPrefix: std::string(config->thinLTOPrefixReplaceNativeObject),
106 ShouldEmitImportsFiles: config->thinLTOEmitImportsFiles, LinkedObjectsFile: indexFile.get(), OnWrite: onIndexWrite);
107 } else {
108 backend = lto::createInProcessThinBackend(
109 Parallelism: llvm::heavyweight_hardware_concurrency(Num: config->thinLTOJobs),
110 OnWrite: onIndexWrite, ShouldEmitIndexFiles: config->thinLTOEmitIndexFiles,
111 ShouldEmitImportsFiles: config->thinLTOEmitImportsFiles);
112 }
113
114 ltoObj = std::make_unique<lto::LTO>(args: createConfig(), args&: backend);
115}
116
117void BitcodeCompiler::add(BitcodeFile &f) {
118 lto::InputFile &obj = *f.obj;
119
120 if (config->thinLTOEmitIndexFiles)
121 thinIndices.insert(V: obj.getName());
122
123 ArrayRef<lto::InputFile::Symbol> objSyms = obj.symbols();
124 std::vector<lto::SymbolResolution> resols;
125 resols.reserve(n: objSyms.size());
126
127 // Provide a resolution to the LTO API for each symbol.
128 bool exportDynamic =
129 config->outputType != MH_EXECUTE || config->exportDynamic;
130 auto symIt = f.symbols.begin();
131 for (const lto::InputFile::Symbol &objSym : objSyms) {
132 resols.emplace_back();
133 lto::SymbolResolution &r = resols.back();
134 Symbol *sym = *symIt++;
135
136 // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
137 // reports two symbols for module ASM defined. Without this check, lld
138 // flags an undefined in IR with a definition in ASM as prevailing.
139 // Once IRObjectFile is fixed to report only one symbol this hack can
140 // be removed.
141 r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
142
143 if (const auto *defined = dyn_cast<Defined>(Val: sym)) {
144 r.ExportDynamic =
145 defined->isExternal() && !defined->privateExtern && exportDynamic;
146 r.FinalDefinitionInLinkageUnit =
147 !defined->isExternalWeakDef() && !defined->interposable;
148 } else if (const auto *common = dyn_cast<CommonSymbol>(Val: sym)) {
149 r.ExportDynamic = !common->privateExtern && exportDynamic;
150 r.FinalDefinitionInLinkageUnit = true;
151 }
152
153 r.VisibleToRegularObj =
154 sym->isUsedInRegularObj || (r.Prevailing && r.ExportDynamic);
155
156 // Un-define the symbol so that we don't get duplicate symbol errors when we
157 // load the ObjFile emitted by LTO compilation.
158 if (r.Prevailing)
159 replaceSymbol<Undefined>(s: sym, arg: sym->getName(), arg: sym->getFile(),
160 arg: RefState::Strong, /*wasBitcodeSymbol=*/arg: true);
161
162 // TODO: set the other resolution configs properly
163 }
164 checkError(e: ltoObj->add(Obj: std::move(f.obj), Res: resols));
165 hasFiles = true;
166}
167
168// If LazyObjFile has not been added to link, emit empty index files.
169// This is needed because this is what GNU gold plugin does and we have a
170// distributed build system that depends on that behavior.
171static void thinLTOCreateEmptyIndexFiles() {
172 DenseSet<StringRef> linkedBitCodeFiles;
173 for (InputFile *file : inputFiles)
174 if (auto *f = dyn_cast<BitcodeFile>(Val: file))
175 if (!f->lazy)
176 linkedBitCodeFiles.insert(V: f->getName());
177
178 for (InputFile *file : inputFiles) {
179 if (auto *f = dyn_cast<BitcodeFile>(Val: file)) {
180 if (!f->lazy)
181 continue;
182 if (linkedBitCodeFiles.contains(V: f->getName()))
183 continue;
184 std::string path =
185 replaceThinLTOSuffix(path: getThinLTOOutputFile(modulePath: f->obj->getName()));
186 std::unique_ptr<raw_fd_ostream> os = openFile(file: path + ".thinlto.bc");
187 if (!os)
188 continue;
189
190 ModuleSummaryIndex m(/*HaveGVs=*/false);
191 m.setSkipModuleByDistributedBackend();
192 writeIndexToFile(Index: m, Out&: *os);
193 if (config->thinLTOEmitImportsFiles)
194 openFile(file: path + ".imports");
195 }
196 }
197}
198
199// Merge all the bitcode files we have seen, codegen the result
200// and return the resulting ObjectFile(s).
201std::vector<ObjFile *> BitcodeCompiler::compile() {
202 unsigned maxTasks = ltoObj->getMaxTasks();
203 buf.resize(new_size: maxTasks);
204 files.resize(new_size: maxTasks);
205
206 // The -cache_path_lto option specifies the path to a directory in which
207 // to cache native object files for ThinLTO incremental builds. If a path was
208 // specified, configure LTO to use it as the cache directory.
209 FileCache cache;
210 if (!config->thinLTOCacheDir.empty())
211 cache = check(e: localCache(CacheNameRef: "ThinLTO", TempFilePrefixRef: "Thin", CacheDirectoryPathRef: config->thinLTOCacheDir,
212 AddBuffer: [&](size_t task, const Twine &moduleName,
213 std::unique_ptr<MemoryBuffer> mb) {
214 files[task] = std::move(mb);
215 }));
216
217 if (hasFiles)
218 checkError(e: ltoObj->run(
219 AddStream: [&](size_t task, const Twine &moduleName) {
220 return std::make_unique<CachedFileStream>(
221 args: std::make_unique<raw_svector_ostream>(args&: buf[task]));
222 },
223 Cache: cache));
224
225 // Emit empty index files for non-indexed files
226 for (StringRef s : thinIndices) {
227 std::string path = getThinLTOOutputFile(modulePath: s);
228 openFile(file: path + ".thinlto.bc");
229 if (config->thinLTOEmitImportsFiles)
230 openFile(file: path + ".imports");
231 }
232
233 if (config->thinLTOEmitIndexFiles)
234 thinLTOCreateEmptyIndexFiles();
235
236 // In ThinLTO mode, Clang passes a temporary directory in -object_path_lto,
237 // while the argument is a single file in FullLTO mode.
238 bool objPathIsDir = true;
239 if (!config->ltoObjPath.empty()) {
240 if (std::error_code ec = fs::create_directories(path: config->ltoObjPath))
241 fatal(msg: "cannot create LTO object path " + config->ltoObjPath + ": " +
242 ec.message());
243
244 if (!fs::is_directory(Path: config->ltoObjPath)) {
245 objPathIsDir = false;
246 unsigned objCount =
247 count_if(Range&: buf, P: [](const SmallString<0> &b) { return !b.empty(); });
248 if (objCount > 1)
249 fatal(msg: "-object_path_lto must specify a directory when using ThinLTO");
250 }
251 }
252
253 auto outputFilePath = [objPathIsDir](int i) {
254 SmallString<261> filePath("/tmp/lto.tmp");
255 if (!config->ltoObjPath.empty()) {
256 filePath = config->ltoObjPath;
257 if (objPathIsDir)
258 path::append(path&: filePath, a: Twine(i) + "." +
259 getArchitectureName(Arch: config->arch()) +
260 ".lto.o");
261 }
262 return filePath;
263 };
264
265 // ThinLTO with index only option is required to generate only the index
266 // files. After that, we exit from linker and ThinLTO backend runs in a
267 // distributed environment.
268 if (config->thinLTOIndexOnly) {
269 if (!config->ltoObjPath.empty())
270 saveBuffer(buffer: buf[0], path: outputFilePath(0));
271 if (indexFile)
272 indexFile->close();
273 return {};
274 }
275
276 if (!config->thinLTOCacheDir.empty())
277 pruneCache(Path: config->thinLTOCacheDir, Policy: config->thinLTOCachePolicy, Files: files);
278
279 std::vector<ObjFile *> ret;
280 for (unsigned i = 0; i < maxTasks; ++i) {
281 // Get the native object contents either from the cache or from memory. Do
282 // not use the cached MemoryBuffer directly to ensure dsymutil does not
283 // race with the cache pruner.
284 StringRef objBuf;
285 std::optional<StringRef> cachePath;
286 if (files[i]) {
287 objBuf = files[i]->getBuffer();
288 cachePath = files[i]->getBufferIdentifier();
289 } else {
290 objBuf = buf[i];
291 }
292 if (objBuf.empty())
293 continue;
294
295 // FIXME: should `saveTemps` and `ltoObjPath` use the same file name?
296 if (config->saveTemps)
297 saveBuffer(buffer: objBuf,
298 path: config->outputFile + ((i == 0) ? "" : Twine(i)) + ".lto.o");
299
300 auto filePath = outputFilePath(i);
301 uint32_t modTime = 0;
302 if (!config->ltoObjPath.empty()) {
303 saveOrHardlinkBuffer(buffer: objBuf, path: filePath, originalPath: cachePath);
304 modTime = getModTime(path: filePath);
305 }
306 ret.push_back(x: make<ObjFile>(
307 args: MemoryBufferRef(objBuf, saver().save(S: filePath.str())), args&: modTime,
308 /*archiveName=*/args: "", /*lazy=*/args: false,
309 /*forceHidden=*/args: false, /*compatArch=*/args: true, /*builtFromBitcode=*/args: true));
310 }
311
312 return ret;
313}
314