Skip to content

Commit e92e66f

Browse files
[InterfaceFile] Improve flag extraction from interface file
Improve the version/flags extract from interface file by moving away from using Regex and limiting the search to the beginning of the file. Switch away from Regex will give 5-10% improvement in time and instruction counts, and limiting the search lines can save a lot of time if the swiftinterface is large. For example, the extract time for Swift stdlib is 10x faster after the patch. Current strategey for limiting the line to search is by only parsing the first comment block.
1 parent 9fdb0e7 commit e92e66f

File tree

3 files changed

+32
-23
lines changed

3 files changed

+32
-23
lines changed

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "llvm/Support/MemoryBuffer.h"
3838
#include "llvm/Support/Path.h"
3939
#include "llvm/Support/CommandLine.h"
40+
#include <optional>
4041
#include <system_error>
4142

4243
using namespace swift;
@@ -1259,16 +1260,32 @@ void swift::serialization::diagnoseSerializedASTLoadFailureTransitive(
12591260
}
12601261
}
12611262

1263+
static std::optional<StringRef> getFlagsFromInterfaceFile(StringRef &file,
1264+
StringRef prefix) {
1265+
StringRef line, buffer = file;
1266+
while (!buffer.empty()) {
1267+
std::tie(line, buffer) = buffer.split('\n');
1268+
// If the line is no longer comments, return not found.
1269+
if (!line.consume_front("// "))
1270+
return std::nullopt;
1271+
1272+
if (line.consume_front(prefix) && line.consume_front(":")) {
1273+
file = buffer;
1274+
return line;
1275+
}
1276+
}
1277+
1278+
return std::nullopt;
1279+
}
1280+
12621281
bool swift::extractCompilerFlagsFromInterface(
12631282
StringRef interfacePath, StringRef buffer, llvm::StringSaver &ArgSaver,
12641283
SmallVectorImpl<const char *> &SubArgs,
12651284
std::optional<llvm::Triple> PreferredTarget) {
1266-
SmallVector<StringRef, 1> FlagMatches;
1267-
auto FlagRe = llvm::Regex("^// swift-module-flags:(.*)$", llvm::Regex::Newline);
1268-
if (!FlagRe.match(buffer, &FlagMatches))
1285+
auto FlagMatch = getFlagsFromInterfaceFile(buffer, SWIFT_MODULE_FLAGS_KEY);
1286+
if (!FlagMatch)
12691287
return true;
1270-
assert(FlagMatches.size() == 2);
1271-
llvm::cl::TokenizeGNUCommandLine(FlagMatches[1], ArgSaver, SubArgs);
1288+
llvm::cl::TokenizeGNUCommandLine(*FlagMatch, ArgSaver, SubArgs);
12721289

12731290
// If the target triple parsed from the Swift interface file differs
12741291
// only in subarchitecture from the compatible target triple, then
@@ -1289,28 +1306,22 @@ bool swift::extractCompilerFlagsFromInterface(
12891306
SubArgs[I] = ArgSaver.save(target.str()).data();
12901307
}
12911308

1292-
SmallVector<StringRef, 1> IgnFlagMatches;
1293-
// Cherry-pick supported options from the ignorable list.
1294-
auto IgnFlagRe = llvm::Regex("^// swift-module-flags-ignorable:(.*)$",
1295-
llvm::Regex::Newline);
1296-
auto hasIgnorableFlags = IgnFlagRe.match(buffer, &IgnFlagMatches);
1297-
1298-
// Check for ignorable-private flags
1299-
SmallVector<StringRef, 1> IgnPrivateFlagMatches;
1300-
auto IgnPrivateFlagRe = llvm::Regex("^// swift-module-flags-ignorable-private:(.*)$",
1301-
llvm::Regex::Newline);
1302-
auto hasIgnorablePrivateFlags = IgnPrivateFlagRe.match(buffer, &IgnPrivateFlagMatches);
1309+
auto IgnFlagMatch =
1310+
getFlagsFromInterfaceFile(buffer, SWIFT_MODULE_FLAGS_IGNORABLE_KEY);
1311+
auto IgnPrivateFlagMatch = getFlagsFromInterfaceFile(
1312+
buffer, SWIFT_MODULE_FLAGS_IGNORABLE_PRIVATE_KEY);
13031313

13041314
// It's OK the interface doesn't have the ignorable list (private or not), we just
13051315
// ignore them all.
1306-
if (!hasIgnorableFlags && !hasIgnorablePrivateFlags)
1316+
if (!IgnFlagMatch && !IgnPrivateFlagMatch)
13071317
return false;
13081318

13091319
SmallVector<const char *, 8> IgnSubArgs;
1310-
if (hasIgnorableFlags)
1311-
llvm::cl::TokenizeGNUCommandLine(IgnFlagMatches[1], ArgSaver, IgnSubArgs);
1312-
if (hasIgnorablePrivateFlags)
1313-
llvm::cl::TokenizeGNUCommandLine(IgnPrivateFlagMatches[1], ArgSaver, IgnSubArgs);
1320+
if (IgnFlagMatch)
1321+
llvm::cl::TokenizeGNUCommandLine(*IgnFlagMatch, ArgSaver, IgnSubArgs);
1322+
if (IgnPrivateFlagMatch)
1323+
llvm::cl::TokenizeGNUCommandLine(*IgnPrivateFlagMatch, ArgSaver,
1324+
IgnSubArgs);
13141325

13151326
std::unique_ptr<llvm::opt::OptTable> table = swift::createSwiftOptTable();
13161327
unsigned missingArgIdx = 0;

test/ModuleInterface/SmokeTest.swiftinterface

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// The "flags" line in this test deliberately has no flags and no space after
22
// the colon, just to make sure that works (even though it'll never be printed
33
// that way).
4-
54
// swift-module-flags:
65
// swift-interface-format-version: 1.0
76

test/SPI/spi_only_import_flag_check.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
@_spiOnly import Empty // expected-error {{'@_spiOnly' requires setting the frontend flag '-experimental-spi-only-imports'}}
3232

3333
//--- Client.private.swiftinterface
34-
3534
// swift-interface-format-version: 1.0
3635
// swift-compiler-version: Swift version 5.8-dev effective-4.1.50
3736
// swift-module-flags: -swift-version 4 -module-name Client

0 commit comments

Comments
 (0)