Skip to content

Commit e2f888b

Browse files
Merge pull request #70384 from cachemeifyoucan/eng/PR-119387650
[Caching] Encoding cache key for input file with index instead of path
2 parents 2d6eabf + 76bde39 commit e2f888b

File tree

16 files changed

+246
-87
lines changed

16 files changed

+246
-87
lines changed

include/swift-c/DependencyScan/DependencyScan.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
/// SWIFTSCAN_VERSION_MINOR should increase when there are API additions.
2626
/// SWIFTSCAN_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
2727
#define SWIFTSCAN_VERSION_MAJOR 0
28-
#define SWIFTSCAN_VERSION_MINOR 6
28+
#define SWIFTSCAN_VERSION_MINOR 7
2929

3030
SWIFTSCAN_BEGIN_DECLS
3131

@@ -505,10 +505,26 @@ SWIFTSCAN_PUBLIC void swiftscan_cas_dispose(swiftscan_cas_t cas);
505505
/// swift input on the command-line by convention. Return \c CacheKey as string.
506506
/// If error happens, the error message is returned via `error` parameter, and
507507
/// caller needs to free the error message via `swiftscan_string_dispose`.
508+
/// This API is DEPRECATED and in favor of using
509+
/// `swiftscan_cache_compute_key_from_input_index`.
508510
SWIFTSCAN_PUBLIC swiftscan_string_ref_t
509511
swiftscan_cache_compute_key(swiftscan_cas_t cas, int argc, const char **argv,
510512
const char *input, swiftscan_string_ref_t *error);
511513

514+
/// Compute \c CacheKey for the outputs of a primary input file from a compiler
515+
/// invocation with command-line \c argc and \c argv and the index for the
516+
/// input. The index of the input is computed from the position of the input
517+
/// file from all input files. When primary input file is not available for
518+
/// compilation, e.g., using WMO, primary file is the first swift input on the
519+
/// command-line by convention. Return \c CacheKey as string. If error happens,
520+
/// the error message is returned via `error` parameter, and caller needs to
521+
/// free the error message via `swiftscan_string_dispose`.
522+
SWIFTSCAN_PUBLIC swiftscan_string_ref_t
523+
swiftscan_cache_compute_key_from_input_index(swiftscan_cas_t cas, int argc,
524+
const char **argv,
525+
unsigned input_index,
526+
swiftscan_string_ref_t *error);
527+
512528
/// Query the result of the compilation using the output cache key. \c globally
513529
/// suggests if the lookup should check remote cache if such operation exists.
514530
/// Returns the cached compilation of the result if found, or nullptr if output

include/swift/Frontend/CASOutputBackends.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ class SwiftCASOutputBackend : public llvm::vfs::OutputBackend {
3333
llvm::Optional<llvm::vfs::OutputConfig> Config) override;
3434

3535
virtual llvm::Error storeImpl(llvm::StringRef Path, llvm::StringRef Bytes,
36-
llvm::StringRef CorrespondingInput,
37-
file_types::ID OutputKind);
36+
unsigned InputIndex, file_types::ID OutputKind);
3837

3938
private:
4039
file_types::ID getOutputFileType(llvm::StringRef Path) const;
@@ -47,7 +46,7 @@ class SwiftCASOutputBackend : public llvm::vfs::OutputBackend {
4746
FrontendOptions::ActionType Action);
4847
~SwiftCASOutputBackend();
4948

50-
llvm::Error storeCachedDiagnostics(llvm::StringRef InputFile,
49+
llvm::Error storeCachedDiagnostics(unsigned InputIndex,
5150
llvm::StringRef Bytes);
5251

5352
private:

include/swift/Frontend/CompileJobCacheKey.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ createCompileJobBaseCacheKey(llvm::cas::ObjectStore &CAS,
3636
ArrayRef<const char *> Args);
3737

3838
/// Compute CompileJobKey for the compiler outputs. The key for the output
39-
/// is computed from the base key for the compilation, the output kind and the
40-
/// input file path that is associated with this specific output.
39+
/// is computed from the base key for the compilation and the input file index
40+
/// which is the index for the input among all the input files (not just the
41+
/// output producing inputs).
4142
llvm::Expected<llvm::cas::ObjectRef>
4243
createCompileJobCacheKeyForOutput(llvm::cas::ObjectStore &CAS,
4344
llvm::cas::ObjectRef BaseKey,
44-
StringRef ProducingInput);
45+
unsigned InputIndex);
4546
} // namespace swift
4647

4748
#endif

include/swift/Frontend/FrontendInputsAndOutputs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ class FrontendInputsAndOutputs {
159159

160160
const InputFile &getFirstOutputProducingInput() const;
161161

162+
unsigned getIndexOfFirstOutputProducingInput() const;
163+
162164
bool isInputPrimary(StringRef file) const;
163165

164166
unsigned numberOfPrimaryInputsEndingWith(StringRef extension) const;

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ updateModuleCacheKey(ModuleDependencyInfo &depInfo,
179179
if (cache.getScanService().hasPathMapping())
180180
InputPath = cache.getScanService().remapPath(InputPath);
181181

182-
auto key = createCompileJobCacheKeyForOutput(CAS, *base, InputPath);
182+
// Module compilation commands always have only one input and the input
183+
// index is always 0.
184+
auto key = createCompileJobCacheKeyForOutput(CAS, *base, /*InputIndex=*/0);
183185
if (!key)
184186
return key.takeError();
185187

lib/DriverTool/swift_cache_tool_main.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,10 @@ int SwiftCacheToolInvocation::printOutputKeys() {
284284

285285
std::vector<OutputEntry> OutputKeys;
286286
bool hasError = false;
287-
auto addFromInputFile = [&](const InputFile &Input) {
287+
auto addFromInputFile = [&](const InputFile &Input, unsigned InputIndex) {
288288
auto InputPath = Input.getFileName();
289289
auto OutputKey =
290-
createCompileJobCacheKeyForOutput(CAS, *BaseKey, InputPath);
290+
createCompileJobCacheKeyForOutput(CAS, *BaseKey, InputIndex);
291291
if (!OutputKey) {
292292
llvm::errs() << "cannot create cache key for " << InputPath << ": "
293293
<< toString(OutputKey.takeError()) << "\n";
@@ -310,9 +310,10 @@ int SwiftCacheToolInvocation::printOutputKeys() {
310310
Outputs.emplace_back(file_types::getTypeName(ID), File);
311311
});
312312
};
313-
llvm::for_each(
314-
Invocation.getFrontendOptions().InputsAndOutputs.getAllInputs(),
315-
addFromInputFile);
313+
auto AllInputs =
314+
Invocation.getFrontendOptions().InputsAndOutputs.getAllInputs();
315+
for (unsigned Index = 0; Index < AllInputs.size(); ++Index)
316+
addFromInputFile(AllInputs[Index], Index);
316317

317318
// Add diagnostics file.
318319
if (!OutputKeys.empty())

lib/Frontend/CASOutputBackends.cpp

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class SwiftCASOutputBackend::Implementation {
6868
auto ProducingInput = OutputToInputMap.find(ResolvedPath);
6969
assert(ProducingInput != OutputToInputMap.end() && "Unknown output file");
7070

71-
std::string InputFilename = ProducingInput->second.first.getFileName();
71+
unsigned InputIndex = ProducingInput->second.first;
7272
auto OutputType = ProducingInput->second.second;
7373

7474
// Uncached output kind.
@@ -77,18 +77,18 @@ class SwiftCASOutputBackend::Implementation {
7777

7878
return std::make_unique<SwiftCASOutputFile>(
7979
ResolvedPath,
80-
[this, InputFilename, OutputType](StringRef Path,
81-
StringRef Bytes) -> Error {
82-
return storeImpl(Path, Bytes, InputFilename, OutputType);
80+
[this, InputIndex, OutputType](StringRef Path,
81+
StringRef Bytes) -> Error {
82+
return storeImpl(Path, Bytes, InputIndex, OutputType);
8383
});
8484
}
8585

8686
void initBackend(const FrontendInputsAndOutputs &InputsAndOutputs);
8787

88-
Error storeImpl(StringRef Path, StringRef Bytes, StringRef CorrespondingInput,
88+
Error storeImpl(StringRef Path, StringRef Bytes, unsigned InputIndex,
8989
file_types::ID OutputKind);
9090

91-
Error finalizeCacheKeysFor(StringRef Input);
91+
Error finalizeCacheKeysFor(unsigned InputIndex);
9292

9393
private:
9494
friend class SwiftCASOutputBackend;
@@ -98,8 +98,11 @@ class SwiftCASOutputBackend::Implementation {
9898
const FrontendInputsAndOutputs &InputsAndOutputs;
9999
FrontendOptions::ActionType Action;
100100

101-
StringMap<std::pair<const InputFile &, file_types::ID>> OutputToInputMap;
102-
StringMap<DenseMap<file_types::ID, ObjectRef>> OutputRefs;
101+
// Map from output path to the input index and output kind.
102+
StringMap<std::pair<unsigned, file_types::ID>> OutputToInputMap;
103+
104+
// A vector of output refs where the index is the input index.
105+
SmallVector<DenseMap<file_types::ID, ObjectRef>> OutputRefs;
103106
};
104107

105108
SwiftCASOutputBackend::SwiftCASOutputBackend(
@@ -127,14 +130,14 @@ file_types::ID SwiftCASOutputBackend::getOutputFileType(StringRef Path) const {
127130
}
128131

129132
Error SwiftCASOutputBackend::storeImpl(StringRef Path, StringRef Bytes,
130-
StringRef CorrespondingInput,
133+
unsigned InputIndex,
131134
file_types::ID OutputKind) {
132-
return Impl.storeImpl(Path, Bytes, CorrespondingInput, OutputKind);
135+
return Impl.storeImpl(Path, Bytes, InputIndex, OutputKind);
133136
}
134137

135-
Error SwiftCASOutputBackend::storeCachedDiagnostics(StringRef InputFile,
138+
Error SwiftCASOutputBackend::storeCachedDiagnostics(unsigned InputIndex,
136139
StringRef Bytes) {
137-
return storeImpl("<cached-diagnostics>", Bytes, InputFile,
140+
return storeImpl("<cached-diagnostics>", Bytes, InputIndex,
138141
file_types::ID::TY_CachedDiagnostics);
139142
}
140143

@@ -145,57 +148,63 @@ void SwiftCASOutputBackend::Implementation::initBackend(
145148
// input it actually comes from. Maybe the solution is just not to cache
146149
// any commands write output to `-`.
147150
file_types::ID mainOutputType = InputsAndOutputs.getPrincipalOutputType();
148-
auto addInput = [&](const InputFile &Input) {
151+
auto addInput = [&](const InputFile &Input, unsigned Index) {
149152
if (!Input.outputFilename().empty())
150153
OutputToInputMap.insert(
151-
{Input.outputFilename(), {Input, mainOutputType}});
154+
{Input.outputFilename(), {Index, mainOutputType}});
152155
Input.getPrimarySpecificPaths()
153156
.SupplementaryOutputs.forEachSetOutputAndType(
154157
[&](const std::string &Out, file_types::ID ID) {
155158
if (!file_types::isProducedFromDiagnostics(ID))
156-
OutputToInputMap.insert({Out, {Input, ID}});
159+
OutputToInputMap.insert({Out, {Index, ID}});
157160
});
158161
};
159-
llvm::for_each(InputsAndOutputs.getAllInputs(), addInput);
162+
163+
for (unsigned idx = 0; idx < InputsAndOutputs.getAllInputs().size(); ++idx)
164+
addInput(InputsAndOutputs.getAllInputs()[idx], idx);
160165

161166
// FIXME: Cached diagnostics is associated with the first output producing
162167
// input file.
163-
OutputToInputMap.insert({"<cached-diagnostics>",
164-
{InputsAndOutputs.getFirstOutputProducingInput(),
165-
file_types::TY_CachedDiagnostics}});
168+
OutputToInputMap.insert(
169+
{"<cached-diagnostics>",
170+
{InputsAndOutputs.getIndexOfFirstOutputProducingInput(),
171+
file_types::TY_CachedDiagnostics}});
172+
173+
// Resize the output refs to hold all inputs.
174+
OutputRefs.resize(InputsAndOutputs.getAllInputs().size());
166175
}
167176

168177
Error SwiftCASOutputBackend::Implementation::storeImpl(
169-
StringRef Path, StringRef Bytes, StringRef CorrespondingInput,
178+
StringRef Path, StringRef Bytes, unsigned InputIndex,
170179
file_types::ID OutputKind) {
171180
Optional<ObjectRef> BytesRef;
172181
if (Error E = CAS.storeFromString(None, Bytes).moveInto(BytesRef))
173182
return E;
174183

175184
LLVM_DEBUG(llvm::dbgs() << "DEBUG: producing CAS output of type \'"
176185
<< file_types::getTypeName(OutputKind)
177-
<< "\' for input \'" << CorrespondingInput << "\': \'"
186+
<< "\' for input \'" << InputIndex << "\': \'"
178187
<< CAS.getID(*BytesRef).toString() << "\'\n";);
179188

180-
OutputRefs[CorrespondingInput].insert({OutputKind, *BytesRef});
189+
OutputRefs[InputIndex].insert({OutputKind, *BytesRef});
181190

182-
return finalizeCacheKeysFor(CorrespondingInput);
191+
return finalizeCacheKeysFor(InputIndex);
183192
}
184193

185194
Error SwiftCASOutputBackend::Implementation::finalizeCacheKeysFor(
186-
StringRef Input) {
187-
auto Entry = OutputRefs.find(Input);
188-
assert(Entry != OutputRefs.end() && "Unexpected input");
195+
unsigned InputIndex) {
196+
auto ProducedOutputs = OutputRefs[InputIndex];
197+
assert(!ProducedOutputs.empty() && "Expect outputs for this input");
189198

190199
// If not all outputs for the input are emitted, return.
191200
if (!llvm::all_of(OutputToInputMap, [&](auto &E) {
192-
return (E.second.first.getFileName() != Input ||
193-
Entry->second.count(E.second.second));
201+
return (E.second.first != InputIndex ||
202+
ProducedOutputs.count(E.second.second));
194203
}))
195204
return Error::success();
196205

197206
std::vector<std::pair<file_types::ID, ObjectRef>> OutputsForInput;
198-
llvm::for_each(Entry->second, [&OutputsForInput](auto E) {
207+
llvm::for_each(ProducedOutputs, [&OutputsForInput](auto E) {
199208
OutputsForInput.emplace_back(E.first, E.second);
200209
});
201210
// Sort to a stable ordering for deterministic output cache object.
@@ -237,14 +246,14 @@ Error SwiftCASOutputBackend::Implementation::finalizeCacheKeysFor(
237246
return Err;
238247
}
239248

240-
auto CacheKey = createCompileJobCacheKeyForOutput(CAS, BaseKey, Input);
249+
auto CacheKey = createCompileJobCacheKeyForOutput(CAS, BaseKey, InputIndex);
241250
if (!CacheKey)
242251
return CacheKey.takeError();
243252

244-
LLVM_DEBUG(llvm::dbgs() << "DEBUG: writing cache entry for input \'" << Input
245-
<< "\': \'" << CAS.getID(*CacheKey).toString()
246-
<< "\' => \'" << CAS.getID(*Result).toString()
247-
<< "\'\n";);
253+
LLVM_DEBUG(llvm::dbgs() << "DEBUG: writing cache entry for input \'"
254+
<< InputIndex << "\': \'"
255+
<< CAS.getID(*CacheKey).toString() << "\' => \'"
256+
<< CAS.getID(*Result).toString() << "\'\n";);
248257

249258
if (auto E = Cache.put(CAS.getID(*CacheKey), CAS.getID(*Result)))
250259
return E;

lib/Frontend/CachedDiagnostics.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -777,8 +777,7 @@ CachingDiagnosticsProcessor::CachingDiagnosticsProcessor(
777777
auto Err = Instance.getCASOutputBackend().storeCachedDiagnostics(
778778
Instance.getInvocation()
779779
.getFrontendOptions()
780-
.InputsAndOutputs.getFirstOutputProducingInput()
781-
.getFileName(),
780+
.InputsAndOutputs.getIndexOfFirstOutputProducingInput(),
782781
Content);
783782

784783
if (Err) {

lib/Frontend/CachingUtils.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,12 @@ bool replayCachedCompilerOutputs(
145145
Optional<OutputEntry> DiagnosticsOutput;
146146

147147
auto replayOutputsForInputFile = [&](const std::string &InputPath,
148+
unsigned InputIndex,
148149
const DenseMap<file_types::ID,
149150
std::string> &Outputs) {
150151
auto lookupFailed = [&CanReplayAllOutput] { CanReplayAllOutput = false; };
151-
auto OutputKey = createCompileJobCacheKeyForOutput(CAS, BaseKey, InputPath);
152+
auto OutputKey =
153+
createCompileJobCacheKeyForOutput(CAS, BaseKey, InputIndex);
152154

153155
if (!OutputKey) {
154156
Diag.diagnose(SourceLoc(), diag::error_cas,
@@ -199,7 +201,8 @@ bool replayCachedCompilerOutputs(
199201
}
200202
};
201203

202-
auto replayOutputFromInput = [&](const InputFile &Input) {
204+
auto replayOutputFromInput = [&](const InputFile &Input,
205+
unsigned InputIndex) {
203206
auto InputPath = Input.getFileName();
204207
DenseMap<file_types::ID, std::string> Outputs;
205208
if (!Input.outputFilename().empty())
@@ -225,27 +228,33 @@ bool replayCachedCompilerOutputs(
225228
Outputs.try_emplace(file_types::ID::TY_CachedDiagnostics,
226229
"<cached-diagnostics>");
227230

228-
return replayOutputsForInputFile(InputPath, Outputs);
231+
return replayOutputsForInputFile(InputPath, InputIndex, Outputs);
229232
};
230233

234+
auto AllInputs = InputsAndOutputs.getAllInputs();
231235
// If there are primary inputs, look up only the primary input files.
232236
// Otherwise, prepare to do cache lookup for all inputs.
233-
if (InputsAndOutputs.hasPrimaryInputs())
234-
InputsAndOutputs.forEachPrimaryInput([&](const InputFile &File) {
235-
replayOutputFromInput(File);
236-
return false;
237-
});
238-
else
239-
llvm::for_each(InputsAndOutputs.getAllInputs(), replayOutputFromInput);
237+
for (unsigned Index = 0; Index < AllInputs.size(); ++Index) {
238+
const auto &Input = AllInputs[Index];
239+
if (InputsAndOutputs.hasPrimaryInputs() && !Input.isPrimary())
240+
continue;
241+
242+
replayOutputFromInput(Input, Index);
243+
}
244+
245+
if (!CanReplayAllOutput)
246+
return false;
240247

241248
// If there is not diagnostic output, this is a job that produces no output
242249
// and only diagnostics, like `typecheck-module-from-interface`, look up
243250
// diagnostics from first file.
244251
if (!DiagnosticsOutput)
245252
replayOutputsForInputFile(
246-
InputsAndOutputs.getFirstOutputProducingInput().getFileName(),
253+
"<cached-diagnostics>",
254+
InputsAndOutputs.getIndexOfFirstOutputProducingInput(),
247255
{{file_types::ID::TY_CachedDiagnostics, "<cached-diagnostics>"}});
248256

257+
// Check again to make sure diagnostics is fetched successfully.
249258
if (!CanReplayAllOutput)
250259
return false;
251260

lib/Frontend/CompileJobCacheKey.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/CAS/ObjectStore.h"
2424
#include "llvm/Option/ArgList.h"
2525
#include "llvm/Option/OptTable.h"
26+
#include "llvm/Support/EndianStream.h"
2627
#include "llvm/Support/Error.h"
2728
#include "llvm/Support/MemoryBuffer.h"
2829

@@ -84,13 +85,16 @@ llvm::Expected<llvm::cas::ObjectRef> swift::createCompileJobBaseCacheKey(
8485
return Out.takeError();
8586
}
8687

87-
llvm::Expected<llvm::cas::ObjectRef> swift::createCompileJobCacheKeyForOutput(
88-
llvm::cas::ObjectStore &CAS, llvm::cas::ObjectRef BaseKey,
89-
StringRef ProducingInput) {
90-
SmallString<256> OutputInfo;
88+
llvm::Expected<llvm::cas::ObjectRef>
89+
swift::createCompileJobCacheKeyForOutput(llvm::cas::ObjectStore &CAS,
90+
llvm::cas::ObjectRef BaseKey,
91+
unsigned InputIndex) {
92+
std::string InputInfo;
93+
llvm::raw_string_ostream OS(InputInfo);
9194

92-
// CacheKey is the producting input + the base key.
93-
OutputInfo.append(ProducingInput);
95+
// CacheKey is the index of the producting input + the base key.
96+
// Encode the unsigned value as little endian in the field.
97+
llvm::support::endian::write<uint32_t>(OS, InputIndex, llvm::support::little);
9498

95-
return CAS.storeFromString({BaseKey}, OutputInfo);
99+
return CAS.storeFromString({BaseKey}, OS.str());
96100
}

0 commit comments

Comments
 (0)