Skip to content

Commit 2f9ee20

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 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 unresoved.
1 parent 840c0d9 commit 2f9ee20

File tree

8 files changed

+247
-202
lines changed

8 files changed

+247
-202
lines changed

include/swift/SIL/SILOpenedArchetypesTracker.h

Lines changed: 2 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);

lib/SIL/SILOpenedArchetypesTracker.cpp

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

1515
using namespace swift;
1616

17+
void SILOpenedArchetypesTracker::addOpenedArchetypeDef(Type archetype,
18+
SILValue Def) {
19+
auto OldDef = getOpenedArchetypeDef(archetype);
20+
if (OldDef && isa<GlobalAddrInst>(OldDef)) {
21+
// It is a forward definition created during deserialization.
22+
// Replace it with the real definition now.
23+
OldDef->replaceAllUsesWith(Def);
24+
OldDef = SILValue();
25+
}
26+
assert(!OldDef &&
27+
"There can be only one definition of an opened archetype");
28+
OpenedArchetypeDefs[archetype] = Def;
29+
}
30+
1731
// Register archetypes opened by a given instruction.
1832
// Can be used to incrementally populate the mapping, e.g.
1933
// if it is done when performing a scan of all instructions

lib/Serialization/DeserializeSIL.cpp

Lines changed: 205 additions & 167 deletions
Large diffs are not rendered by default.

lib/Serialization/DeserializeSIL.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ namespace swift {
108108
readDefaultWitnessTable(serialization::DeclID,
109109
SILDefaultWitnessTable *existingWt);
110110

111+
/// A helper method to get a type based on a TypeID.
112+
/// If this type is an opened archetype and its
113+
/// definition is not seen yet, create a placeholder
114+
/// SILValue representing a forward definition and
115+
/// register it as a definition of this opened archetype.
116+
Type getType(SILBuilder &Builder, ModuleFile *MF,
117+
serialization::TypeID TID);
118+
111119
public:
112120
Identifier getModuleIdentifier() const {
113121
return MF->getAssociatedModule()->getName();

lib/Serialization/SerializeSIL.cpp

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -392,31 +392,20 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) {
392392
// Assign a value ID to each SILInstruction that has value and to each basic
393393
// block argument.
394394
unsigned ValueID = 0;
395-
llvm::ReversePostOrderTraversal<SILFunction *> RPOT(
396-
const_cast<SILFunction *>(&F));
397-
for (auto Iter = RPOT.begin(), E = RPOT.end(); Iter != E; ++Iter) {
398-
auto &BB = **Iter;
395+
for (const auto &BB : F) {
399396
BasicBlockMap.insert(std::make_pair(&BB, BasicID++));
400397

401398
for (auto I = BB.bbarg_begin(), E = BB.bbarg_end(); I != E; ++I)
402399
ValueIDs[static_cast<const ValueBase*>(*I)] = ++ValueID;
403400

404-
for (const SILInstruction &SI : BB)
401+
for (const auto &SI : BB)
405402
if (SI.hasValue())
406403
ValueIDs[&SI] = ++ValueID;
407404
}
408405

409-
// Write SIL basic blocks in the RPOT order
410-
// to make sure that instructions defining open archetypes
411-
// are serialized before instructions using those opened
412-
// archetypes.
413-
unsigned SerializedBBNum = 0;
414-
for (auto Iter = RPOT.begin(), E = RPOT.end(); Iter != E; ++Iter) {
415-
auto *BB = *Iter;
416-
writeSILBasicBlock(*BB);
417-
SerializedBBNum++;
406+
for (const auto &BB : F) {
407+
writeSILBasicBlock(BB);
418408
}
419-
assert(BasicID == SerializedBBNum && "Wrong number of BBs was serialized");
420409
}
421410

422411
void SILSerializer::writeSILBasicBlock(const SILBasicBlock &BB) {

test/ClangModules/serialization-sil.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,36 @@ public func testPartialApply(_ obj: Test) {
1010
// CHECK-LABEL: @_TF4Test16testPartialApplyFPSo4Test_T_ : $@convention(thin) (@owned Test) -> () {
1111
if let curried1 = obj.normalObject {
1212
// CHECK: dynamic_method_br [[CURRIED1_OBJ:%.+]] : $@opened([[CURRIED1_EXISTENTIAL:.+]]) Test, #Test.normalObject!1.foreign, [[CURRIED1_TRUE:[^,]+]], [[CURRIED1_FALSE:[^,]+]]
13-
// CHECK: [[CURRIED1_FALSE]]:
1413
// CHECK: [[CURRIED1_TRUE]]([[CURRIED1_METHOD:%.+]] : $@convention(objc_method) (@opened([[CURRIED1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject):
1514
// CHECK: [[CURRIED1_PARTIAL:%.+]] = partial_apply [[CURRIED1_METHOD]]([[CURRIED1_OBJ]]) : $@convention(objc_method) (@opened([[CURRIED1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject
1615
// CHECK: [[CURRIED1_THUNK:%.+]] = function_ref @_TTRXFo__oPs9AnyObject__XFo_iT__iPS___ : $@convention(thin) (@in (), @owned @callee_owned () -> @owned AnyObject) -> @out AnyObject
1716
// CHECK: = partial_apply [[CURRIED1_THUNK]]([[CURRIED1_PARTIAL]]) : $@convention(thin) (@in (), @owned @callee_owned () -> @owned AnyObject) -> @out AnyObject
17+
// CHECK: [[CURRIED1_FALSE]]:
1818
curried1()
1919
}
2020
if let curried2 = obj.innerPointer {
2121
// CHECK: dynamic_method_br [[CURRIED2_OBJ:%.+]] : $@opened([[CURRIED2_EXISTENTIAL:.+]]) Test, #Test.innerPointer!1.foreign, [[CURRIED2_TRUE:[^,]+]], [[CURRIED2_FALSE:[^,]+]]
22-
// CHECK: [[CURRIED2_FALSE]]:
2322
// CHECK: [[CURRIED2_TRUE]]([[CURRIED2_METHOD:%.+]] : $@convention(objc_method) (@opened([[CURRIED2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutablePointer<()>):
2423
// CHECK: [[CURRIED2_PARTIAL:%.+]] = partial_apply [[CURRIED2_METHOD]]([[CURRIED2_OBJ]]) : $@convention(objc_method) (@opened([[CURRIED2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutablePointer<()>
2524
// CHECK: [[CURRIED2_THUNK:%.+]] = function_ref @_TTRXFo__dGSpT___XFo_iT__iGSpT___ : $@convention(thin) (@in (), @owned @callee_owned () -> UnsafeMutablePointer<()>) -> @out UnsafeMutablePointer<()>
2625
// CHECK: = partial_apply [[CURRIED2_THUNK]]([[CURRIED2_PARTIAL]]) : $@convention(thin) (@in (), @owned @callee_owned () -> UnsafeMutablePointer<()>) -> @out UnsafeMutablePointer<()>
26+
// CHECK: [[CURRIED2_FALSE]]:
2727
curried2()
2828
}
2929
if let prop1 = obj.normalObjectProp {
3030
// CHECK: dynamic_method_br [[PROP1_OBJ:%.+]] : $@opened([[PROP1_EXISTENTIAL:.+]]) Test, #Test.normalObjectProp!getter.1.foreign, [[PROP1_TRUE:[^,]+]], [[PROP1_FALSE:[^,]+]]
31-
// CHECK: [[PROP1_FALSE]]:
3231
// CHECK: [[PROP1_TRUE]]([[PROP1_METHOD:%.+]] : $@convention(objc_method) (@opened([[PROP1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject):
3332
// CHECK: [[PROP1_PARTIAL:%.+]] = partial_apply [[PROP1_METHOD]]([[PROP1_OBJ]]) : $@convention(objc_method) (@opened([[PROP1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject
3433
// CHECK: = apply [[PROP1_PARTIAL]]() : $@callee_owned () -> @owned AnyObject
34+
// CHECK: [[PROP1_FALSE]]:
3535
_ = prop1
3636
}
3737
if let prop2 = obj.innerPointerProp {
3838
// CHECK: dynamic_method_br [[PROP2_OBJ:%.+]] : $@opened([[PROP2_EXISTENTIAL:.+]]) Test, #Test.innerPointerProp!getter.1.foreign, [[PROP2_TRUE:[^,]+]], [[PROP2_FALSE:[^,]+]]
39-
// CHECK: [[PROP2_FALSE]]:
4039
// CHECK: [[PROP2_TRUE]]([[PROP2_METHOD:%.+]] : $@convention(objc_method) (@opened([[PROP2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutablePointer<()>):
4140
// CHECK: [[PROP2_PARTIAL:%.+]] = partial_apply [[PROP2_METHOD]]([[PROP2_OBJ]]) : $@convention(objc_method) (@opened([[PROP2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutablePointer<()>
4241
// CHECK: = apply [[PROP2_PARTIAL]]() : $@callee_owned () -> UnsafeMutablePointer<()>
42+
// CHECK: [[PROP2_FALSE]]:
4343
_ = prop2
4444
}
4545
} // CHECK: {{^}$}}

test/Serialization/Inputs/def_basic.sil

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ bb1:
7777
// CHECK-LABEL: sil public_external [fragile] @test2 : $@convention(thin) (Int) -> ()
7878
sil [fragile] @test2 : $@convention(thin) (Int) -> () {
7979
// CHECK: bb1:
80-
// CHECK: %[[VAL:[0-9]+]] = tuple ()
81-
// CHECK: br bb2
80+
// CHECK: return %5 : $()
8281
// CHECK: bb2:
83-
// CHECK: return %[[VAL]] : $()
82+
// CHECK: %5 = tuple ()
83+
// CHECK: br bb1
8484
bb0(%0 : $Int):
8585
br bb2
8686
bb1:
@@ -602,7 +602,7 @@ bb3(%6 : $Builtin.Word):
602602
sil [fragile] @test_cond_branch_basic_block_args : $@convention(thin) (Int, Builtin.Int1) -> Int {
603603
bb0(%0 : $Int, %1 : $Builtin.Int1):
604604
cond_br %1, bb1(%0 : $Int), bb2(%0 : $Int)
605-
// CHECK: cond_br %1, bb2(%0 : $Int), bb1(%0 : $Int)
605+
// CHECK: cond_br %1, bb1(%0 : $Int), bb2(%0 : $Int)
606606
bb1(%3 : $Int):
607607
br bb3 (%3 : $Int)
608608
bb2(%2 : $Int):
@@ -716,13 +716,12 @@ bb1:
716716
bb2:
717717
%7 = function_ref @_TF6switch1aFT_T_ : $@convention(thin) () -> ()
718718
%8 = apply %7() : $@convention(thin) () -> ()
719-
br bb5
719+
br bb5 // CHECK: br
720720

721721
bb3(%10 : $Int):
722722
// CHECK: unchecked_enum_data {{%.*}} : $MaybePair, #MaybePair.Left!enumelt.1
723723
%x = unchecked_enum_data %3 : $MaybePair, #MaybePair.Left!enumelt.1
724724
br bb4(%x : $Int)
725-
// CHECK: br
726725

727726
bb4(%y : $Int):
728727
%12 = function_ref @_TF6switch1bFT_T_ : $@convention(thin) () -> ()
@@ -764,7 +763,7 @@ bb3:
764763
// CHECK-LABEL: sil public_external [fragile] @test_switch_value : $@convention(thin) (Builtin.Word) -> ()
765764
sil [fragile] @test_switch_value : $@convention(thin) (Builtin.Word) -> () {
766765
bb0(%0 : $Builtin.Word):
767-
// CHECK: switch_value %{{.*}} : $Builtin.Word, case %1: bb2, case %2: bb1
766+
// CHECK: switch_value %{{.*}} : $Builtin.Word, case %1: bb1, case %2: bb2
768767
%1 = integer_literal $Builtin.Word, 1
769768
%2 = integer_literal $Builtin.Word, 2
770769
switch_value %0 : $Builtin.Word, case %1: bb1, case %2: bb2
@@ -1017,7 +1016,7 @@ sil [fragile] @block_invoke : $@convention(c) (@inout_aliasable @block_storage I
10171016
// CHECK-LABEL: sil public_external [fragile] @test_try_apply : $@convention(thin) (@convention(thin) () -> @error Error) -> @error Error {
10181017
sil [fragile] @test_try_apply : $@convention(thin) (@convention(thin) () -> @error Error) -> @error Error {
10191018
bb0(%0 : $@convention(thin) () -> @error Error):
1020-
// CHECK: try_apply %0() : $@convention(thin) () -> @error Error, normal bb2, error bb1
1019+
// CHECK: try_apply %0() : $@convention(thin) () -> @error Error, normal bb1, error bb2
10211020
try_apply %0() : $@convention(thin) () -> @error Error, normal bb1, error bb2
10221021

10231022
bb1(%1 : $()):

test/Serialization/transparent.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ func wrap_br() {
4444
// SIL: bb0(%0 : $MaybePair):
4545
// SIL: retain_value %0 : $MaybePair
4646
// SIL: switch_enum %0 : $MaybePair, case #MaybePair.Neither!enumelt: bb[[CASE1:[0-9]+]], case #MaybePair.Left!enumelt.1: bb[[CASE2:[0-9]+]], case #MaybePair.Right!enumelt.1: bb[[CASE3:[0-9]+]], case #MaybePair.Both!enumelt.1: bb[[CASE4:[0-9]+]]
47-
// SIL: bb[[CASE4]](%{{.*}} : $(Int32, String)):
48-
// SIL: bb[[CASE3]](%{{.*}} : $String):
49-
// SIL: bb[[CASE2]](%{{.*}} : $Int32):
5047
// SIL: bb[[CASE1]]:
48+
// SIL: bb[[CASE2]](%{{.*}} : $Int32):
49+
// SIL: bb[[CASE3]](%{{.*}} : $String):
50+
// SIL: bb[[CASE4]](%{{.*}} : $(Int32, String)):
5151
func test_switch(u: MaybePair) {
5252
do_switch(u: u)
5353
}

0 commit comments

Comments
 (0)