llvm.org GIT mirror llvm / dbca62e
[ThinLTO] Add an API to trigger file-based API for returning objects to the linker Summary: The motivation is to support better the -object_path_lto option on Darwin. The linker needs to write down the generate object files on disk for later use by lldb or dsymutil (debug info are not present in the final binary). We're moving this into libLTO so that we can be smarter when a cache is enabled and hard-link when possible instead of duplicating the files. Reviewers: tejohnson, deadalnix, pcc Subscribers: dexonsmith, llvm-commits Differential Revision: https://reviews.llvm.org/D27507 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289631 91177308-0d34-0410-b5e6-96231b3b80d8 Mehdi Amini 2 years ago
10 changed file(s) with 240 addition(s) and 25 deletion(s). Raw diff Collapse all Expand all
7171 /**
7272 * Process all the modules that were added to the code generator in parallel.
7373 *
74 * Client can access the resulting object files using getProducedBinaries()
74 * Client can access the resulting object files using getProducedBinaries(),
75 * unless setGeneratedObjectsDirectory() has been called, in which case
76 * results are available through getProducedBinaryFiles().
7577 */
7678 void run();
7779
7880 /**
79 * Return the "in memory" binaries produced by the code generator.
81 * Return the "in memory" binaries produced by the code generator. This is
82 * filled after run() unless setGeneratedObjectsDirectory() has been
83 * called, in which case results are available through
84 * getProducedBinaryFiles().
8085 */
8186 std::vector> &getProducedBinaries() {
8287 return ProducedBinaries;
88 }
89
90 /**
91 * Return the "on-disk" binaries produced by the code generator. This is
92 * filled after run() when setGeneratedObjectsDirectory() has been
93 * called, in which case results are available through getProducedBinaries().
94 */
95 std::vector &getProducedBinaryFiles() {
96 return ProducedBinaryFiles;
8397 }
8498
8599 /**
155169 /// the processing.
156170 void setSaveTempsDir(std::string Path) { SaveTempsDir = std::move(Path); }
157171
172 /// Set the path to a directory where to save generated object files. This
173 /// path can be used by a linker to request on-disk files instead of in-memory
174 /// buffers. When set, results are available through getProducedBinaryFiles()
175 /// instead of getProducedBinaries().
176 void setGeneratedObjectsDirectory(std::string Path) {
177 SavedObjectsDirectoryPath = std::move(Path);
178 }
179
158180 /// CPU to use to initialize the TargetMachine
159181 void setCpu(std::string Cpu) { TMBuilder.MCpu = std::move(Cpu); }
160182
243265 /// Helper factory to build a TargetMachine
244266 TargetMachineBuilder TMBuilder;
245267
246 /// Vector holding the in-memory buffer containing the produced binaries.
268 /// Vector holding the in-memory buffer containing the produced binaries, when
269 /// SavedObjectsDirectoryPath isn't set.
247270 std::vector> ProducedBinaries;
271
272 /// Path to generated files in the supplied SavedObjectsDirectoryPath if any.
273 std::vector ProducedBinaryFiles;
248274
249275 /// Vector holding the input buffers containing the bitcode modules to
250276 /// process.
262288
263289 /// Path to a directory to save the temporary bitcode files.
264290 std::string SaveTempsDir;
291
292 /// Path to a directory to save the generated object files.
293 std::string SavedObjectsDirectoryPath;
265294
266295 /// Flag to enable/disable CodeGen. When set to true, the process stops after
267296 /// optimizations and a bitcode is produced.
341341 /// specific error_code.
342342 std::error_code create_link(const Twine &to, const Twine &from);
343343
344 /// Create a hard link from \a from to \a to, or return an error.
345 ///
346 /// @param to The path to hard link to.
347 /// @param from The path to hard link from. This is created.
348 /// @returns errc::success if the link was created, otherwise a platform
349 /// specific error_code.
350 std::error_code create_hard_link(const Twine &to, const Twine &from);
351
344352 /// @brief Get the current path.
345353 ///
346354 /// @param result Holds the current path on return.
4343 * @{
4444 */
4545
46 #define LTO_API_VERSION 20
46 #define LTO_API_VERSION 21
4747
4848 /**
4949 * \since prior to LTO_API_VERSION=3
636636 unsigned int index);
637637
638638 /**
639 * Returns the number of object files produced by the ThinLTO CodeGenerator.
640 *
641 * It usually matches the number of input files, but this is not a guarantee of
642 * the API and may change in future implementation, so the client should not
643 * assume it.
644 *
645 * \since LTO_API_VERSION=21
646 */
647 unsigned int thinlto_module_get_num_object_files(thinlto_code_gen_t cg);
648
649 /**
650 * Returns the path to the ith object file produced by the ThinLTO
651 * CodeGenerator.
652 *
653 * Client should use \p thinlto_module_get_num_object_files() to get the number
654 * of available objects.
655 *
656 * \since LTO_API_VERSION=21
657 */
658 const char *thinlto_module_get_object_file(thinlto_code_gen_t cg,
659 unsigned int index);
660
661 /**
639662 * Sets which PIC code model to generate.
640663 * Returns true on error (check lto_get_error_message() for details).
641664 *
724747 const char *save_temps_dir);
725748
726749 /**
750 * Set the path to a directory where to save generated object files. This
751 * path can be used by a linker to request on-disk files instead of in-memory
752 * buffers. When set, results are available through
753 * thinlto_module_get_object_file() instead of thinlto_module_get_object().
754 *
755 * \since LTO_API_VERSION=21
756 */
757 void thinlto_set_generated_objects_dir(thinlto_code_gen_t cg,
758 const char *save_temps_dir);
759
760 /**
727761 * Sets the cpu to generate code for.
728762 *
729763 * \since LTO_API_VERSION=18
342342 }
343343
344344 // Cache the Produced object file
345 std::unique_ptr
346 write(std::unique_ptr OutputBuffer) {
345 void write(const MemoryBuffer &OutputBuffer) {
347346 if (EntryPath.empty())
348 return OutputBuffer;
347 return;
349348
350349 // Write to a temporary to avoid race condition
351350 SmallString<128> TempFilename;
358357 }
359358 {
360359 raw_fd_ostream OS(TempFD, /* ShouldClose */ true);
361 OS << OutputBuffer->getBuffer();
360 OS << OutputBuffer.getBuffer();
362361 }
363362 // Rename to final destination (hopefully race condition won't matter here)
364363 EC = sys::fs::rename(TempFilename, EntryPath);
368367 if (EC)
369368 report_fatal_error(Twine("Failed to open ") + EntryPath +
370369 " to save cached entry\n");
371 OS << OutputBuffer->getBuffer();
372 }
373 auto ReloadedBufferOrErr = MemoryBuffer::getFile(EntryPath);
374 if (auto EC = ReloadedBufferOrErr.getError()) {
375 // FIXME diagnose
376 errs() << "error: can't reload cached file '" << EntryPath
377 << "': " << EC.message() << "\n";
378 return OutputBuffer;
379 }
380 return std::move(*ReloadedBufferOrErr);
370 OS << OutputBuffer.getBuffer();
371 }
381372 }
382373 };
383374
744735 return codegenModule(TheModule, *TMBuilder.create());
745736 }
746737
738 /// Write out the generated object file, either from CacheEntryPath or from
739 /// OutputBuffer, preferring hard-link when possible.
740 /// Returns the path to the generated file in SavedObjectsDirectoryPath.
741 static std::string writeGeneratedObject(int count, StringRef CacheEntryPath,
742 StringRef SavedObjectsDirectoryPath,
743 const MemoryBuffer &OutputBuffer) {
744 SmallString<128> OutputPath(SavedObjectsDirectoryPath);
745 llvm::sys::path::append(OutputPath, Twine(count) + ".thinlto.o");
746 OutputPath.c_str(); // Ensure the string is null terminated.
747 if (sys::fs::exists(OutputPath))
748 sys::fs::remove(OutputPath);
749
750 // We don't return a memory buffer to the linker, just a list of files.
751 if (!CacheEntryPath.empty()) {
752 // Cache is enabled, hard-link the entry (or copy if hard-link fails).
753 auto Err = sys::fs::create_hard_link(CacheEntryPath, OutputPath);
754 if (!Err)
755 return OutputPath.str();
756 // Hard linking failed, try to copy.
757 Err = sys::fs::copy_file(CacheEntryPath, OutputPath);
758 if (!Err)
759 return OutputPath.str();
760 // Copy failed (could be because the CacheEntry was removed from the cache
761 // in the meantime by another process), fall back and try to write down the
762 // buffer to the output.
763 errs() << "error: can't link or copy from cached entry '" << CacheEntryPath
764 << "' to '" << OutputPath << "'\n";
765 }
766 // No cache entry, just write out the buffer.
767 std::error_code Err;
768 raw_fd_ostream OS(OutputPath, Err, sys::fs::F_None);
769 if (Err)
770 report_fatal_error("Can't open output '" + OutputPath + "'\n");
771 OS << OutputBuffer.getBuffer();
772 return OutputPath.str();
773 }
774
747775 // Main entry point for the ThinLTO processing
748776 void ThinLTOCodeGenerator::run() {
749777 if (CodeGenOnly) {
784812
785813 // Prepare the resulting object vector
786814 assert(ProducedBinaries.empty() && "The generator should not be reused");
787 ProducedBinaries.resize(Modules.size());
815 if (SavedObjectsDirectoryPath.empty())
816 ProducedBinaries.resize(Modules.size());
817 else {
818 sys::fs::create_directories(SavedObjectsDirectoryPath);
819 bool IsDir;
820 sys::fs::is_directory(SavedObjectsDirectoryPath, IsDir);
821 if (!IsDir)
822 report_fatal_error("Unexistent dir: '" + SavedObjectsDirectoryPath + "'");
823 ProducedBinaryFiles.resize(Modules.size());
824 }
788825
789826 // Prepare the module map.
790827 auto ModuleMap = generateModuleMap(Modules);
864901 ImportLists[ModuleIdentifier], ExportList,
865902 ResolvedODR[ModuleIdentifier],
866903 DefinedFunctions, GUIDPreservedSymbols);
904 auto CacheEntryPath = CacheEntry.getEntryPath();
867905
868906 {
869907 auto ErrOrBuffer = CacheEntry.tryLoadingBuffer();
870908 DEBUG(dbgs() << "Cache " << (ErrOrBuffer ? "hit" : "miss") << " '"
871 << CacheEntry.getEntryPath() << "' for buffer " << count
872 << " " << ModuleIdentifier << "\n");
909 << CacheEntryPath << "' for buffer " << count << " "
910 << ModuleIdentifier << "\n");
873911
874912 if (ErrOrBuffer) {
875913 // Cache Hit!
876 ProducedBinaries[count] = std::move(ErrOrBuffer.get());
914 if (SavedObjectsDirectoryPath.empty())
915 ProducedBinaries[count] = std::move(ErrOrBuffer.get());
916 else
917 ProducedBinaryFiles[count] = writeGeneratedObject(
918 count, CacheEntryPath, SavedObjectsDirectoryPath,
919 *ErrOrBuffer.get());
877920 return;
878921 }
879922 }
902945 ModuleToDefinedGVSummaries[ModuleIdentifier], CacheOptions,
903946 DisableCodeGen, SaveTempsDir, count);
904947
905 OutputBuffer = CacheEntry.write(std::move(OutputBuffer));
906 ProducedBinaries[count] = std::move(OutputBuffer);
948 // Commit to the cache (if enabled)
949 CacheEntry.write(*OutputBuffer);
950
951 if (SavedObjectsDirectoryPath.empty()) {
952 // We need to generated a memory buffer for the linker.
953 if (!CacheEntryPath.empty()) {
954 // Cache is enabled, reload from the cache
955 // We do this to lower memory pressuree: the buffer is on the heap
956 // and releasing it frees memory that can be used for the next input
957 // file. The final binary link will read from the VFS cache
958 // (hopefully!) or from disk if the memory pressure wasn't too high.
959 auto ReloadedBufferOrErr = CacheEntry.tryLoadingBuffer();
960 if (auto EC = ReloadedBufferOrErr.getError()) {
961 // On error, keeping the preexisting buffer and printing a
962 // diagnostic is more friendly than just crashing.
963 errs() << "error: can't reload cached file '" << CacheEntryPath
964 << "': " << EC.message() << "\n";
965 } else {
966 OutputBuffer = std::move(*ReloadedBufferOrErr);
967 }
968 }
969 ProducedBinaries[count] = std::move(OutputBuffer);
970 return;
971 }
972 ProducedBinaryFiles[count] = writeGeneratedObject(
973 count, CacheEntryPath, SavedObjectsDirectoryPath, *OutputBuffer);
907974 }, IndexCount);
908975 }
909976 }
284284 return std::error_code();
285285 }
286286
287 std::error_code create_hard_link(const Twine &to, const Twine &from) {
288 // Get arguments.
289 SmallString<128> from_storage;
290 SmallString<128> to_storage;
291 StringRef f = from.toNullTerminatedStringRef(from_storage);
292 StringRef t = to.toNullTerminatedStringRef(to_storage);
293
294 if (::link(t.begin(), f.begin()) == -1)
295 return std::error_code(errno, std::generic_category());
296
297 return std::error_code();
298 }
299
287300 std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
288301 SmallString<128> path_storage;
289302 StringRef p = path.toNullTerminatedStringRef(path_storage);
231231 return std::error_code();
232232 }
233233
234 std::error_code create_hard_link(const Twine &to, const Twine &from) {
235 return create_link(to, from);
236 }
237
234238 std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
235239 SmallVector path_utf16;
236240
0 ; RUN: opt -module-hash -module-summary %s -o %t.bc
1 ; RUN: opt -module-hash -module-summary %p/Inputs/cache.ll -o %t2.bc
2
3 ; Check that the generating object files is working without cache
4 ; RUN: rm -Rf %t.thin.out
5 ; RUN: llvm-lto -thinlto-save-objects=%t.thin.out -thinlto-action=run %t2.bc %t.bc -exported-symbol=main
6 ; RUN: ls %t.thin.out | count 2
7
8 ; Same with cache
9 ; RUN: rm -Rf %t.thin.out
10 ; RUN: rm -Rf %t.cache && mkdir %t.cache
11 ; RUN: llvm-lto -thinlto-save-objects=%t.thin.out -thinlto-action=run %t2.bc %t.bc -exported-symbol=main -thinlto-cache-dir %t.cache
12 ; RUN: ls %t.thin.out | count 2
13 ; RUN: ls %t.cache | count 3
14
15 ; Same with hot cache
16 ; RUN: rm -Rf %t.thin.out
17 ; RUN: rm -Rf %t.cache && mkdir %t.cache
18 ; RUN: llvm-lto -thinlto-save-objects=%t.thin.out -thinlto-action=run %t2.bc %t.bc -exported-symbol=main -thinlto-cache-dir %t.cache
19 ; RUN: ls %t.thin.out | count 2
20 ; RUN: ls %t.cache | count 3
21
22
23 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
24 target triple = "x86_64-apple-macosx10.11.0"
25
26 define void @globalfunc() #0 {
27 entry:
28 ret void
29 }
129129 cl::desc("Save ThinLTO temp files using filenames created by adding "
130130 "suffixes to the given file path prefix."));
131131
132 static cl::opt ThinLTOGeneratedObjectsDir(
133 "thinlto-save-objects",
134 cl::desc("Save ThinLTO generated object files using filenames created in "
135 "the given directory."));
136
132137 static cl::opt
133138 SaveModuleFile("save-merged-module", cl::init(false),
134139 cl::desc("Write merged LTO module to file before CodeGen"));
706711
707712 if (!ThinLTOSaveTempsPrefix.empty())
708713 ThinGenerator.setSaveTempsDir(ThinLTOSaveTempsPrefix);
714
715 if (!ThinLTOGeneratedObjectsDir.empty()) {
716 ThinGenerator.setGeneratedObjectsDirectory(ThinLTOGeneratedObjectsDir);
717 ThinGenerator.run();
718 return;
719 }
720
709721 ThinGenerator.run();
710722
711723 auto &Binaries = ThinGenerator.getProducedBinaries();
487487 MemBuffer->getBufferSize()};
488488 }
489489
490 unsigned int thinlto_module_get_num_object_files(thinlto_code_gen_t cg) {
491 return unwrap(cg)->getProducedBinaryFiles().size();
492 }
493 const char *thinlto_module_get_object_file(thinlto_code_gen_t cg,
494 unsigned int index) {
495 assert(index < unwrap(cg)->getProducedBinaryFiles().size() &&
496 "Index overflow");
497 return unwrap(cg)->getProducedBinaryFiles()[index].c_str();
498 }
499
490500 void thinlto_codegen_disable_codegen(thinlto_code_gen_t cg,
491501 lto_bool_t disable) {
492502 unwrap(cg)->disableCodeGen(disable);
550560 return unwrap(cg)->setSaveTempsDir(save_temps_dir);
551561 }
552562
563 void thinlto_set_generated_objects_dir(thinlto_code_gen_t cg,
564 const char *save_temps_dir) {
565 unwrap(cg)->setGeneratedObjectsDirectory(save_temps_dir);
566 }
567
553568 lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg,
554569 lto_codegen_model model) {
555570 switch (model) {
6363 thinlto_codegen_add_cross_referenced_symbol
6464 thinlto_codegen_set_final_cache_size_relative_to_available_space
6565 thinlto_codegen_set_codegen_only
66 thinlto_codegen_disable_codegen
66 thinlto_codegen_disable_codegen
67 thinlto_module_get_num_object_files
68 thinlto_module_get_object_file
69 thinlto_set_generated_objects_dir