Skip to content

Commit 2f7f657

Browse files
authored
Merge pull request #72066 from eeckstein/fix-cse
CSE: visit uses of block arguments when replacing an open_existental_ref
2 parents cccd1b4 + f8640e6 commit 2f7f657

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

lib/SILOptimizer/Transforms/CSE.cpp

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,8 @@ bool CSE::processLazyPropertyGetters(SILFunction &F) {
832832
/// according to the provided type substitution map.
833833
static void updateBasicBlockArgTypes(SILBasicBlock *BB,
834834
ArchetypeType *OldOpenedArchetype,
835-
ArchetypeType *NewOpenedArchetype) {
835+
ArchetypeType *NewOpenedArchetype,
836+
InstructionWorklist &usersToHandle) {
836837
// Check types of all BB arguments.
837838
for (auto *Arg : BB->getSILPhiArguments()) {
838839
if (!Arg->getType().hasOpenedExistential())
@@ -868,6 +869,7 @@ static void updateBasicBlockArgTypes(SILBasicBlock *BB,
868869
// Restore all uses to refer to the BB argument with updated type.
869870
for (auto ArgUse : OriginalArgUses) {
870871
ArgUse->set(NewArg);
872+
usersToHandle.pushIfNotVisited(ArgUse->getUser());
871873
}
872874
}
873875
}
@@ -879,7 +881,7 @@ static void updateBasicBlockArgTypes(SILBasicBlock *BB,
879881
/// \V is the dominating open_existential_ref instruction
880882
bool CSE::processOpenExistentialRef(OpenExistentialRefInst *Inst,
881883
OpenExistentialRefInst *VI) {
882-
llvm::SmallSetVector<SILInstruction *, 16> Candidates;
884+
InstructionWorklist usersToHandle(Inst->getFunction());
883885
const auto OldOpenedArchetype = Inst->getDefinedOpenedArchetype();
884886
const auto NewOpenedArchetype = VI->getDefinedOpenedArchetype();
885887

@@ -895,8 +897,7 @@ bool CSE::processOpenExistentialRef(OpenExistentialRefInst *Inst,
895897
}
896898
}
897899
}
898-
899-
Candidates.insert(User);
900+
usersToHandle.pushIfNotVisited(User);
900901
}
901902

902903
// Now process candidates.
@@ -907,43 +908,36 @@ bool CSE::processOpenExistentialRef(OpenExistentialRefInst *Inst,
907908
OldOpenedArchetype->castTo<ArchetypeType>(), NewOpenedArchetype);
908909
auto &Builder = Cloner.getBuilder();
909910

910-
InstructionSet Processed(Inst->getFunction());
911911
// Now clone each candidate and replace the opened archetype
912912
// by a dominating one.
913-
while (!Candidates.empty()) {
914-
auto Candidate = Candidates.pop_back_val();
915-
if (Processed.contains(Candidate))
916-
continue;
917-
918-
if (isa<TermInst>(Candidate)) {
913+
while (SILInstruction *user = usersToHandle.pop()) {
914+
if (isa<TermInst>(user)) {
919915
// The current use of the opened archetype is a terminator instruction.
920916
// Check if any of the successor BBs uses this opened archetype in the
921917
// types of its basic block arguments. If this is the case, replace
922918
// those uses by the new opened archetype.
923-
// FIXME: What about uses of those arguments?
924-
for (auto *Successor : Candidate->getParent()->getSuccessorBlocks()) {
919+
for (auto *Successor : user->getParent()->getSuccessorBlocks()) {
925920
if (Successor->args_empty())
926921
continue;
927922
// If a BB has any arguments, update their types if necessary.
928923
updateBasicBlockArgTypes(Successor, OldOpenedArchetype,
929-
NewOpenedArchetype);
924+
NewOpenedArchetype, usersToHandle);
930925
}
931926
}
932927

933928
// Compute if a candidate depends on the old opened archetype.
934929
// It always does if it has any type-dependent operands.
935930
bool DependsOnOldOpenedArchetype =
936-
!Candidate->getTypeDependentOperands().empty();
931+
!user->getTypeDependentOperands().empty();
937932

938933
// Look for dependencies propagated via the candidate's results.
939-
for (auto CandidateResult : Candidate->getResults()) {
940-
if (CandidateResult->use_empty() ||
941-
!CandidateResult->getType().hasOpenedExistential())
934+
for (auto result : user->getResults()) {
935+
if (result->use_empty() || !result->getType().hasOpenedExistential())
942936
continue;
943937

944938
// Check if the result type depends on this specific opened existential.
945939
auto ResultDependsOnOldOpenedArchetype =
946-
CandidateResult->getType().getASTType().findIf(
940+
result->getType().getASTType().findIf(
947941
[&OldOpenedArchetype](Type t) -> bool {
948942
return (CanType(t) == OldOpenedArchetype);
949943
});
@@ -953,24 +947,22 @@ bool CSE::processOpenExistentialRef(OpenExistentialRefInst *Inst,
953947
DependsOnOldOpenedArchetype = true;
954948

955949
// The users of this candidate are new candidates.
956-
for (auto Use : CandidateResult->getUses()) {
957-
Candidates.insert(Use->getUser());
950+
for (auto Use : result->getUses()) {
951+
usersToHandle.pushIfNotVisited(Use->getUser());
958952
}
959953
}
960954
}
961-
// Remember that this candidate was processed already.
962-
Processed.insert(Candidate);
963955

964956
// No need to clone if there is no dependency on the old opened archetype.
965957
if (!DependsOnOldOpenedArchetype)
966958
continue;
967959

968-
Builder.setInsertionPoint(Candidate);
969-
auto NewI = Cloner.clone(Candidate);
960+
Builder.setInsertionPoint(user);
961+
auto NewI = Cloner.clone(user);
970962
// Result types of candidate's uses instructions may be using this archetype.
971963
// Thus, we need to try to replace it there.
972-
Candidate->replaceAllUsesPairwiseWith(NewI);
973-
eraseFromParentWithDebugInsts(Candidate);
964+
user->replaceAllUsesPairwiseWith(NewI);
965+
eraseFromParentWithDebugInsts(user);
974966
}
975967
return true;
976968
}

test/SILOptimizer/cse_objc.sil

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,3 +277,30 @@ sil_vtable Bar {
277277
#Bar.walk: @_TFC4test3Bar4walkfS0_FT_T_ // test.Bar.walk (test.Bar)() -> ()
278278
#Bar.deinit!deallocator: @_TFC4test3BarD // test.Bar.__deallocating_deinit
279279
}
280+
281+
@objc public protocol P {
282+
@objc optional func f() -> Bool
283+
}
284+
285+
// CHECK-LABEL: sil @test_open_existential :
286+
// CHECK: partial_apply [callee_guaranteed] {{%[0-9]+}}(%1) : $@convention(objc_method) (@opened("2FD52A00-DA20-11EE-8801-0EA13E3AABAF", any P) Self) -> ObjCBool // type-defs: %1
287+
// CHECK: } // end sil function 'test_open_existential'
288+
sil @test_open_existential : $@convention(thin) (@guaranteed P) -> () {
289+
bb0(%0 : $any P):
290+
%1 = open_existential_ref %0 : $any P to $@opened("2FD52A00-DA20-11EE-8801-0EA13E3AABAF", any P) Self
291+
fix_lifetime %1 : $@opened("2FD52A00-DA20-11EE-8801-0EA13E3AABAF", any P) Self
292+
%2 = open_existential_ref %0 : $any P to $@opened("2FD52A04-DA20-11EE-8801-0EA13E3AABAF", any P) Self
293+
br bb2
294+
295+
bb1(%4 : $@convention(objc_method) (@opened("2FD52A04-DA20-11EE-8801-0EA13E3AABAF", any P) Self) -> ObjCBool):
296+
%5 = partial_apply [callee_guaranteed] %4(%2) : $@convention(objc_method) (@opened("2FD52A04-DA20-11EE-8801-0EA13E3AABAF", any P) Self) -> ObjCBool
297+
%r = tuple ()
298+
return %r : $()
299+
300+
bb2:
301+
dynamic_method_br %2 : $@opened("2FD52A04-DA20-11EE-8801-0EA13E3AABAF", any P) Self, #P.f!foreign, bb1, bb3
302+
303+
bb3:
304+
unreachable
305+
}
306+

0 commit comments

Comments
 (0)