llvm.org GIT mirror llvm / 91d99c6
LTO: Simplify caching interface. The NativeObjectOutput class has a design problem: it mixes up the caching policy with the interface for output streams, which makes the client-side code hard to follow and would for example make it harder to replace the cache implementation in an arbitrary client. This change separates the two aspects by moving the caching policy to a separate field in Config, replacing NativeObjectOutput with a NativeObjectStream class which only deals with streams and does not need to be overridden by most clients and introducing an AddFile callback for adding files (e.g. from the cache) to the link. Differential Revision: https://reviews.llvm.org/D24622 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282299 91177308-0d34-0410-b5e6-96231b3b80d8 Peter Collingbourne 4 years ago
9 changed file(s) with 211 addition(s) and 308 deletion(s). Raw diff Collapse all Expand all
66 //
77 //===----------------------------------------------------------------------===//
88 //
9 // This file defines the lto::CacheObjectOutput data structure, which allows
10 // clients to add a filesystem cache to ThinLTO
9 // This file defines the localCache function, which allows clients to add a
10 // filesystem cache to ThinLTO.
1111 //
1212 //===----------------------------------------------------------------------===//
1313
1414 #ifndef LLVM_LTO_CACHING_H
1515 #define LLVM_LTO_CACHING_H
1616
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/LTO/Config.h"
19 #include "llvm/Support/MemoryBuffer.h"
17 #include "llvm/LTO/LTO.h"
18 #include
2019
2120 namespace llvm {
2221 namespace lto {
23 /// Type for client-supplied callback when a buffer is loaded from the cache.
24 typedef std::function AddBufferFn;
2522
26 /// Manage caching on the filesystem.
23 /// This type defines the callback to add a pre-existing native object file
24 /// (e.g. in a cache).
2725 ///
28 /// The general scheme is the following:
29 ///
30 /// void do_stuff(AddBufferFn CallBack) {
31 /// /* ... */
32 /// {
33 /// /* Create the CacheObjectOutput pointing to a cache directory */
34 /// auto Output = CacheObjectOutput("/tmp/cache", CallBack)
35 ///
36 /// /* Call some processing function */
37 /// process(Output);
38 ///
39 /// } /* Callback is only called now, on destruction of the Output object */
40 /// /* ... */
41 /// }
42 ///
43 ///
44 /// void process(NativeObjectOutput &Output) {
45 /// /* check if caching is supported */
46 /// if (Output.isCachingEnabled()) {
47 /// auto Key = ComputeKeyForEntry(...); // "expensive" call
48 /// if (Output.tryLoadFromCache())
49 /// return; // Cache hit
50 /// }
51 ///
52 /// auto OS = Output.getStream();
53 ///
54 /// OS << ...;
55 /// /* Note that the callback is not called here, but only when the caller
56 /// destroys Output */
57 /// }
58 ///
59 class CacheObjectOutput : public NativeObjectOutput {
60 /// Path to the on-disk cache directory
61 StringRef CacheDirectoryPath;
62 /// Path to this entry in the cache, initialized by tryLoadFromCache().
63 SmallString<128> EntryPath;
64 /// Path to temporary file used to buffer output that will be committed to the
65 /// cache entry when this object is destroyed
66 SmallString<128> TempFilename;
67 /// User-supplied callback, used to provide path to cache entry
68 /// (potentially after creating it).
69 AddBufferFn AddBuffer;
26 /// File callbacks must be thread safe.
27 typedef std::function AddFileFn;
7028
71 public:
72 /// The destructor pulls the entry from the cache and calls the AddBuffer
73 /// callback, after committing the entry into the cache on miss.
74 ~CacheObjectOutput();
75
76 /// Create a CacheObjectOutput: the client is supposed to create it in the
77 /// callback supplied to LTO::run. The \p CacheDirectoryPath points to the
78 /// directory on disk where to store the cache, and \p AddBuffer will be
79 /// called when the buffer is ready to be pulled out of the cache
80 /// (potentially after creating it).
81 CacheObjectOutput(StringRef CacheDirectoryPath, AddBufferFn AddBuffer)
82 : CacheDirectoryPath(CacheDirectoryPath), AddBuffer(AddBuffer) {}
83
84 /// Return an allocated stream for the output, or null in case of failure.
85 std::unique_ptr getStream() override;
86
87 /// Set EntryPath, try loading from a possible cache first, return true on
88 /// cache hit.
89 bool tryLoadFromCache(StringRef Key) override;
90
91 /// Returns true to signal that this implementation of NativeObjectFile
92 /// support caching.
93 bool isCachingEnabled() const override { return true; }
94 };
29 /// Create a local file system cache which uses the given cache directory and
30 /// file callback.
31 NativeObjectCache localCache(std::string CacheDirectoryPath, AddFileFn AddFile);
9532
9633 } // namespace lto
9734 } // namespace llvm
2828 class raw_pwrite_stream;
2929
3030 namespace lto {
31
32 /// Abstract class representing a single Task output to be implemented by the
33 /// client of the LTO API.
34 ///
35 /// The general scheme the API is called is the following:
36 ///
37 /// void process(NativeObjectOutput &Output) {
38 /// /* check if caching is supported */
39 /// if (Output.isCachingEnabled()) {
40 /// auto Key = ComputeKeyForEntry(...); // "expensive" call
41 /// if (Output.tryLoadFromCache())
42 /// return; // Cache hit
43 /// }
44 ///
45 /// auto OS = Output.getStream();
46 ///
47 /// OS << ....;
48 /// }
49 ///
50 class NativeObjectOutput {
51 public:
52 // Return an allocated stream for the output, or null in case of failure.
53 virtual std::unique_ptr getStream() = 0;
54
55 // Try loading from a possible cache first, return true on cache hit.
56 virtual bool tryLoadFromCache(StringRef Key) { return false; }
57
58 // Returns true if a cache is available
59 virtual bool isCachingEnabled() const { return false; }
60
61 virtual ~NativeObjectOutput() = default;
62 };
6331
6432 /// LTO configuration. A linker can configure LTO by setting fields in this data
6533 /// structure and passing it to the lto::LTO constructor.
234202 bool UseInputModulePath = false);
235203 };
236204
237 /// This type defines the callback to add a native object that is generated on
238 /// the fly.
239 ///
240 /// Output callbacks must be thread safe.
241 typedef std::function(unsigned Task)>
242 AddOutputFn;
243
244205 /// A derived class of LLVMContext that initializes itself according to a given
245206 /// Config object. The purpose of this class is to tie ownership of the
246207 /// diagnostic handler to the context, as opposed to the Config object (which
246246 }
247247 };
248248
249 /// This class wraps an output stream for a native object. Most clients should
250 /// just be able to return an instance of this base class from the stream
251 /// callback, but if a client needs to perform some action after the stream is
252 /// written to, that can be done by deriving from this class and overriding the
253 /// destructor.
254 class NativeObjectStream {
255 public:
256 NativeObjectStream(std::unique_ptr OS) : OS(std::move(OS)) {}
257 std::unique_ptr OS;
258 virtual ~NativeObjectStream() = default;
259 };
260
261 /// This type defines the callback to add a native object that is generated on
262 /// the fly.
263 ///
264 /// Stream callbacks must be thread safe.
265 typedef std::function(unsigned Task)>
266 AddStreamFn;
267
268 /// This is the type of a native object cache. To request an item from the
269 /// cache, pass a unique string as the Key. For hits, the cached file will be
270 /// added to the link and this function will return AddStreamFn(). For misses,
271 /// the cache will return a stream callback which must be called at most once to
272 /// produce content for the stream. The native object stream produced by the
273 /// stream callback will add the file to the link after the stream is written
274 /// to.
275 ///
276 /// Clients generally look like this:
277 ///
278 /// if (AddStreamFn AddStream = Cache(Task, Key))
279 /// ProduceContent(AddStream);
280 typedef std::function
281 NativeObjectCache;
282
249283 /// A ThinBackend defines what happens after the thin-link phase during ThinLTO.
250284 /// The details of this type definition aren't important; clients can only
251285 /// create a ThinBackend using one of the create*ThinBackend() functions below.
252286 typedef std::function(
253287 Config &C, ModuleSummaryIndex &CombinedIndex,
254288 StringMap &ModuleToDefinedGVSummaries,
255 AddOutputFn AddOutput)>
289 AddStreamFn AddStream, NativeObjectCache Cache)>
256290 ThinBackend;
257291
258292 /// This ThinBackend runs the individual backend jobs in-process.
285319 /// and pass it and an array of symbol resolutions to the add() function.
286320 /// - Call the getMaxTasks() function to get an upper bound on the number of
287321 /// native object files that LTO may add to the link.
288 /// - Call the run() function. This function will use the supplied AddOutput
289 /// function to add up to getMaxTasks() native object files to the link.
322 /// - Call the run() function. This function will use the supplied AddStream
323 /// and Cache functions to add up to getMaxTasks() native object files to
324 /// the link.
290325 class LTO {
291326 friend InputFile;
292327
309344 /// full description of tasks see LTOBackend.h.
310345 unsigned getMaxTasks() const;
311346
312 /// Runs the LTO pipeline. This function calls the supplied AddOutput function
313 /// to add native object files to the link.
314 Error run(AddOutputFn AddOutput);
347 /// Runs the LTO pipeline. This function calls the supplied AddStream
348 /// function to add native object files to the link.
349 ///
350 /// The Cache parameter is optional. If supplied, it will be used to cache
351 /// native object files and add them to the link.
352 ///
353 /// The client will receive at most one callback (via either AddStream or
354 /// Cache) for each task identifier.
355 Error run(AddStreamFn AddStream, NativeObjectCache Cache = nullptr);
315356
316357 private:
317358 Config Conf;
392433 Error addThinLTO(std::unique_ptr Input,
393434 ArrayRef Res);
394435
395 Error runRegularLTO(AddOutputFn AddOutput);
396 Error runThinLTO(AddOutputFn AddOutput, bool HasRegularLTO);
436 Error runRegularLTO(AddStreamFn AddStream);
437 Error runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
438 bool HasRegularLTO);
397439
398440 mutable bool CalledGetMaxTasks = false;
399441 };
1919 #include "llvm/ADT/MapVector.h"
2020 #include "llvm/IR/DiagnosticInfo.h"
2121 #include "llvm/IR/ModuleSummaryIndex.h"
22 #include "llvm/LTO/Config.h"
22 #include "llvm/LTO/LTO.h"
2323 #include "llvm/Support/MemoryBuffer.h"
2424 #include "llvm/Target/TargetOptions.h"
2525 #include "llvm/Transforms/IPO/FunctionImport.h"
3333 namespace lto {
3434
3535 /// Runs a regular LTO backend.
36 Error backend(Config &C, AddOutputFn AddStream,
36 Error backend(Config &C, AddStreamFn AddStream,
3737 unsigned ParallelCodeGenParallelismLevel,
3838 std::unique_ptr M);
3939
4040 /// Runs a ThinLTO backend.
41 Error thinBackend(Config &C, unsigned Task, AddOutputFn AddStream, Module &M,
41 Error thinBackend(Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
4242 ModuleSummaryIndex &CombinedIndex,
4343 const FunctionImporter::ImportMapTy &ImportList,
4444 const GVSummaryMapTy &DefinedGlobals,
1111 //===----------------------------------------------------------------------===//
1212
1313 #include "llvm/LTO/Caching.h"
14
15 #ifdef HAVE_LLVM_REVISION
16 #include "LLVMLTORevision.h"
17 #endif
18
1914 #include "llvm/ADT/StringExtras.h"
2015 #include "llvm/Support/FileSystem.h"
16 #include "llvm/Support/MemoryBuffer.h"
2117 #include "llvm/Support/Path.h"
2218 #include "llvm/Support/raw_ostream.h"
2319
2925 auto EC = sys::fs::rename(TempFilename, EntryPath);
3026 if (EC) {
3127 // Renaming failed, probably not the same filesystem, copy and delete.
28 // FIXME: Avoid needing to do this by creating the temporary file in the
29 // cache directory.
3230 {
3331 auto ReloadedBufferOrErr = MemoryBuffer::getFile(TempFilename);
3432 if (auto EC = ReloadedBufferOrErr.getError())
4745 }
4846 }
4947
50 CacheObjectOutput::~CacheObjectOutput() {
51 if (EntryPath.empty())
52 // The entry was never used by the client (tryLoadFromCache() wasn't called)
53 return;
54 // TempFilename is only set if getStream() was called, i.e. on cache miss when
55 // tryLoadFromCache() returned false. And EntryPath is valid if a Key was
56 // submitted, otherwise it has been set to CacheDirectoryPath in
57 // tryLoadFromCache.
58 if (!TempFilename.empty()) {
59 if (EntryPath == CacheDirectoryPath)
60 // The Key supplied to tryLoadFromCache was empty, do not commit the temp.
61 EntryPath = TempFilename;
62 else
63 // We commit the tempfile into the cache now, by moving it to EntryPath.
64 commitEntry(TempFilename, EntryPath);
65 }
66 // Supply the cache path to the user.
67 AddBuffer(EntryPath.str());
48 NativeObjectCache lto::localCache(std::string CacheDirectoryPath,
49 AddFileFn AddFile) {
50 return [=](unsigned Task, StringRef Key) -> AddStreamFn {
51 // First, see if we have a cache hit.
52 SmallString<64> EntryPath;
53 sys::path::append(EntryPath, CacheDirectoryPath, Key);
54 if (sys::fs::exists(EntryPath)) {
55 AddFile(Task, EntryPath);
56 return AddStreamFn();
57 }
58
59 // This native object stream is responsible for commiting the resulting
60 // file to the cache and calling AddFile to add it to the link.
61 struct CacheStream : NativeObjectStream {
62 AddFileFn AddFile;
63 std::string TempFilename;
64 std::string EntryPath;
65 unsigned Task;
66
67 CacheStream(std::unique_ptr OS, AddFileFn AddFile,
68 std::string TempFilename, std::string EntryPath,
69 unsigned Task)
70 : NativeObjectStream(std::move(OS)), AddFile(AddFile),
71 TempFilename(TempFilename), EntryPath(EntryPath), Task(Task) {}
72
73 ~CacheStream() {
74 // Make sure the file is closed before committing it.
75 OS.reset();
76 commitEntry(TempFilename, EntryPath);
77 AddFile(Task, EntryPath);
78 }
79 };
80
81 return [=](size_t Task) -> std::unique_ptr {
82 // Write to a temporary to avoid race condition
83 int TempFD;
84 SmallString<64> TempFilename;
85 std::error_code EC =
86 sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename);
87 if (EC) {
88 errs() << "Error: " << EC.message() << "\n";
89 report_fatal_error("ThinLTO: Can't get a temporary file");
90 }
91
92 // This CacheStream will move the temporary file into the cache when done.
93 return make_unique(
94 llvm::make_unique(TempFD, /* ShouldClose */ true),
95 AddFile, TempFilename.str(), EntryPath.str(), Task);
96 };
97 };
6898 }
69
70 // Return an allocated stream for the output, or null in case of failure.
71 std::unique_ptr CacheObjectOutput::getStream() {
72 assert(!EntryPath.empty() && "API Violation: client didn't call "
73 "tryLoadFromCache() before getStream()");
74 // Write to a temporary to avoid race condition
75 int TempFD;
76 std::error_code EC =
77 sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename);
78 if (EC) {
79 errs() << "Error: " << EC.message() << "\n";
80 report_fatal_error("ThinLTO: Can't get a temporary file");
81 }
82 return llvm::make_unique(TempFD, /* ShouldClose */ true);
83 }
84
85 // Try loading from a possible cache first, return true on cache hit.
86 bool CacheObjectOutput::tryLoadFromCache(StringRef Key) {
87 assert(!CacheDirectoryPath.empty() &&
88 "CacheObjectOutput was initialized without a cache path");
89 if (Key.empty()) {
90 // Client didn't compute a valid key. EntryPath has been set to
91 // CacheDirectoryPath.
92 EntryPath = CacheDirectoryPath;
93 return false;
94 }
95 sys::path::append(EntryPath, CacheDirectoryPath, Key);
96 return sys::fs::exists(EntryPath);
97 }
408408 return RegularLTO.ParallelCodeGenParallelismLevel + ThinLTO.ModuleMap.size();
409409 }
410410
411 Error LTO::run(AddOutputFn AddOutput) {
411 Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) {
412412 // Save the status of having a regularLTO combined module, as
413413 // this is needed for generating the ThinLTO Task ID, and
414414 // the CombinedModule will be moved at the end of runRegularLTO.
415415 bool HasRegularLTO = RegularLTO.CombinedModule != nullptr;
416416 // Invoke regular LTO if there was a regular LTO module to start with.
417417 if (HasRegularLTO)
418 if (auto E = runRegularLTO(AddOutput))
418 if (auto E = runRegularLTO(AddStream))
419419 return E;
420 return runThinLTO(AddOutput, HasRegularLTO);
421 }
422
423 Error LTO::runRegularLTO(AddOutputFn AddOutput) {
420 return runThinLTO(AddStream, Cache, HasRegularLTO);
421 }
422
423 Error LTO::runRegularLTO(AddStreamFn AddStream) {
424424 // Make sure commons have the right size/alignment: we kept the largest from
425425 // all the prevailing when adding the inputs, and we apply it here.
426426 const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout();
477477 !Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule))
478478 return Error();
479479 }
480 return backend(Conf, AddOutput, RegularLTO.ParallelCodeGenParallelismLevel,
480 return backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
481481 std::move(RegularLTO.CombinedModule));
482482 }
483483
506506
507507 class InProcessThinBackend : public ThinBackendProc {
508508 ThreadPool BackendThreadPool;
509 AddOutputFn AddOutput;
509 AddStreamFn AddStream;
510 NativeObjectCache Cache;
510511
511512 Optional Err;
512513 std::mutex ErrMu;
516517 Config &Conf, ModuleSummaryIndex &CombinedIndex,
517518 unsigned ThinLTOParallelismLevel,
518519 const StringMap &ModuleToDefinedGVSummaries,
519 AddOutputFn AddOutput)
520 AddStreamFn AddStream, NativeObjectCache Cache)
520521 : ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries),
521522 BackendThreadPool(ThinLTOParallelismLevel),
522 AddOutput(std::move(AddOutput)) {}
523 AddStream(std::move(AddStream)), Cache(std::move(Cache)) {}
523524
524525 Error runThinLTOBackendThread(
525 AddOutputFn AddOutput, unsigned Task, MemoryBufferRef MBRef,
526 ModuleSummaryIndex &CombinedIndex,
526 AddStreamFn AddStream, NativeObjectCache Cache, unsigned Task,
527 MemoryBufferRef MBRef, ModuleSummaryIndex &CombinedIndex,
527528 const FunctionImporter::ImportMapTy &ImportList,
528529 const FunctionImporter::ExportSetTy &ExportList,
529530 const std::map &ResolvedODR,
530531 const GVSummaryMapTy &DefinedGlobals,
531532 MapVector &ModuleMap) {
532
533 auto ModuleIdentifier = MBRef.getBufferIdentifier();
534 auto Output = AddOutput(Task);
535 if (Output->isCachingEnabled()) {
536 SmallString<40> Key;
537 // The module may be cached, this helps handling it.
538 computeCacheKey(Key, CombinedIndex, ModuleIdentifier, ImportList,
539 ExportList, ResolvedODR, DefinedGlobals);
540 if (Output->tryLoadFromCache(Key))
541 return Error();
542 }
543
544 LTOLLVMContext BackendContext(Conf);
545 ErrorOr> MOrErr =
546 parseBitcodeFile(MBRef, BackendContext);
547 assert(MOrErr && "Unable to load module in thread?");
548
549 auto AddOutputWrapper = [&](unsigned TaskId) {
550 assert(Task == TaskId && "Unexpexted TaskId mismatch");
551 return std::move(Output);
533 auto RunThinBackend = [&](AddStreamFn AddStream) {
534 LTOLLVMContext BackendContext(Conf);
535 ErrorOr> MOrErr =
536 parseBitcodeFile(MBRef, BackendContext);
537 assert(MOrErr && "Unable to load module in thread?");
538
539 return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex,
540 ImportList, DefinedGlobals, ModuleMap);
552541 };
553 return thinBackend(Conf, Task, AddOutputWrapper, **MOrErr, CombinedIndex,
554 ImportList, DefinedGlobals, ModuleMap);
542
543 if (!Cache)
544 return RunThinBackend(AddStream);
545
546 SmallString<40> Key;
547 // The module may be cached, this helps handling it.
548 computeCacheKey(Key, CombinedIndex, MBRef.getBufferIdentifier(),
549 ImportList, ExportList, ResolvedODR, DefinedGlobals);
550 if (AddStreamFn CacheAddStream = Cache(Task, Key))
551 return RunThinBackend(CacheAddStream);
552
553 return Error();
555554 }
556555
557556 Error start(
573572 const GVSummaryMapTy &DefinedGlobals,
574573 MapVector &ModuleMap) {
575574 Error E = runThinLTOBackendThread(
576 AddOutput, Task, MBRef, CombinedIndex, ImportList, ExportList,
577 ResolvedODR, DefinedGlobals, ModuleMap);
575 AddStream, Cache, Task, MBRef, CombinedIndex, ImportList,
576 ExportList, ResolvedODR, DefinedGlobals, ModuleMap);
578577 if (E) {
579578 std::unique_lock L(ErrMu);
580579 if (Err)
601600 ThinBackend lto::createInProcessThinBackend(unsigned ParallelismLevel) {
602601 return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
603602 const StringMap &ModuleToDefinedGVSummaries,
604 AddOutputFn AddOutput) {
603 AddStreamFn AddStream, NativeObjectCache Cache) {
605604 return llvm::make_unique(
606605 Conf, CombinedIndex, ParallelismLevel, ModuleToDefinedGVSummaries,
607 AddOutput);
606 AddStream, Cache);
608607 };
609608 }
610609
692691 std::string LinkedObjectsFile) {
693692 return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
694693 const StringMap &ModuleToDefinedGVSummaries,
695 AddOutputFn AddOutput) {
694 AddStreamFn AddStream, NativeObjectCache Cache) {
696695 return llvm::make_unique(
697696 Conf, CombinedIndex, ModuleToDefinedGVSummaries, OldPrefix, NewPrefix,
698697 ShouldEmitImportsFiles, LinkedObjectsFile);
699698 };
700699 }
701700
702 Error LTO::runThinLTO(AddOutputFn AddOutput, bool HasRegularLTO) {
701 Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
702 bool HasRegularLTO) {
703703 if (ThinLTO.ModuleMap.empty())
704704 return Error();
705705
758758 thinLTOResolveWeakForLinkerInIndex(ThinLTO.CombinedIndex, isPrevailing,
759759 recordNewLinkage);
760760
761 std::unique_ptr BackendProc = ThinLTO.Backend(
762 Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, AddOutput);
761 std::unique_ptr BackendProc =
762 ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
763 AddStream, Cache);
763764
764765 // Partition numbers for ThinLTO jobs start at 1 (see comments for
765766 // GlobalResolution in LTO.h). Task numbers, however, start at
198198 return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod);
199199 }
200200
201 /// Monolithic LTO does not support caching (yet), this is a convenient wrapper
202 /// around AddOutput to workaround this.
203 static AddOutputFn getUncachedOutputWrapper(AddOutputFn &AddOutput,
204 unsigned Task) {
205 return [Task, &AddOutput](unsigned TaskId) {
206 auto Output = AddOutput(Task);
207 if (Output->isCachingEnabled() && Output->tryLoadFromCache(""))
208 report_fatal_error("Cache hit without a valid key?");
209 assert(Task == TaskId && "Unexpexted TaskId mismatch");
210 return Output;
211 };
212 }
213
214 void codegen(Config &Conf, TargetMachine *TM, AddOutputFn AddOutput,
201 void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream,
215202 unsigned Task, Module &Mod) {
216203 if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod))
217204 return;
218205
219 auto Output = AddOutput(Task);
220 std::unique_ptr OS = Output->getStream();
206 auto Stream = AddStream(Task);
221207 legacy::PassManager CodeGenPasses;
222 if (TM->addPassesToEmitFile(CodeGenPasses, *OS,
208 if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS,
223209 TargetMachine::CGFT_ObjectFile))
224210 report_fatal_error("Failed to setup codegen");
225211 CodeGenPasses.run(Mod);
226212 }
227213
228 void splitCodeGen(Config &C, TargetMachine *TM, AddOutputFn AddOutput,
214 void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream,
229215 unsigned ParallelCodeGenParallelismLevel,
230216 std::unique_ptr Mod) {
231217 ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel);
259245 std::unique_ptr TM =
260246 createTargetMachine(C, MPartInCtx->getTargetTriple(), T);
261247
262 codegen(C, TM.get(),
263 getUncachedOutputWrapper(AddOutput, ThreadId), ThreadId,
264 *MPartInCtx);
248 codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx);
265249 },
266250 // Pass BC using std::move to ensure that it get moved rather than
267251 // copied into the thread's context.
298282 updateCompilerUsed(Mod, TM, AsmUndefinedRefs);
299283 }
300284
301 Error lto::backend(Config &C, AddOutputFn AddOutput,
285 Error lto::backend(Config &C, AddStreamFn AddStream,
302286 unsigned ParallelCodeGenParallelismLevel,
303287 std::unique_ptr Mod) {
304288 Expected TOrErr = initAndLookupTarget(C, *Mod);
315299 return Error();
316300
317301 if (ParallelCodeGenParallelismLevel == 1) {
318 codegen(C, TM.get(), getUncachedOutputWrapper(AddOutput, 0), 0, *Mod);
302 codegen(C, TM.get(), AddStream, 0, *Mod);
319303 } else {
320 splitCodeGen(C, TM.get(), AddOutput, ParallelCodeGenParallelismLevel,
304 splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel,
321305 std::move(Mod));
322306 }
323307 return Error();
324308 }
325309
326 Error lto::thinBackend(Config &Conf, unsigned Task, AddOutputFn AddOutput,
310 Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream,
327311 Module &Mod, ModuleSummaryIndex &CombinedIndex,
328312 const FunctionImporter::ImportMapTy &ImportList,
329313 const GVSummaryMapTy &DefinedGlobals,
338322 handleAsmUndefinedRefs(Mod, *TM);
339323
340324 if (Conf.CodeGenOnly) {
341 codegen(Conf, TM.get(), AddOutput, Task, Mod);
325 codegen(Conf, TM.get(), AddStream, Task, Mod);
342326 return Error();
343327 }
344328
378362 if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLto=*/true))
379363 return Error();
380364
381 codegen(Conf, TM.get(), AddOutput, Task, Mod);
365 codegen(Conf, TM.get(), AddStream, Task, Mod);
382366 return Error();
383367 }
674674 NewPrefix = Split.second.str();
675675 }
676676
677 namespace {
678 // Define the LTOOutput handling
679 class LTOOutput : public lto::NativeObjectOutput {
680 StringRef Path;
681
682 public:
683 LTOOutput(StringRef Path) : Path(Path) {}
684 // Open the filename \p Path and allocate a stream.
685 std::unique_ptr getStream() override {
686 int FD;
687 std::error_code EC = sys::fs::openFileForWrite(Path, FD, sys::fs::F_None);
688 if (EC)
689 message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
690 return llvm::make_unique(FD, true);
691 }
692 };
693 }
694
695677 static std::unique_ptr createLTO() {
696678 Config Conf;
697679 ThinBackend Backend;
830812 std::vector IsTemporary(MaxTasks);
831813 std::vector> Filenames(MaxTasks);
832814
833 auto AddOutput =
834 [&](size_t Task) -> std::unique_ptr {
835 auto &OutputName = Filenames[Task];
836 getOutputFileName(Filename, /*TempOutFile=*/!SaveTemps, OutputName,
815 auto AddStream =
816 [&](size_t Task) -> std::unique_ptr {
817 IsTemporary[Task] = !SaveTemps;
818 getOutputFileName(Filename, /*TempOutFile=*/!SaveTemps, Filenames[Task],
837819 MaxTasks > 1 ? Task : -1);
838 IsTemporary[Task] = !SaveTemps && options::cache_dir.empty();
839 if (options::cache_dir.empty())
840 return llvm::make_unique(OutputName);
841
842 return llvm::make_unique(
843 options::cache_dir,
844 [&OutputName](std::string EntryPath) { OutputName = EntryPath; });
820 int FD;
821 std::error_code EC =
822 sys::fs::openFileForWrite(Filenames[Task], FD, sys::fs::F_None);
823 if (EC)
824 message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
825 return llvm::make_unique(
826 llvm::make_unique(FD, true));
845827 };
846828
847 check(Lto->run(AddOutput));
829 auto AddFile = [&](size_t Task, StringRef Path) { Filenames[Task] = Path; };
830
831 NativeObjectCache Cache;
832 if (!options::cache_dir.empty())
833 Cache = localCache(options::cache_dir, AddFile);
834
835 check(Lto->run(AddStream, Cache));
848836
849837 if (options::TheOutputType == options::OT_DISABLE ||
850838 options::TheOutputType == options::OT_BC_ONLY)
9292 return std::move(*E);
9393 check(E.getError(), Msg);
9494 return T();
95 }
96
97 namespace {
98 // Define the LTOOutput handling
99 class LTOOutput : public lto::NativeObjectOutput {
100 std::string Path;
101
102 public:
103 LTOOutput(std::string Path) : Path(std::move(Path)) {}
104 std::unique_ptr getStream() override {
105 std::error_code EC;
106 auto S = llvm::make_unique(Path, EC, sys::fs::F_None);
107 check(EC, Path);
108 return std::move(S);
109 }
110 };
11195 }
11296
11397 int main(int argc, char **argv) {
202186 if (HasErrors)
203187 return 1;
204188
205 auto AddOutput =
206 [&](size_t Task) -> std::unique_ptr {
189 auto AddStream =
190 [&](size_t Task) -> std::unique_ptr {
207191 std::string Path = OutputFilename + "." + utostr(Task);
208 if (CacheDir.empty())
209 return llvm::make_unique(std::move(Path));
210
211 return llvm::make_unique(
212 CacheDir, [Path](std::string EntryPath) {
213 // Load the entry from the cache now.
214 auto ReloadedBufferOrErr = MemoryBuffer::getFile(EntryPath);
215 if (auto EC = ReloadedBufferOrErr.getError())
216 report_fatal_error(Twine("Can't reload cached file '") + EntryPath +
217 "': " + EC.message() + "\n");
218
219 *LTOOutput(Path).getStream() << (*ReloadedBufferOrErr)->getBuffer();
220 });
192
193 std::error_code EC;
194 auto S = llvm::make_unique(Path, EC, sys::fs::F_None);
195 check(EC, Path);
196 return llvm::make_unique(std::move(S));
221197 };
222198
223 check(Lto.run(AddOutput), "LTO::run failed");
224 }
199 auto AddFile = [&](size_t Task, StringRef Path) {
200 auto ReloadedBufferOrErr = MemoryBuffer::getFile(Path);
201 if (auto EC = ReloadedBufferOrErr.getError())
202 report_fatal_error(Twine("Can't reload cached file '") + Path + "': " +
203 EC.message() + "\n");
204
205 *AddStream(Task)->OS << (*ReloadedBufferOrErr)->getBuffer();
206 };
207
208 NativeObjectCache Cache;
209 if (!CacheDir.empty())
210 Cache = localCache(CacheDir, AddFile);
211
212 check(Lto.run(AddStream, Cache), "LTO::run failed");
213 }