Skip to content

Commit b5570a1

Browse files
authored
Merge pull request #30872 from atrick/cse-init-existential-metatype
Add init_existential_metatype to CSE.
2 parents 25d531c + a22d0f2 commit b5570a1

File tree

7 files changed

+110
-1
lines changed

7 files changed

+110
-1
lines changed

lib/SIL/IR/SILInstruction.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,21 @@ namespace {
859859
return true;
860860
}
861861

862+
bool
863+
visitInitExistentialMetatypeInst(const InitExistentialMetatypeInst *RHS) {
864+
auto *X = cast<InitExistentialMetatypeInst>(LHS);
865+
ArrayRef<ProtocolConformanceRef> lhsConformances = X->getConformances();
866+
ArrayRef<ProtocolConformanceRef> rhsConformances = RHS->getConformances();
867+
if (lhsConformances.size() != rhsConformances.size())
868+
return false;
869+
870+
for (unsigned i : indices(lhsConformances)) {
871+
if (lhsConformances[i] != rhsConformances[i])
872+
return false;
873+
}
874+
return true;
875+
}
876+
862877
private:
863878
const SILInstruction *LHS;
864879
};

lib/SILOptimizer/Transforms/CSE.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,13 @@ class HashVisitor : public SILInstructionVisitor<HashVisitor, llvm::hash_code> {
241241
return llvm::hash_combine(X->getKind(), X->getType());
242242
}
243243

244+
hash_code visitInitExistentialMetatypeInst(InitExistentialMetatypeInst *X) {
245+
return llvm::hash_combine(
246+
X->getKind(), X->getType(), X->getOperand(),
247+
llvm::hash_combine_range(X->getConformances().begin(),
248+
X->getConformances().end()));
249+
}
250+
244251
hash_code visitObjCProtocolInst(ObjCProtocolInst *X) {
245252
return llvm::hash_combine(X->getKind(), X->getType(), X->getProtocol());
246253
}
@@ -1032,6 +1039,7 @@ bool CSE::canHandle(SILInstruction *Inst) {
10321039
case SILInstructionKind::PointerToThinFunctionInst:
10331040
case SILInstructionKind::MarkDependenceInst:
10341041
case SILInstructionKind::OpenExistentialRefInst:
1042+
case SILInstructionKind::InitExistentialMetatypeInst:
10351043
case SILInstructionKind::WitnessMethodInst:
10361044
// Intentionally we don't handle (prev_)dynamic_function_ref.
10371045
// They change at runtime.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Modules B and C will have separate conformance from A to P.
2+
public struct A {}
3+
4+
public protocol P {
5+
static func foo()
6+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import moda
2+
3+
// module B
4+
extension A: P {
5+
public static func foo() {
6+
print("modA\n")
7+
}
8+
} // conformance B
9+
10+
@inlinable
11+
public func getPFromB() -> P.Type {
12+
return A.self
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import moda
2+
3+
// module C
4+
extension A: P {
5+
public static func foo() {
6+
print("modC\n")
7+
}
8+
} // conformance C
9+
10+
@inlinable
11+
public func getPFromC() -> P.Type {
12+
return A.self
13+
}

test/SILOptimizer/cse.sil

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1294,4 +1294,21 @@ bb0:
12941294
return %35 : $Int64
12951295
}
12961296

1297-
1297+
// Test init_existential_metatype combining.
1298+
protocol SomeP {}
1299+
1300+
public enum SpecialEnum : SomeP {}
1301+
1302+
// CHECK-LABEL: sil @testCSEInitExistentialMetatype : $@convention(thin) (@thick SpecialEnum.Type) -> Bool {
1303+
// CHECK: [[EMT:%.*]] = init_existential_metatype %0 : $@thick SpecialEnum.Type, $@thick Any.Type
1304+
// CHECK-NOT: init_existential_metatype
1305+
// CHECK: builtin "is_same_metatype"([[EMT]] : $@thick Any.Type, [[EMT]] : $@thick Any.Type) : $Builtin.Int1
1306+
// CHECK-LABEL: } // end sil function 'testCSEInitExistentialMetatype'
1307+
sil @testCSEInitExistentialMetatype : $@convention(thin) (@thick SpecialEnum.Type) -> Bool {
1308+
bb0(%0 : $@thick SpecialEnum.Type):
1309+
%1 = init_existential_metatype %0 : $@thick SpecialEnum.Type, $@thick Any.Type
1310+
%2 = init_existential_metatype %0 : $@thick SpecialEnum.Type, $@thick Any.Type
1311+
%3 = builtin "is_same_metatype"(%1 : $@thick Any.Type, %2 : $@thick Any.Type) : $Builtin.Int1
1312+
%4 = struct $Bool (%3 : $Builtin.Int1)
1313+
return %4 : $Bool
1314+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %S/Inputs/cse_metatype_conformanceA.swift -module-name moda -emit-module -emit-module-path %t/moda.swiftmodule
3+
// RUN: %target-swift-frontend %S/Inputs/cse_metatype_conformanceB.swift -module-name modb -emit-module -emit-module-path %t/modb.swiftmodule -I %t
4+
// RUN: %target-swift-frontend %S/Inputs/cse_metatype_conformanceC.swift -module-name modc -emit-module -emit-module-path %t/modc.swiftmodule -I %t
5+
// RUN: %target-swift-frontend -I %t -O -emit-sil -sil-verify-all -parse-as-library %s | %FileCheck %s --check-prefix=CHECK
6+
7+
// Test CSE of init_existential_metatype. Combine instructions with
8+
// conformance from the same module. Don't combine instructions with
9+
// conformances from different modules.
10+
11+
// swift -frontend -emit-sil ./checkprotocoltype.swift -O -parse-as-library
12+
import moda
13+
import modb
14+
import modc
15+
16+
@inline(never)
17+
func callFoo(ptype: P.Type) {
18+
ptype.foo()
19+
}
20+
21+
// CHECK-LABEL: sil @$s24cse_metatype_conformance15testConformanceyyF : $@convention(thin) () -> () {
22+
// CHECK: [[MT:%.*]] = metatype $@thick A.Type
23+
// CHECK: [[MTB:%.*]] = init_existential_metatype %0 : $@thick A.Type, $@thick P.Type
24+
// CHECK: [[F:%.*]] = function_ref @$s24cse_metatype_conformance7callFoo5ptypey4moda1P_pXp_tF : $@convention(thin) (@thick P.Type) -> ()
25+
// CHECK: apply [[F]]([[MTB]]) : $@convention(thin) (@thick P.Type) -> ()
26+
// CHECK: apply [[F]]([[MTB]]) : $@convention(thin) (@thick P.Type) -> ()
27+
// CHECK: [[MTC:%.*]] = init_existential_metatype %0 : $@thick A.Type, $@thick P.Type
28+
// CHECK: apply [[F]]([[MTC]]) : $@convention(thin) (@thick P.Type) -> ()
29+
// CHECK-LABEL: } // end sil function '$s24cse_metatype_conformance15testConformanceyyF'
30+
public func testConformance() {
31+
let ptb1: P.Type = getPFromB()
32+
callFoo(ptype: ptb1)
33+
let ptb2: P.Type = getPFromB()
34+
callFoo(ptype: ptb2)
35+
let ptc: P.Type = getPFromC()
36+
callFoo(ptype: ptc)
37+
}

0 commit comments

Comments
 (0)