Skip to content

Commit 5572c83

Browse files
committed
SILOptimizer: replace existential archetypes with concrete types in witness_method instructions
1 parent 71de3d9 commit 5572c83

File tree

6 files changed

+97
-5
lines changed

6 files changed

+97
-5
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,5 @@ swift_compiler_sources(Optimizer
3838
SimplifyTuple.swift
3939
SimplifyTupleExtract.swift
4040
SimplifyUncheckedEnumData.swift
41-
SimplifyValueToBridgeObject.swift)
41+
SimplifyValueToBridgeObject.swift
42+
SimplifyWitnessMethod.swift)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===--- SimplifyWitnessMethod.swift --------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import AST
14+
import SIL
15+
16+
extension WitnessMethodInst : Simplifiable, SILCombineSimplifiable {
17+
func simplify(_ context: SimplifyContext) {
18+
_ = tryReplaceExistentialArchetype(of: self, context)
19+
}
20+
}
21+
22+
/// If the witness_method operates on an existential archetype (`@opened("...")`) and the concrete
23+
/// type is known, replace the existential archetype with the concrete type.
24+
/// For example:
25+
/// ```
26+
/// %3 = witness_method $@opened("...", P) Self, #P.foo, %2
27+
/// ```
28+
/// ->
29+
/// ```
30+
/// %3 = witness_method $ConcreteType, #P.foo, %2
31+
/// ```
32+
private func tryReplaceExistentialArchetype(of witnessMethod: WitnessMethodInst, _ context: SimplifyContext) -> Bool {
33+
guard let concreteType = witnessMethod.concreteTypeOfDependentExistentialArchetype else {
34+
return false
35+
}
36+
let conf = concreteType.checkConformance(to: witnessMethod.lookupProtocol)
37+
guard conf.isValid else {
38+
return false
39+
}
40+
41+
let builder = Builder(before: witnessMethod, context)
42+
let newWmi = builder.createWitnessMethod(lookupType: concreteType,
43+
conformance: conf,
44+
member: witnessMethod.member,
45+
methodType: witnessMethod.type)
46+
witnessMethod.replace(with: newWmi, context)
47+
return true
48+
}

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ private func registerSwiftPasses() {
119119
registerForSILCombine(ClassifyBridgeObjectInst.self, { run(ClassifyBridgeObjectInst.self, $0) })
120120
registerForSILCombine(PointerToAddressInst.self, { run(PointerToAddressInst.self, $0) })
121121
registerForSILCombine(UncheckedEnumDataInst.self, { run(UncheckedEnumDataInst.self, $0) })
122+
registerForSILCombine(WitnessMethodInst.self, { run(WitnessMethodInst.self, $0) })
122123
registerForSILCombine(UnconditionalCheckedCastInst.self, { run(UnconditionalCheckedCastInst.self, $0) })
123124
registerForSILCombine(ApplyInst.self, { run(ApplyInst.self, $0) })
124125
registerForSILCombine(TryApplyInst.self, { run(TryApplyInst.self, $0) })

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ SWIFT_SILCOMBINE_PASS(DestructureTupleInst)
539539
SWIFT_SILCOMBINE_PASS(PointerToAddressInst)
540540
SWIFT_SILCOMBINE_PASS(TypeValueInst)
541541
SWIFT_SILCOMBINE_PASS(UncheckedEnumDataInst)
542+
SWIFT_SILCOMBINE_PASS(WitnessMethodInst)
542543
SWIFT_SILCOMBINE_PASS_WITH_LEGACY(UnconditionalCheckedCastInst)
543544
SWIFT_SILCOMBINE_PASS_WITH_LEGACY(ApplyInst)
544545
SWIFT_SILCOMBINE_PASS_WITH_LEGACY(TryApplyInst)

test/SILOptimizer/sil_combine.sil

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,10 +3447,10 @@ class ClientSocket : Socket {
34473447
}
34483448

34493449
// CHECK-LABEL: static_existential
3450-
// CHECK:bb0:
3451-
// CHECK: [[META:%.*]] = metatype $@thick ClientSocket.Type
3452-
// CHECK: [[WM:%.*]] = witness_method $ClientSocket
3453-
// CHECK: try_apply [[WM]]<ClientSocket>([[META]])
3450+
// CHECK: bb0:
3451+
// CHECK-DAG: [[META:%.*]] = metatype $@thick ClientSocket.Type
3452+
// CHECK-DAG: [[WM:%.*]] = witness_method $ClientSocket
3453+
// CHECK: try_apply [[WM]]<ClientSocket>([[META]])
34543454
sil @static_existential : $@convention(thin) () -> (Builtin.Int32, @error MyErrorType) {
34553455
bb0:
34563456
%0 = metatype $@thick ClientSocket.Type
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %target-sil-opt %s -simplification -simplify-instruction=witness_method | %FileCheck %s
2+
3+
import Swift
4+
import Builtin
5+
6+
protocol P {
7+
func foo()
8+
}
9+
10+
struct S: P {
11+
var x: Int
12+
13+
func foo()
14+
}
15+
16+
// CHECK-LABEL: sil [ossa] @replace_archetype :
17+
// CHECK: = witness_method $S, #P.foo : <Self where Self : P> (Self) -> () -> () : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> ()
18+
// CHECK: } // end sil function 'replace_archetype'
19+
sil [ossa] @replace_archetype : $@convention(thin) () -> () {
20+
bb0:
21+
%0 = metatype $@thick S.Type
22+
%1 = init_existential_metatype %0, $@thick P.Type
23+
%2 = open_existential_metatype %1 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type
24+
%3 = witness_method $@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self, #P.foo, %2 : $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> ()
25+
%4 = apply %3<@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self>(%2) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> ()
26+
%5 = tuple ()
27+
return %5
28+
}
29+
30+
// CHECK-LABEL: sil [ossa] @dont_replace_archetype_unknown_concrete_type :
31+
// CHECK: = witness_method $@opened
32+
// CHECK: } // end sil function 'dont_replace_archetype_unknown_concrete_type'
33+
sil [ossa] @dont_replace_archetype_unknown_concrete_type : $@convention(thin) (@thick any P.Type) -> () {
34+
bb0(%0 : $@thick any P.Type):
35+
%2 = open_existential_metatype %0 to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type
36+
%3 = witness_method $@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self, #P.foo, %2 : $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self).Type : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> ()
37+
%4 = apply %3<@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", P) Self>(%2) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@thick τ_0_0.Type) -> ()
38+
%5 = tuple ()
39+
return %5
40+
}
41+

0 commit comments

Comments
 (0)