@@ -133,6 +133,134 @@ createSwiftCachingOutputBackend(
133133 InputsAndOutputs);
134134}
135135
136+ bool replayCachedCompilerOutputs (
137+ ObjectStore &CAS, ActionCache &Cache, ObjectRef BaseKey,
138+ DiagnosticEngine &Diag, const FrontendInputsAndOutputs &InputsAndOutputs,
139+ CachingDiagnosticsProcessor &CDP) {
140+ clang::cas::CompileJobResultSchema Schema (CAS);
141+ bool CanReplayAllOutput = true ;
142+ struct OutputEntry {
143+ std::string Path;
144+ std::string Key;
145+ llvm::cas::ObjectProxy Proxy;
146+ };
147+ SmallVector<OutputEntry> OutputProxies;
148+
149+ auto replayOutputFile = [&](StringRef InputName, file_types::ID OutputKind,
150+ StringRef OutputPath) -> Optional<OutputEntry> {
151+ LLVM_DEBUG (llvm::dbgs ()
152+ << " DEBUG: lookup output \' " << OutputPath << " \' type \' "
153+ << file_types::getTypeName (OutputKind) << " \' input \' "
154+ << InputName << " \n " ;);
155+
156+ auto OutputKey =
157+ createCompileJobCacheKeyForOutput (CAS, BaseKey, InputName, OutputKind);
158+ if (!OutputKey) {
159+ Diag.diagnose (SourceLoc (), diag::error_cas,
160+ toString (OutputKey.takeError ()));
161+ return None;
162+ }
163+ auto OutputKeyID = CAS.getID (*OutputKey);
164+ auto Lookup = Cache.get (OutputKeyID);
165+ if (!Lookup) {
166+ Diag.diagnose (SourceLoc (), diag::error_cas, toString (Lookup.takeError ()));
167+ return None;
168+ }
169+ if (!*Lookup) {
170+ Diag.diagnose (SourceLoc (), diag::output_cache_miss, OutputPath,
171+ OutputKeyID.toString ());
172+ return None;
173+ }
174+ auto OutputRef = CAS.getReference (**Lookup);
175+ if (!OutputRef) {
176+ return None;
177+ }
178+ auto Result = Schema.load (*OutputRef);
179+ if (!Result) {
180+ Diag.diagnose (SourceLoc (), diag::error_cas, toString (Result.takeError ()));
181+ return None;
182+ }
183+ auto MainOutput = Result->getOutput (
184+ clang::cas::CompileJobCacheResult::OutputKind::MainOutput);
185+ if (!MainOutput) {
186+ return None;
187+ }
188+ auto LoadedResult = CAS.getProxy (MainOutput->Object );
189+ if (!LoadedResult) {
190+ Diag.diagnose (SourceLoc (), diag::error_cas,
191+ toString (LoadedResult.takeError ()));
192+ return None;
193+ }
194+
195+ return OutputEntry{OutputPath.str (), OutputKeyID.toString (), *LoadedResult};
196+ };
197+
198+ auto replayOutputFromInput = [&](const InputFile &Input) {
199+ auto InputPath = Input.getFileName ();
200+ if (!Input.outputFilename ().empty ()) {
201+ if (auto Result = replayOutputFile (
202+ InputPath, InputsAndOutputs.getPrincipalOutputType (),
203+ Input.outputFilename ()))
204+ OutputProxies.emplace_back (*Result);
205+ else
206+ CanReplayAllOutput = false ;
207+ }
208+
209+ Input.getPrimarySpecificPaths ()
210+ .SupplementaryOutputs .forEachSetOutputAndType (
211+ [&](const std::string &File, file_types::ID ID) {
212+ if (ID == file_types::ID::TY_SerializedDiagnostics)
213+ return ;
214+
215+ if (auto Result = replayOutputFile (InputPath, ID, File))
216+ OutputProxies.emplace_back (*Result);
217+ else
218+ CanReplayAllOutput = false ;
219+ });
220+ };
221+
222+ llvm::for_each (InputsAndOutputs.getAllInputs (), replayOutputFromInput);
223+
224+ auto DiagnosticsOutput = replayOutputFile (
225+ " <cached-diagnostics>" , file_types::ID::TY_CachedDiagnostics,
226+ " <cached-diagnostics>" );
227+ if (!DiagnosticsOutput)
228+ CanReplayAllOutput = false ;
229+
230+ if (!CanReplayAllOutput)
231+ return false ;
232+
233+ // Replay Diagnostics first so the output failures comes after.
234+ // Also if the diagnostics replay failed, proceed to re-compile.
235+ if (auto E = CDP.replayCachedDiagnostics (
236+ DiagnosticsOutput->Proxy .getData ())) {
237+ Diag.diagnose (SourceLoc (), diag::error_replay_cached_diag,
238+ toString (std::move (E)));
239+ return false ;
240+ }
241+
242+ // Replay the result only when everything is resolved.
243+ // Use on disk output backend directly here to write to disk.
244+ llvm::vfs::OnDiskOutputBackend Backend;
245+ for (auto &Output : OutputProxies) {
246+ auto File = Backend.createFile (Output.Path );
247+ if (!File) {
248+ Diag.diagnose (SourceLoc (), diag::error_opening_output, Output.Path ,
249+ toString (File.takeError ()));
250+ continue ;
251+ }
252+ *File << Output.Proxy .getData ();
253+ if (auto E = File->keep ()) {
254+ Diag.diagnose (SourceLoc (), diag::error_closing_output, Output.Path ,
255+ toString (std::move (E)));
256+ continue ;
257+ }
258+ Diag.diagnose (SourceLoc (), diag::replay_output, Output.Path , Output.Key );
259+ }
260+
261+ return true ;
262+ }
263+
136264static Expected<std::unique_ptr<llvm::MemoryBuffer>>
137265loadCachedCompileResultFromCacheKeyImpl (ObjectStore &CAS, ActionCache &Cache,
138266 StringRef CacheKey,
0 commit comments