Skip to content

Commit 2285785

Browse files
authored
Merge pull request swiftlang#78224 from benlangmuir/cherry-pick-140286819-61
[CAS] Cache symbol graph outputs
2 parents 98ab6b2 + fd15f55 commit 2285785

File tree

10 files changed

+127
-10
lines changed

10 files changed

+127
-10
lines changed

include/swift/Basic/FileTypes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ TYPE("swiftoverlay", SwiftOverlayFile, "swiftoverlay", "")
9898

9999
// Misc types
100100
TYPE("pcm", ClangModuleFile, "pcm", "")
101+
TYPE("symbol-graph", SymbolGraphFile, "symbols.json", "")
101102
TYPE("pch", PCH, "pch", "")
102103
TYPE("none", Nothing, "", "")
103104

include/swift/Frontend/CASOutputBackends.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class SwiftCASOutputBackend : public llvm::vfs::OutputBackend {
4646
llvm::cas::ActionCache &Cache,
4747
llvm::cas::ObjectRef BaseKey,
4848
const FrontendInputsAndOutputs &InputsAndOutputs,
49+
const FrontendOptions &Opts,
4950
FrontendOptions::ActionType Action);
5051
~SwiftCASOutputBackend();
5152

include/swift/Frontend/CachingUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ createSwiftCachingOutputBackend(
3636
llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &Cache,
3737
llvm::cas::ObjectRef BaseKey,
3838
const FrontendInputsAndOutputs &InputsAndOutputs,
39-
FrontendOptions::ActionType Action);
39+
const FrontendOptions &Opts, FrontendOptions::ActionType Action);
4040

4141
/// Replay the output of the compilation from cache.
4242
/// Return true if outputs are replayed, false otherwise.

lib/Basic/FileTypes.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ bool file_types::isTextual(ID Id) {
116116
case file_types::TY_SwiftABIDescriptor:
117117
case file_types::TY_SwiftAPIDescriptor:
118118
case file_types::TY_ConstValues:
119+
case file_types::TY_SymbolGraphFile:
119120
return true;
120121
case file_types::TY_Image:
121122
case file_types::TY_Object:
@@ -202,6 +203,7 @@ bool file_types::isAfterLLVM(ID Id) {
202203
case file_types::TY_SwiftFixIt:
203204
case file_types::TY_ModuleSemanticInfo:
204205
case file_types::TY_CachedDiagnostics:
206+
case file_types::TY_SymbolGraphFile:
205207
return false;
206208
case file_types::TY_INVALID:
207209
llvm_unreachable("Invalid type ID.");
@@ -263,6 +265,7 @@ bool file_types::isPartOfSwiftCompilation(ID Id) {
263265
case file_types::TY_SwiftFixIt:
264266
case file_types::TY_ModuleSemanticInfo:
265267
case file_types::TY_CachedDiagnostics:
268+
case file_types::TY_SymbolGraphFile:
266269
return false;
267270
case file_types::TY_INVALID:
268271
llvm_unreachable("Invalid type ID.");
@@ -324,6 +327,7 @@ bool file_types::isProducedFromDiagnostics(ID Id) {
324327
case file_types::TY_SwiftAPIDescriptor:
325328
case file_types::TY_ConstValues:
326329
case file_types::TY_ModuleSemanticInfo:
330+
case file_types::TY_SymbolGraphFile:
327331
return false;
328332
case file_types::TY_INVALID:
329333
llvm_unreachable("Invalid type ID.");

lib/Driver/Driver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,7 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
17081708
case file_types::TY_SwiftFixIt:
17091709
case file_types::TY_ModuleSemanticInfo:
17101710
case file_types::TY_CachedDiagnostics:
1711+
case file_types::TY_SymbolGraphFile:
17111712
// We could in theory handle assembly or LLVM input, but let's not.
17121713
// FIXME: What about LTO?
17131714
Diags.diagnose(SourceLoc(), diag::error_unexpected_input_file,

lib/Driver/ToolChains.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,7 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const {
779779
case file_types::TY_SwiftFixIt:
780780
case file_types::TY_ModuleSemanticInfo:
781781
case file_types::TY_CachedDiagnostics:
782+
case file_types::TY_SymbolGraphFile:
782783
llvm_unreachable("Output type can never be primary output.");
783784
case file_types::TY_INVALID:
784785
llvm_unreachable("Invalid type ID");
@@ -1054,6 +1055,7 @@ ToolChain::constructInvocation(const BackendJobAction &job,
10541055
case file_types::TY_SwiftFixIt:
10551056
case file_types::TY_ModuleSemanticInfo:
10561057
case file_types::TY_CachedDiagnostics:
1058+
case file_types::TY_SymbolGraphFile:
10571059
llvm_unreachable("Output type can never be primary output.");
10581060
case file_types::TY_INVALID:
10591061
llvm_unreachable("Invalid type ID");

lib/Frontend/CASOutputBackends.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,39 @@ class SwiftCASOutputBackend::Implementation {
5757
public:
5858
Implementation(ObjectStore &CAS, ActionCache &Cache, ObjectRef BaseKey,
5959
const FrontendInputsAndOutputs &InputsAndOutputs,
60+
const FrontendOptions &Opts,
6061
FrontendOptions::ActionType Action)
6162
: CAS(CAS), Cache(Cache), BaseKey(BaseKey),
62-
InputsAndOutputs(InputsAndOutputs), Action(Action) {
63+
InputsAndOutputs(InputsAndOutputs), Opts(Opts), Action(Action) {
6364
initBackend(InputsAndOutputs);
6465
}
6566

6667
llvm::Expected<std::unique_ptr<llvm::vfs::OutputFileImpl>>
6768
createFileImpl(llvm::StringRef ResolvedPath,
6869
std::optional<llvm::vfs::OutputConfig> Config) {
6970
auto ProducingInput = OutputToInputMap.find(ResolvedPath);
71+
if (ProducingInput == OutputToInputMap.end() &&
72+
ResolvedPath.starts_with(Opts.SymbolGraphOutputDir)) {
73+
return std::make_unique<SwiftCASOutputFile>(
74+
ResolvedPath, [this](StringRef Path, StringRef Bytes) -> Error {
75+
bool Shortened = Path.consume_front(Opts.SymbolGraphOutputDir);
76+
assert(Shortened && "symbol graph path outside output dir");
77+
(void)Shortened;
78+
std::optional<ObjectRef> PathRef;
79+
if (Error E =
80+
CAS.storeFromString(std::nullopt, Path).moveInto(PathRef))
81+
return E;
82+
std::optional<ObjectRef> BytesRef;
83+
if (Error E =
84+
CAS.storeFromString(std::nullopt, Bytes).moveInto(BytesRef))
85+
return E;
86+
auto Ref = CAS.store({*PathRef, *BytesRef}, {});
87+
if (!Ref)
88+
return Ref.takeError();
89+
SymbolGraphOutputRefs.push_back(*Ref);
90+
return Error::success();
91+
});
92+
}
7093
assert(ProducingInput != OutputToInputMap.end() && "Unknown output file");
7194

7295
unsigned InputIndex = ProducingInput->second.first;
@@ -97,21 +120,24 @@ class SwiftCASOutputBackend::Implementation {
97120
ActionCache &Cache;
98121
ObjectRef BaseKey;
99122
const FrontendInputsAndOutputs &InputsAndOutputs;
123+
const FrontendOptions &Opts;
100124
FrontendOptions::ActionType Action;
101125

102126
// Map from output path to the input index and output kind.
103127
StringMap<std::pair<unsigned, file_types::ID>> OutputToInputMap;
104128

105129
// A vector of output refs where the index is the input index.
106130
SmallVector<DenseMap<file_types::ID, ObjectRef>> OutputRefs;
131+
132+
SmallVector<ObjectRef> SymbolGraphOutputRefs;
107133
};
108134

109135
SwiftCASOutputBackend::SwiftCASOutputBackend(
110136
ObjectStore &CAS, ActionCache &Cache, ObjectRef BaseKey,
111137
const FrontendInputsAndOutputs &InputsAndOutputs,
112-
FrontendOptions::ActionType Action)
138+
const FrontendOptions &Opts, FrontendOptions::ActionType Action)
113139
: Impl(*new SwiftCASOutputBackend::Implementation(
114-
CAS, Cache, BaseKey, InputsAndOutputs, Action)) {}
140+
CAS, Cache, BaseKey, InputsAndOutputs, Opts, Action)) {}
115141

116142
SwiftCASOutputBackend::~SwiftCASOutputBackend() { delete &Impl; }
117143

@@ -122,7 +148,8 @@ bool SwiftCASOutputBackend::isStoredDirectly(file_types::ID Kind) {
122148

123149
IntrusiveRefCntPtr<OutputBackend> SwiftCASOutputBackend::cloneImpl() const {
124150
return makeIntrusiveRefCnt<SwiftCASOutputBackend>(
125-
Impl.CAS, Impl.Cache, Impl.BaseKey, Impl.InputsAndOutputs, Impl.Action);
151+
Impl.CAS, Impl.Cache, Impl.BaseKey, Impl.InputsAndOutputs, Impl.Opts,
152+
Impl.Action);
126153
}
127154

128155
Expected<std::unique_ptr<OutputFileImpl>>
@@ -243,6 +270,13 @@ Error SwiftCASOutputBackend::Implementation::finalizeCacheKeysFor(
243270
llvm::for_each(ProducedOutputs, [&OutputsForInput](auto E) {
244271
OutputsForInput.emplace_back(E.first, E.second);
245272
});
273+
if (InputIndex == InputsAndOutputs.getIndexOfFirstOutputProducingInput() &&
274+
!SymbolGraphOutputRefs.empty()) {
275+
auto SGRef = CAS.store(SymbolGraphOutputRefs, {});
276+
if (!SGRef)
277+
return SGRef.takeError();
278+
OutputsForInput.emplace_back(file_types::ID::TY_SymbolGraphFile, *SGRef);
279+
}
246280
// Sort to a stable ordering for deterministic output cache object.
247281
llvm::sort(OutputsForInput,
248282
[](auto &LHS, auto &RHS) { return LHS.first < RHS.first; });

lib/Frontend/CachingUtils.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,13 @@ using namespace llvm::vfs;
5454

5555
namespace swift {
5656

57-
llvm::IntrusiveRefCntPtr<SwiftCASOutputBackend>
58-
createSwiftCachingOutputBackend(
57+
llvm::IntrusiveRefCntPtr<SwiftCASOutputBackend> createSwiftCachingOutputBackend(
5958
llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &Cache,
6059
llvm::cas::ObjectRef BaseKey,
6160
const FrontendInputsAndOutputs &InputsAndOutputs,
62-
FrontendOptions::ActionType Action) {
63-
return makeIntrusiveRefCnt<SwiftCASOutputBackend>(CAS, Cache, BaseKey,
64-
InputsAndOutputs, Action);
61+
const FrontendOptions &Opts, FrontendOptions::ActionType Action) {
62+
return makeIntrusiveRefCnt<SwiftCASOutputBackend>(
63+
CAS, Cache, BaseKey, InputsAndOutputs, Opts, Action);
6564
}
6665

6766
Error cas::CachedResultLoader::replay(CallbackTy Callback) {
@@ -197,6 +196,31 @@ bool replayCachedCompilerOutputs(
197196
assert(!DiagnosticsOutput && "more than 1 diagnotics found");
198197
DiagnosticsOutput.emplace(
199198
OutputEntry{OutputPath->second, OutID, Kind, Input, *Proxy});
199+
} else if (Kind == file_types::ID::TY_SymbolGraphFile &&
200+
!Opts.SymbolGraphOutputDir.empty()) {
201+
auto Err = Proxy->forEachReference([&](ObjectRef Ref) -> Error {
202+
auto Proxy = CAS.getProxy(Ref);
203+
if (!Proxy)
204+
return Proxy.takeError();
205+
auto PathRef = Proxy->getReference(0);
206+
auto ContentRef = Proxy->getReference(1);
207+
auto Path = CAS.getProxy(PathRef);
208+
auto Content = CAS.getProxy(ContentRef);
209+
if (!Path)
210+
return Path.takeError();
211+
if (!Content)
212+
return Content.takeError();
213+
214+
SmallString<128> OutputPath(Opts.SymbolGraphOutputDir);
215+
llvm::sys::path::append(OutputPath, Path->getData());
216+
217+
OutputProxies.emplace_back(OutputEntry{
218+
std::string(OutputPath), OutID, Kind, Input, *Content});
219+
220+
return Error::success();
221+
});
222+
if (Err)
223+
return Err;
200224
} else
201225
OutputProxies.emplace_back(
202226
OutputEntry{OutputPath->second, OutID, Kind, Input, *Proxy});
@@ -234,6 +258,9 @@ bool replayCachedCompilerOutputs(
234258
Outputs.try_emplace(file_types::ID::TY_CachedDiagnostics,
235259
"<cached-diagnostics>");
236260

261+
// Add symbol graph entry for lookup. Output path doesn't matter here.
262+
Outputs.try_emplace(file_types::ID::TY_SymbolGraphFile, "<symbol-graph>");
263+
237264
return replayOutputsForInputFile(Input, InputPath, InputIndex, Outputs);
238265
};
239266

lib/Frontend/Frontend.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ void CompilerInstance::setupOutputBackend() {
486486
auto &InAndOuts = Invocation.getFrontendOptions().InputsAndOutputs;
487487
CASOutputBackend = createSwiftCachingOutputBackend(
488488
*CAS, *ResultCache, *CompileJobBaseKey, InAndOuts,
489+
Invocation.getFrontendOptions(),
489490
Invocation.getFrontendOptions().RequestedAction);
490491

491492
if (Invocation.getIRGenOptions().UseCASBackend) {

test/CAS/symbol-graph.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/clang-module-cache -O \
5+
// RUN: -parse-stdlib -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
6+
// RUN: %t/main.swift -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -I %t/include \
7+
// RUN: -emit-symbol-graph -emit-symbol-graph-dir %t/symbol-graph1
8+
9+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json A > %t/A.cmd
10+
// RUN: %swift_frontend_plain @%t/A.cmd
11+
12+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Test > %t/Test.cmd
13+
// RUN: %target-swift-frontend -module-name Test -module-cache-path %t/clang-module-cache -O \
14+
// RUN: -parse-stdlib -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
15+
// RUN: %t/main.swift -o %t/Test.swiftmodule -swift-version 5 -cache-compile-job -cas-path %t/cas -I %t/include \
16+
// RUN: -emit-symbol-graph -emit-symbol-graph-dir %t/symbol-graph1 \
17+
// RUN: -emit-module @%t/Test.cmd -Rcache-compile-job 2>&1 | %FileCheck %s --check-prefix=CACHE-MISS
18+
19+
// CACHE-MISS: remark: cache miss for input
20+
21+
// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Test > %t/Test.cmd
22+
// RUN: %target-swift-frontend -module-name Test -module-cache-path %t/clang-module-cache -O \
23+
// RUN: -parse-stdlib -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
24+
// RUN: %t/main.swift -o %t/Test.swiftmodule -swift-version 5 -cache-compile-job -cas-path %t/cas -I %t/include \
25+
// RUN: -emit-symbol-graph -emit-symbol-graph-dir %t/symbol-graph2 \
26+
// RUN: -emit-module @%t/Test.cmd -Rcache-compile-job 2>&1 | %FileCheck %s --check-prefix=CACHE-MISS
27+
28+
// CACHE-HIT: remark: replay output file '{{.*}}{{/|\\}}symbol-graph2{{/|\\}}Test.symbols.json': key 'llvmcas://{{.*}}'
29+
// CACHE-HIT: remark: replay output file '{{.*}}{{/|\\}}symbol-graph2{{/|\\}}[email protected]': key 'llvmcas://{{.*}}'
30+
31+
// RUN: diff -r -u %t/symbol-graph1 %t/symbol-graph2
32+
33+
//--- include/A.swiftinterface
34+
// swift-interface-format-version: 1.0
35+
// swift-module-flags: -module-name A -O -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -user-module-version 1.0
36+
37+
public struct A {}
38+
39+
//--- main.swift
40+
import A
41+
42+
public struct Foo {}
43+
44+
extension A {
45+
public func bar() {}
46+
}

0 commit comments

Comments
 (0)