Skip to content

Commit ca41d2b

Browse files
Virtualize swift-frontend outputs
Using a virutal output backend to capture all the outputs from swift-frontend invocation. This allows future virtualization of swift compiler outputs.
1 parent d75b65c commit ca41d2b

37 files changed

+425
-213
lines changed

include/swift/AST/ASTContext.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "llvm/ADT/TinyPtrVector.h"
4545
#include "llvm/Support/Allocator.h"
4646
#include "llvm/Support/DataTypes.h"
47+
#include "llvm/Support/VirtualOutputBackend.h"
4748
#include <functional>
4849
#include <memory>
4950
#include <utility>
@@ -227,6 +228,7 @@ class ASTContext final {
227228
ClangImporterOptions &ClangImporterOpts,
228229
symbolgraphgen::SymbolGraphOptions &SymbolGraphOpts,
229230
SourceManager &SourceMgr, DiagnosticEngine &Diags,
231+
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> OutBackend = nullptr,
230232
std::function<bool(llvm::StringRef, bool)> PreModuleImportCallback = {});
231233

232234
public:
@@ -244,6 +246,7 @@ class ASTContext final {
244246
ClangImporterOptions &ClangImporterOpts,
245247
symbolgraphgen::SymbolGraphOptions &SymbolGraphOpts,
246248
SourceManager &SourceMgr, DiagnosticEngine &Diags,
249+
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> OutBackend = nullptr,
247250
std::function<bool(llvm::StringRef, bool)> PreModuleImportCallback = {});
248251
~ASTContext();
249252

@@ -277,6 +280,9 @@ class ASTContext final {
277280
/// Diags - The diagnostics engine.
278281
DiagnosticEngine &Diags;
279282

283+
/// OutputBackend for writing outputs.
284+
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> Backend;
285+
280286
/// If the shared pointer is not a \c nullptr and the pointee is \c true,
281287
/// all operations working on this ASTContext should be aborted at the next
282288
/// possible opportunity.
@@ -1450,6 +1456,18 @@ class ASTContext final {
14501456
/// search within the library.
14511457
void *getAddressOfSymbol(const char *name, void *libraryHandleHint = nullptr);
14521458

1459+
/// Get the output backend. The output backend needs to be initialized via
1460+
/// constructor or `setOutputBackend`.
1461+
llvm::vfs::OutputBackend &getOutputBackend() const {
1462+
assert(Backend && "OutputBackend is not setup");
1463+
return *Backend;
1464+
}
1465+
/// Set output backend for virtualized outputs.
1466+
void setOutputBackend(
1467+
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> OutputBackend) {
1468+
Backend = std::move(OutputBackend);
1469+
}
1470+
14531471
private:
14541472
friend Decl;
14551473

include/swift/AST/AbstractSourceFileDepGraphFactory.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/AST/Decl.h"
1717
#include "swift/AST/DeclContext.h"
1818
#include "swift/AST/FineGrainedDependencies.h"
19+
#include "llvm/Support/VirtualOutputBackend.h"
1920

2021
namespace swift {
2122
class DiagnosticEngine;
@@ -39,6 +40,9 @@ class AbstractSourceFileDepGraphFactory {
3940

4041
DiagnosticEngine &diags;
4142

43+
/// OutputBackend.
44+
llvm::vfs::OutputBackend &backend;
45+
4246
/// Graph under construction
4347
SourceFileDepGraph g;
4448

@@ -49,7 +53,8 @@ class AbstractSourceFileDepGraphFactory {
4953
StringRef swiftDeps,
5054
Fingerprint fileFingerprint,
5155
bool emitDotFileAfterConstruction,
52-
DiagnosticEngine &diags);
56+
DiagnosticEngine &diags,
57+
llvm::vfs::OutputBackend &outputBackend);
5358

5459
virtual ~AbstractSourceFileDepGraphFactory() = default;
5560

include/swift/AST/FileSystem.h

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,38 @@
1616
#include "swift/Basic/FileSystem.h"
1717
#include "swift/AST/DiagnosticEngine.h"
1818
#include "swift/AST/DiagnosticsCommon.h"
19+
#include "llvm/Support/VirtualOutputBackend.h"
20+
#include "llvm/Support/VirtualOutputConfig.h"
1921

2022
namespace swift {
21-
22-
/// A wrapper around swift::atomicallyWritingToFile that handles diagnosing any
23-
/// filesystem errors and asserts the output path is nonempty.
23+
/// A wrapper around llvm::vfs::OutputBackend to handle diagnosing any file
24+
/// system errors during output creation.
2425
///
2526
/// \returns true if there were any errors, either from the filesystem
2627
/// operations or from \p action returning true.
2728
inline bool
28-
withOutputFile(DiagnosticEngine &diags, StringRef outputPath,
29-
llvm::function_ref<bool(llvm::raw_pwrite_stream &)> action) {
29+
withOutputBackend(DiagnosticEngine &diags, llvm::vfs::OutputBackend &Backend,
30+
StringRef outputPath,
31+
llvm::function_ref<bool(llvm::raw_pwrite_stream &)> action) {
3032
assert(!outputPath.empty());
33+
llvm::vfs::OutputConfig config;
34+
config.setOverwriteOnlyDifferent();
35+
36+
auto outputFile = Backend.createFile(outputPath, config);
37+
if (!outputFile) {
38+
diags.diagnose(SourceLoc(), diag::error_opening_output, outputPath,
39+
toString(outputFile.takeError()));
40+
return false;
41+
}
3142

32-
bool actionFailed = false;
33-
std::error_code EC = swift::atomicallyWritingToFile(
34-
outputPath,
35-
[&](llvm::raw_pwrite_stream &out) { actionFailed = action(out); });
36-
if (EC) {
43+
bool result = action(*outputFile);
44+
// If there is an error, discard output. Otherwise keep the output file.
45+
if (auto error = result ? outputFile->discard() : outputFile->keep()) {
3746
diags.diagnose(SourceLoc(), diag::error_opening_output, outputPath,
38-
EC.message());
39-
return true;
47+
toString(std::move(error)));
48+
return false;
4049
}
41-
return actionFailed;
50+
return result;
4251
}
4352
} // end namespace swift
4453

include/swift/AST/FineGrainedDependencies.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/ADT/SetVector.h"
2525
#include "llvm/Support/MD5.h"
2626
#include "llvm/Support/MemoryBuffer.h"
27+
#include "llvm/Support/VirtualOutputBackend.h"
2728
#include "llvm/Support/YAMLParser.h"
2829
#include "llvm/Support/YAMLTraits.h"
2930
#include "llvm/Support/raw_ostream.h"
@@ -357,8 +358,9 @@ class BiIndexedTwoStageMap {
357358
/// \Note The returned graph should not be escaped from the callback.
358359
bool withReferenceDependencies(
359360
llvm::PointerUnion<const ModuleDecl *, const SourceFile *> MSF,
360-
const DependencyTracker &depTracker, StringRef outputPath,
361-
bool alsoEmitDotFile, llvm::function_ref<bool(SourceFileDepGraph &&)>);
361+
const DependencyTracker &depTracker, llvm::vfs::OutputBackend &backend,
362+
StringRef outputPath, bool alsoEmitDotFile,
363+
llvm::function_ref<bool(SourceFileDepGraph &&)>);
362364

363365
//==============================================================================
364366
// MARK: Enums
@@ -895,7 +897,8 @@ class SourceFileDepGraph {
895897

896898
bool verifySequenceNumber() const;
897899

898-
void emitDotFile(StringRef outputPath, DiagnosticEngine &diags);
900+
void emitDotFile(llvm::vfs::OutputBackend &outputBackend,
901+
StringRef outputPath, DiagnosticEngine &diags);
899902

900903
void addNode(SourceFileDepGraphNode *n) {
901904
n->setSequenceNumber(allNodes.size());

include/swift/AST/FineGrainedDependencyFormat.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
namespace llvm {
2020
class MemoryBuffer;
21+
namespace vfs {
22+
class OutputBackend;
23+
}
2124
}
2225

2326
namespace swift {
@@ -132,6 +135,7 @@ bool readFineGrainedDependencyGraph(llvm::StringRef path,
132135
/// Tries to write the dependency graph to the given path name.
133136
/// Returns true if there was an error.
134137
bool writeFineGrainedDependencyGraphToPath(DiagnosticEngine &diags,
138+
llvm::vfs::OutputBackend &backend,
135139
llvm::StringRef path,
136140
const SourceFileDepGraph &g);
137141

include/swift/AST/ModuleLoader.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232

3333
namespace llvm {
3434
class FileCollectorBase;
35+
namespace vfs {
36+
class OutputBackend;
37+
}
3538
}
3639

3740
namespace clang {
@@ -156,6 +159,7 @@ class ModuleInterfaceChecker {
156159
virtual bool tryEmitForwardingModule(StringRef moduleName,
157160
StringRef interfacePath,
158161
ArrayRef<std::string> candidates,
162+
llvm::vfs::OutputBackend &backend,
159163
StringRef outPath) = 0;
160164
virtual ~ModuleInterfaceChecker() = default;
161165
};

include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
namespace llvm {
2020
class MemoryBuffer;
21+
namespace vfs{
22+
class OutputBackend;
23+
}
2124
}
2225

2326
namespace swift {
@@ -187,6 +190,7 @@ bool readInterModuleDependenciesCache(llvm::StringRef path,
187190
/// Tries to write the dependency graph to the given path name.
188191
/// Returns true if there was an error.
189192
bool writeInterModuleDependenciesCache(DiagnosticEngine &diags,
193+
llvm::vfs::OutputBackend &backend,
190194
llvm::StringRef path,
191195
const SwiftDependencyScanningService &cache);
192196

include/swift/Driver/FineGrainedDependencyDriverGraph.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
#include "swift/Basic/OptionSet.h"
2121
#include "swift/Driver/Job.h"
2222
#include "llvm/ADT/ArrayRef.h"
23+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
2324
#include "llvm/ADT/STLExtras.h"
2425
#include "llvm/ADT/StringRef.h"
2526
#include "llvm/ADT/iterator_range.h"
2627
#include "llvm/Support/Path.h"
2728
#include "llvm/Support/PointerLikeTypeTraits.h"
29+
#include "llvm/Support/VirtualOutputBackend.h"
30+
#include "llvm/Support/VirtualOutputBackends.h"
2831
#include <string>
2932
#include <unordered_map>
3033
#include <unordered_set>
@@ -201,6 +204,9 @@ class ModuleDepGraph {
201204
std::vector<const ModuleDepGraphNode *>>
202205
dependencyPathsToJobs;
203206

207+
/// VirtualOutputBackend for emitting graphs.
208+
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> backend;
209+
204210
/// For helping with performance tuning, may be null:
205211
UnifiedStatsReporter *stats;
206212

@@ -306,6 +312,10 @@ class ModuleDepGraph {
306312
: None),
307313
stats(stats) {
308314
assert(verify() && "ModuleDepGraph should be fine when created");
315+
316+
// Create a OnDiskOutputBackend for emitting graphs. Currently, this is
317+
// only used by driver so the backend is not shared with a CompilerInstance.
318+
backend = llvm::makeIntrusiveRefCnt<llvm::vfs::OnDiskOutputBackend>();
309319
}
310320

311321
/// For unit tests.

include/swift/Frontend/Frontend.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "llvm/Option/ArgList.h"
4848
#include "llvm/Support/Host.h"
4949
#include "llvm/Support/MemoryBuffer.h"
50+
#include "llvm/Support/VirtualOutputBackend.h"
5051

5152
#include <memory>
5253

@@ -449,6 +450,9 @@ class CompilerInstance {
449450
/// instance has completed its setup, this will be null.
450451
std::unique_ptr<UnifiedStatsReporter> Stats;
451452

453+
/// Virtual OutputBackend.
454+
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> TheOutputBackend = nullptr;
455+
452456
mutable ModuleDecl *MainModule = nullptr;
453457
SerializedModuleLoaderBase *DefaultSerializedLoader = nullptr;
454458
MemoryBufferSerializedModuleLoader *MemoryBufferLoader = nullptr;
@@ -499,6 +503,12 @@ class CompilerInstance {
499503
SourceMgr.setFileSystem(FS);
500504
}
501505

506+
llvm::vfs::OutputBackend &getOutputBackend() { return *TheOutputBackend; }
507+
void
508+
setOutputBackend(llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> Backend) {
509+
TheOutputBackend = std::move(Backend);
510+
}
511+
502512
ASTContext &getASTContext() { return *Context; }
503513
const ASTContext &getASTContext() const { return *Context; }
504514

@@ -609,6 +619,7 @@ class CompilerInstance {
609619
bool setUpASTContextIfNeeded();
610620
void setupStatsReporter();
611621
void setupDependencyTrackerIfNeeded();
622+
void setupOutputBackend();
612623

613624
/// \return false if successful, true on error.
614625
bool setupDiagnosticVerifierIfNeeded();

include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,9 @@ class FrontendOptions {
424424
/// \return true if the given action requires input files to be provided.
425425
static bool doesActionRequireInputs(ActionType action);
426426

427+
/// \return true if the given action writes any output files.
428+
static bool doesActionRequireOutputBackend(ActionType action);
429+
427430
/// \return true if the given action requires input files to be provided.
428431
static bool doesActionPerformEndOfPipelineActions(ActionType action);
429432

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ class ModuleInterfaceCheckerImpl: public ModuleInterfaceChecker {
380380
bool tryEmitForwardingModule(StringRef moduleName,
381381
StringRef interfacePath,
382382
ArrayRef<std::string> candidates,
383+
llvm::vfs::OutputBackend &backend,
383384
StringRef outPath) override;
384385
bool isCached(StringRef DepPath);
385386
};

include/swift/Subsystems.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ namespace llvm {
3535
class Module;
3636
class TargetOptions;
3737
class TargetMachine;
38+
namespace vfs {
39+
class OutputBackend;
40+
}
3841
}
3942

4043
namespace swift {
@@ -275,13 +278,15 @@ namespace swift {
275278
/// \param Module LLVM module to code gen, required.
276279
/// \param TargetMachine target of code gen, required.
277280
/// \param OutputFilename Filename for output.
281+
/// \param Backend OutputBackend for writing output.
278282
bool performLLVM(const IRGenOptions &Opts,
279283
DiagnosticEngine &Diags,
280284
llvm::sys::Mutex *DiagMutex,
281285
llvm::GlobalVariable *HashGlobal,
282286
llvm::Module *Module,
283287
llvm::TargetMachine *TargetMachine,
284288
StringRef OutputFilename,
289+
llvm::vfs::OutputBackend &Backend,
285290
UnifiedStatsReporter *Stats);
286291

287292
/// Dump YAML describing all fixed-size types imported from the given module.

lib/AST/ASTContext.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
#include "llvm/Support/Allocator.h"
6969
#include "llvm/Support/Compiler.h"
7070
#include "llvm/Support/FormatVariadic.h"
71+
#include "llvm/Support/VirtualOutputBackend.h"
72+
#include "llvm/Support/VirtualOutputBackends.h"
7173
#include <algorithm>
7274
#include <queue>
7375
#include <memory>
@@ -621,6 +623,7 @@ ASTContext *ASTContext::get(
621623
ClangImporterOptions &ClangImporterOpts,
622624
symbolgraphgen::SymbolGraphOptions &SymbolGraphOpts,
623625
SourceManager &SourceMgr, DiagnosticEngine &Diags,
626+
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> OutputBackend,
624627
std::function<bool(llvm::StringRef, bool)> PreModuleImportCallback) {
625628
// If more than two data structures are concatentated, then the aggregate
626629
// size math needs to become more complicated due to per-struct alignment
@@ -632,9 +635,10 @@ ASTContext *ASTContext::get(
632635
impl = reinterpret_cast<void *>(
633636
llvm::alignAddr(impl, llvm::Align(alignof(Implementation))));
634637
new (impl) Implementation();
635-
return new (mem) ASTContext(langOpts, typecheckOpts, silOpts, SearchPathOpts,
636-
ClangImporterOpts, SymbolGraphOpts, SourceMgr,
637-
Diags, PreModuleImportCallback);
638+
return new (mem)
639+
ASTContext(langOpts, typecheckOpts, silOpts, SearchPathOpts,
640+
ClangImporterOpts, SymbolGraphOpts, SourceMgr, Diags,
641+
std::move(OutputBackend), PreModuleImportCallback);
638642
}
639643

640644
ASTContext::ASTContext(
@@ -643,17 +647,19 @@ ASTContext::ASTContext(
643647
ClangImporterOptions &ClangImporterOpts,
644648
symbolgraphgen::SymbolGraphOptions &SymbolGraphOpts,
645649
SourceManager &SourceMgr, DiagnosticEngine &Diags,
650+
llvm::IntrusiveRefCntPtr<llvm::vfs::OutputBackend> OutputBackend,
646651
std::function<bool(llvm::StringRef, bool)> PreModuleImportCallback)
647652
: LangOpts(langOpts), TypeCheckerOpts(typecheckOpts), SILOpts(silOpts),
648653
SearchPathOpts(SearchPathOpts), ClangImporterOpts(ClangImporterOpts),
649654
SymbolGraphOpts(SymbolGraphOpts), SourceMgr(SourceMgr), Diags(Diags),
650-
evaluator(Diags, langOpts), TheBuiltinModule(createBuiltinModule(*this)),
655+
Backend(std::move(OutputBackend)), evaluator(Diags, langOpts),
656+
TheBuiltinModule(createBuiltinModule(*this)),
651657
StdlibModuleName(getIdentifier(STDLIB_NAME)),
652658
SwiftShimsModuleName(getIdentifier(SWIFT_SHIMS_NAME)),
653659
PreModuleImportCallback(PreModuleImportCallback),
654660
TheErrorType(new (*this, AllocationArena::Permanent) ErrorType(
655661
*this, Type(), RecursiveTypeProperties::HasError)),
656-
TheUnresolvedType(new (*this, AllocationArena::Permanent)
662+
TheUnresolvedType(new(*this, AllocationArena::Permanent)
657663
UnresolvedType(*this)),
658664
TheEmptyTupleType(TupleType::get(ArrayRef<TupleTypeElt>(), *this)),
659665
TheEmptyPackType(PackType::get(*this, {})),
@@ -692,6 +698,10 @@ ASTContext::ASTContext(
692698
registerAccessRequestFunctions(evaluator);
693699
registerNameLookupRequestFunctions(evaluator);
694700

701+
// Provide a default OnDiskOutputBackend if user didn't supply one.
702+
if (!Backend)
703+
Backend = llvm::makeIntrusiveRefCnt<llvm::vfs::OnDiskOutputBackend>();
704+
695705
loadCompilerPlugins();
696706
}
697707

0 commit comments

Comments
 (0)