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