71
71
72
72
#include " clang/Lex/Preprocessor.h"
73
73
74
+ #include " llvm/ADT/IntrusiveRefCntPtr.h"
75
+ #include " llvm/ADT/STLExtras.h"
74
76
#include " llvm/ADT/Statistic.h"
77
+ #include " llvm/ADT/StringExtras.h"
75
78
#include " llvm/ADT/StringMap.h"
76
79
#include " llvm/IR/LLVMContext.h"
77
80
#include " llvm/IR/Module.h"
78
81
#include " llvm/IRReader/IRReader.h"
79
82
#include " llvm/Option/Option.h"
80
83
#include " llvm/Option/OptTable.h"
84
+ #include " llvm/Support/BLAKE3.h"
81
85
#include " llvm/Support/Error.h"
82
86
#include " llvm/Support/ErrorHandling.h"
87
+ #include " llvm/Support/HashingOutputBackend.h"
83
88
#include " llvm/Support/Path.h"
84
89
#include " llvm/Support/VirtualOutputBackend.h"
90
+ #include " llvm/Support/VirtualOutputBackends.h"
85
91
#include " llvm/Support/raw_ostream.h"
86
92
#include " llvm/Support/FileSystem.h"
87
93
@@ -2345,6 +2351,38 @@ int swift::performFrontend(ArrayRef<const char *> Args,
2345
2351
PDC.setSuppressOutput (true );
2346
2352
}
2347
2353
2354
+ using HashBackendTy = llvm::vfs::HashingOutputBackend<llvm::BLAKE3>;
2355
+ llvm::IntrusiveRefCntPtr<HashBackendTy> HashBackend, ReHashBackend;
2356
+ int ReturnValueTest = 0 ;
2357
+ if (Invocation.getFrontendOptions ().DeterministicCheck ) {
2358
+ std::unique_ptr<CompilerInstance> VerifyInstance =
2359
+ std::make_unique<CompilerInstance>();
2360
+ std::string InstanceSetupError;
2361
+ // This should not fail because it passed already.
2362
+ (void )VerifyInstance->setup (Invocation, InstanceSetupError);
2363
+
2364
+ // Create a mirroring outputbackend to produce hash for output files.
2365
+ // We cannot skip disk here since swift compiler is expecting to read back
2366
+ // some output file in later stages.
2367
+ // TODO: Implement diagnostics determinism check. We didn't setup any diag
2368
+ // consumer currently.
2369
+ HashBackend = llvm::makeIntrusiveRefCnt<HashBackendTy>();
2370
+ auto VerifyBackend = llvm::vfs::makeMirroringOutputBackend (
2371
+ llvm::makeIntrusiveRefCnt<llvm::vfs::OnDiskOutputBackend>(),
2372
+ HashBackend);
2373
+ VerifyInstance->setOutputBackend (VerifyBackend);
2374
+ // Run the first time without observer and discard return value;
2375
+ (void )performCompile (*VerifyInstance, ReturnValueTest,
2376
+ /* observer*/ nullptr );
2377
+
2378
+ // Mirror the output to disk on second run.
2379
+ ReHashBackend = llvm::makeIntrusiveRefCnt<HashBackendTy>();
2380
+ auto FinalBackend = llvm::vfs::makeMirroringOutputBackend (
2381
+ llvm::makeIntrusiveRefCnt<llvm::vfs::OnDiskOutputBackend>(),
2382
+ ReHashBackend);
2383
+ Instance->setOutputBackend (FinalBackend);
2384
+ }
2385
+
2348
2386
int ReturnValue = 0 ;
2349
2387
bool HadError = performCompile (*Instance, ReturnValue, observer);
2350
2388
@@ -2359,6 +2397,43 @@ int swift::performFrontend(ArrayRef<const char *> Args,
2359
2397
}
2360
2398
}
2361
2399
2400
+ if (Invocation.getFrontendOptions ().DeterministicCheck ) {
2401
+ // Collect all output files.
2402
+ std::set<std::string> AllOutputs;
2403
+ llvm::for_each (HashBackend->outputFiles (), [&](StringRef F) {
2404
+ AllOutputs.insert (F.str ());
2405
+ });
2406
+ llvm::for_each (ReHashBackend->outputFiles (), [&](StringRef F) {
2407
+ AllOutputs.insert (F.str ());
2408
+ });
2409
+
2410
+ DiagnosticEngine &diags = Instance->getDiags ();
2411
+ for (auto &Filename : AllOutputs) {
2412
+ auto O1 = HashBackend->getHashValueForFile (Filename);
2413
+ if (!O1) {
2414
+ diags.diagnose (SourceLoc (), diag::error_output_missing, Filename,
2415
+ /* SecondRun=*/ false );
2416
+ HadError = true ;
2417
+ continue ;
2418
+ }
2419
+ auto O2 = ReHashBackend->getHashValueForFile (Filename);
2420
+ if (!O2) {
2421
+ diags.diagnose (SourceLoc (), diag::error_output_missing, Filename,
2422
+ /* SecondRun=*/ true );
2423
+ HadError = true ;
2424
+ continue ;
2425
+ }
2426
+ if (*O1 != *O2) {
2427
+ diags.diagnose (SourceLoc (), diag::error_nondeterministic_output,
2428
+ Filename, *O1, *O2);
2429
+ HadError = true ;
2430
+ continue ;
2431
+ }
2432
+ diags.diagnose (SourceLoc (), diag::matching_output_produced, Filename,
2433
+ *O1);
2434
+ }
2435
+ }
2436
+
2362
2437
auto r = finishDiagProcessing (HadError ? 1 : ReturnValue, verifierEnabled);
2363
2438
if (auto *StatsReporter = Instance->getStatsReporter ())
2364
2439
StatsReporter->noteCurrentProcessExitStatus (r);
0 commit comments