Skip to content

Commit 2521f38

Browse files
committed
[Dependency Scanning] Serialize visible Clang module sets for each by-name queried Clang module
Re-use them on successive incremental scanning actions
1 parent 7426a4f commit 2521f38

File tree

8 files changed

+147
-34
lines changed

8 files changed

+147
-34
lines changed

include/swift/AST/ModuleDependencies.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,8 @@ class ModuleDependencyInfoStorageBase {
277277
/// The macro dependencies.
278278
std::map<std::string, MacroPluginDependency> macroDependencies;
279279

280-
/// A list of Clang modules that are visible to this Swift module. This
281-
/// includes both direct Clang modules as well as transitive Clang
282-
/// module dependencies when they are exported
280+
/// A list of Clang modules that are visible to this Swift module
281+
/// as re-exported modular includes of its bridging header.
283282
std::vector<std::string> bridgingHeaderVisibleClangModules;
284283

285284
/// ModuleDependencyInfo is finalized (with all transitive dependencies

include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ using llvm::BCVBR;
4141
const unsigned char MODULE_DEPENDENCY_CACHE_FORMAT_SIGNATURE[] = {'I', 'M', 'D','C'};
4242
const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MAJOR = 10;
4343
/// Increment this on every change.
44-
const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MINOR = 4;
44+
const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MINOR = 5;
4545

4646
/// Various identifiers in this format will rely on having their strings mapped
4747
/// using this ID.
@@ -81,6 +81,7 @@ using FileIDArrayIDField = IdentifierIDField;
8181
using ContextHashIDField = IdentifierIDField;
8282
using ModuleCacheKeyIDField = IdentifierIDField;
8383
using ImportArrayIDField = IdentifierIDField;
84+
using VisibleModulesArrayIDField = IdentifierIDField;
8485
using LinkLibrariesArrayIDField = IdentifierIDField;
8586
using MacroDependenciesArrayIDField = IdentifierIDField;
8687
using SearchPathArrayIDField = IdentifierIDField;
@@ -109,6 +110,7 @@ enum {
109110
MACRO_DEPENDENCY_ARRAY_NODE,
110111
SEARCH_PATH_NODE,
111112
SEARCH_PATH_ARRAY_NODE,
113+
VISIBLE_MODULES_NODE,
112114
IMPORT_STATEMENT_NODE,
113115
IMPORT_STATEMENT_ARRAY_NODE,
114116
OPTIONAL_IMPORT_STATEMENT_ARRAY_NODE,
@@ -187,6 +189,14 @@ using SearchPathLayout =
187189
using SearchPathArrayLayout =
188190
BCRecordLayout<SEARCH_PATH_ARRAY_NODE, IdentifierIDArryField>;
189191

192+
// A record capturing information about all Clang modules visible
193+
// from a given named Clang module dependency query
194+
using VisibleModulesLayout =
195+
BCRecordLayout<VISIBLE_MODULES_NODE, // ID
196+
IdentifierIDField, // moduleIdentifier
197+
VisibleModulesArrayIDField // visibleModulesArrayIdentifier
198+
>;
199+
190200
// A record capturing information about a given 'import' statement
191201
// captured in a dependency node, including its source location.
192202
using ImportStatementLayout =
@@ -199,6 +209,7 @@ using ImportStatementLayout =
199209
IsExportedImport, // isExported
200210
AccessLevelField // accessLevel
201211
>;
212+
202213
using ImportStatementArrayLayout =
203214
BCRecordLayout<IMPORT_STATEMENT_ARRAY_NODE, IdentifierIDArryField>;
204215
using OptionalImportStatementArrayLayout =

lib/AST/ModuleDependencies.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,10 @@ void ModuleDependenciesCache::updateDependency(
879879
void ModuleDependenciesCache::removeDependency(ModuleDependencyID moduleID) {
880880
auto &map = getDependenciesMap(moduleID.Kind);
881881
map.erase(moduleID.ModuleName);
882+
// If we are removing a Clang module which was queried by-name
883+
// in a prior scan, we must re-compute its set of visible modules.
884+
if (moduleID.Kind == ModuleDependencyKind::Clang)
885+
clangModulesVisibleFromNamedLookup.erase(moduleID.ModuleName);
882886
}
883887

884888
void ModuleDependenciesCache::setImportedSwiftDependencies(
@@ -973,14 +977,11 @@ llvm::StringSet<> ModuleDependenciesCache::getAllVisibleClangModules(
973977
}
974978
for (const auto &clangDepID :
975979
findKnownDependency(moduleID).getImportedClangDependencies()) {
976-
// FIXME: This scenario should not occur
977-
// assert(hasVisibleClangModulesFrom(clangDepID.ModuleName));
978-
if (hasVisibleClangModulesFromLookup(clangDepID.ModuleName)) {
979-
auto visibleModulesViaImport =
980-
getVisibleClangModulesFromLookup(clangDepID.ModuleName);
981-
result.insert(visibleModulesViaImport.begin(),
982-
visibleModulesViaImport.end());
983-
}
980+
assert(hasVisibleClangModulesFromLookup(clangDepID.ModuleName));
981+
auto visibleModulesViaImport =
982+
getVisibleClangModulesFromLookup(clangDepID.ModuleName);
983+
result.insert(visibleModulesViaImport.begin(),
984+
visibleModulesViaImport.end());
984985
}
985986
return result;
986987
}

lib/DependencyScan/ModuleDependencyCacheSerialization.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,23 @@ bool ModuleDependenciesCacheDeserializer::readGraph(
411411
break;
412412
}
413413

414+
case VISIBLE_MODULES_NODE: {
415+
uint64_t identifierID;
416+
uint64_t valueArrayID;
417+
VisibleModulesLayout::readRecord(Scratch, identifierID, valueArrayID);
418+
auto moduleName = getIdentifier(identifierID);
419+
if (!moduleName)
420+
llvm::report_fatal_error(
421+
"Bad visible modules info: no module name");
422+
auto values = getStringArray(valueArrayID);
423+
if (!values)
424+
llvm::report_fatal_error(
425+
"Bad visible modules info: modules");
426+
427+
cache.clangModulesVisibleFromNamedLookup[moduleName.value()] = values.value();
428+
break;
429+
}
430+
414431
case IMPORT_STATEMENT_NODE: {
415432
unsigned importIdentifierID, bufferIdentifierID;
416433
unsigned lineNumber, columnNumber;
@@ -1056,6 +1073,7 @@ enum ModuleIdentifierArrayKind : uint8_t {
10561073
BridgingHeaderBuildCommandLine,
10571074
NonPathCommandLine,
10581075
FileDependencies,
1076+
VisibleClangModulesFromLookup,
10591077
LastArrayKind
10601078
};
10611079

@@ -1166,6 +1184,7 @@ class ModuleDependenciesCacheSerializer {
11661184
unsigned writeSearchPaths(const SwiftBinaryModuleDependencyStorage &dependencyInfo);
11671185
void writeSearchPathsArray(unsigned startIndex, unsigned count);
11681186

1187+
void writeVisibleClangModuleInfo(const ModuleDependenciesCache &cache);
11691188
void writeImportStatementInfos(const ModuleDependenciesCache &cache);
11701189
unsigned writeImportStatementInfos(const ModuleDependencyInfo &dependencyInfo,
11711190
bool optional);
@@ -1435,6 +1454,21 @@ void ModuleDependenciesCacheSerializer::writeSearchPathsArray(unsigned startInde
14351454
Out, ScratchRecord, AbbrCodes[SearchPathArrayLayout::Code], vec);
14361455
}
14371456

1457+
void ModuleDependenciesCacheSerializer::writeVisibleClangModuleInfo(
1458+
const ModuleDependenciesCache &cache) {
1459+
using namespace graph_block;
1460+
for (const auto &entry : cache.clangModulesVisibleFromNamedLookup) {
1461+
auto moduleID =
1462+
ModuleDependencyID{entry.getKey().str(), ModuleDependencyKind::Clang};
1463+
VisibleModulesLayout::emitRecord(
1464+
Out, ScratchRecord, AbbrCodes[VisibleModulesLayout::Code],
1465+
getIdentifier(moduleID.ModuleName),
1466+
getIdentifierArrayID(
1467+
moduleID,
1468+
ModuleIdentifierArrayKind::VisibleClangModulesFromLookup));
1469+
}
1470+
}
1471+
14381472
void ModuleDependenciesCacheSerializer::writeImportStatementInfos(
14391473
const ModuleDependenciesCache &cache) {
14401474
unsigned lastImportInfoIndex = 0;
@@ -1798,6 +1832,15 @@ unsigned ModuleDependenciesCacheSerializer::getOptionalImportStatementsArrayID(
17981832
void ModuleDependenciesCacheSerializer::collectStringsAndArrays(
17991833
const ModuleDependenciesCache &cache) {
18001834
addIdentifier(cache.scannerContextHash);
1835+
1836+
for (const auto &entry : cache.clangModulesVisibleFromNamedLookup) {
1837+
auto moduleName = entry.getKey().str();
1838+
addIdentifier(moduleName);
1839+
addStringArray({moduleName, ModuleDependencyKind::Clang},
1840+
ModuleIdentifierArrayKind::VisibleClangModulesFromLookup,
1841+
entry.second);
1842+
}
1843+
18011844
for (auto kind = ModuleDependencyKind::FirstKind;
18021845
kind != ModuleDependencyKind::LastKind; ++kind) {
18031846
auto modMap = cache.getDependenciesMap(kind);
@@ -1973,6 +2016,7 @@ void ModuleDependenciesCacheSerializer::writeInterModuleDependenciesCache(
19732016
registerRecordAbbr<MacroDependencyArrayLayout>();
19742017
registerRecordAbbr<SearchPathLayout>();
19752018
registerRecordAbbr<SearchPathArrayLayout>();
2019+
registerRecordAbbr<VisibleModulesLayout>();
19762020
registerRecordAbbr<ImportStatementLayout>();
19772021
registerRecordAbbr<ImportStatementArrayLayout>();
19782022
registerRecordAbbr<OptionalImportStatementArrayLayout>();
@@ -1998,6 +2042,9 @@ void ModuleDependenciesCacheSerializer::writeInterModuleDependenciesCache(
19982042
// Write the arrays
19992043
writeArraysOfIdentifiers();
20002044

2045+
// Write the cached sets of visible modules
2046+
writeVisibleClangModuleInfo(cache);
2047+
20012048
// Write all the import statement info
20022049
writeImportStatementInfos(cache);
20032050

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,25 +1197,31 @@ void ModuleDependencyScanner::processBatchClangModuleQueryResult(
11971197
auto dependencyID =
11981198
ModuleDependencyID{moduleIdentifier, ModuleDependencyKind::Clang};
11991199

1200-
// Add visible Clang modules for the queried dependency
1200+
// A successful named query will have returned a set of visible modules
12011201
if (lookupResult.visibleModules.contains(moduleIdentifier)) {
12021202
ScanDiagnosticReporter.registerNamedClangDependency();
12031203
DependencyCache.setVisibleClangModulesFromLookup(
12041204
dependencyID, lookupResult.visibleModules.at(moduleIdentifier));
1205-
}
1206-
1207-
if (DependencyCache.hasDependency(dependencyID))
12081205
resolvedClangDependenciesMap[moduleID].insert(dependencyID);
1209-
else if (lookupResult.discoveredDependencyInfos.contains(
1210-
moduleIdentifier)) {
1211-
resolvedClangDependenciesMap[moduleID].insert(dependencyID);
1212-
auto dependencyInfo = lookupResult.discoveredDependencyInfos.at(
1213-
moduleImport.importIdentifier);
1214-
allDiscoveredClangModules.insert(dependencyID);
1215-
DependencyCache.recordClangDependency(
1216-
dependencyInfo, ScanASTContext.Diags, [this](auto &clangDep) {
1217-
return bridgeClangModuleDependency(clangDep);
1218-
});
1206+
1207+
// If this module was not seen before as a transitive dependency
1208+
// of another lookup, record it into the cache
1209+
if (lookupResult.discoveredDependencyInfos.contains(
1210+
moduleIdentifier)) {
1211+
allDiscoveredClangModules.insert(dependencyID);
1212+
DependencyCache.recordClangDependency(
1213+
lookupResult.discoveredDependencyInfos.at(
1214+
moduleImport.importIdentifier),
1215+
ScanASTContext.Diags, [this](auto &clangDep) {
1216+
return bridgeClangModuleDependency(clangDep);
1217+
});
1218+
} else {
1219+
// If the query produced a set of visible modules but not
1220+
// a `ModuleDeps` info for the queried module itself, then
1221+
// it has to have been included in the set of already-seen
1222+
// module dependencies from a prior query.
1223+
assert(DependencyCache.hasDependency(dependencyID));
1224+
}
12191225
} else if (!optionalImport) {
12201226
// Otherwise, we failed to resolve this dependency. We will try
12211227
// again using the cache after all other imports have been

test/ScanDependencies/basic_query_metrics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// Ensure that despite being a common dependency to multiple Swift modules, only 1 query is performed to find 'C'
1010
// CHECK: remark: Number of Swift module queries: '6'
1111
// CHECK: remark: Number of named Clang module queries: '1'
12-
// CHEKC: remark: Number of recorded Clang module dependencies queried by-name from a Swift client: '1'
12+
// CHECK: remark: Number of recorded Clang module dependencies queried by-name from a Swift client: '1'
1313
// CHECK: remark: Number of recorded Swift module dependencies: '2'
1414
// CHECK: remark: Number of recorded Clang module dependencies: '1'
1515

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %empty-directory(%t/module-cache)
3+
// RUN: %empty-directory(%t/inputs)
4+
// RUN: split-file %s %t
5+
6+
// RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/module-cache -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib %t/test.swift -o %t/deps.json -I %t/inputs -Rdependency-scan -no-parallel-scan &> %t/remarks.txt
7+
// RUN: cat %t/remarks.txt | %FileCheck %s
8+
9+
// Ensure that although the Swift overlay dependency 'A' shares a dependency on 'B' and 'C'
10+
// it does not incur additional namedqueries for them.
11+
//
12+
// CHECK: remark: Number of Swift module queries: '9'
13+
// CHECK: remark: Number of named Clang module queries: '2'
14+
// CHECK: remark: Number of recorded Clang module dependencies queried by-name from a Swift client: '2'
15+
// CHECK: remark: Number of recorded Swift module dependencies: '1'
16+
// CHECK: remark: Number of recorded Clang module dependencies: '3'
17+
18+
//--- test.swift
19+
import B
20+
import C
21+
public func test() {}
22+
23+
//--- inputs/A.swiftinterface
24+
// swift-interface-format-version: 1.0
25+
// swift-module-flags: -module-name A -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -user-module-version 1.0
26+
import B
27+
import C
28+
public func a() { }
29+
30+
//--- inputs/A.h
31+
#include "A.h"
32+
void b(void);
33+
34+
//--- inputs/B.h
35+
#include "A.h"
36+
void b(void);
37+
38+
//--- inputs/C.h
39+
void c(void);
40+
41+
//--- inputs/module.modulemap
42+
module A {
43+
header "A.h"
44+
export *
45+
}
46+
module B {
47+
header "B.h"
48+
export *
49+
}
50+
module C {
51+
header "C.h"
52+
export *
53+
}

test/ScanDependencies/module_deps_cache_reuse.swift

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,9 @@ import SubE
2929
// CHECK-REMARK-SAVE: remark: Incremental module scan: Serializing module scanning dependency cache to:
3030

3131
// CHECK-REMARK-LOAD: remark: Incremental module scan: Re-using serialized module scanning dependency cache from:
32-
// 'SwiftShims', 'C' and 'B' are Clang modules which are directly imorted from Swift code in this test, without a corresponding Swift overlay module. Because we do not serialize negative Swift dependency lookup results, resolving a dependency on these modules involves a query for whether a Swift module under this name can be found. This query fails and the subsequent query for this identifier as a Clang dependency is then able to re-use the loaded serialized cache.
33-
34-
// CHECK-REMARK-LOAD: remark: Number of Swift module queries: '7'
35-
// FIXME: Today, we do not serialize dependencies of the main source module which results in a lookup for 'C' even though
36-
// it is fully redundant.
37-
// CHECK-REMARK-LOAD: remark: Number of named Clang module queries: '1'
38-
// CHECK-REMARK-LOAD: remark: Number of recorded Clang module dependencies queried by-name from a Swift client: '1'
32+
// CHECK-REMARK-LOAD: remark: Number of Swift module queries: '12'
33+
// CHECK-REMARK-LOAD: remark: Number of named Clang module queries: '0'
34+
// CHECK-REMARK-LOAD: remark: Number of recorded Clang module dependencies queried by-name from a Swift client: '0'
3935
// CHECK-REMARK-LOAD: remark: Number of recorded Swift module dependencies: '8'
4036
// CHECK-REMARK-LOAD: remark: Number of recorded Clang module dependencies: '7'
4137

0 commit comments

Comments
 (0)