Skip to content

Commit 89c41ca

Browse files
committed
[sil-serializer] Do not use RPOT order for serializing SIL basic blocks
My earlier patch started serializing SIL basic blocks using the RPOT order. While it works, changing the existing order of BBs during the serialization may be very surprising for users. After all, serialization is not supposed to transform the code. Therefore, this patch follows a different approach. It uses the existing order of BBs during the serialization. When it deserializes/parses SIL and detects a use of an opened archetype before its definition, it basically introduced a forward definition of this opened archetype. Later on, when the actual definition of the opened archetype is found, it replaces the forward definition. There is a correctness check at the end of a SIL function deserialization, which verifies that there are no forward definitions of opened archetypes left unresolved.
1 parent 183cb54 commit 89c41ca

File tree

7 files changed

+123
-8
lines changed

7 files changed

+123
-8
lines changed

include/swift/SIL/SILOpenedArchetypesTracker.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,8 @@ class SILOpenedArchetypesTracker : public DeleteNotificationHandler {
4949

5050
const SILFunction &getFunction() const { return F; }
5151

52-
void addOpenedArchetypeDef(Type archetype, SILValue Def) {
53-
assert(!getOpenedArchetypeDef(archetype) &&
54-
"There can be only one definition of an opened archetype");
55-
OpenedArchetypeDefs[archetype] = Def;
56-
}
52+
// Register a definiton of a given opened archetype.
53+
void addOpenedArchetypeDef(Type archetype, SILValue Def);
5754

5855
void removeOpenedArchetypeDef(Type archetype, SILValue Def) {
5956
auto FoundDef = getOpenedArchetypeDef(archetype);
@@ -83,10 +80,19 @@ class SILOpenedArchetypesTracker : public DeleteNotificationHandler {
8380
// the typedef operands of this instruction.
8481
void registerUsedOpenedArchetypes(const SILInstruction *I);
8582

83+
// Register opened archetypes referenced by this type, if they
84+
// are not registered yet. Create placeholders representing forward
85+
// definitions of these opened archetypes.
86+
void registerUsedOpenedArchetypes(Type Ty);
87+
8688
// Unregister archetypes opened by a given instruction.
8789
// Should be only called when this instruction is to be removed.
8890
void unregisterOpenedArchetypes(const SILInstruction *I);
8991

92+
// Returns true of some of the forward opened archetype definitions
93+
// are unresolved.
94+
bool hasUnresolvedOpenedArchetypeDefinitions();
95+
9096
// Handling of instruction removal notifications.
9197
bool needsNotifications() { return true; }
9298

include/swift/Serialization/ModuleFile.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class ProtocolConformance;
4343
/// A serialized module, along with the tools to access it.
4444
class ModuleFile : public LazyMemberLoader {
4545
friend class SerializedASTFile;
46+
friend class SILDeserializer;
4647
using Status = serialization::Status;
4748

4849
/// A reference back to the AST representation of the file.
@@ -76,6 +77,9 @@ class ModuleFile : public LazyMemberLoader {
7677
/// The data blob containing all of the module's identifiers.
7778
StringRef IdentifierData;
7879

80+
/// A callback to be invoked every time a type was deserialized.
81+
llvm::function_ref<void(Type)> DeserializedTypeCallback;
82+
7983
public:
8084
/// Represents another module that has been imported as a dependency.
8185
class Dependency {

lib/Parse/ParseSIL.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "swift/Basic/Defer.h"
1314
#include "swift/Basic/Fallthrough.h"
1415
#include "swift/AST/ArchetypeBuilder.h"
1516
#include "swift/AST/NameLookup.h"
@@ -94,6 +95,7 @@ namespace {
9495
};
9596

9697
class SILParser {
98+
friend Parser;
9799
public:
98100
Parser &P;
99101
SILModule &SILMod;
@@ -112,14 +114,19 @@ namespace {
112114
llvm::StringMap<ValueBase*> LocalValues;
113115
llvm::StringMap<SourceLoc> ForwardRefLocalValues;
114116

117+
/// A callback to be invoked every time a type was deserialized.
118+
llvm::function_ref<void(Type)> ParsedTypeCallback;
119+
120+
115121
bool performTypeLocChecking(TypeLoc &T, bool IsSIL = true);
116122
bool parseSpecConformanceSubstitutions(
117123
SmallVectorImpl<ParsedSubstitution> &parsed);
118124
ProtocolConformance *parseProtocolConformanceHelper(ProtocolDecl *&proto,
119125
bool localScope);
120126
public:
121-
122-
SILParser(Parser &P) : P(P), SILMod(*P.SIL->M), TUState(*P.SIL->S) {}
127+
SILParser(Parser &P)
128+
: P(P), SILMod(*P.SIL->M), TUState(*P.SIL->S),
129+
ParsedTypeCallback([](Type ty) {}) {}
123130

124131
/// diagnoseProblems - After a function is fully parse, emit any diagnostics
125132
/// for errors and return true if there were any.
@@ -796,6 +803,8 @@ bool SILParser::parseASTType(CanType &result) {
796803
if (performTypeLocChecking(loc, false))
797804
return true;
798805
result = loc.getType()->getCanonicalType();
806+
// Invoke the callback on the parsed type.
807+
ParsedTypeCallback(loc.getType());
799808
return false;
800809
}
801810

@@ -838,6 +847,10 @@ bool SILParser::parseSILTypeWithoutQualifiers(SILType &Result,
838847

839848
Result = SILType::getPrimitiveType(Ty.getType()->getCanonicalType(),
840849
category);
850+
851+
// Invoke the callback on the parsed type.
852+
ParsedTypeCallback(Ty.getType());
853+
841854
return false;
842855

843856
}
@@ -3922,6 +3935,17 @@ bool Parser::parseDeclSIL() {
39223935
// is required for adding typedef operands to instructions.
39233936
B.setOpenedArchetypesTracker(&OpenedArchetypesTracker);
39243937

3938+
// Define a callback to be invoked on the deserialized types.
3939+
auto OldParsedTypeCallback = FunctionState.ParsedTypeCallback;
3940+
SWIFT_DEFER {
3941+
FunctionState.ParsedTypeCallback = OldParsedTypeCallback;
3942+
};
3943+
3944+
FunctionState.ParsedTypeCallback = [&OpenedArchetypesTracker,
3945+
&FunctionState](Type ty) {
3946+
OpenedArchetypesTracker.registerUsedOpenedArchetypes(ty);
3947+
};
3948+
39253949
do {
39263950
if (FunctionState.parseSILBasicBlock(B))
39273951
return true;
@@ -3930,6 +3954,12 @@ bool Parser::parseDeclSIL() {
39303954
SourceLoc RBraceLoc;
39313955
parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
39323956
LBraceLoc);
3957+
3958+
// Check that there are no unresolved forward definitions of opened
3959+
// archetypes.
3960+
if (OpenedArchetypesTracker.hasUnresolvedOpenedArchetypeDefinitions())
3961+
llvm_unreachable(
3962+
"All forward definitions of opened archetypes should be resolved");
39333963
}
39343964

39353965
FunctionState.F->setLinkage(resolveSILLinkage(FnLinkage, isDefinition));

lib/SIL/SILOpenedArchetypesTracker.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,60 @@
1414

1515
using namespace swift;
1616

17+
void SILOpenedArchetypesTracker::addOpenedArchetypeDef(Type archetype,
18+
SILValue Def) {
19+
archetype = archetype->getDesugaredType();
20+
assert(archetype->is<ArchetypeType>() && "The type should be an archetype");
21+
auto OldDef = getOpenedArchetypeDef(archetype);
22+
if (OldDef && isa<GlobalAddrInst>(OldDef)) {
23+
// It is a forward definition created during deserialization.
24+
// Replace it with the real definition now.
25+
OldDef->replaceAllUsesWith(Def);
26+
OldDef = SILValue();
27+
}
28+
assert(!OldDef &&
29+
"There can be only one definition of an opened archetype");
30+
OpenedArchetypeDefs[archetype] = Def;
31+
}
32+
33+
/// Check if there are any unresolved forward definitions of opened
34+
/// archetypes.
35+
bool SILOpenedArchetypesTracker::hasUnresolvedOpenedArchetypeDefinitions() {
36+
for (auto &KV : getOpenedArchetypeDefs()) {
37+
assert(KV.getFirst()->is<ArchetypeType>() && "The type should be an archetype");
38+
if (!KV.getSecond() || isa<GlobalAddrInst>(KV.getSecond()))
39+
return true;
40+
}
41+
return false;
42+
}
43+
44+
void SILOpenedArchetypesTracker::registerUsedOpenedArchetypes(Type Ty) {
45+
// Nothing else to be done if the type does not contain an opened archetype.
46+
if (!Ty || !Ty->hasOpenedExistential())
47+
return;
48+
49+
// Find all opened existentials used by this type and check if their
50+
// definitions are known.
51+
Ty.visit([&](Type ty) {
52+
if (!ty->isOpenedExistential())
53+
return;
54+
55+
ty = ty->getDesugaredType();
56+
57+
// Nothing to do if a definition was seen already.
58+
if (getOpenedArchetypeDef(ty))
59+
return;
60+
61+
auto &SILMod = this->getFunction().getModule();
62+
// Create a placeholder representing a forward definition.
63+
auto Placeholder = new (SILMod)
64+
GlobalAddrInst(SILDebugLocation(), SILMod.Types.getLoweredType(ty));
65+
// Make it available to SILBuilder, so that instructions using this
66+
// archetype can be constructed.
67+
addOpenedArchetypeDef(ty, Placeholder);
68+
});
69+
}
70+
1771
// Register archetypes opened by a given instruction.
1872
// Can be used to incrementally populate the mapping, e.g.
1973
// if it is done when performing a scan of all instructions

lib/Serialization/Deserialization.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4072,6 +4072,9 @@ Type ModuleFile::getType(TypeID TID) {
40724072
return nullptr;
40734073
}
40744074

4075+
// Invoke the callback on the deserialized type.
4076+
DeserializedTypeCallback(typeOrOffset);
4077+
40754078
return typeOrOffset;
40764079
}
40774080

lib/Serialization/DeserializeSIL.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#define DEBUG_TYPE "deserialize"
1414
#include "DeserializeSIL.h"
15+
#include "swift/Basic/Defer.h"
1516
#include "swift/Serialization/ModuleFile.h"
1617
#include "SILFormat.h"
1718
#include "swift/SIL/SILArgument.h"
@@ -559,6 +560,16 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
559560
// is required for adding typedef operands to instructions.
560561
Builder.setOpenedArchetypesTracker(&OpenedArchetypesTracker);
561562

563+
// Define a callback to be invoked on the deserialized types.
564+
auto OldDeserializedTypeCallback = MF->DeserializedTypeCallback;
565+
SWIFT_DEFER {
566+
MF->DeserializedTypeCallback = OldDeserializedTypeCallback;
567+
};
568+
569+
MF->DeserializedTypeCallback = [&OpenedArchetypesTracker] (Type ty) {
570+
OpenedArchetypesTracker.registerUsedOpenedArchetypes(ty);
571+
};
572+
562573
// Another SIL_FUNCTION record means the end of this SILFunction.
563574
// SIL_VTABLE or SIL_GLOBALVAR or SIL_WITNESS_TABLE record also means the end
564575
// of this SILFunction.
@@ -598,6 +609,12 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
598609
if (fn->empty() && errorIfEmptyBody)
599610
return nullptr;
600611

612+
// Check that there are no unresolved forward definitions of opened
613+
// archetypes.
614+
if (OpenedArchetypesTracker.hasUnresolvedOpenedArchetypeDefinitions())
615+
llvm_unreachable(
616+
"All forward definitions of opened archetypes should be resolved");
617+
601618
if (Callback)
602619
Callback->didDeserializeFunctionBody(MF->getAssociatedModule(), fn);
603620

lib/Serialization/ModuleFile.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,8 @@ ModuleFile::ModuleFile(
755755
ModuleInputReader(getStartBytePtr(this->ModuleInputBuffer.get()),
756756
getEndBytePtr(this->ModuleInputBuffer.get())),
757757
ModuleDocInputReader(getStartBytePtr(this->ModuleDocInputBuffer.get()),
758-
getEndBytePtr(this->ModuleDocInputBuffer.get())) {
758+
getEndBytePtr(this->ModuleDocInputBuffer.get())),
759+
DeserializedTypeCallback([](Type ty) {}) {
759760
assert(getStatus() == Status::Valid);
760761
Bits.IsFramework = isFramework;
761762

0 commit comments

Comments
 (0)