12
12
13
13
#include " swift/Frontend/CachingUtils.h"
14
14
15
+ #include " swift/AST/DiagnosticEngine.h"
15
16
#include " swift/AST/DiagnosticsFrontend.h"
16
17
#include " swift/Basic/Assertions.h"
18
+ #include " swift/Basic/Defer.h"
17
19
#include " swift/Basic/FileTypes.h"
18
20
#include " swift/Basic/LLVM.h"
19
21
#include " swift/Frontend/CASOutputBackends.h"
20
22
#include " swift/Frontend/CompileJobCacheKey.h"
21
23
#include " swift/Frontend/CompileJobCacheResult.h"
24
+ #include " swift/Frontend/DiagnosticHelper.h"
22
25
#include " swift/Frontend/FrontendOptions.h"
23
26
#include " swift/Frontend/MakeStyleDependencies.h"
24
27
#include " swift/Option/Options.h"
25
28
#include " clang/CAS/CASOptions.h"
26
29
#include " clang/CAS/IncludeTree.h"
27
30
#include " clang/Frontend/CompileJobCacheResult.h"
28
- #include " llvm/ADT/STLExtras.h"
29
31
#include " llvm/CAS/BuiltinUnifiedCASDatabases.h"
30
32
#include " llvm/CAS/CASFileSystem.h"
31
33
#include " llvm/CAS/HierarchicalTreeBuilder.h"
40
42
#include " llvm/Support/MemoryBuffer.h"
41
43
#include " llvm/Support/Path.h"
42
44
#include " llvm/Support/VirtualFileSystem.h"
45
+ #include " llvm/Support/VirtualOutputBackend.h"
43
46
#include " llvm/Support/VirtualOutputBackends.h"
44
- #include " llvm/Support/VirtualOutputFile.h"
45
47
#include < memory>
46
48
47
49
#define DEBUG_TYPE " cache-util"
@@ -133,10 +135,19 @@ lookupCacheKey(ObjectStore &CAS, ActionCache &Cache, ObjectRef CacheKey) {
133
135
return CAS.getReference (**Lookup);
134
136
}
135
137
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) {
140
151
bool CanReplayAllOutput = true ;
141
152
struct OutputEntry {
142
153
std::string Path;
@@ -151,34 +162,11 @@ bool replayCachedCompilerOutputs(
151
162
auto replayOutputsForInputFile = [&](const InputFile &Input,
152
163
const std::string &InputPath,
153
164
unsigned InputIndex,
165
+ ObjectRef OutputRef,
154
166
const DenseMap<file_types::ID,
155
167
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);
182
170
LLVM_DEBUG (llvm::dbgs () << " DEBUG: lookup cache key \' " << OutID.toString ()
183
171
<< " \' for input \' " << InputPath << " \n " ;);
184
172
if (auto Err = Loader.replay ([&](file_types::ID Kind,
@@ -228,12 +216,12 @@ bool replayCachedCompilerOutputs(
228
216
})) {
229
217
Diag.diagnose (SourceLoc (), diag::cache_replay_failed,
230
218
toString (std::move (Err)));
231
- return lookupFailed () ;
219
+ CanReplayAllOutput = false ;
232
220
}
233
221
};
234
222
235
223
auto replayOutputFromInput = [&](const InputFile &Input,
236
- unsigned InputIndex) {
224
+ unsigned InputIndex, ObjectRef OutputRef ) {
237
225
auto InputPath = Input.getFileName ();
238
226
DenseMap<file_types::ID, std::string> Outputs;
239
227
if (!Input.outputFilename ().empty ())
@@ -251,8 +239,11 @@ bool replayCachedCompilerOutputs(
251
239
252
240
// If this input doesn't produce any outputs, don't try to look up cache.
253
241
// 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 ())
256
247
return ;
257
248
258
249
// Add cached diagnostic entry for lookup. Output path doesn't matter here.
@@ -262,53 +253,41 @@ bool replayCachedCompilerOutputs(
262
253
// Add symbol graph entry for lookup. Output path doesn't matter here.
263
254
Outputs.try_emplace (file_types::ID::TY_SymbolGraphFile, " <symbol-graph>" );
264
255
265
- return replayOutputsForInputFile (Input, InputPath, InputIndex, Outputs);
256
+ return replayOutputsForInputFile (Input, InputPath, InputIndex, OutputRef,
257
+ Outputs);
266
258
};
267
259
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 );
278
262
279
263
if (!CanReplayAllOutput)
280
264
return false ;
281
265
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 );
294
269
return false ;
270
+ };
295
271
296
272
// Replay Diagnostics first so the output failures comes after.
297
273
// 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
+ }
303
284
}
304
285
305
286
if (CacheRemarks)
306
287
Diag.diagnose (SourceLoc (), diag::replay_output, " <cached-diagnostics>" ,
307
288
DiagnosticsOutput->Key .toString ());
308
289
309
290
// 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;
312
291
for (auto &Output : OutputProxies) {
313
292
auto File = Backend.createFile (Output.Path );
314
293
if (!File) {
@@ -321,14 +300,14 @@ bool replayCachedCompilerOutputs(
321
300
auto Schema = std::make_unique<llvm::mccasformats::v1::MCSchema>(CAS);
322
301
if (auto E = Schema->serializeObjectFile (Output.Proxy , *File)) {
323
302
Diag.diagnose (SourceLoc (), diag::error_mccas, toString (std::move (E)));
324
- return false ;
303
+ return failedReplay () ;
325
304
}
326
305
} else if (Output.Kind == file_types::ID::TY_Dependencies) {
327
306
if (emitMakeDependenciesFromSerializedBuffer (
328
307
Output.Proxy .getData (), *File, Opts, Output.Input , Diag)) {
329
308
Diag.diagnose (SourceLoc (), diag::cache_replay_failed,
330
309
" failed to emit dependency file" );
331
- return false ;
310
+ return failedReplay () ;
332
311
}
333
312
} else
334
313
*File << Output.Proxy .getData ();
@@ -343,9 +322,83 @@ bool replayCachedCompilerOutputs(
343
322
Output.Key .toString ());
344
323
}
345
324
325
+ if (DiagHelper)
326
+ DiagHelper->endMessage (/* retCode=*/ 0 );
346
327
return true ;
347
328
}
348
329
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
+
349
402
std::unique_ptr<llvm::MemoryBuffer>
350
403
loadCachedCompileResultFromCacheKey (ObjectStore &CAS, ActionCache &Cache,
351
404
DiagnosticEngine &Diag, StringRef CacheKey,
0 commit comments