xref: /freebsd-12.1/contrib/llvm/lib/LTO/Caching.cpp (revision bb7d0109)
1 //===-Caching.cpp - LLVM Link Time Optimizer Cache Handling ---------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Caching for ThinLTO.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/LTO/Caching.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/Support/FileSystem.h"
17 #include "llvm/Support/MemoryBuffer.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/raw_ostream.h"
20 
21 using namespace llvm;
22 using namespace llvm::lto;
23 
24 static void commitEntry(StringRef TempFilename, StringRef EntryPath) {
25   // Rename to final destination (hopefully race condition won't matter here)
26   auto EC = sys::fs::rename(TempFilename, EntryPath);
27   if (EC) {
28     // Renaming failed, probably not the same filesystem, copy and delete.
29     // FIXME: Avoid needing to do this by creating the temporary file in the
30     // cache directory.
31     {
32       auto ReloadedBufferOrErr = MemoryBuffer::getFile(TempFilename);
33       if (auto EC = ReloadedBufferOrErr.getError())
34         report_fatal_error(Twine("Failed to open temp file '") + TempFilename +
35                            "': " + EC.message() + "\n");
36 
37       raw_fd_ostream OS(EntryPath, EC, sys::fs::F_None);
38       if (EC)
39         report_fatal_error(Twine("Failed to open ") + EntryPath +
40                            " to save cached entry\n");
41       // I'm not sure what are the guarantee if two processes are doing this
42       // at the same time.
43       OS << (*ReloadedBufferOrErr)->getBuffer();
44     }
45     sys::fs::remove(TempFilename);
46   }
47 }
48 
49 NativeObjectCache lto::localCache(std::string CacheDirectoryPath,
50                                   AddFileFn AddFile) {
51   return [=](unsigned Task, StringRef Key) -> AddStreamFn {
52     // First, see if we have a cache hit.
53     SmallString<64> EntryPath;
54     sys::path::append(EntryPath, CacheDirectoryPath, Key);
55     if (sys::fs::exists(EntryPath)) {
56       AddFile(Task, EntryPath);
57       return AddStreamFn();
58     }
59 
60     // This native object stream is responsible for commiting the resulting
61     // file to the cache and calling AddFile to add it to the link.
62     struct CacheStream : NativeObjectStream {
63       AddFileFn AddFile;
64       std::string TempFilename;
65       std::string EntryPath;
66       unsigned Task;
67 
68       CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddFileFn AddFile,
69                   std::string TempFilename, std::string EntryPath,
70                   unsigned Task)
71           : NativeObjectStream(std::move(OS)), AddFile(AddFile),
72             TempFilename(TempFilename), EntryPath(EntryPath), Task(Task) {}
73 
74       ~CacheStream() {
75         // Make sure the file is closed before committing it.
76         OS.reset();
77         commitEntry(TempFilename, EntryPath);
78         AddFile(Task, EntryPath);
79       }
80     };
81 
82     return [=](size_t Task) -> std::unique_ptr<NativeObjectStream> {
83       // Write to a temporary to avoid race condition
84       int TempFD;
85       SmallString<64> TempFilename;
86       std::error_code EC =
87           sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename);
88       if (EC) {
89         errs() << "Error: " << EC.message() << "\n";
90         report_fatal_error("ThinLTO: Can't get a temporary file");
91       }
92 
93       // This CacheStream will move the temporary file into the cache when done.
94       return llvm::make_unique<CacheStream>(
95           llvm::make_unique<raw_fd_ostream>(TempFD, /* ShouldClose */ true),
96           AddFile, TempFilename.str(), EntryPath.str(), Task);
97     };
98   };
99 }
100