Skip to content

Commit 318c308

Browse files
committed
Swift Optimizer: eliminate ARC operations on types which are marked as immortal
A type (mostly classes) can be attributed with `@_semantics("arc.immortal")`. ARC operations on values of such types are eliminated. This is useful for the bridged SIL objects in the swift compiler sources.
1 parent 86444a3 commit 318c308

File tree

6 files changed

+110
-1
lines changed

6 files changed

+110
-1
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyStrongRetainRelease.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ extension StrongReleaseInst : Simplifyable, SILCombineSimplifyable {
6767
/// Returns true if \p value is something where reference counting instructions
6868
/// don't have any effect.
6969
private func isNotReferenceCounted(value: Value) -> Bool {
70+
if value.type.isMarkedAsImmortal {
71+
return true
72+
}
7073
switch value {
7174
case let cfi as ConvertFunctionInst:
7275
return isNotReferenceCounted(value: cfi.fromFunction)

SwiftCompilerSources/Sources/SIL/Type.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
5858
}
5959

6060
public var isCalleeConsumedFunction: Bool { SILType_isCalleeConsumedFunction(bridged) }
61-
61+
62+
public var isMarkedAsImmortal: Bool { SILType_isMarkedAsImmortal(bridged) }
63+
6264
public func getIndexOfEnumCase(withName name: String) -> Int? {
6365
let idx = name._withStringRef {
6466
SILType_getCaseIdxOfEnumType(bridged, $0)

include/swift/AST/SemanticAttrs.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ SEMANTICS_ATTR(OPTIMIZE_SIL_SPECIALIZE_GENERIC_SIZE_NEVER,
7676
SEMANTICS_ATTR(OPTIMIZE_SIL_SPECIALIZE_OWNED2GUARANTEE_NEVER,
7777
"optimize.sil.specialize.owned2guarantee.never")
7878

79+
// To be used on a nominal type declaration.
80+
// Assumes that a class (or class references inside a nominal type) are immortal.
81+
// ARC operations on such types can be eliminated.
82+
// If specified on a protocol declaration, all types which conform to that protocol
83+
// are assumed to be immortal.
84+
SEMANTICS_ATTR(ARC_IMMORTAL, "arc.immortal")
85+
7986
SEMANTICS_ATTR(OSLOG_MESSAGE_TYPE, "oslog.message.type")
8087
SEMANTICS_ATTR(OSLOG_MESSAGE_INIT_INTERPOLATION, "oslog.message.init_interpolation")
8188
SEMANTICS_ATTR(OSLOG_MESSAGE_INIT_STRING_LITERAL, "oslog.message.init_stringliteral")

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ BridgedType SILType_instanceTypeOfMetatype(BridgedType type, BridgedFunction fun
345345
BridgedDecl SILType_getNominal(BridgedType type);
346346
bool SILType_isOrContainsObjectiveCClass(BridgedType type);
347347
bool SILType_isCalleeConsumedFunction(BridgedType type);
348+
bool SILType_isMarkedAsImmortal(BridgedType type);
348349
SwiftInt SILType_getNumTupleElements(BridgedType type);
349350
BridgedType SILType_getTupleElementType(BridgedType type, SwiftInt elementIdx);
350351
SwiftInt SILType_getNumNominalFields(BridgedType type);

lib/SIL/Utils/SILBridging.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/Basic/BridgingUtils.h"
14+
#include "swift/AST/Attr.h"
15+
#include "swift/AST/SemanticAttrs.h"
1416
#include "swift/SIL/SILNode.h"
1517
#include "swift/SIL/ApplySite.h"
1618
#include "swift/SIL/SILBridgingUtils.h"
@@ -587,6 +589,48 @@ bool SILType_isCalleeConsumedFunction(BridgedType type) {
587589
return funcTy->isCalleeConsumed() && !funcTy->isNoEscape();
588590
}
589591

592+
static bool hasImmortalAttr(NominalTypeDecl *nominal) {
593+
if (auto *semAttr = nominal->getAttrs().getAttribute<SemanticsAttr>()) {
594+
if (semAttr->Value == semantics::ARC_IMMORTAL) {
595+
return true;
596+
}
597+
}
598+
return false;
599+
}
600+
601+
static bool isMarkedAsImmortal(NominalTypeDecl *nominal) {
602+
if (hasImmortalAttr(nominal))
603+
return true;
604+
605+
if (!isa<ProtocolDecl>(nominal)) {
606+
for (ProtocolDecl *p : nominal->getAllProtocols()) {
607+
if (hasImmortalAttr(p))
608+
return true;
609+
}
610+
}
611+
return false;
612+
}
613+
614+
bool SILType_isMarkedAsImmortal(BridgedType type) {
615+
SILType ty = castToSILType(type);
616+
NominalTypeDecl *nominal = ty.getNominalOrBoundGenericNominal();
617+
if (!nominal)
618+
return false;
619+
620+
if (isMarkedAsImmortal(nominal))
621+
return true;
622+
623+
if (ClassDecl *cl = dyn_cast<ClassDecl>(nominal)) {
624+
cl = cl->getSuperclassDecl();
625+
while (cl) {
626+
if (isMarkedAsImmortal(cl))
627+
return true;
628+
cl = cl->getSuperclassDecl();
629+
}
630+
}
631+
return false;
632+
}
633+
590634
SwiftInt SILType_getNumTupleElements(BridgedType type) {
591635
TupleType *tupleTy = castToSILType(type).castTo<TupleType>();
592636
return tupleTy->getNumElements();

test/SILOptimizer/immortal-arc-elimination.sil

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,55 @@ bb0:
6161
return %1 : $Builtin.BridgeObject
6262
}
6363

64+
@_semantics("arc.immortal") protocol P : AnyObject {
65+
}
66+
67+
@_semantics("arc.immortal") class C {
68+
init()
69+
}
70+
71+
@_inheritsConvenienceInitializers class D : C {
72+
override init()
73+
}
74+
75+
class E : P {
76+
init()
77+
}
78+
79+
// CHECK-LABEL: sil @testSemanticsOnClass
80+
// CHECK-NOT: retain
81+
// CHECK: } // end sil function 'testSemanticsOnClass'
82+
sil @testSemanticsOnClass : $@convention(thin) (@guaranteed C) -> @owned C {
83+
bb0(%0 : $C):
84+
strong_retain %0 : $C
85+
return %0 : $C // id: %3
86+
}
87+
88+
// CHECK-LABEL: sil @testSemanticsOnDerivedClass
89+
// CHECK-NOT: retain
90+
// CHECK: } // end sil function 'testSemanticsOnDerivedClass'
91+
sil @testSemanticsOnDerivedClass : $@convention(thin) (@guaranteed D) -> @owned D {
92+
bb0(%0 : $D):
93+
strong_retain %0 : $D
94+
return %0 : $D
95+
}
96+
97+
// CHECK-LABEL: sil @testSemanticsOnConformingClass
98+
// CHECK-NOT: retain
99+
// CHECK: } // end sil function 'testSemanticsOnConformingClass'
100+
sil @testSemanticsOnConformingClass : $@convention(thin) (@guaranteed E) -> @owned E {
101+
bb0(%0 : $E):
102+
strong_retain %0 : $E
103+
return %0 : $E
104+
}
105+
106+
// CHECK-LABEL: sil @testSemanticsOnProtocol
107+
// CHECK-NOT: retain
108+
// CHECK: } // end sil function 'testSemanticsOnProtocol'
109+
sil @testSemanticsOnProtocol : $@convention(thin) (@guaranteed any P) -> @owned any P {
110+
bb0(%0 : $any P):
111+
strong_retain %0 : $any P
112+
return %0 : $any P
113+
}
114+
115+

0 commit comments

Comments
 (0)