Skip to content

Commit 069858b

Browse files
committed
[sil-cse] Types of basic block arguments should be updated during the CSE of open_existential_ref (#3559)
Opened archetypes may be used by types of basic block arguments. Therefore, when performing the CSE of open_existential_ref instructions, one should also update the type of any basic block argument that may have used the archetype opened by the open_existential_ref being replaced. rdar://problem/27386065
1 parent 2a10ef8 commit 069858b

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

lib/SILOptimizer/Transforms/CSE.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,42 @@ namespace {
591591
};
592592
}
593593

594+
/// Update SIL basic block's arguments types which refer to opened
595+
/// archetypes. Replace such types by performing type substitutions
596+
/// according to the provided type substitution map.
597+
static void updateBasicBlockArgTypes(SILBasicBlock *BB,
598+
TypeSubstitutionMap &TypeSubstMap) {
599+
// Check types of all BB arguments.
600+
for (auto &Arg : BB->getBBArgs()) {
601+
if (!Arg->getType().getSwiftRValueType()->hasOpenedExistential())
602+
continue;
603+
// Type of this BB argument uses an opened existential.
604+
// Try to apply substitutions to it and if it produces a different type,
605+
// use this type as new type of the BB argument.
606+
auto NewArgType = Arg->getType().subst(
607+
BB->getModule(), BB->getModule().getSwiftModule(), TypeSubstMap);
608+
if (NewArgType == Arg->getType())
609+
continue;
610+
// Replace the type of this BB argument. The type of a BBArg
611+
// can only be changed using replaceBBArg, if the BBArg has no uses.
612+
// So, make it look as if it has no uses.
613+
614+
// First collect all uses, before changing the type.
615+
SmallVector<Operand *, 4> OriginalArgUses;
616+
for (auto *ArgUse : Arg->getUses()) {
617+
OriginalArgUses.push_back(ArgUse);
618+
}
619+
// Then replace all uses by an undef.
620+
Arg->replaceAllUsesWith(SILUndef::get(Arg->getType(), BB->getModule()));
621+
// Replace the type of the BB argument.
622+
BB->replaceBBArg(Arg->getIndex(), NewArgType, Arg->getDecl());
623+
// Restore all uses to refer to the BB argument with updated type.
624+
for (auto ArgUse : OriginalArgUses) {
625+
ArgUse->set(Arg);
626+
}
627+
}
628+
}
629+
594630
/// Handle CSE of open_existential_ref instructions.
595631
/// Returns true if uses of open_existential_ref can
596632
/// be replaced by a dominating instruction.
@@ -601,6 +637,10 @@ bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V,
601637
SILBasicBlock::iterator &I) {
602638
assert(isa<OpenExistentialRefInst>(Inst));
603639
llvm::SmallSetVector<SILInstruction *, 16> Candidates;
640+
auto OldOpenedArchetype = getOpenedArchetypeOf(Inst);
641+
auto NewOpenedArchetype = getOpenedArchetypeOf(dyn_cast<SILInstruction>(V));
642+
TypeSubstitutionMap TypeSubstMap;
643+
TypeSubstMap[OldOpenedArchetype.getPointer()] = NewOpenedArchetype;
604644
// Collect all candidates that may contain opened archetypes
605645
// that need to be replaced.
606646
for (auto Use : Inst->getUses()) {
@@ -614,10 +654,21 @@ bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V,
614654
}
615655
Candidates.insert(User);
616656
}
657+
if (!isa<TermInst>(User))
658+
continue;
659+
// The current use of the opened archetype is a terminator instruction.
660+
// Check if any of the successor BBs uses this opened archetype in the
661+
// types of its basic block arguments. If this is the case, replace
662+
// those uses by the new opened archetype.
663+
auto Successors = User->getParent()->getSuccessorBlocks();
664+
for (auto Successor : Successors) {
665+
if (Successor->bbarg_empty())
666+
continue;
667+
// If a BB has any arguments, update their types if necessary.
668+
updateBasicBlockArgTypes(Successor, TypeSubstMap);
669+
}
617670
}
618671
// Now process candidates.
619-
auto OldOpenedArchetype = getOpenedArchetypeOf(Inst);
620-
auto NewOpenedArchetype = getOpenedArchetypeOf(dyn_cast<SILInstruction>(V));
621672
// TODO: Move it to CSE instance to avoid recreating it every time?
622673
SILOpenedArchetypesTracker OpenedArchetypesTracker(*Inst->getFunction());
623674
// Register the new archetype to be used.

test/SILOptimizer/cse_objc.sil

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,41 @@ bb0(%0 : $Walkable):
119119
return %9 : $() // id: %10
120120
}
121121

122+
// Check that the open_existential_ref is CSEed not only in instructions, but also in the types
123+
// of BB arguments. The type of BB2 argument should use the same opened existential as the
124+
// one opened in the entry block.
125+
126+
// CHECK-LABEL: sil @cse_open_existential_in_bbarg : $@convention(thin) (@owned AnyObject) -> ()
127+
// CHECK: open_existential_ref %0 : $AnyObject to $[[OPENED:@opened\(.*\) AnyObject]]
128+
// CHECK: bb1(%{{[0-9]*}} : $@convention(objc_method) ([[OPENED]]) -> @autoreleased Optional<NSString>):
129+
// CHECK-NOT: open_existential_ref
130+
// CHECK: bb2(%{{[0-9]*}} : $@convention(objc_method) ([[OPENED]]) -> @autoreleased Optional<NSString>):
131+
// CHECK-NOT: open_existential_ref
132+
// CHECK: return
133+
sil @cse_open_existential_in_bbarg : $@convention(thin) (@owned AnyObject) -> () {
134+
bb0(%0 : $AnyObject):
135+
%1 = open_existential_ref %0 : $AnyObject to $@opened("CCEAC0E2-4BB2-11E6-86F8-B8E856428C60") AnyObject
136+
dynamic_method_br %1 : $@opened("CCEAC0E2-4BB2-11E6-86F8-B8E856428C60") AnyObject, #NSProxy.description!getter.1.foreign, bb1, bb3
137+
138+
bb1(%3 : $@convention(objc_method) (@opened("CCEAC0E2-4BB2-11E6-86F8-B8E856428C60") AnyObject) -> @autoreleased Optional<NSString>):
139+
strong_retain %1 : $@opened("CCEAC0E2-4BB2-11E6-86F8-B8E856428C60") AnyObject
140+
%5 = partial_apply %3(%1) : $@convention(objc_method) (@opened("CCEAC0E2-4BB2-11E6-86F8-B8E856428C60") AnyObject) -> @autoreleased Optional<NSString>
141+
%6 = apply %5() : $@callee_owned () -> @owned Optional<NSString>
142+
%7 = open_existential_ref %0 : $AnyObject to $@opened("CCEDAF1E-4BB2-11E6-86F8-B8E856428C60") AnyObject
143+
dynamic_method_br %7 : $@opened("CCEDAF1E-4BB2-11E6-86F8-B8E856428C60") AnyObject, #NSProxy.description!getter.1.foreign, bb2, bb3
144+
145+
bb2(%9 : $@convention(objc_method) (@opened("CCEDAF1E-4BB2-11E6-86F8-B8E856428C60") AnyObject) -> @autoreleased Optional<NSString>):
146+
strong_retain %7 : $@opened("CCEDAF1E-4BB2-11E6-86F8-B8E856428C60") AnyObject
147+
%10 = partial_apply %9(%7) : $@convention(objc_method) (@opened("CCEDAF1E-4BB2-11E6-86F8-B8E856428C60") AnyObject) -> @autoreleased Optional<NSString>
148+
%11 = apply %10() : $@callee_owned () -> @owned Optional<NSString>
149+
br bb3
150+
151+
bb3:
152+
strong_release %0 : $AnyObject
153+
%13 = tuple ()
154+
return %13 : $()
155+
}
156+
122157
sil_vtable Bar {
123158
#Bar.init!initializer.1: _TFC4test3BarcfMS0_FT_S0_ // test.Bar.init (test.Bar.Type)() -> test.Bar
124159
#Bar.walk!1: _TFC4test3Bar4walkfS0_FT_T_ // test.Bar.walk (test.Bar)() -> ()

0 commit comments

Comments
 (0)