Skip to content

Commit bb106ee

Browse files
committed
[sil-cse] Fix a bug in the CSE of open_existential_ref instructions
When performing a CSE of open_existential_ref instructions, we replace the new archetype by the old archetype by cloning the uses and re-mapping the archetypes. But we also need to consider that some of the uses of a open_existential_ref instruction (e.g. loads) may produce results depending on the opened archetype being replaced. Therefore, for every such use its own uses (and their uses) should be eventually recursively cloned and type-remapped as well if they depend on the opened archetype being replaced. Fixes rdar://28136015 and https://bugs.swift.org/browse/SR-2545
1 parent 1a4328b commit bb106ee

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

lib/SILOptimizer/Transforms/CSE.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,13 +681,48 @@ bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V,
681681
auto &Builder = Cloner.getBuilder();
682682
Builder.setOpenedArchetypesTracker(&OpenedArchetypesTracker);
683683

684+
llvm::SmallPtrSet<SILInstruction *, 16> Processed;
684685
// Now clone each candidate and replace the opened archetype
685686
// by a dominating one.
686-
for (auto Candidate : Candidates) {
687+
while (!Candidates.empty()) {
688+
auto Candidate = Candidates.pop_back_val();
689+
if (Processed.count(Candidate))
690+
continue;
691+
// True if a candidate depends on the old opened archetype.
692+
bool DependsOnOldOpenedArchetype = !Candidate->getTypeDependentOperands().empty();
693+
if (!Candidate->use_empty() &&
694+
Candidate->getType().getSwiftRValueType()->hasOpenedExistential()) {
695+
// Check if the result type of the candidate depends on the opened
696+
// existential in question.
697+
auto ResultDependsOnOldOpenedArchetype =
698+
Candidate->getType().getSwiftRValueType().findIf(
699+
[&OldOpenedArchetype](Type t) -> bool {
700+
if (t.getCanonicalTypeOrNull() == OldOpenedArchetype)
701+
return true;
702+
return false;
703+
});
704+
if (ResultDependsOnOldOpenedArchetype) {
705+
DependsOnOldOpenedArchetype |= ResultDependsOnOldOpenedArchetype;
706+
// We need to update uses of this candidate, because their types
707+
// may be affected.
708+
for (auto Use : Candidate->getUses()) {
709+
Candidates.insert(Use->getUser());
710+
}
711+
}
712+
}
713+
// Remember that this candidate was processed already.
714+
Processed.insert(Candidate);
715+
716+
// No need to clone if there is no dependency on the old opened archetype.
717+
if (!DependsOnOldOpenedArchetype)
718+
continue;
719+
687720
Builder.getOpenedArchetypes().addOpenedArchetypeOperands(
688721
Candidate->getTypeDependentOperands());
689722
Builder.setInsertionPoint(Candidate);
690723
auto NewI = Cloner.clone(Candidate);
724+
// Result types of candidate's uses instructions may be using this archetype.
725+
// Thus, we need to try to replace it there.
691726
Candidate->replaceAllUsesWith(NewI);
692727
if (I == Candidate->getIterator())
693728
I = NewI->getIterator();

test/SILOptimizer/cse.sil

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,8 @@ protocol Proto : class {
13251325
}
13261326

13271327
// Check that all open_existential_ref instructions are CSEd
1328+
// Any reference to the $@opened("1B685052-4796-11E6-B7DF-B8E856428C60") Proto should be replaced by
1329+
// references to $@opened("1B68354A-4796-11E6-B7DF-B8E856428C60") Proto.
13281330
// CHECK-LABEL: sil @cse_open_existential : $@convention(thin) (@guaranteed Proto, Bool) -> ()
13291331
// CHECK: bb0
13301332
// CHECK: %[[OPENED_EXISTENTIAL:[0-9]+]] = open_existential_ref %{{[0-9]+}} : $Proto to $@opened("1B68354A-4796-11E6-B7DF-B8E856428C60") Proto
@@ -1334,10 +1336,12 @@ protocol Proto : class {
13341336
// CHECK: bb1:
13351337
// CHECK-NEXT: %[[WM2:[0-9]+]] = witness_method $@opened("1B68354A-4796-11E6-B7DF-B8E856428C60") Proto, #Proto.doThat!1
13361338
// CHECK-NEXT: apply %[[WM2]]{{.*}}(%[[OPENED_EXISTENTIAL]])
1337-
// CHECK-NEXT: br bb
1339+
// CHECK-NOT: 1B6851A6-4796-11E6-B7DF-B8E856428C60
1340+
// CHECK: br bb
13381341
// CHECK: bb2:
13391342
// CHECK-NEXT: apply %[[WM1]]{{.*}}(%[[OPENED_EXISTENTIAL]])
1340-
// CHECK-NEXT: br bb
1343+
// CHECK-NOT: 1B6851A6-4796-11E6-B7DF-B8E856428C60
1344+
// CHECK: br bb
13411345
// CHECK: bb3:
13421346
// CHECK-NEXT: tuple
13431347
// CHECK-NEXT: return
@@ -1359,10 +1363,16 @@ bb2: // Preds: bb0
13591363
%13 = open_existential_ref %0 : $Proto to $@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60") Proto
13601364
%14 = witness_method $@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60") Proto, #Proto.doThis!1, %13 : $@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60") Proto : $@convention(witness_method) <τ_0_0 where τ_0_0 : Proto> (@guaranteed τ_0_0) -> ()
13611365
%15 = apply %14<@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60") Proto>(%13) : $@convention(witness_method) <τ_0_0 where τ_0_0 : Proto> (@guaranteed τ_0_0) -> ()
1366+
%16 = alloc_stack $@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60") Proto
1367+
store %13 to %16 : $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60") Proto
1368+
// This is to check that result types of instructions are updated by CSE as well.
1369+
%17 = load %16 : $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60") Proto
1370+
strong_release %17 : $@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60") Proto
1371+
dealloc_stack %16 : $*@opened("1B6851A6-4796-11E6-B7DF-B8E856428C60") Proto
13621372
br bb3
13631373

13641374
bb3:
1365-
%17 = tuple ()
1366-
return %17 : $()
1375+
%20 = tuple ()
1376+
return %20 : $()
13671377
}
13681378

0 commit comments

Comments
 (0)