Skip to content

Commit d8bf949

Browse files
committed
BasicCalleeAnalysis: improve finding the actual called deinits of a destroy/release instruction
* C++: add a function `getDestructors(SILType type, bool isExactType)’: if the type is a final class or `isExactType` is true, then return the one and only destructor of that class. * swift: add `getDestructor(ofExactType type: Type)` and `getIncompleteCallees` * swift: remove `getDestructor` from the PassContext. The API of the `calleeAnalysis` can be used instead.
1 parent 2befdbe commit d8bf949

File tree

8 files changed

+58
-48
lines changed

8 files changed

+58
-48
lines changed

SwiftCompilerSources/Sources/Optimizer/Analysis/CalleeAnalysis.swift

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,32 @@ import SIL
1616
public struct CalleeAnalysis {
1717
let bridged: BridgedCalleeAnalysis
1818

19-
public func getCallees(callee: Value) -> FunctionArray {
19+
public func getCallees(callee: Value) -> FunctionArray? {
20+
let bridgedFuncs = CalleeAnalysis_getCallees(bridged, callee.bridged)
21+
if bridgedFuncs.incomplete != 0 {
22+
return nil
23+
}
24+
return FunctionArray(bridged: bridgedFuncs)
25+
}
26+
27+
public func getIncompleteCallees(callee: Value) -> FunctionArray {
2028
return FunctionArray(bridged: CalleeAnalysis_getCallees(bridged, callee.bridged))
2129
}
2230

23-
public func getDestructors(destroyInst: Instruction) -> FunctionArray {
24-
return FunctionArray(bridged:
25-
CalleeAnalysis_getInstCallees(bridged, destroyInst.bridged))
31+
public func getDestructor(ofExactType type: Type) -> Function? {
32+
let destructors = FunctionArray(bridged: CalleeAnalysis_getDestructors(bridged, type.bridged, /*isExactType*/ 1))
33+
if destructors.count == 1 {
34+
return destructors[0]
35+
}
36+
return nil
37+
}
38+
39+
public func getDestructors(of type: Type) -> FunctionArray? {
40+
let bridgedDtors = CalleeAnalysis_getDestructors(bridged, type.bridged, /*isExactType*/ 0)
41+
if bridgedDtors.incomplete != 0 {
42+
return nil
43+
}
44+
return FunctionArray(bridged: bridgedDtors)
2645
}
2746
}
2847

@@ -35,6 +54,4 @@ public struct FunctionArray : RandomAccessCollection, FormattedLikeArray {
3554
public subscript(_ index: Int) -> Function {
3655
return BridgedFunctionArray_get(bridged, index).function
3756
}
38-
39-
public var allCalleesKnown: Bool { bridged.incomplete == 0 }
4057
}

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ReleaseDevirtualizer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ private func tryDevirtualizeReleaseOfObject(
8282

8383
let type = allocRefInstruction.type
8484

85-
guard let dealloc = context.getDestructor(ofClass: type) else {
85+
guard let dealloc = context.calleeAnalysis.getDestructor(ofExactType: type) else {
8686
return
8787
}
8888

SwiftCompilerSources/Sources/Optimizer/PassManager/PassUtils.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,6 @@ struct PassContext {
112112
PassContext_fixStackNesting(_bridged, function.bridged)
113113
}
114114

115-
func getDestructor(ofClass type: Type) -> Function? {
116-
PassContext_getDestructor(_bridged, type.bridged).function
117-
}
118-
119115
func getContextSubstitutionMap(for type: Type) -> SubstitutionMap {
120116
SubstitutionMap(PassContext_getContextSubstitutionMap(_bridged, type.bridged))
121117
}

include/swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class CalleeCache {
147147

148148
/// Return the list of callees that can potentially be called at the
149149
/// given instruction. E.g. it could be destructors.
150-
CalleeList getCalleeList(SILInstruction *I) const;
150+
CalleeList getDestructors(SILType type, bool isExactType) const;
151151

152152
CalleeList getCalleeList(SILDeclRef Decl) const;
153153

@@ -224,9 +224,9 @@ class BasicCalleeAnalysis : public SILAnalysis {
224224
return Cache->getCalleeListOfValue(callee);
225225
}
226226

227-
CalleeList getCalleeList(SILInstruction *I) {
227+
CalleeList getDestructors(SILType type, bool isExactType) {
228228
updateCache();
229-
return Cache->getCalleeList(I);
229+
return Cache->getDestructors(type, isExactType);
230230
}
231231
};
232232

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ BridgedCalleeAnalysis PassContext_getCalleeAnalysis(BridgedPassContext context);
9696

9797
BridgedCalleeList CalleeAnalysis_getCallees(BridgedCalleeAnalysis calleeAnalysis,
9898
BridgedValue callee);
99-
BridgedCalleeList CalleeAnalysis_getInstCallees(BridgedCalleeAnalysis calleeAnalysis,
100-
BridgedInstruction inst);
99+
BridgedCalleeList CalleeAnalysis_getDestructors(BridgedCalleeAnalysis calleeAnalysis,
100+
BridgedType type,
101+
SwiftInt isExactType);
101102
SwiftInt BridgedFunctionArray_size(BridgedCalleeList callees);
102103
BridgedFunction BridgedFunctionArray_get(BridgedCalleeList callees,
103104
SwiftInt index);
@@ -140,9 +141,6 @@ BridgedFunction BasicBlockSet_getFunction(BridgedBasicBlockSet set);
140141

141142
void AllocRefInstBase_setIsStackAllocatable(BridgedInstruction arb);
142143

143-
OptionalBridgedFunction PassContext_getDestructor(BridgedPassContext context,
144-
BridgedType type);
145-
146144
BridgedSubstitutionMap
147145
PassContext_getContextSubstitutionMap(BridgedPassContext context,
148146
BridgedType bridgedType);

lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -287,19 +287,28 @@ CalleeList CalleeCache::getCalleeList(FullApplySite FAS) const {
287287
return getCalleeListForCalleeKind(FAS.getCalleeOrigin());
288288
}
289289

290-
// Return the list of functions that can be called via the given instruction.
291-
CalleeList CalleeCache::getCalleeList(SILInstruction *I) const {
292-
// We support only deallocation instructions at the moment.
293-
assert((isa<StrongReleaseInst>(I) || isa<ReleaseValueInst>(I)) &&
294-
"A deallocation instruction expected");
295-
auto Ty = I->getOperand(0)->getType();
296-
while (auto payloadTy = Ty.getOptionalObjectType())
297-
Ty = payloadTy;
298-
auto Class = Ty.getClassOrBoundGenericClass();
299-
if (!Class || Class->hasClangNode())
290+
/// Return the list of destructors of the class type \p type.
291+
///
292+
/// If \p type is an optional, look through that optional.
293+
/// If \p exactType is true, then \p type is treated like a final class type.
294+
CalleeList CalleeCache::getDestructors(SILType type, bool isExactType) const {
295+
while (auto payloadTy = type.getOptionalObjectType()) {
296+
type = payloadTy;
297+
}
298+
ClassDecl *classDecl = type.getClassOrBoundGenericClass();
299+
if (!classDecl || classDecl->hasClangNode())
300+
return CalleeList();
301+
302+
if (isExactType || classDecl->isFinal()) {
303+
// In case of a final class, just pick the deinit of the class.
304+
SILDeclRef destructor = SILDeclRef(classDecl->getDestructor());
305+
if (SILFunction *destrImpl = M.lookUpFunction(destructor))
306+
return CalleeList(destrImpl);
300307
return CalleeList();
301-
SILDeclRef Destructor = SILDeclRef(Class->getDestructor());
302-
return getCalleeList(Destructor);
308+
}
309+
// If all that doesn't help get the list of deinits as we do for regular class
310+
// methods.
311+
return getCalleeList(SILDeclRef(classDecl->getDestructor()));
303312
}
304313

305314
void BasicCalleeAnalysis::dump() const {
@@ -332,10 +341,11 @@ BridgedCalleeList CalleeAnalysis_getCallees(BridgedCalleeAnalysis calleeAnalysis
332341
return {cl.getOpaquePtr(), cl.getOpaqueKind(), cl.isIncomplete()};
333342
}
334343

335-
BridgedCalleeList CalleeAnalysis_getInstCallees(BridgedCalleeAnalysis calleeAnalysis,
336-
BridgedInstruction inst) {
344+
BridgedCalleeList CalleeAnalysis_getDestructors(BridgedCalleeAnalysis calleeAnalysis,
345+
BridgedType type,
346+
SwiftInt isExactType) {
337347
BasicCalleeAnalysis *bca = static_cast<BasicCalleeAnalysis *>(calleeAnalysis.bca);
338-
CalleeList cl = bca->getCalleeList(castToInst(inst));
348+
CalleeList cl = bca->getDestructors(castToSILType(type), isExactType != 0);
339349
return {cl.getOpaquePtr(), cl.getOpaqueKind(), cl.isIncomplete()};
340350
}
341351

lib/SILOptimizer/Analysis/FunctionOrder.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ void BottomUpFunctionOrder::DFS(SILFunction *Start) {
4343
if (!FAS && !isa<StrongReleaseInst>(&I) && !isa<ReleaseValueInst>(&I))
4444
continue;
4545

46-
auto Callees = FAS ? BCA->getCalleeList(FAS) : BCA->getCalleeList(&I);
46+
auto Callees = FAS ? BCA->getCalleeList(FAS)
47+
: BCA->getDestructors(I.getOperand(0)->getType(),
48+
/*isExactType*/ false);
4749
for (auto *CalleeFn : Callees) {
4850
// If not yet visited, visit the callee.
4951
if (DFSNum.find(CalleeFn) == DFSNum.end()) {

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,19 +1391,6 @@ void AllocRefInstBase_setIsStackAllocatable(BridgedInstruction arb) {
13911391
castToInst<AllocRefInstBase>(arb)->setStackAllocatable();
13921392
}
13931393

1394-
OptionalBridgedFunction PassContext_getDestructor(BridgedPassContext context,
1395-
BridgedType type) {
1396-
auto *cd = castToSILType(type).getClassOrBoundGenericClass();
1397-
assert(cd && "no class type allocated with alloc_ref");
1398-
1399-
auto *pm = castToPassInvocation(context)->getPassManager();
1400-
// Find the destructor of the type.
1401-
auto *destructor = cd->getDestructor();
1402-
SILDeclRef deallocRef(destructor, SILDeclRef::Kind::Deallocator);
1403-
1404-
return {pm->getModule()->lookUpFunction(deallocRef)};
1405-
}
1406-
14071394
BridgedSubstitutionMap
14081395
PassContext_getContextSubstitutionMap(BridgedPassContext context,
14091396
BridgedType bridgedType) {

0 commit comments

Comments
 (0)