Skip to content

Commit bc884d4

Browse files
authored
Merge pull request #20977 from rajbarik/raj-extend-existential2generic
Perform ExistentialSpecializer when SoleConformingType is known
2 parents 4d600ff + 0070730 commit bc884d4

File tree

6 files changed

+136
-15
lines changed

6 files changed

+136
-15
lines changed

include/swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/SIL/SILArgument.h"
2020
#include "swift/SIL/SILValue.h"
2121
#include "swift/SILOptimizer/Analysis/Analysis.h"
22+
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h"
2223
#include "llvm/ADT/DenseMap.h"
2324
#include "llvm/ADT/SmallSet.h"
2425
#include "llvm/ADT/SmallVector.h"
@@ -78,6 +79,10 @@ class ProtocolConformanceAnalysis : public SILAnalysis {
7879
/// conforming concrete type.
7980
NominalTypeDecl *findSoleConformingType(ProtocolDecl *Protocol);
8081

82+
// Wrapper function to findSoleConformingType that checks for additional
83+
// constraints for classes using ClassHierarchyAnalysis.
84+
bool getSoleConformingType(ProtocolDecl *Protocol, ClassHierarchyAnalysis *CHA, CanType &ConcreteType);
85+
8186
private:
8287
/// Compute inheritance properties.
8388
void init();

lib/SILOptimizer/Analysis/ProtocolConformanceAnalysis.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,26 @@ ProtocolConformanceAnalysis::findSoleConformingType(ProtocolDecl *Protocol) {
139139
return SoleConformingNTD;
140140
}
141141

142+
// Wrapper function to findSoleConformingType that checks for additional
143+
// constraints for classes using ClassHierarchyAnalysis.
144+
bool ProtocolConformanceAnalysis::getSoleConformingType(
145+
ProtocolDecl *Protocol, ClassHierarchyAnalysis *CHA, CanType &ConcreteType) {
146+
// Determine the sole conforming type.
147+
auto *NTD = findSoleConformingType(Protocol);
148+
if (!NTD)
149+
return false;
150+
151+
// Sole conforming class should not be open access or have any derived class.
152+
ClassDecl *CD;
153+
if ((CD = dyn_cast<ClassDecl>(NTD)) &&
154+
(CD->getEffectiveAccess() == AccessLevel::Open ||
155+
CHA->hasKnownDirectSubclasses(CD))) {
156+
return false;
157+
}
158+
159+
// Save the concrete type.
160+
ConcreteType = NTD->getDeclaredType()->getCanonicalType();
161+
return true;
162+
}
163+
142164
ProtocolConformanceAnalysis::~ProtocolConformanceAnalysis() {}

lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "ExistentialTransform.h"
2020
#include "swift/SIL/SILFunction.h"
2121
#include "swift/SIL/SILInstruction.h"
22+
#include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h"
2223
#include "swift/SILOptimizer/PassManager/Transforms.h"
2324
#include "swift/SILOptimizer/Utils/Existential.h"
2425
#include "swift/SILOptimizer/Utils/Local.h"
@@ -48,9 +49,18 @@ class ExistentialSpecializer : public SILFunctionTransform {
4849
/// Specialize existential args in function F.
4950
void specializeExistentialArgsInAppliesWithinFunction(SILFunction &F);
5051

52+
/// Find concrete type using protocolconformance analysis.
53+
bool findConcreteTypeFromSoleConformingType(
54+
SILFunctionArgument *Arg, CanType &ConcreteType);
55+
5156
/// CallerAnalysis information.
5257
CallerAnalysis *CA;
5358

59+
// Determine the set of types a protocol conforms to in whole-module
60+
// compilation mode.
61+
ProtocolConformanceAnalysis *PCA;
62+
63+
ClassHierarchyAnalysis *CHA;
5464
public:
5565
void run() override {
5666

@@ -64,12 +74,39 @@ class ExistentialSpecializer : public SILFunctionTransform {
6474
/// Get CallerAnalysis information handy.
6575
CA = PM->getAnalysis<CallerAnalysis>();
6676

77+
/// Get ProtocolConformanceAnalysis.
78+
PCA = PM->getAnalysis<ProtocolConformanceAnalysis>();
79+
80+
/// Get ClassHierarchyAnalysis.
81+
CHA = PM->getAnalysis<ClassHierarchyAnalysis>();
6782
/// Perform specialization.
6883
specializeExistentialArgsInAppliesWithinFunction(*F);
6984
}
7085
};
7186
} // namespace
7287

88+
/// Find concrete type from Sole Conforming Type.
89+
bool ExistentialSpecializer::findConcreteTypeFromSoleConformingType(
90+
SILFunctionArgument *Arg, CanType &ConcreteType) {
91+
auto ArgType = Arg->getType();
92+
auto SwiftArgType = ArgType.getASTType();
93+
94+
/// Do not handle composition types yet.
95+
if (isa<ProtocolCompositionType>(SwiftArgType))
96+
return false;
97+
assert(ArgType.isExistentialType());
98+
/// Find the protocol decl.
99+
auto *PD = dyn_cast<ProtocolDecl>(SwiftArgType->getAnyNominal());
100+
if (!PD)
101+
return false;
102+
103+
// Get SoleConformingType in ConcreteType using ProtocolConformanceAnalysis
104+
// and ClassHierarchyAnalysis.
105+
if (!PCA->getSoleConformingType(PD, CHA, ConcreteType))
106+
return false;
107+
return true;
108+
}
109+
73110
/// Check if the argument Arg is used in a destroy_use instruction.
74111
static void
75112
findIfCalleeUsesArgInDestroyUse(SILValue Arg,
@@ -83,6 +120,14 @@ findIfCalleeUsesArgInDestroyUse(SILValue Arg,
83120
}
84121
}
85122

123+
/// Helper function to ensure that the argument is not InOut or InOut_Aliasable
124+
static bool isNonInoutIndirectArgument(SILValue Arg,
125+
SILArgumentConvention ArgConvention) {
126+
return !Arg->getType().isObject() && ArgConvention.isIndirectConvention() &&
127+
ArgConvention != SILArgumentConvention::Indirect_Inout &&
128+
ArgConvention != SILArgumentConvention::Indirect_InoutAliasable;
129+
}
130+
86131
/// Check if any apply argument meets the criteria for existential
87132
/// specialization.
88133
bool ExistentialSpecializer::canSpecializeExistentialArgsInFunction(
@@ -122,7 +167,14 @@ bool ExistentialSpecializer::canSpecializeExistentialArgsInFunction(
122167
Operand &ArgOper = Apply.getArgumentRef(Idx);
123168
CanType ConcreteType =
124169
ConcreteExistentialInfo(ArgOper.get(), ArgOper.getUser()).ConcreteType;
125-
if (!ConcreteType) {
170+
auto ArgConvention = F->getConventions().getSILArgumentConvention(Idx);
171+
/// Find the concrete type, either via sole type or via
172+
/// findInitExistential..
173+
CanType SoleConcreteType;
174+
if (!((F->getModule().isWholeModule() &&
175+
isNonInoutIndirectArgument(CalleeArg, ArgConvention) &&
176+
findConcreteTypeFromSoleConformingType(CalleeArg, SoleConcreteType)) ||
177+
ConcreteType)) {
126178
LLVM_DEBUG(
127179
llvm::dbgs()
128180
<< "ExistentialSpecializer Pass: Bail! cannot find ConcreteType "

lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ void ExistentialTransform::populateThunkBody() {
401401
break;
402402
}
403403
case ExistentialRepresentation::Class: {
404+
/// If the operand is not object type, we would need an explicit load.
405+
assert(OrigOperand->getType().isObject());
404406
archetypeValue =
405407
Builder.createOpenExistentialRef(Loc, OrigOperand, OpenedSILType);
406408
ApplyArgs.push_back(archetypeValue);

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -667,22 +667,10 @@ SILCombiner::buildConcreteOpenedExistentialInfoFromSoleConformingType(
667667
return None;
668668

669669
// Determine the sole conforming type.
670-
auto *NTD = PCA->findSoleConformingType(PD);
671-
if (!NTD)
670+
CanType ConcreteType;
671+
if (!PCA->getSoleConformingType(PD, CHA, ConcreteType))
672672
return None;
673673

674-
// Sole conforming class should not be open access or have any derived class.
675-
ClassDecl *CD;
676-
if ((CD = dyn_cast<ClassDecl>(NTD)) &&
677-
(CD->getEffectiveAccess() == AccessLevel::Open ||
678-
CHA->hasKnownDirectSubclasses(CD))) {
679-
return None;
680-
}
681-
682-
// Create SIL type for the concrete type.
683-
auto ElementType = NTD->getDeclaredType();
684-
auto ConcreteType = ElementType->getCanonicalType();
685-
686674
// Determine OpenedArchetypeDef and SubstituionMap.
687675
ConcreteOpenedExistentialInfo COAI(ArgOperand, ConcreteType, PD);
688676
if (!COAI.CEI)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %target-swift-frontend -O -wmo -sil-existential-specializer -Xllvm -sil-disable-pass=GenericSpecializer -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=SILCombine -emit-sil -sil-verify-all %s | %FileCheck %s
2+
3+
internal protocol SPP {
4+
func bar() -> Int32
5+
}
6+
internal class SCC: SPP {
7+
@inline(never) func bar() -> Int32 {
8+
return 5
9+
}
10+
}
11+
12+
@inline(never) internal func opt2(b:SPP) -> Int32{
13+
return b.bar()
14+
}
15+
16+
@inline(never) internal func opt1(b:SPP) -> Int32{
17+
return opt2(b:b)
18+
}
19+
20+
// CHECK-LABEL: sil hidden [noinline] @$s30existential_transform_soletype4opt11bs5Int32VAA3SPP_p_tF : $@convention(thin) (@in_guaranteed SPP) -> Int32 {
21+
// CHECK: bb0(%0 : $*SPP):
22+
// CHECK: debug_value_addr
23+
// CHECK: function_ref @$s30existential_transform_soletype4opt21bs5Int32VAA3SPP_p_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : SPP> (@in_guaranteed τ_0_0) -> Int32 // user: %4
24+
// CHECK: open_existential_addr
25+
// CHECK: apply
26+
// CHECK: return
27+
// CHECK-LABEL: } // end sil function '$s30existential_transform_soletype4opt11bs5Int32VAA3SPP_p_tF'
28+
29+
// CHECK-LABEL: sil shared [noinline] @$s30existential_transform_soletype4opt21bs5Int32VAA3SPP_p_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : SPP> (@in_guaranteed τ_0_0) -> Int32 {
30+
// CHECK: bb0(%0 : $*τ_0_0):
31+
// CHECK: alloc_stack
32+
// CHECK: init_existential_addr
33+
// CHECK: copy_addr
34+
// CHECK: debug_value_addr
35+
// CHECK: open_existential_addr
36+
// CHECK: witness_method
37+
// CHECK: apply
38+
// CHECK: dealloc_stack
39+
// CHECK: return
40+
// CHECK-LABEL: } // end sil function '$s30existential_transform_soletype4opt21bs5Int32VAA3SPP_p_tFTf4e_n'
41+
42+
43+
@_optimize(none) func foo(number:Int32)->Int32 {
44+
var b:SPP
45+
if number < 5 {
46+
b = SCC()
47+
} else {
48+
b = SCC()
49+
}
50+
let x = opt1(b:b)
51+
return x
52+
}

0 commit comments

Comments
 (0)