Skip to content

Commit 2d2dc39

Browse files
Merge pull request swiftlang#78302 from cachemeifyoucan/eng/stevenwu/cache-replay-rewrite
[Caching][NFC] Unify the two cache replay code path
2 parents f57217f + 627c64f commit 2d2dc39

File tree

6 files changed

+222
-278
lines changed

6 files changed

+222
-278
lines changed

include/swift/Frontend/CachingUtils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
namespace swift {
3131

32+
class DiagnosticHelper;
33+
3234
/// Create a swift caching output backend that stores the output from
3335
/// compiler into a CAS.
3436
llvm::IntrusiveRefCntPtr<cas::SwiftCASOutputBackend>
@@ -48,6 +50,19 @@ bool replayCachedCompilerOutputs(llvm::cas::ObjectStore &CAS,
4850
CachingDiagnosticsProcessor &CDP,
4951
bool CacheRemarks, bool UseCASBackend);
5052

53+
/// Replay the output of the compilation from cache for one input file.
54+
/// Return true if outputs are replayed, false otherwise.
55+
bool replayCachedCompilerOutputsForInput(llvm::cas::ObjectStore &CAS,
56+
llvm::cas::ObjectRef OutputRef,
57+
const InputFile &Input,
58+
unsigned InputIndex,
59+
DiagnosticEngine &Diag,
60+
DiagnosticHelper &DiagHelper,
61+
llvm::vfs::OutputBackend &OutBackend,
62+
const FrontendOptions &Opts,
63+
CachingDiagnosticsProcessor &CDP,
64+
bool CacheRemarks, bool UseCASBackend);
65+
5166
/// Load the cached compile result from cache.
5267
std::unique_ptr<llvm::MemoryBuffer> loadCachedCompileResultFromCacheKey(
5368
llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &Cache,

include/swift/Frontend/DiagnosticHelper.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,13 @@ class DiagnosticHelper {
3434
/// OS is the stream to print diagnostics. useQuasiPID determines if using
3535
/// real PID when priting parseable output.
3636
static DiagnosticHelper create(CompilerInstance &instance,
37+
const CompilerInvocation &invocation,
38+
ArrayRef<const char *> args,
3739
llvm::raw_pwrite_stream &OS = llvm::errs(),
3840
bool useQuasiPID = false);
3941

40-
/// Initialized all DiagConsumers and add to the CompilerInstance.
41-
void initDiagConsumers(CompilerInvocation &invocation);
42-
4342
/// Begin emitting the message, specifically the parseable output message.
44-
void beginMessage(CompilerInvocation &invocation,
45-
ArrayRef<const char *> args);
43+
void beginMessage();
4644

4745
/// End emitting all diagnostics. This has to be called if beginMessage() is
4846
/// called.
@@ -61,7 +59,9 @@ class DiagnosticHelper {
6159
~DiagnosticHelper();
6260

6361
private:
64-
DiagnosticHelper(CompilerInstance &instance, llvm::raw_pwrite_stream &OS,
62+
DiagnosticHelper(CompilerInstance &instance,
63+
const CompilerInvocation &invocation,
64+
ArrayRef<const char *> args, llvm::raw_pwrite_stream &OS,
6565
bool useQuasiPID);
6666
};
6767

lib/Frontend/CachingUtils.cpp

Lines changed: 121 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,22 @@
1212

1313
#include "swift/Frontend/CachingUtils.h"
1414

15+
#include "swift/AST/DiagnosticEngine.h"
1516
#include "swift/AST/DiagnosticsFrontend.h"
1617
#include "swift/Basic/Assertions.h"
18+
#include "swift/Basic/Defer.h"
1719
#include "swift/Basic/FileTypes.h"
1820
#include "swift/Basic/LLVM.h"
1921
#include "swift/Frontend/CASOutputBackends.h"
2022
#include "swift/Frontend/CompileJobCacheKey.h"
2123
#include "swift/Frontend/CompileJobCacheResult.h"
24+
#include "swift/Frontend/DiagnosticHelper.h"
2225
#include "swift/Frontend/FrontendOptions.h"
2326
#include "swift/Frontend/MakeStyleDependencies.h"
2427
#include "swift/Option/Options.h"
2528
#include "clang/CAS/CASOptions.h"
2629
#include "clang/CAS/IncludeTree.h"
2730
#include "clang/Frontend/CompileJobCacheResult.h"
28-
#include "llvm/ADT/STLExtras.h"
2931
#include "llvm/CAS/BuiltinUnifiedCASDatabases.h"
3032
#include "llvm/CAS/CASFileSystem.h"
3133
#include "llvm/CAS/HierarchicalTreeBuilder.h"
@@ -40,8 +42,8 @@
4042
#include "llvm/Support/MemoryBuffer.h"
4143
#include "llvm/Support/Path.h"
4244
#include "llvm/Support/VirtualFileSystem.h"
45+
#include "llvm/Support/VirtualOutputBackend.h"
4346
#include "llvm/Support/VirtualOutputBackends.h"
44-
#include "llvm/Support/VirtualOutputFile.h"
4547
#include <memory>
4648

4749
#define DEBUG_TYPE "cache-util"
@@ -133,10 +135,19 @@ lookupCacheKey(ObjectStore &CAS, ActionCache &Cache, ObjectRef CacheKey) {
133135
return CAS.getReference(**Lookup);
134136
}
135137

136-
bool replayCachedCompilerOutputs(
137-
ObjectStore &CAS, ActionCache &Cache, ObjectRef BaseKey,
138-
DiagnosticEngine &Diag, const FrontendOptions &Opts,
139-
CachingDiagnosticsProcessor &CDP, bool CacheRemarks, bool UseCASBackend) {
138+
namespace {
139+
struct CacheInputEntry {
140+
const InputFile &Input;
141+
unsigned Index;
142+
ObjectRef OutputRef;
143+
};
144+
} // namespace
145+
146+
static bool replayCachedCompilerOutputsImpl(
147+
ArrayRef<CacheInputEntry> Inputs, ObjectStore &CAS, DiagnosticEngine &Diag,
148+
const FrontendOptions &Opts, CachingDiagnosticsProcessor &CDP,
149+
DiagnosticHelper *DiagHelper, OutputBackend &Backend, bool CacheRemarks,
150+
bool UseCASBackend) {
140151
bool CanReplayAllOutput = true;
141152
struct OutputEntry {
142153
std::string Path;
@@ -151,34 +162,11 @@ bool replayCachedCompilerOutputs(
151162
auto replayOutputsForInputFile = [&](const InputFile &Input,
152163
const std::string &InputPath,
153164
unsigned InputIndex,
165+
ObjectRef OutputRef,
154166
const DenseMap<file_types::ID,
155167
std::string> &Outputs) {
156-
auto lookupFailed = [&CanReplayAllOutput] { CanReplayAllOutput = false; };
157-
auto OutputKey =
158-
createCompileJobCacheKeyForOutput(CAS, BaseKey, InputIndex);
159-
160-
if (!OutputKey) {
161-
Diag.diagnose(SourceLoc(), diag::error_cas,
162-
toString(OutputKey.takeError()));
163-
return lookupFailed();
164-
}
165-
166-
auto OutID = CAS.getID(*OutputKey);
167-
auto OutputRef = lookupCacheKey(CAS, Cache, *OutputKey);
168-
if (!OutputRef) {
169-
Diag.diagnose(SourceLoc(), diag::error_cas,
170-
toString(OutputRef.takeError()));
171-
return lookupFailed();
172-
}
173-
174-
if (!*OutputRef) {
175-
if (CacheRemarks)
176-
Diag.diagnose(SourceLoc(), diag::output_cache_miss, InputPath,
177-
OutID.toString());
178-
return lookupFailed();
179-
}
180-
181-
CachedResultLoader Loader(CAS, **OutputRef);
168+
CachedResultLoader Loader(CAS, OutputRef);
169+
auto OutID = CAS.getID(OutputRef);
182170
LLVM_DEBUG(llvm::dbgs() << "DEBUG: lookup cache key \'" << OutID.toString()
183171
<< "\' for input \'" << InputPath << "\n";);
184172
if (auto Err = Loader.replay([&](file_types::ID Kind,
@@ -228,12 +216,12 @@ bool replayCachedCompilerOutputs(
228216
})) {
229217
Diag.diagnose(SourceLoc(), diag::cache_replay_failed,
230218
toString(std::move(Err)));
231-
return lookupFailed();
219+
CanReplayAllOutput = false;
232220
}
233221
};
234222

235223
auto replayOutputFromInput = [&](const InputFile &Input,
236-
unsigned InputIndex) {
224+
unsigned InputIndex, ObjectRef OutputRef) {
237225
auto InputPath = Input.getFileName();
238226
DenseMap<file_types::ID, std::string> Outputs;
239227
if (!Input.outputFilename().empty())
@@ -251,8 +239,11 @@ bool replayCachedCompilerOutputs(
251239

252240
// If this input doesn't produce any outputs, don't try to look up cache.
253241
// This can be a standalone emitModule action that only one input produces
254-
// output.
255-
if (Outputs.empty())
242+
// output. The input can be skipped if it is not the first output producing
243+
// input, where it can have diagnostics and symbol graphs attached.
244+
if (Outputs.empty() &&
245+
InputIndex !=
246+
Opts.InputsAndOutputs.getIndexOfFirstOutputProducingInput())
256247
return;
257248

258249
// Add cached diagnostic entry for lookup. Output path doesn't matter here.
@@ -262,53 +253,41 @@ bool replayCachedCompilerOutputs(
262253
// Add symbol graph entry for lookup. Output path doesn't matter here.
263254
Outputs.try_emplace(file_types::ID::TY_SymbolGraphFile, "<symbol-graph>");
264255

265-
return replayOutputsForInputFile(Input, InputPath, InputIndex, Outputs);
256+
return replayOutputsForInputFile(Input, InputPath, InputIndex, OutputRef,
257+
Outputs);
266258
};
267259

268-
auto AllInputs = Opts.InputsAndOutputs.getAllInputs();
269-
// If there are primary inputs, look up only the primary input files.
270-
// Otherwise, prepare to do cache lookup for all inputs.
271-
for (unsigned Index = 0; Index < AllInputs.size(); ++Index) {
272-
const auto &Input = AllInputs[Index];
273-
if (Opts.InputsAndOutputs.hasPrimaryInputs() && !Input.isPrimary())
274-
continue;
275-
276-
replayOutputFromInput(Input, Index);
277-
}
260+
for (auto In : Inputs)
261+
replayOutputFromInput(In.Input, In.Index, In.OutputRef);
278262

279263
if (!CanReplayAllOutput)
280264
return false;
281265

282-
// If there is not diagnostic output, this is a job that produces no output
283-
// and only diagnostics, like `typecheck-module-from-interface`, look up
284-
// diagnostics from first file.
285-
if (!DiagnosticsOutput)
286-
replayOutputsForInputFile(
287-
Opts.InputsAndOutputs.getFirstOutputProducingInput(),
288-
"<cached-diagnostics>",
289-
Opts.InputsAndOutputs.getIndexOfFirstOutputProducingInput(),
290-
{{file_types::ID::TY_CachedDiagnostics, "<cached-diagnostics>"}});
291-
292-
// Check again to make sure diagnostics is fetched successfully.
293-
if (!CanReplayAllOutput)
266+
auto failedReplay = [DiagHelper]() {
267+
if (DiagHelper)
268+
DiagHelper->endMessage(/*retCode=*/1);
294269
return false;
270+
};
295271

296272
// Replay Diagnostics first so the output failures comes after.
297273
// Also if the diagnostics replay failed, proceed to re-compile.
298-
if (auto E = CDP.replayCachedDiagnostics(
299-
DiagnosticsOutput->Proxy.getData())) {
300-
Diag.diagnose(SourceLoc(), diag::error_replay_cached_diag,
301-
toString(std::move(E)));
302-
return false;
274+
if (DiagnosticsOutput) {
275+
// Only starts message if there are diagnostics.
276+
if (DiagHelper)
277+
DiagHelper->beginMessage();
278+
if (auto E =
279+
CDP.replayCachedDiagnostics(DiagnosticsOutput->Proxy.getData())) {
280+
Diag.diagnose(SourceLoc(), diag::error_replay_cached_diag,
281+
toString(std::move(E)));
282+
return failedReplay();
283+
}
303284
}
304285

305286
if (CacheRemarks)
306287
Diag.diagnose(SourceLoc(), diag::replay_output, "<cached-diagnostics>",
307288
DiagnosticsOutput->Key.toString());
308289

309290
// Replay the result only when everything is resolved.
310-
// Use on disk output backend directly here to write to disk.
311-
llvm::vfs::OnDiskOutputBackend Backend;
312291
for (auto &Output : OutputProxies) {
313292
auto File = Backend.createFile(Output.Path);
314293
if (!File) {
@@ -321,14 +300,14 @@ bool replayCachedCompilerOutputs(
321300
auto Schema = std::make_unique<llvm::mccasformats::v1::MCSchema>(CAS);
322301
if (auto E = Schema->serializeObjectFile(Output.Proxy, *File)) {
323302
Diag.diagnose(SourceLoc(), diag::error_mccas, toString(std::move(E)));
324-
return false;
303+
return failedReplay();
325304
}
326305
} else if (Output.Kind == file_types::ID::TY_Dependencies) {
327306
if (emitMakeDependenciesFromSerializedBuffer(
328307
Output.Proxy.getData(), *File, Opts, Output.Input, Diag)) {
329308
Diag.diagnose(SourceLoc(), diag::cache_replay_failed,
330309
"failed to emit dependency file");
331-
return false;
310+
return failedReplay();
332311
}
333312
} else
334313
*File << Output.Proxy.getData();
@@ -343,9 +322,83 @@ bool replayCachedCompilerOutputs(
343322
Output.Key.toString());
344323
}
345324

325+
if (DiagHelper)
326+
DiagHelper->endMessage(/*retCode=*/0);
346327
return true;
347328
}
348329

330+
bool replayCachedCompilerOutputs(
331+
ObjectStore &CAS, ActionCache &Cache, ObjectRef BaseKey,
332+
DiagnosticEngine &Diag, const FrontendOptions &Opts,
333+
CachingDiagnosticsProcessor &CDP, bool CacheRemarks, bool UseCASBackend) {
334+
// Compute all the inputs need replay.
335+
llvm::SmallVector<CacheInputEntry> Inputs;
336+
auto AllInputs = Opts.InputsAndOutputs.getAllInputs();
337+
auto lookupEntry = [&](unsigned InputIndex,
338+
StringRef InputPath) -> std::optional<ObjectRef> {
339+
auto OutputKey =
340+
createCompileJobCacheKeyForOutput(CAS, BaseKey, InputIndex);
341+
342+
if (!OutputKey) {
343+
Diag.diagnose(SourceLoc(), diag::error_cas,
344+
toString(OutputKey.takeError()));
345+
return std::nullopt;
346+
}
347+
348+
auto OutID = CAS.getID(*OutputKey);
349+
auto OutputRef = lookupCacheKey(CAS, Cache, *OutputKey);
350+
if (!OutputRef) {
351+
Diag.diagnose(SourceLoc(), diag::error_cas,
352+
toString(OutputRef.takeError()));
353+
return std::nullopt;
354+
}
355+
356+
if (!*OutputRef) {
357+
if (CacheRemarks)
358+
Diag.diagnose(SourceLoc(), diag::output_cache_miss, InputPath,
359+
OutID.toString());
360+
return std::nullopt;
361+
}
362+
363+
return *OutputRef;
364+
};
365+
366+
// If there are primary inputs, look up only the primary input files.
367+
// Otherwise, prepare to do cache lookup for all inputs.
368+
for (unsigned Index = 0; Index < AllInputs.size(); ++Index) {
369+
const auto &Input = AllInputs[Index];
370+
if (Opts.InputsAndOutputs.hasPrimaryInputs() && !Input.isPrimary())
371+
continue;
372+
373+
if (Input.outputFilename().empty() &&
374+
Input.getPrimarySpecificPaths().SupplementaryOutputs.empty() &&
375+
Index != Opts.InputsAndOutputs.getIndexOfFirstOutputProducingInput())
376+
continue;
377+
378+
if (auto OutputRef = lookupEntry(Index, Input.getFileName()))
379+
Inputs.push_back({Input, Index, *OutputRef});
380+
else
381+
return false;
382+
}
383+
384+
// Use on disk output backend directly here to write to disk.
385+
llvm::vfs::OnDiskOutputBackend Backend;
386+
return replayCachedCompilerOutputsImpl(Inputs, CAS, Diag, Opts, CDP,
387+
/*DiagHelper=*/nullptr, Backend,
388+
CacheRemarks, UseCASBackend);
389+
}
390+
391+
bool replayCachedCompilerOutputsForInput(
392+
ObjectStore &CAS, ObjectRef OutputRef, const InputFile &Input,
393+
unsigned InputIndex, DiagnosticEngine &Diag, DiagnosticHelper &DiagHelper,
394+
OutputBackend &OutBackend, const FrontendOptions &Opts,
395+
CachingDiagnosticsProcessor &CDP, bool CacheRemarks, bool UseCASBackend) {
396+
llvm::SmallVector<CacheInputEntry> Inputs = {{Input, InputIndex, OutputRef}};
397+
return replayCachedCompilerOutputsImpl(Inputs, CAS, Diag, Opts, CDP,
398+
&DiagHelper, OutBackend, CacheRemarks,
399+
UseCASBackend);
400+
}
401+
349402
std::unique_ptr<llvm::MemoryBuffer>
350403
loadCachedCompileResultFromCacheKey(ObjectStore &CAS, ActionCache &Cache,
351404
DiagnosticEngine &Diag, StringRef CacheKey,

0 commit comments

Comments
 (0)