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/ErrorHandler.h" 17 #include "lld/Common/Strings.h" 18 #include "lld/Common/TargetOptionsCommandFlags.h" 19 #include "llvm/LTO/LTO.h" 20 #include "llvm/Support/FileSystem.h" 21 #include "llvm/Support/Path.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include "llvm/Transforms/ObjCARC.h" 24 25 using namespace lld; 26 using namespace lld::macho; 27 using namespace llvm; 28 using namespace llvm::sys; 29 30 static lto::Config createConfig() { 31 lto::Config c; 32 c.Options = initTargetOptionsFromCodeGenFlags(); 33 c.CodeModel = getCodeModelFromCMModel(); 34 c.CPU = getCPUStr(); 35 c.MAttrs = getMAttrs(); 36 c.UseNewPM = config->ltoNewPassManager; 37 c.PreCodeGenPassesHook = [](legacy::PassManager &pm) { 38 pm.add(createObjCARCContractPass()); 39 }; 40 c.TimeTraceEnabled = config->timeTraceEnabled; 41 c.TimeTraceGranularity = config->timeTraceGranularity; 42 return c; 43 } 44 45 BitcodeCompiler::BitcodeCompiler() { 46 lto::ThinBackend backend = lto::createInProcessThinBackend( 47 heavyweight_hardware_concurrency(config->thinLTOJobs)); 48 ltoObj = std::make_unique<lto::LTO>(createConfig(), backend); 49 } 50 51 void BitcodeCompiler::add(BitcodeFile &f) { 52 ArrayRef<lto::InputFile::Symbol> objSyms = f.obj->symbols(); 53 std::vector<lto::SymbolResolution> resols; 54 resols.reserve(objSyms.size()); 55 56 // Provide a resolution to the LTO API for each symbol. 57 auto symIt = f.symbols.begin(); 58 for (const lto::InputFile::Symbol &objSym : objSyms) { 59 resols.emplace_back(); 60 lto::SymbolResolution &r = resols.back(); 61 Symbol *sym = *symIt++; 62 63 // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile 64 // reports two symbols for module ASM defined. Without this check, lld 65 // flags an undefined in IR with a definition in ASM as prevailing. 66 // Once IRObjectFile is fixed to report only one symbol this hack can 67 // be removed. 68 r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f; 69 70 // Un-define the symbol so that we don't get duplicate symbol errors when we 71 // load the ObjFile emitted by LTO compilation. 72 if (r.Prevailing) 73 replaceSymbol<Undefined>(sym, sym->getName(), sym->getFile(), 74 RefState::Strong); 75 76 // TODO: set the other resolution configs properly 77 r.VisibleToRegularObj = true; 78 } 79 checkError(ltoObj->add(std::move(f.obj), resols)); 80 } 81 82 // Merge all the bitcode files we have seen, codegen the result 83 // and return the resulting ObjectFile(s). 84 std::vector<ObjFile *> BitcodeCompiler::compile() { 85 unsigned maxTasks = ltoObj->getMaxTasks(); 86 buf.resize(maxTasks); 87 88 checkError(ltoObj->run([&](size_t task) { 89 return std::make_unique<lto::NativeObjectStream>( 90 std::make_unique<raw_svector_ostream>(buf[task])); 91 })); 92 93 if (config->saveTemps) { 94 if (!buf[0].empty()) 95 saveBuffer(buf[0], config->outputFile + ".lto.o"); 96 for (unsigned i = 1; i != maxTasks; ++i) 97 saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o"); 98 } 99 100 if (!config->ltoObjPath.empty()) 101 fs::create_directories(config->ltoObjPath); 102 103 std::vector<ObjFile *> ret; 104 for (unsigned i = 0; i != maxTasks; ++i) { 105 if (buf[i].empty()) 106 continue; 107 SmallString<261> filePath("/tmp/lto.tmp"); 108 uint32_t modTime = 0; 109 if (!config->ltoObjPath.empty()) { 110 filePath = config->ltoObjPath; 111 path::append(filePath, Twine(i) + "." + 112 getArchitectureName(config->target.Arch) + 113 ".lto.o"); 114 saveBuffer(buf[i], filePath); 115 modTime = getModTime(filePath); 116 } 117 ret.push_back(make<ObjFile>( 118 MemoryBufferRef(buf[i], saver.save(filePath.str())), modTime, "")); 119 } 120 121 return ret; 122 } 123