Skip to content

Commit c85f167

Browse files
committed
Serialize library level into .swiftmodule binary format
Add a LIBRARY_LEVEL record to the .swiftmodule options block so the declared -library-level value survives across compilations. Without this, imported modules have to always fell back to a path heuristic that could only distinguish API vs SPI and never returned IPI. rdar://174255626
1 parent abdfece commit c85f167

13 files changed

Lines changed: 121 additions & 11 deletions

File tree

include/swift/AST/Decl.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
778778
HasLazyUnderlyingSubstitutions : 1
779779
);
780780

781-
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+8+1,
781+
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+8+1+2,
782782
/// If the module is compiled as static library.
783783
StaticLibrary : 1,
784784

@@ -854,7 +854,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
854854

855855
/// Whether this module was compile with "aggressive" CMO i.e
856856
/// the flag: -cross-module-optimization.
857-
AggressiveCMOEnabled : 1
857+
AggressiveCMOEnabled : 1,
858+
859+
/// The stored library level from deserialized module data (LibraryLevel).
860+
StoredLibraryLevel : 2
858861
);
859862

860863
SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2,

include/swift/AST/Module.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,15 @@ class ModuleDecl
715715
/// Distribution level of the module.
716716
LibraryLevel getLibraryLevel() const;
717717

718+
/// The stored library level from deserialized module data.
719+
/// Returns LibraryLevel::Other if no level was stored.
720+
LibraryLevel getStoredLibraryLevel() const {
721+
return LibraryLevel(Bits.ModuleDecl.StoredLibraryLevel);
722+
}
723+
void setStoredLibraryLevel(LibraryLevel level) {
724+
Bits.ModuleDecl.StoredLibraryLevel = unsigned(level);
725+
}
726+
718727
/// Returns true if this module was or is being compiled for testing.
719728
bool hasIncrementalInfo() const { return Bits.ModuleDecl.HasIncrementalInfo; }
720729
void setHasIncrementalInfo(bool enabled = true) {

include/swift/Serialization/Validation.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/AST/Identifier.h"
1717
#include "swift/Basic/CXXStdlibKind.h"
1818
#include "swift/Basic/LLVM.h"
19+
#include "swift/Basic/LangOptions.h"
1920
#include "swift/Basic/SourceLoc.h"
2021
#include "swift/Basic/Version.h"
2122
#include "swift/Parse/ParseVersion.h"
@@ -153,6 +154,7 @@ class ExtendedValidationInfo {
153154
unsigned StrictMemorySafety: 1;
154155
unsigned DeferredCodeGen: 1;
155156
unsigned AggressiveCMOEnabled : 1;
157+
unsigned LibraryLevel : 2;
156158
} Bits;
157159

158160
public:
@@ -277,6 +279,13 @@ class ExtendedValidationInfo {
277279
Bits.AggressiveCMOEnabled = val;
278280
}
279281

282+
LibraryLevel getLibraryLevel() const {
283+
return LibraryLevel(Bits.LibraryLevel);
284+
}
285+
void setLibraryLevel(LibraryLevel level) {
286+
Bits.LibraryLevel = unsigned(level);
287+
}
288+
280289
bool hasCxxInteroperability() const { return Bits.HasCxxInteroperability; }
281290
void setHasCxxInteroperability(bool val) {
282291
Bits.HasCxxInteroperability = val;

lib/AST/Module.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3331,8 +3331,13 @@ ModuleLibraryLevelRequest::evaluate(Evaluator &evaluator,
33313331
return ctx.LangOpts.LibraryLevel;
33323332

33333333
} else {
3334-
// Other Swift modules are SPI if they are from the PrivateFrameworks
3335-
// folder in the SDK.
3334+
// IPI is never returned by the path heuristic, so the stored value
3335+
// is the only way to detect it.
3336+
auto stored = module->getStoredLibraryLevel();
3337+
if (stored == LibraryLevel::IPI)
3338+
return stored;
3339+
3340+
// For API/SPI, use the path heuristic as before.
33363341
auto modulePath = module->getModuleFilename();
33373342
return fromPrivateFrameworks(modulePath) ?
33383343
LibraryLevel::SPI : LibraryLevel::API;

lib/Serialization/ModuleFile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,9 @@ class ModuleFile
722722
/// (the flag -cross-module-optimization).
723723
bool isAggressiveCMOEnabled() const { return Core->isAggressiveCMOEnabled(); }
724724

725+
/// The library level of this module.
726+
LibraryLevel getLibraryLevel() const { return Core->getLibraryLevel(); }
727+
725728
/// Associates this module file with the AST node representing it.
726729
///
727730
/// Checks that the file is compatible with the AST module it's being loaded

lib/Serialization/ModuleFileSharedCore.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,12 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
237237
case options_block::AGGRESSIVE_CMO:
238238
extendedInfo.setAggressiveCMOEnabled(true);
239239
break;
240+
case options_block::LIBRARY_LEVEL: {
241+
unsigned rawLevel;
242+
options_block::LibraryLevelLayout::readRecord(scratch, rawLevel);
243+
extendedInfo.setLibraryLevel(LibraryLevel(rawLevel));
244+
break;
245+
}
240246
default:
241247
// Unknown options record, possibly for use by a future version of the
242248
// module format.
@@ -1605,6 +1611,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
16051611
Bits.StrictMemorySafety = extInfo.strictMemorySafety();
16061612
Bits.DeferredCodeGen = extInfo.deferredCodeGen();
16071613
Bits.AggressiveCMOEnabled = extInfo.isAggressiveCMOEnabled();
1614+
Bits.LibraryLevel = unsigned(extInfo.getLibraryLevel());
16081615
MiscVersion = info.miscVersion;
16091616
SDKVersion = info.sdkVersion;
16101617
ModuleABIName = extInfo.getModuleABIName();

lib/Serialization/ModuleFileSharedCore.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,9 @@ class ModuleFileSharedCore {
425425
/// Whether this module used deferred code generation.
426426
unsigned AggressiveCMOEnabled : 1;
427427

428+
/// Discriminator for library level (LibraryLevel enum).
429+
unsigned LibraryLevel : 2;
430+
428431
// Explicitly pad out to the next word boundary if neccessary.
429432
} Bits = {};
430433
static_assert(sizeof(ModuleBits) <= 8, "The bit set should be small");
@@ -702,6 +705,10 @@ class ModuleFileSharedCore {
702705

703706
bool isAggressiveCMOEnabled() const { return Bits.AggressiveCMOEnabled; }
704707

708+
LibraryLevel getLibraryLevel() const {
709+
return LibraryLevel(Bits.LibraryLevel);
710+
}
711+
705712
/// How should \p dependency be loaded for a transitive import via \c this?
706713
///
707714
/// If \p importNonPublicDependencies, more transitive dependencies

lib/Serialization/ModuleFormat.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 990; // vtable conformance entries
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 991; // add LIBRARY_LEVEL to options_block
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -1004,6 +1004,7 @@ namespace options_block {
10041004
DEFERRED_CODE_GEN,
10051005
OSLOG_STRING_SECTION_NAME,
10061006
AGGRESSIVE_CMO,
1007+
LIBRARY_LEVEL,
10071008
};
10081009

10091010
using SDKPathLayout = BCRecordLayout<
@@ -1126,6 +1127,11 @@ namespace options_block {
11261127
SWIFT_INTERFACE_COMPILER_VERSION,
11271128
BCBlob // version tuple
11281129
>;
1130+
1131+
using LibraryLevelLayout = BCRecordLayout<
1132+
LIBRARY_LEVEL,
1133+
BCFixed<2>
1134+
>;
11291135
}
11301136

11311137
/// The record types within the input block.

lib/Serialization/ScanningLoaders.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,23 @@ SwiftModuleScanner::scanInterfaceFile(Identifier moduleID,
222222
bool isStrictMemorySafety =
223223
llvm::find(ArgsRefs, "-strict-memory-safety") != ArgsRefs.end();
224224

225+
LibraryLevel libraryLevel = LibraryLevel::Other;
226+
auto libLevelIt = llvm::find(ArgsRefs, "-library-level");
227+
if (libLevelIt != ArgsRefs.end() &&
228+
(libLevelIt + 1) != ArgsRefs.end()) {
229+
libraryLevel = llvm::StringSwitch<LibraryLevel>(*(libLevelIt + 1))
230+
.Case("api", LibraryLevel::API)
231+
.Case("spi", LibraryLevel::SPI)
232+
.Case("ipi", LibraryLevel::IPI)
233+
.Default(LibraryLevel::Other);
234+
}
235+
225236
Result = ModuleDependencyInfo::forSwiftInterfaceModule(
226237
InPath, compiledCandidatesRefs, ArgsRefs, {}, {}, linkLibraries,
227238
isFramework, isStatic, isStrictMemorySafety, {},
228239
/*module-cache-key*/ "", UserModVer);
240+
if (libraryLevel == LibraryLevel::IPI)
241+
Result->setLibraryLevel(libraryLevel);
229242

230243
// Walk the source file to find the import declarations.
231244
llvm::StringSet<> alreadyAddedModules;
@@ -282,8 +295,8 @@ SwiftModuleScanner::scanInterfaceFile(Identifier moduleID,
282295
if (code) {
283296
return code;
284297
}
285-
// Compute library level based on the interface file path.
286-
{
298+
// Use path heuristic for API/SPI; IPI was already set from the flags above.
299+
if (Result->getLibraryLevel() != LibraryLevel::IPI) {
287300
SmallString<256> modulePathBuf;
288301
StringRef modulePath = moduleInterfacePath.toStringRef(modulePathBuf);
289302
Result->setLibraryLevel(libraryLevelFromPath(
@@ -384,11 +397,17 @@ llvm::ErrorOr<ModuleDependencyInfo> SwiftModuleScanner::scanBinaryModuleFile(
384397
deps->ExecutablePath);
385398
}
386399

387-
// Compute library level based on the binary module path.
400+
// Use the stored value only for IPI; path heuristic handles API/SPI as
401+
// before.
388402
{
389-
dependencies.setLibraryLevel(libraryLevelFromPath(
390-
definingModulePath, Ctx.SearchPathOpts.getSDKPath(),
391-
Ctx.LangOpts.Target));
403+
auto storedLevel = loadedModuleFile->getLibraryLevel();
404+
if (storedLevel == LibraryLevel::IPI) {
405+
dependencies.setLibraryLevel(storedLevel);
406+
} else {
407+
dependencies.setLibraryLevel(libraryLevelFromPath(
408+
definingModulePath, Ctx.SearchPathOpts.getSDKPath(),
409+
Ctx.LangOpts.Target));
410+
}
392411
}
393412

394413
return std::move(dependencies);

lib/Serialization/Serialization.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,7 @@ void Serializer::writeBlockInfoBlock() {
893893
BLOCK_RECORD(options_block, CXX_STDLIB_KIND);
894894
BLOCK_RECORD(options_block, PUBLIC_MODULE_NAME);
895895
BLOCK_RECORD(options_block, SWIFT_INTERFACE_COMPILER_VERSION);
896+
BLOCK_RECORD(options_block, LIBRARY_LEVEL);
896897

897898
BLOCK(INPUT_BLOCK);
898899
BLOCK_RECORD(input_block, IMPORTED_MODULE);
@@ -1225,6 +1226,10 @@ void Serializer::writeHeader() {
12251226
static_cast<uint8_t>(M->getCXXStdlibKind()));
12261227
}
12271228

1229+
options_block::LibraryLevelLayout LibLevel(Out);
1230+
LibLevel.emit(ScratchRecord,
1231+
unsigned(M->getASTContext().LangOpts.LibraryLevel));
1232+
12281233
if (M->isAggressiveCMOEnabled()) {
12291234
options_block::AggressiveCMOEnabledLayout AggressiveCMOEnabled(Out);
12301235
AggressiveCMOEnabled.emit(ScratchRecord);

0 commit comments

Comments
 (0)