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