Skip to content

Commit bd2a020

Browse files
committed
SILOptimizer: Don't devirtualize witness method calls to tuple conformances that might vanish
1 parent 9c2557d commit bd2a020

File tree

3 files changed

+30
-6
lines changed

3 files changed

+30
-6
lines changed

lib/AST/Type.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4765,8 +4765,9 @@ case TypeKind::Id:
47654765
if (!anyChanged)
47664766
return *this;
47674767

4768-
// If the transform would yield a singleton tuple, and we didn't
4769-
// start with one, flatten to produce the element type.
4768+
// Handle vanishing tuples -- If the transform would yield a singleton
4769+
// tuple, and we didn't start with one, flatten to produce the
4770+
// element type.
47704771
if (elements.size() == 1 &&
47714772
!elements[0].getType()->is<PackExpansionType>() &&
47724773
!(tuple->getNumElements() == 1 &&

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,15 @@ static bool canDevirtualizeWitnessMethod(ApplySite applySite, bool isMandatory)
11461146

11471147
auto *wmi = cast<WitnessMethodInst>(applySite.getCallee());
11481148

1149+
// Handle vanishing tuples: don't devirtualize a call to a tuple conformance
1150+
// if the lookup type can possibly be unwrapped after substitution.
1151+
if (auto tupleType = dyn_cast<TupleType>(wmi->getLookupType())) {
1152+
if (tupleType->containsPackExpansionType() &&
1153+
tupleType->getNumScalarElements() <= 1) {
1154+
return false;
1155+
}
1156+
}
1157+
11491158
std::tie(f, wt) = applySite.getModule().lookUpFunctionInWitnessTable(
11501159
wmi->getConformance(), wmi->getMember(), SILModule::LinkingMode::LinkAll);
11511160

test/SILOptimizer/tuple-conformances.swift

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,20 @@ public func transparentCallee<T: P>(t: T.Type) {
2222
t.protocolMethod()
2323
}
2424

25+
// Make sure we don't devirtualize the call when we inline transparentCallee()
26+
// into transparentCaller(), because we might unwrap the tuple conformance
27+
// later.
28+
29+
// CHECK-LABEL: sil [transparent] @$s4main17transparentCaller5tupleyxxQp_tm_tRvzAA1PRzlF : $@convention(thin) <each T where repeat each T : P> (@thin (repeat each T).Type) -> () {
2530
@_transparent public func transparentCaller<each T: P>(tuple: (repeat each T).Type) {
2631
callee(t: tuple)
32+
33+
// CHECK: [[FN:%.*]] = witness_method $(repeat each T), #P.protocolMethod : <Self where Self : P> (Self.Type) -> () -> () : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> ()
34+
// CHECK: apply [[FN:%.*]]<(repeat each T)>({{.*}})
35+
2736
transparentCallee(t: tuple)
37+
38+
// FIXME: This one is wrong in the AST
2839
tuple.protocolMethod()
2940
}
3041

@@ -39,10 +50,13 @@ public func caller() {
3950
// CHECK: [[FN:%.*]] = function_ref @$s4main6callee1tyxm_tAA1PRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> ()
4051
// CHECK: apply [[FN]]<Int>({{.*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> ()
4152

42-
// FIXME: These should call Int.protocolMethod()!
53+
// Make sure the witness method call in transparentCallee() was devirtualized to Int.protocolMethod().
4354

44-
// CHECK: [[FN:%.*]] = function_ref @$sBT4mainRvzAA1PRzlE14protocolMethodyyFZ : $@convention(method) <each τ_0_0 where repeat each τ_0_0 : P> (@thin (repeat each τ_0_0).Type) -> ()
45-
// CHECK: apply [[FN]]<Pack{Int}>(%4) : $@convention(method) <each τ_0_0 where repeat each τ_0_0 : P> (@thin (repeat each τ_0_0).Type) -> ()
55+
// CHECK: [[FN:%.*]] = function_ref @$sSi4mainE14protocolMethodyyFZ : $@convention(method) (@thin Int.Type) -> () // user: %6
56+
// CHECK: apply [[FN]]({{.*}}) : $@convention(method) (@thin Int.Type) -> ()
57+
58+
// FIXME: This is the `tuple.protocolMethod()` in transparentCaller(). It should
59+
// also refer to Int.protocolMethod()!
4660

4761
// CHECK: [[FN:%.*]] = function_ref @$sBT4mainRvzAA1PRzlE14protocolMethodyyFZ : $@convention(method) <each τ_0_0 where repeat each τ_0_0 : P> (@thin (repeat each τ_0_0).Type) -> ()
48-
// CHECK: apply [[FN]]<Pack{Int}>(%0) : $@convention(method) <each τ_0_0 where repeat each τ_0_0 : P> (@thin (repeat each τ_0_0).Type) -> ()
62+
// CHECK: apply [[FN]]<Pack{Int}>({{.*}}) : $@convention(method) <each τ_0_0 where repeat each τ_0_0 : P> (@thin (repeat each τ_0_0).Type) -> ()

0 commit comments

Comments
 (0)